PSCF v1.4.0
EinsteinCrystalPerturbation.tpp
1#ifndef RP_EINSTEIN_CRYSTAL_PERTURBATION_TPP
2#define RP_EINSTEIN_CRYSTAL_PERTURBATION_TPP
3
4// Derived classes must include headers for:
5// T::Simulator
6// T::System
7// T::Mixture
8// T::Domain
9// T::VecOp
10// T::Reduce
11
12#include "EinsteinCrystalPerturbation.h"
13#include <prdc/crystal/UnitCell.h>
14#include <util/global.h>
15
16namespace Pscf {
17namespace Rp {
18
19 using namespace Util;
20
21 /*
22 * Constructor.
23 */
24 template <int D, class T>
26 typename T::Simulator& simulator)
27 : PerturbationT(simulator),
28 ecHamiltonian_(0.0),
29 unperturbedHamiltonian_(0.0),
30 stateEcHamiltonian_(0.0),
31 stateUnperturbedHamiltonian_(0.0),
32 hasEpsilon_(false)
33 { ParamComposite::setClassName("EinsteinCrystalPerturbation"); }
34
35 /*
36 * Read parameters from stream, empty default implementation.
37 */
38 template <int D, class T>
40 {
41 ParamComposite::read(in, "lambda", lambda_);
43 // Allocate and initialize epsilon_ array
44 const int nMonomer = system().mixture().nMonomer();
45 epsilon_.allocate(nMonomer - 1);
46 for (int i = 0; i < nMonomer - 1 ; ++i) {
47 epsilon_[i] = 0.0;
48 }
49
50 // Optionally read array of epsilon parameters
51 int nc = nMonomer - 1;
52 hasEpsilon_ = ParamComposite::readOptionalDArray(in, "epsilon",
53 epsilon_, nc).isActive();
55 ParamComposite::read(in, "fieldFileName", fieldFileName_);
56 }
57
58 /*
59 * Setup before simulation.
60 */
61 template <int D, class T>
63 {
64 const int nMonomer = system().mixture().nMonomer();
65 const IntVec<D> meshDimensions
66 = system().domain().mesh().dimensions();
67
68 // Allocate memory for reference field
69 w0_.allocate(nMonomer);
70 wc0_.allocate(nMonomer);
71 for (int i = 0; i < nMonomer; ++i) {
72 w0_[i].allocate(meshDimensions);
73 wc0_[i].allocate(meshDimensions);
74 }
75 dw_.allocate(meshDimensions);
77 /*
78 * If the user did not input epsilon_ values, set values to -1.0
79 * times the nontrivial eigenvalues of the projected chi matrix.
80 */
81 if (!hasEpsilon_){
82 for (int i = 0; i < nMonomer - 1 ; ++i) {
83 epsilon_[i] = -1.0 * simulator().chiEval(i);
84 }
85 }
86
87 // Check that all epsilon values are positive
88 for (int i = 0; i < nMonomer - 1 ; ++i) {
89 UTIL_CHECK(epsilon_[i] > 0.0);
90 }
91
92 // Read in reference field from a file
93 UnitCell<D> tempUnitCell;
94 typename T::FieldIo const & fieldIo = system().domain().fieldIo();
95 fieldIo.readFieldsRGrid(fieldFileName_, w0_, tempUnitCell);
96
97 // Compute eigenvector components of the reference field
98 computeWcReference();
99 }
100
101 /*
102 * Compute and return perturbation to Hamiltonian.
103 */
104 template <int D, class T>
105 double
107 double unperturbedHamiltonian)
108 {
109 // Set unperturbedHamiltonian_ member variable
110 unperturbedHamiltonian_ = unperturbedHamiltonian;
111
112 // Constants
113 const int nMonomer = system().mixture().nMonomer();
114 const double vMonomer = system().mixture().vMonomer();
115 typename T::Domain const & domain = system().domain();
116 const int meshSize = domain.mesh().size();
117 const double vSystem = domain.unitCell().volume();
118 const double nMonomerSystem = vSystem / vMonomer;
119
120 // Compute Einstein crystal Hamiltonian
121 double prefactor;
122 ecHamiltonian_ = 0.0;
123 for (int j = 0; j < nMonomer - 1; ++j) {
124 VecOp::subVV(dw_, simulator().wc(j), wc0_[j]);
125 prefactor = double(nMonomer)/(2.0 * epsilon_[j]);
126 ecHamiltonian_ += prefactor * Reduce::sumSq(dw_);
127 }
128 ecHamiltonian_ /= double(meshSize);
129 ecHamiltonian_ *= nMonomerSystem;
130
131 return (1.0 - lambda_)*(ecHamiltonian_ - unperturbedHamiltonian_);
132 }
133
134 /*
135 * Modify functional derivatives.
136 */
137 template <int D, class T>
138 void
140 {
141 const int nMonomer = system().mixture().nMonomer();
142 const double vMonomer = system().mixture().vMonomer();
143 double prefactor;
144
145 // Loop over composition eigenvectors (exclude the last)
146 for (int i = 0; i < nMonomer - 1; ++i) {
147 prefactor = double(nMonomer) / (epsilon_[i] * vMonomer);
148
149 // dw_ = prefactor * (wc - wc0_)
150 VecOp::subVV(dw_, simulator().wc(i), wc0_[i]);
151 VecOp::mulEqS(dw_, prefactor);
152
153 // dc = dc * lambda_ + dw_ * (1 - lambda_)
154 VecOp::mulEqS(dc[i], lambda_);
155 VecOp::addEqVc(dc[i], dw_, 1.0 - lambda_);
156 }
157 }
158
159 /*
160 * Compute and return derivative of free energy with respect to lambda.
161 */
162 template <int D, class T>
164 { return unperturbedHamiltonian_ - ecHamiltonian_; }
165
166 /*
167 * Save any required internal state variables.
168 */
169 template <int D, class T>
171 {
172 stateEcHamiltonian_ = ecHamiltonian_;
173 stateUnperturbedHamiltonian_ = unperturbedHamiltonian_;
174 }
175
176 /*
177 * Save any required internal state variables.
178 */
179 template <int D, class T>
181 {
182 ecHamiltonian_ = stateEcHamiltonian_;
183 unperturbedHamiltonian_ = stateUnperturbedHamiltonian_;
184 }
185
186 /*
187 * Compute the eigenvector components of the w fields, using the
188 * eigenvectors chiEvecs of the projected chi matrix as a basis.
189 */
190 template <int D, class T>
191 void EinsteinCrystalPerturbation<D,T>::computeWcReference()
192 {
193 const int nMonomer = system().mixture().nMonomer();
194 int i, j;
195
196 // Loop over eigenvectors
197 for (i = 0; i < nMonomer; ++i) {
198
199 // Initialize to zero
200 VecOp::eqS(wc0_[i], 0.0);
201
202 // Loop over monomer types
203 for (j = 0; j < nMonomer; ++j) {
204 double vec = simulator().chiEvecs(i, j)/double(nMonomer);
205 VecOp::addEqVc(wc0_[i], w0_[j], vec);
206 }
207 }
208 }
209
210}
211}
212#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
virtual void setup()
Complete any required initialization.
virtual double hamiltonian(double unperturbedHamiltonian)
Compute and return the perturbation to the Hamiltonian.
EinsteinCrystalPerturbation(typename T::Simulator &simulator)
Constructor.
virtual void saveState()
Save any required internal state variables.
virtual void restoreState()
Restore any required internal state variables.
virtual void incrementDc(DArray< typename T::RField > &dc)
Modify the generalized forces to include perturbation.
virtual double df()
Compute and return derivative of free energy w/ respect to lambda.
virtual void readParameters(std::istream &in)
Read body of parameter file block and initialize.
Dynamically allocatable contiguous array template.
Definition DArray.h:32
DArrayParam< Type > & readOptionalDArray(std::istream &in, const char *label, DArray< Type > &array, int n)
Add and read an optional DArray < Type > parameter.
ScalarParam< Type > & read(std::istream &in, const char *label, Type &value)
Add and read a new required ScalarParam < Type > object.
void setClassName(const char *className)
Set class name string.
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
double sumSq(Array< double > const &in)
Compute sum of of squares of array elements (real).
Definition Reduce.cpp:82
void mulEqS(Array< double > &a, double b)
Vector-scalar in-place multiplication, a[i] *= b (real).
Definition VecOp.cpp:265
void subVV(Array< double > &a, Array< double > const &b, Array< double > const &c)
Vector-vector subtraction, a[i] = b[i] - c[i] (real)
Definition VecOp.cpp:95
void eqS(Array< double > &a, double b)
Vector assignment, a[i] = b (real).
Definition VecOp.cpp:50
void addEqVc(Array< double > &a, Array< double > const &b, const double c)
Add scaled vector in-place, a[i] += b[i]*c (real).
Definition VecOp.cpp:395
Class templates for real-valued periodic fields.
PSCF package top-level namespace.