PSCF v1.4.0
rp/fts/simulator/Simulator.tpp
1#ifndef RP_SIMULATOR_TPP
2#define RP_SIMULATOR_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field
6*
7* Copyright 2015 - 2025, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "Simulator.h"
12
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>
18#include <util/global.h>
19#include <gsl/gsl_eigen.h>
20
21namespace Pscf {
22namespace Rp {
23
24 using namespace Util;
25
26 /*
27 * Constructor.
28 */
29 template <int D, class T>
30 Simulator<D,T>::Simulator(typename T::System& system,
31 typename T::Simulator& simulator)
32 : hamiltonian_(0.0),
36 iStep_(0),
37 iTotalStep_(0),
38 seed_(0),
39 hasHamiltonian_(false),
40 hasWc_(false),
41 hasCc_(false),
42 hasDc_(false),
43 systemPtr_(&system),
44 simulatorPtr_(&simulator),
45 randomPtr_(nullptr),
46 vecRandomPtr_(nullptr),
47 compressorFactoryPtr_(nullptr),
48 compressorPtr_(nullptr),
49 perturbationFactoryPtr_(nullptr),
50 perturbationPtr_(nullptr),
51 rampFactoryPtr_(nullptr),
52 rampPtr_(nullptr),
53 isAllocated_(false)
54 {
56 randomPtr_ = new Random();
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);
62 }
63
64 /*
65 * Destructor.
66 */
67 template <int D, class T>
69 {
70 if (compressorFactoryPtr_) {
71 delete compressorFactoryPtr_;
72 }
73 if (compressorPtr_) {
74 delete compressorPtr_;
75 }
76 if (perturbationFactoryPtr_) {
77 delete perturbationFactoryPtr_;
78 }
79 if (perturbationPtr_) {
80 delete perturbationPtr_;
81 }
82 if (rampFactoryPtr_) {
83 delete rampFactoryPtr_;
84 }
85 if (rampPtr_) {
86 delete rampPtr_;
87 }
88 }
89
90 /*
91 * Allocate required memory.
92 */
93 template <int D, class T>
95 {
96 UTIL_CHECK(!isAllocated_);
97
98 const int nMonomer = system().mixture().nMonomer();
99
100 // Allocate projected chi matrix chiP_ and associated arrays
101 chiP_.allocate(nMonomer, nMonomer);
102 chiEvals_.allocate(nMonomer);
103 chiEvecs_.allocate(nMonomer, nMonomer);
104 sc_.allocate(nMonomer);
105
106 // Allocate memory for eignevector components of w and c fields
107 wc_.allocate(nMonomer);
108 cc_.allocate(nMonomer);
109 const IntVec<D> dimensions = system().domain().mesh().dimensions();
110 for (int i = 0; i < nMonomer; ++i) {
111 wc_[i].allocate(dimensions);
112 cc_[i].allocate(dimensions);
113 }
114
115 // Allocate memory for components of d (functional derivative)
116 dc_.allocate(nMonomer-1);
117 for (int i = 0; i < nMonomer - 1; ++i) {
118 dc_[i].allocate(dimensions);
119 }
120
121 // Allocate memory for r-field used as workspace
122 tmpField_.allocate(dimensions);
124 // Allocate state, if necessary.
125 if (!state().isAllocated) {
126 state().allocate(nMonomer, dimensions);
127 }
128
129 isAllocated_ = true;
130 }
131
132 /*
133 * Read parameter block.
134 *
135 * Virtual function - this default version is only used for unit tests.
136 */
137 template <int D, class T>
138 void Simulator<D,T>::readParameters(std::istream &in)
139 {
140 // Optionally read a random number generator seed
142
143 bool isEnd = false;
144
145 // Optionally read a Compressor block
146 readCompressor(in, isEnd);
147
148 // Optionally read a Perturbation block
149 readPerturbation(in, isEnd);
150
151 // Optionally read a Ramp block
152 readRamp(in, isEnd);
153 }
154
155 /*
156 * Perform a field theoretic simulation (unimplemented default).
157 */
158 template <int D, class T>
160 { UTIL_THROW("Error: Unimplemented function Simulator<D,T>::simulate"); }
161
162 /*
163 * Open, read and analyze a trajectory file (unimplemented default).
164 */
165 template <int D, class T>
166 void Simulator<D,T>::analyze(int min, int max,
167 std::string classname,
168 std::string filename)
169 { UTIL_THROW("Error: Unimplemented function Simulator<D,T>::analyze"); }
170
171 /*
172 * Clear all local state data (field eigen-components and Hamiltonian)
173 */
174 template <int D, class T>
176 {
177 hasHamiltonian_ = false;
178 hasWc_ = false;
179 hasCc_ = false;
180 hasDc_ = false;
182
183 /*
184 * Compute field theoretic Hamiltonian and its components.
185 */
186 template <int D, class T>
188 {
189 UTIL_CHECK(isAllocated_);
190 UTIL_CHECK(system().w().hasData());
191 UTIL_CHECK(system().c().hasData());
193 hasHamiltonian_ = false;
194
195 typename T::Mixture const & mixture = system().mixture();
196 typename T::Domain const & domain = system().domain();
197
198 const int nMonomer = mixture.nMonomer();
199 const int meshSize = domain.mesh().size();
200
201 const int np = mixture.nPolymer();
202 const int ns = mixture.nSolvent();
203 double phi, mu;
204
205 // Compute field Hamiltonian contribution
206 idealHamiltonian_ = 0.0;
207
208 // Polymer ideal gas contribution
209 if (np > 0) {
210 typename T::Polymer const * polymerPtr;
211 double length;
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();
218 } else {
219 length = (double)polymerPtr->nBead();
220 }
221 // Recall: mu = ln(phi/q)
222 if (phi > 1.0E-08) {
223 idealHamiltonian_ += phi * ( mu - 1.0 ) / length;
224 }
225 }
226 }
227
228 // Compute solvent ideal gas contributions to idealHamiltonian_
229 if (ns > 0) {
230 typename T::Solvent const * solventPtr;
231 double size;
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();
237 // Recall: mu = ln(phi/q)
238 if (phi > 1.0E-8) {
239 idealHamiltonian_ += phi * ( mu - 1.0 ) / size;
240 }
241 }
242 }
243
244 // Subtract spatial average of pressure field from idealHamiltonian_
245 double sum_xi = Reduce::sum(wc_[nMonomer-1]);
246 idealHamiltonian_ -= sum_xi / double(meshSize);
247
248 // idealHamiltonian_ now contains a final value per monomer
249
250 // Compute field Hamiltonian contribution
251 fieldHamiltonian_ = 0.0;
252
253 // Quadratic field contribution
254 double prefactor, wSquare;
255 for (int j = 0; j < nMonomer - 1; ++j) {
256 UTIL_CHECK(tmpField_.capacity() == meshSize);
257 // Subtract constant shift sc_[j]
258 VecOp::subVS(tmpField_, wc_[j], sc_[j]);
259 wSquare = Reduce::sumSq(tmpField_);
260 prefactor = -0.5*double(nMonomer)/chiEvals_[j];
261 fieldHamiltonian_ += prefactor * wSquare;
262 }
263 fieldHamiltonian_ /= double(meshSize);
264
265 // Add constant term K/2 per monomer ( K = s = e^{T}chi e/M^2 )
266 fieldHamiltonian_ += 0.5*sc_[nMonomer - 1];
267
268 // fieldHamiltonian_ now contains a final value per monomer
269
270 // Compute nMonomerSystem = number of monomers in the system
271 const double vSystem = domain.unitCell().volume();
272 const double vMonomer = mixture.vMonomer();
273 const double nMonomerSystem = vSystem / vMonomer;
274
275 // Convert per monomer values to extensive values
276 fieldHamiltonian_ *= nMonomerSystem;
277 idealHamiltonian_ *= nMonomerSystem;
278
279 hamiltonian_ = idealHamiltonian_ + fieldHamiltonian_;
280
281 // Add perturbationHamiltonian_, if any
282 if (hasPerturbation()) {
283 perturbationHamiltonian_
284 = perturbation().hamiltonian(hamiltonian_);
285 hamiltonian_ += perturbationHamiltonian_;
286 } else {
288 }
289
290 hasHamiltonian_ = true;
291 }
292
293 /*
294 * Compute eigenvalues and eigenvectors of the projected chi matrix.
295 */
296 template <int D, class T>
298 {
299 UTIL_CHECK(isAllocated_);
300
301 const int nMonomer = system().mixture().nMonomer();
302 DMatrix<double> const & chi = system().interaction().chi();
303 double d = 1.0/double(nMonomer);
304 int i, j, k;
305
306 // Compute orthogonal projection matrix P
308 P.allocate(nMonomer, nMonomer);
309 for (i = 0; i < nMonomer; ++i) {
310 for (j = 0; j < nMonomer; ++j) {
311 P(i,j) = -d;
312 }
313 P(i,i) += 1.0;
314 }
315
316 // Compute CP = chi*P (temporary matrix)
318 CP.allocate(nMonomer, nMonomer);
319 for (i = 0; i < nMonomer; ++i) {
320 for (j = 0; j < nMonomer; ++j) {
321 CP(i, j) = 0.0;
322 for (k = 0; k < nMonomer; ++k) {
323 CP(i,j) += chi(i,k)*P(k,j);
324 }
325 }
326 }
327
328 // Compute chiP = = P*chi*P = P*CP
329 DMatrix<double> chiP;
330 chiP.allocate(nMonomer, nMonomer);
331 for (i = 0; i < nMonomer; ++i) {
332 for (j = 0; j < nMonomer; ++j) {
333 chiP(i, j) = 0.0;
334 for (k = 0; k < nMonomer; ++k) {
335 chiP(i,j) += P(i,k)*CP(k,j);
336 }
337 }
338 }
339
340 // Eigenvalue calculations use data structures and
341 // functions from the Gnu Scientific Library (GSL)
342
343 // Allocate GSL matrix A that will hold a copy of chiP
344 gsl_matrix* A = gsl_matrix_alloc(nMonomer, nMonomer);
345
346 // Copy DMatrix<double> chiP to gsl_matrix A
347 for (i = 0; i < nMonomer; ++i) {
348 for (j = 0; j < nMonomer; ++j) {
349 gsl_matrix_set(A, i, j, chiP(i, j));
350 }
351 }
352
353 // Compute eigenvalues and eigenvectors of chiP (or A)
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);
357 int error;
358 error = gsl_eigen_symmv(A, Avals, Avecs, work);
359 UTIL_CHECK(error == 0);
360
361 // Requirements:
362 // - A has exactly one zero eigenvalue, with eigenvector (1,...,1)
363 // - All other eigenvalues must be negative.
364
365 // Copy eigenpairs with non-null eigenvalues
366 int iNull = -1; // index for null eigenvalue
367 int nNull = 0; // number of null eigenvalue
368 k = 0; // re-ordered index for non-null eigenvalue
369 double val;
370 for (i = 0; i < nMonomer; ++i) {
371 val = gsl_vector_get(Avals, i);
372 if (std::abs(val) < 1.0E-8) {
373 ++nNull;
374 iNull = i;
375 UTIL_CHECK(nNull <= 1);
376 } else {
377 chiEvals_[k] = val;
378 UTIL_CHECK(val < 0.0);
379 for (j = 0; j < nMonomer; ++j) {
380 chiEvecs_(k, j) = gsl_matrix_get(Avecs, j, i);
381 }
382 if (chiEvecs_(k, 0) < 0.0) {
383 for (j = 0; j < nMonomer; ++j) {
384 chiEvecs_(k, j) = -chiEvecs_(k, j);
385 }
386 }
387 ++k;
388 }
389 }
390 UTIL_CHECK(nNull == 1);
391 UTIL_CHECK(iNull >= 0);
392
393 // Set eigenpair with zero eigenvalue
394 i = nMonomer - 1;
395 chiEvals_[i] = 0.0;
396 for (j = 0; j < nMonomer; ++j) {
397 chiEvecs_(i, j) = gsl_matrix_get(Avecs, j, iNull);
398 }
399 if (chiEvecs_(i, 0) < 0) {
400 for (j = 0; j < nMonomer; ++j) {
401 chiEvecs_(i, j) = -chiEvecs_(i, j);
402 }
403 }
404
405 // Normalize all eigenvectors so that the sum of squares = nMonomer
406 double vec, norm, prefactor;
407 for (i = 0; i < nMonomer; ++i) {
408 norm = 0.0;
409 for (j = 0; j < nMonomer; ++j) {
410 vec = chiEvecs_(i, j);
411 norm += vec*vec;
412 }
413 prefactor = sqrt( double(nMonomer)/norm );
414 for (j = 0; j < nMonomer; ++j) {
415 chiEvecs_(i, j) *= prefactor;
417 }
418
419 // Check final eigenvector is (1, ..., 1)
420 for (j = 0; j < nMonomer; ++j) {
421 UTIL_CHECK(std::abs(chiEvecs_(nMonomer-1, j) - 1.0) < 1.0E-8);
422 }
423
424 // Compute vector s in monomer basis
426 s.allocate(nMonomer);
427 for (i = 0; i < nMonomer; ++i) {
428 s[i] = 0.0;
429 for (j = 0; j < nMonomer; ++j) {
430 s[i] += chi(i,j);
431 }
432 s[i] = s[i]/double(nMonomer);
433 }
434
435 // Compute components of s in eigenvector basis -> sc_
436 for (i = 0; i < nMonomer; ++i) {
437 sc_[i] = 0.0;
438 for (j = 0; j < nMonomer; ++j) {
439 sc_[i] += chiEvecs_(i,j)*s[j];
440 }
441 sc_[i] = sc_[i]/double(nMonomer);
442 }
443
444 }
445
446 /*
447 * Compute the eigenvector components of the w fields, using the
448 * eigenvectors chiEvecs_ of the projected chi matrix as a basis.
449 */
450 template <int D, class T>
452 {
453 UTIL_CHECK(isAllocated_);
454
455 double vec;
456 int i, j;
457 const int nMonomer = system().mixture().nMonomer();
458
459 // Loop over eigenvectors (i is an eigenvector index)
460 for (i = 0; i < nMonomer; ++i) {
461
462 // Initialize field wc_[i] to zero
463 typename T::RField& Wc = wc_[i];
464 VecOp::eqS(Wc, 0.0);
465
466 // Loop over monomer types (j is a monomer index)
467 for (j = 0; j < nMonomer; ++j) {
468 vec = chiEvecs_(i, j)/double(nMonomer);
469 VecOp::addEqVc(Wc, system().w().rgrid(j), vec);
470 }
471 }
472
473 hasWc_ = true;
474 }
475
476 /*
477 * Compute the eigenvector components of the c-fields, using the
478 * eigenvectors chiEvecs_ of the projected chi matrix as a basis.
479 */
480 template <int D, class T>
482 {
483 // Preconditions
484 UTIL_CHECK(isAllocated_);
485 UTIL_CHECK(system().w().hasData());
486 UTIL_CHECK(system().c().hasData());
487
488 double vec;
489 int i, j;
490 const int nMonomer = system().mixture().nMonomer();
491
492 // Loop over eigenvectors (i is an eigenvector index)
493 for (i = 0; i < nMonomer; ++i) {
494
495 // Initialize field cc_[i] to zero
496 typename T::RField& Cc = cc_[i];
497 VecOp::eqS(Cc, 0.0);
498
499 // Loop over monomer types (j is a monomer index)
500 for (j = 0; j < nMonomer; ++j) {
501 vec = chiEvecs_(i, j);
502 VecOp::addEqVc(Cc, system().c().rgrid(j), vec);
503 }
504 }
505
506 hasCc_ = true;
507 }
508
509 /*
510 * Compute d fields, i.e., functional derivatives of H[W].
511 */
512 template <int D, class T>
514 {
515 // Preconditions
516 UTIL_CHECK(isAllocated_);
517 if (!hasWc_) computeWc();
519
520 // Local constants and variables
521 const int nMonomer = system().mixture().nMonomer();
522 const double vMonomer = system().mixture().vMonomer();
523 const double a = 1.0/vMonomer;
524 double b, s;
525
526 // Loop over composition eigenvectors (exclude the last)
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];
532 s = -1.0*b*sc_[i];
533 VecOp::addVcVcS(Dc, Cc, a, Wc, b, s);
534 }
535
536 // Add derivatives arising from a perturbation (if any).
537 if (hasPerturbation()) {
538 perturbation().incrementDc(dc_);
539 }
540
541 hasDc_ = true;
542 }
543
544 /*
545 * Save the current state prior to a next move.
546 *
547 * Invoked before each attempted move.
548 */
549 template <int D, class T>
551 {
552 UTIL_CHECK(system().w().hasData());
553 UTIL_CHECK(hasWc());
554 UTIL_CHECK(state().isAllocated);
555 UTIL_CHECK(!state().hasData);
556
557 const int nMonomer = system().mixture().nMonomer();
558
559 // Save all w-field components
560 for (int i = 0; i < nMonomer; ++i) {
561 state().w[i] = system().w().rgrid(i);
562 state().wc[i] = wc_[i];
563 }
564
565 // Save cc, if needed
566 if (state().needsCc) {
567 UTIL_CHECK(hasCc());
568 UTIL_CHECK(state().cc.isAllocated());
569 for (int i = 0; i < nMonomer; ++i) {
570 state().cc[i] = cc_[i];
571 }
572 }
573
574 // Save dc, if needed
575 if (state().needsDc) {
576 UTIL_CHECK(hasDc());
577 UTIL_CHECK(state().dc.isAllocated());
578 for (int i = 0; i < nMonomer - 1; ++i) {
579 state().dc[i] = dc_[i];
580 }
581 }
582
583 // Save Hamiltonian and its components, if needed
584 if (state().needsHamiltonian){
586 state().hamiltonian = hamiltonian();
587 state().idealHamiltonian = idealHamiltonian();
588 state().fieldHamiltonian = fieldHamiltonian();
589 state().perturbationHamiltonian = perturbationHamiltonian();
590 }
591
592 if (hasPerturbation()) {
593 perturbation().saveState();
594 }
595
596 state().hasData = true;
597 }
598
599 /*
600 * Restore a saved simulation state.
601 *
602 * Invoked after the compressor fails to converge or an attempted
603 * Monte-Carlo move is rejected.
604 */
605 template <int D, class T>
607 {
608 UTIL_CHECK(state().isAllocated);
609 UTIL_CHECK(state().hasData);
610 const int nMonomer = system().mixture().nMonomer();
611
612 // Restore monomer w-field components
613 system().w().setRGrid(state().w);
614
615 // Restore wc_ field components
616 for (int i = 0; i < nMonomer; ++i) {
617 wc_[i] = state().wc[i];
618 }
619 hasWc_ = true;
620
621 // Restore cc_ c-field components, if needed
622 if (state().needsCc) {
623 for (int i = 0; i < nMonomer; ++i) {
624 cc_[i] = state().cc[i];
625 }
626 hasCc_ = true;
627 }
628
629 // Restore dc_ fieldc components, if needed
630 if (state().needsDc) {
631 for (int i = 0; i < nMonomer - 1; ++i) {
632 dc_[i] = state().dc[i];
633 }
634 hasDc_ = true;
635 }
637 // Restore Hamiltonian and its components, if needed
638 if (state().needsHamiltonian){
639 hamiltonian_ = state().hamiltonian;
640 idealHamiltonian_ = state().idealHamiltonian;
641 fieldHamiltonian_ = state().fieldHamiltonian;
642 perturbationHamiltonian_ = state().perturbationHamiltonian;
643 hasHamiltonian_ = true;
644 }
645
646 // Restore internal state of perturbation, if any
648 perturbation().restoreState();
649 }
650
651 // Clear internal state of SimState object
652 state().hasData = false;
653 }
654
655 /*
656 * Clear the saved system state.
657 *
658 * Invoked when an attempted move is accepted.
659 */
660 template <int D, class T>
662 { state().hasData = false; }
664 /*
665 * Output all timer results.
666 */
667 template <int D, class T>
668 void Simulator<D,T>::outputTimers(std::ostream& out) const
669 {
670 UTIL_CHECK(compressorPtr_);
671 outputMdeCounter(out);
672 compressorPtr_->outputTimers(out);
673 }
674
675 /*
676 * Output modified diffusion equation (MDE) counter.
677 */
678 template <int D, class T>
679 void Simulator<D,T>::outputMdeCounter(std::ostream& out) const
680 {
681 UTIL_CHECK(compressorPtr_);
682 out << "MDE counter "
683 << compressorPtr_->mdeCounter() << std::endl;
684 out << std::endl;
685 }
687 /*
688 * Clear all timers.
689 */
690 template <int D, class T>
692 {
694 compressor().clearTimers();
695 }
696
697 // Protected Functions
698
699 /*
700 * Optionally read RNG seed, initialize random number generators.
701 */
702 template <int D, class T>
703 void Simulator<D,T>::readRandomSeed(std::istream& in)
704 {
705 // Optionally read a random number generator seed
706 seed_ = 0;
707 readOptional(in, "seed", seed_);
708
709 // Set random number generator seeds on CPU and GPU
710 // Default value seed_ = 0 uses the clock time.
711 random().setSeed(seed_);
713 }
714
715 // Functions related to a Compressor
716
717 /*
718 * Optionally read a Compressor parameter file block.
719 */
720 template <int D, class T>
721 void Simulator<D,T>::readCompressor(std::istream& in, bool& isEnd)
722 {
723 if (!isEnd) {
724 UTIL_CHECK(compressorFactoryPtr_);
726 std::string className;
727 compressorPtr_ =
728 compressorFactory().readObjectOptional(in, *this,
729 className, isEnd);
730 }
731 if (!compressorPtr_ && ParamComponent::echo()) {
732 Log::file() << indent() << " Compressor{ [absent] }\n";
733 }
734 }
735
736 /*
737 * Get the Compressor factory by reference.
738 */
739 template <int D, class T>
740 typename T::CompressorFactory& Simulator<D,T>::compressorFactory()
741 {
742 UTIL_CHECK(compressorFactoryPtr_);
743 return *compressorFactoryPtr_;
744 }
745
746 // Functions related to a Perturbation
747
748 /*
749 * Optionally read a Perturbation parameter file block.
750 */
751 template <int D, class T>
752 void Simulator<D,T>::readPerturbation(std::istream& in, bool& isEnd)
753 {
754 if (!isEnd) {
755 UTIL_CHECK(perturbationFactoryPtr_);
757 std::string className;
758 perturbationPtr_ =
759 perturbationFactory().readObjectOptional(in, *this,
760 className, isEnd);
761 }
762 if (!perturbationPtr_ && ParamComponent::echo()) {
763 Log::file() << indent() << " Perturbation{ [absent] }\n";
764 }
765 }
766
767 /*
768 * Get the Perturbation factory by reference.
769 */
770 template <int D, class T>
771 typename T::PerturbationFactory& Simulator<D,T>::perturbationFactory()
772 {
773 UTIL_CHECK(perturbationFactoryPtr_);
774 return *perturbationFactoryPtr_;
775 }
776
777 /*
778 * Set the associated Perturbation object.
779 */
780 template <int D, class T>
781 void Simulator<D,T>::setPerturbation(typename T::Perturbation* ptr)
782 {
783 UTIL_CHECK(ptr);
784 perturbationPtr_ = ptr;
785 }
786
787 // Functions related to a Ramp
788
789 /*
790 * Optionally read a Ramp parameter file block.
791 */
792 template <int D, class T>
793 void Simulator<D,T>::readRamp(std::istream& in, bool& isEnd)
794 {
795 if (!isEnd) {
796 UTIL_CHECK(rampFactoryPtr_);
798 std::string className;
799 rampPtr_ =
800 rampFactory().readObjectOptional(in, *this, className, isEnd);
801 }
802 if (!rampPtr_ && ParamComponent::echo()) {
803 Log::file() << indent() << " Ramp{ [absent] }\n";
804 }
805 }
806
807 /*
808 * Get the Ramp factory by reference.
809 */
810 template <int D, class T>
811 typename T::RampFactory& Simulator<D,T>::rampFactory()
812 {
813 UTIL_CHECK(rampFactoryPtr_);
814 return *rampFactoryPtr_;
815 }
816
817 /*
818 * Set the associated Ramp object.
819 */
820 template <int D, class T>
821 void Simulator<D,T>::setRamp(typename T::Ramp* ptr)
822 {
823 UTIL_CHECK(ptr);
824 rampPtr_ = ptr;
825 }
826
827} // namespace Rp
828} // namespace Pscf
829#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
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.
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 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.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:269
Dynamically allocated Matrix.
Definition DMatrix.h:25
void allocate(int capacity1, int capacity2)
Allocate memory for a matrix.
Definition DMatrix.h:170
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:59
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.
Random number generator.
Definition Random.h:47
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:49
double sumSq(Array< double > const &in)
Compute sum of of squares of array elements (real).
Definition Reduce.cpp:82
double sum(Array< double > const &in)
Compute sum of array elements (real).
Definition Reduce.cpp:20
void eqS(Array< double > &a, double b)
Vector assignment, a[i] = b (real).
Definition VecOp.cpp:50
void subVS(Array< double > &a, Array< double > const &b, double c)
Vector-scalar subtraction, a[i] = b[i] - c (real).
Definition VecOp.cpp:110
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
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).
Definition VecOp.cpp:409
PSCF package top-level namespace.