1#ifndef RP_SIMULATOR_TPP
2#define RP_SIMULATOR_TPP
13#include <pscf/interaction/Interaction.h>
14#include <pscf/chem/PolymerModel.h>
15#include <pscf/math/IntVec.h>
16#include <util/misc/Timer.h>
17#include <util/random/Random.h>
19#include <gsl/gsl_eigen.h>
29 template <
int D,
class T>
31 typename T::Simulator& simulator)
44 simulatorPtr_(&simulator),
46 vecRandomPtr_(nullptr),
47 compressorFactoryPtr_(nullptr),
48 compressorPtr_(nullptr),
49 perturbationFactoryPtr_(nullptr),
50 perturbationPtr_(nullptr),
51 rampFactoryPtr_(nullptr),
57 vecRandomPtr_ =
new typename T::VecRandom();
58 compressorFactoryPtr_ =
new typename T::CompressorFactory(
system);
59 perturbationFactoryPtr_
60 =
new typename T::PerturbationFactory(simulator);
61 rampFactoryPtr_ =
new typename T::RampFactory(simulator);
67 template <
int D,
class T>
70 if (compressorFactoryPtr_) {
71 delete compressorFactoryPtr_;
74 delete compressorPtr_;
76 if (perturbationFactoryPtr_) {
77 delete perturbationFactoryPtr_;
79 if (perturbationPtr_) {
80 delete perturbationPtr_;
82 if (rampFactoryPtr_) {
83 delete rampFactoryPtr_;
93 template <
int D,
class T>
98 const int nMonomer =
system().mixture().nMonomer();
101 chiP_.allocate(nMonomer, nMonomer);
102 chiEvals_.allocate(nMonomer);
103 chiEvecs_.allocate(nMonomer, nMonomer);
104 sc_.allocate(nMonomer);
107 wc_.allocate(nMonomer);
108 cc_.allocate(nMonomer);
110 for (
int i = 0; i < nMonomer; ++i) {
111 wc_[i].allocate(dimensions);
112 cc_[i].allocate(dimensions);
116 dc_.allocate(nMonomer-1);
117 for (
int i = 0; i < nMonomer - 1; ++i) {
118 dc_[i].allocate(dimensions);
122 tmpField_.allocate(dimensions);
125 if (!
state().isAllocated) {
126 state().allocate(nMonomer, dimensions);
137 template <
int D,
class T>
158 template <
int D,
class T>
160 {
UTIL_THROW(
"Error: Unimplemented function Simulator<D,T>::simulate"); }
165 template <
int D,
class T>
167 std::string classname,
168 std::string filename)
169 {
UTIL_THROW(
"Error: Unimplemented function Simulator<D,T>::analyze"); }
174 template <
int D,
class T>
186 template <
int D,
class T>
195 typename T::Mixture
const & mixture =
system().mixture();
196 typename T::Domain
const & domain =
system().domain();
198 const int nMonomer = mixture.nMonomer();
199 const int meshSize = domain.mesh().size();
201 const int np = mixture.nPolymer();
202 const int ns = mixture.nSolvent();
210 typename T::Polymer
const * polymerPtr;
212 for (
int i = 0; i < np; ++i) {
213 polymerPtr = &mixture.polymer(i);
214 phi = polymerPtr->phi();
215 mu = polymerPtr->mu();
217 length = polymerPtr->length();
219 length = (double)polymerPtr->nBead();
230 typename T::Solvent
const * solventPtr;
232 for (
int i = 0; i < ns; ++i) {
233 solventPtr = &mixture.solvent(i);
234 phi = solventPtr->phi();
235 mu = solventPtr->mu();
236 size = solventPtr->size();
239 idealHamiltonian_ += phi * ( mu - 1.0 ) / size;
246 idealHamiltonian_ -= sum_xi / double(meshSize);
251 fieldHamiltonian_ = 0.0;
254 double prefactor, wSquare;
255 for (
int j = 0; j < nMonomer - 1; ++j) {
260 prefactor = -0.5*double(nMonomer)/chiEvals_[j];
261 fieldHamiltonian_ += prefactor * wSquare;
263 fieldHamiltonian_ /= double(meshSize);
266 fieldHamiltonian_ += 0.5*sc_[nMonomer - 1];
271 const double vSystem = domain.unitCell().volume();
272 const double vMonomer = mixture.vMonomer();
273 const double nMonomerSystem = vSystem / vMonomer;
276 fieldHamiltonian_ *= nMonomerSystem;
277 idealHamiltonian_ *= nMonomerSystem;
279 hamiltonian_ = idealHamiltonian_ + fieldHamiltonian_;
282 if (hasPerturbation()) {
283 perturbationHamiltonian_
284 = perturbation().hamiltonian(hamiltonian_);
285 hamiltonian_ += perturbationHamiltonian_;
290 hasHamiltonian_ =
true;
296 template <
int D,
class T>
301 const int nMonomer =
system().mixture().nMonomer();
303 double d = 1.0/double(nMonomer);
309 for (i = 0; i < nMonomer; ++i) {
310 for (j = 0; j < nMonomer; ++j) {
319 for (i = 0; i < nMonomer; ++i) {
320 for (j = 0; j < nMonomer; ++j) {
322 for (k = 0; k < nMonomer; ++k) {
323 CP(i,j) += chi(i,k)*P(k,j);
331 for (i = 0; i < nMonomer; ++i) {
332 for (j = 0; j < nMonomer; ++j) {
334 for (k = 0; k < nMonomer; ++k) {
335 chiP(i,j) += P(i,k)*CP(k,j);
344 gsl_matrix* A = gsl_matrix_alloc(nMonomer, nMonomer);
347 for (i = 0; i < nMonomer; ++i) {
348 for (j = 0; j < nMonomer; ++j) {
349 gsl_matrix_set(A, i, j, chiP(i, j));
354 gsl_eigen_symmv_workspace* work = gsl_eigen_symmv_alloc(nMonomer);
355 gsl_vector* Avals = gsl_vector_alloc(nMonomer);
356 gsl_matrix* Avecs = gsl_matrix_alloc(nMonomer, nMonomer);
358 error = gsl_eigen_symmv(A, Avals, Avecs, work);
370 for (i = 0; i < nMonomer; ++i) {
371 val = gsl_vector_get(Avals, i);
372 if (std::abs(val) < 1.0E-8) {
379 for (j = 0; j < nMonomer; ++j) {
380 chiEvecs_(k, j) = gsl_matrix_get(Avecs, j, i);
382 if (chiEvecs_(k, 0) < 0.0) {
383 for (j = 0; j < nMonomer; ++j) {
384 chiEvecs_(k, j) = -chiEvecs_(k, j);
396 for (j = 0; j < nMonomer; ++j) {
397 chiEvecs_(i, j) = gsl_matrix_get(Avecs, j, iNull);
399 if (chiEvecs_(i, 0) < 0) {
400 for (j = 0; j < nMonomer; ++j) {
401 chiEvecs_(i, j) = -chiEvecs_(i, j);
406 double vec, norm, prefactor;
407 for (i = 0; i < nMonomer; ++i) {
409 for (j = 0; j < nMonomer; ++j) {
410 vec = chiEvecs_(i, j);
413 prefactor = sqrt(
double(nMonomer)/norm );
414 for (j = 0; j < nMonomer; ++j) {
415 chiEvecs_(i, j) *= prefactor;
420 for (j = 0; j < nMonomer; ++j) {
421 UTIL_CHECK(std::abs(chiEvecs_(nMonomer-1, j) - 1.0) < 1.0E-8);
427 for (i = 0; i < nMonomer; ++i) {
429 for (j = 0; j < nMonomer; ++j) {
432 s[i] = s[i]/double(nMonomer);
436 for (i = 0; i < nMonomer; ++i) {
438 for (j = 0; j < nMonomer; ++j) {
439 sc_[i] += chiEvecs_(i,j)*s[j];
441 sc_[i] = sc_[i]/double(nMonomer);
450 template <
int D,
class T>
457 const int nMonomer =
system().mixture().nMonomer();
460 for (i = 0; i < nMonomer; ++i) {
463 typename T::RField& Wc =
wc_[i];
467 for (j = 0; j < nMonomer; ++j) {
468 vec = chiEvecs_(i, j)/double(nMonomer);
480 template <
int D,
class T>
490 const int nMonomer =
system().mixture().nMonomer();
493 for (i = 0; i < nMonomer; ++i) {
496 typename T::RField& Cc =
cc_[i];
500 for (j = 0; j < nMonomer; ++j) {
501 vec = chiEvecs_(i, j);
512 template <
int D,
class T>
521 const int nMonomer =
system().mixture().nMonomer();
522 const double vMonomer =
system().mixture().vMonomer();
523 const double a = 1.0/vMonomer;
527 for (
int i = 0; i < nMonomer - 1; ++i) {
528 typename T::RField& Dc =
dc_[i];
529 typename T::RField
const & Wc =
wc_[i];
530 typename T::RField
const & Cc =
cc_[i];
531 b = -1.0*a*double(nMonomer)/chiEvals_[i];
537 if (hasPerturbation()) {
538 perturbation().incrementDc(dc_);
549 template <
int D,
class T>
557 const int nMonomer =
system().mixture().nMonomer();
560 for (
int i = 0; i < nMonomer; ++i) {
566 if (
state().needsCc) {
569 for (
int i = 0; i < nMonomer; ++i) {
575 if (
state().needsDc) {
578 for (
int i = 0; i < nMonomer - 1; ++i) {
584 if (
state().needsHamiltonian){
596 state().hasData =
true;
605 template <
int D,
class T>
610 const int nMonomer =
system().mixture().nMonomer();
616 for (
int i = 0; i < nMonomer; ++i) {
622 if (state().needsCc) {
623 for (
int i = 0; i < nMonomer; ++i) {
630 if (state().needsDc) {
631 for (
int i = 0; i < nMonomer - 1; ++i) {
632 dc_[i] = state().dc[i];
638 if (
state().needsHamiltonian){
660 template <
int D,
class T>
662 {
state().hasData =
false; }
667 template <
int D,
class T>
672 compressorPtr_->outputTimers(out);
678 template <
int D,
class T>
682 out <<
"MDE counter "
683 << compressorPtr_->mdeCounter() << std::endl;
690 template <
int D,
class T>
702 template <
int D,
class T>
720 template <
int D,
class T>
739 template <
int D,
class T>
743 return *compressorFactoryPtr_;
751 template <
int D,
class T>
770 template <
int D,
class T>
774 return *perturbationFactoryPtr_;
780 template <
int D,
class T>
784 perturbationPtr_ = ptr;
792 template <
int D,
class T>
810 template <
int D,
class T>
814 return *rampFactoryPtr_;
820 template <
int D,
class T>
An IntVec<D, T> is a D-component vector of elements of integer type T.
virtual void clearTimers()
Clear timers.
Random & random()
Get the scalar random number generator by reference.
void saveState()
Save a copy of the current system state.
T::CompressorFactory & compressorFactory()
Get the Compressor factory by reference.
virtual void simulate(int nStep)
Perform a field theoretic Monte-Carlo simulation.
T::PerturbationFactory & perturbationFactory()
Get the Perturbation factory by reference.
bool hasDc_
Have functional derivatives of H[W] been computed ?
void computeHamiltonian()
Compute the Hamiltonian used in PS-FTS.
T::System & system()
Get the parent system by reference.
void readRamp(std::istream &in, bool &isEnd)
bool hasWc_
Have eigen-components of the current w fields been computed ?
void clearData()
Clear field eigen-components and Hamiltonian components.
double fieldHamiltonian_
Quadratic field contribution to Hamiltonian.
DArray< RFieldT > const & dc() const
Get all of the current d fields.
void readPerturbation(std::istream &in, bool &isEnd)
DArray< RFieldT > const & cc() const
Get all eigenvector components of the current c fields.
bool hasCc() const
Are eigen-components of the current c fields valid ?
void computeWc()
Compute eigenvector components of the current w fields.
bool hasHamiltonian_
Has the Hamiltonian been computed for the current w and c fields?
void readCompressor(std::istream &in, bool &isEnd)
bool hasDc() const
Are the current d fields valid ?
void computeCc()
Compute eigenvector components of the current c fields.
bool hasWc() const
Are eigen-components of the current w fields valid ?
void allocate()
Allocate required memory during initialization.
void readRandomSeed(std::istream &in)
virtual void outputMdeCounter(std::ostream &out) const
Simulator(typename T::System &system, typename T::Simulator &simulator)
Constructor.
double idealHamiltonian() const
Get an ideal contribution to the Hamiltonian.
void restoreState()
Restore the system to the saved state.
void setPerturbation(typename T::Perturbation *ptr)
Set the associated Perturbation.
virtual void outputTimers(std::ostream &out) const
Output timing results.
void computeDc()
Compute functional derivatives of the Hamiltonian.
long iTotalStep_
Step counter - total number of attempted BD or MC steps.
bool hasPerturbation() const
Does this Simulator have a Perturbation?
T::RampFactory & rampFactory()
Get the Ramp factory by reference.
bool hasRamp() const
Does this Simulator have a Ramp?
double perturbationHamiltonian() const
Get a perturbation to the standard Hamiltonian.
T::Compressor const & compressor() const
double hamiltonian() const
Get the Hamiltonian used in PS-FTS.
bool hasCompressor() const
bool hasCc_
Have eigen-components of the current c fields been computed ?
virtual void analyze(int min, int max, std::string classname, std::string filename)
Read and analyze a trajectory file.
virtual void readParameters(std::istream &in)
Read parameters for a simulation.
T::Perturbation const & perturbation() const
Get a Perturbation by const reference.
virtual void initializeVecRandom()
Initialize the vector RNG.
long iStep_
Step counter - number of steps for which the compressor converged.
void clearState()
Clear the saved copy of the system state.
double idealHamiltonian_
Ideal gas contribution (-lnQ) to Hamiltonian.
double perturbationHamiltonian_
Perturbation contribution to the Hamiltonian.
long seed_
Random number generator seed (input value).
double hamiltonian_
Total field theoretic Hamiltonian H[W] (extensive value).
void analyzeChi()
Perform eigenvalue analysis of projected chi matrix.
bool hasHamiltonian() const
Has the Hamiltonian been computed for the current w and c fields?
double fieldHamiltonian() const
Get the quadratic field contribution to the Hamiltonian.
void setRamp(typename T::Ramp *ptr)
Set the associated Ramp.
Dynamically allocatable contiguous array template.
void allocate(int capacity)
Allocate the underlying C array.
Dynamically allocated Matrix.
void allocate(int capacity1, int capacity2)
Allocate memory for a matrix.
static std::ostream & file()
Get log ostream by reference.
std::string indent() const
Return indent string for this object (string of spaces).
static bool echo()
Get echo parameter.
void setClassName(const char *className)
Set class name string.
ScalarParam< Type > & readOptional(std::istream &in, const char *label, Type &value)
Add and read a new optional ScalarParam < Type > object.
std::string className() const
Get class name string.
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
double sumSq(Array< double > const &in)
Compute sum of of squares of array elements (real).
double sum(Array< double > const &in)
Compute sum of array elements (real).
void eqS(Array< double > &a, double b)
Vector assignment, a[i] = b (real).
void subVS(Array< double > &a, Array< double > const &b, double c)
Vector-scalar subtraction, a[i] = b[i] - c (real).
void addEqVc(Array< double > &a, Array< double > const &b, const double c)
Add scaled vector in-place, a[i] += b[i]*c (real).
bool isThread()
Is the thread model in use ?
Class templates for real-valued periodic fields.
void addVcVcS(Array< double > &a, Array< double > const &b1, const double c1, Array< double > const &b2, const double c2, const double s)
Add scaled vectors + scalar, a[i] = b1[i]*c1 + b2[2]*c2 + s (real).
PSCF package top-level namespace.