PSCF v1.3.3
rpc/fts/simulator/Simulator.tpp
1#ifndef RPC_SIMULATOR_TPP
2#define RPC_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 <rpc/system/System.h>
14#include <rpc/solvers/Mixture.h>
15#include <rpc/solvers/Polymer.h>
16#include <rpc/solvers/Solvent.h>
17#include <rpc/field/Domain.h>
18#include <rpc/fts/compressor/Compressor.h>
19#include <rpc/fts/compressor/CompressorFactory.h>
20#include <rpc/fts/perturbation/Perturbation.h>
21#include <rpc/fts/perturbation/PerturbationFactory.h>
22#include <rpc/fts/ramp/Ramp.h>
23#include <rpc/fts/ramp/RampFactory.h>
24
25#include <pscf/inter/Interaction.h>
26
27#include <util/misc/Timer.h>
28#include <util/random/Random.h>
29#include <util/global.h>
30
31// Gnu scientifie library
32#include <gsl/gsl_eigen.h>
33
34namespace Pscf {
35namespace Rpc {
36
37 using namespace Util;
38
39 /*
40 * Constructor.
41 */
42 template <int D>
43 Simulator<D>::Simulator(System<D>& system)
44 : random_(),
45 hamiltonian_(0.0),
49 iStep_(0),
50 iTotalStep_(0),
51 seed_(0),
52 hasHamiltonian_(false),
53 hasWc_(false),
54 hasCc_(false),
55 hasDc_(false),
56 systemPtr_(&system),
57 compressorFactoryPtr_(nullptr),
58 compressorPtr_(nullptr),
59 perturbationFactoryPtr_(nullptr),
60 perturbationPtr_(nullptr),
61 rampFactoryPtr_(nullptr),
62 rampPtr_(nullptr),
63 isAllocated_(false)
64 {
65 setClassName("Simulator");
66 compressorFactoryPtr_ = new CompressorFactory<D>(system);
67 perturbationFactoryPtr_ = new PerturbationFactory<D>(*this);
68 rampFactoryPtr_ = new RampFactory<D>(*this);
69 }
70
71 /*
72 * Destructor.
73 */
74 template <int D>
76 {
77 if (compressorFactoryPtr_) {
78 delete compressorFactoryPtr_;
79 }
80 if (compressorPtr_ ) {
81 delete compressorPtr_;
82 }
83 if (perturbationFactoryPtr_) {
84 delete perturbationFactoryPtr_;
85 }
86 if (perturbationPtr_) {
87 delete perturbationPtr_;
88 }
89 if (rampFactoryPtr_) {
90 delete rampFactoryPtr_;
91 }
92 if (rampPtr_) {
93 delete rampPtr_;
94 }
95 }
96
97 /*
98 * Allocate required memory.
99 */
100 template <int D>
102 {
103 UTIL_CHECK(!isAllocated_);
104
105 const int nMonomer = system().mixture().nMonomer();
106
107 // Allocate projected chi matrix chiP_ and associated arrays
108 chiP_.allocate(nMonomer, nMonomer);
109 chiEvals_.allocate(nMonomer);
110 chiEvecs_.allocate(nMonomer, nMonomer);
111 sc_.allocate(nMonomer);
112
113 // Allocate memory for eignevector components of w and c fields
114 wc_.allocate(nMonomer);
115 cc_.allocate(nMonomer);
116 const IntVec<D> dimensions = system().domain().mesh().dimensions();
117 for (int i = 0; i < nMonomer; ++i) {
118 wc_[i].allocate(dimensions);
119 cc_[i].allocate(dimensions);
120 }
121
122 // Allocate memory for components of d (functional derivative)
123 dc_.allocate(nMonomer-1);
124 for (int i = 0; i < nMonomer - 1; ++i) {
125 dc_[i].allocate(dimensions);
126 }
127
128 // Allocate state_, if necessary.
129 if (!state_.isAllocated) {
130 const IntVec<D> dimensions = system().domain().mesh().dimensions();
131 state_.allocate(nMonomer, dimensions);
132 }
133
134 isAllocated_ = true;
135 }
136
137 /*
138 * Default implementation - designed to be used by subclasses to read the
139 * initial common part of the parameter file block.
140 */
141 template <int D>
142 void Simulator<D>::readParameters(std::istream &in)
143 {
144 // Optionally read a random number generator seed
145 readRandomSeed(in);
146
147 bool isEnd = false;
148
149 // Read optional Compressor block
150 readCompressor(in, isEnd);
151
152 // Read optional Perturbation block
153 readPerturbation(in, isEnd);
154
155 // Read optional Ramp block
156 readRamp(in, isEnd);
157 }
158
159 /*
160 * Perform a field theoretic simulation (unimplemented by base class).
161 */
162 template <int D>
164 { UTIL_THROW("Error: Unimplemented function Simulator<D>::simulate"); }
165
166 /*
167 * Open, read and analyze a trajectory file (unimplemented by base class).
168 */
169 template <int D>
170 void Simulator<D>::analyze(int min, int max,
171 std::string classname,
172 std::string filename)
173 { UTIL_THROW("Error: Unimplemented function Simulator<D>::analyze"); }
174
175 /*
176 * Clear all local state data (eigen-components of w and Hamiltonian)
177 */
178 template <int D>
180 {
181 hasHamiltonian_ = false;
182 hasWc_ = false;
183 hasCc_ = false;
184 hasDc_ = false;
185 }
186
187 /*
188 * Compute field theoretic Hamiltonian H[W].
189 */
190 template <int D>
192 {
193 UTIL_CHECK(isAllocated_);
194 UTIL_CHECK(system().w().hasData());
195 UTIL_CHECK(system().c().hasData());
197 hasHamiltonian_ = false;
198
199 Mixture<D> const & mixture = system().mixture();
200 Domain<D> const & domain = system().domain();
201
202 const int nMonomer = mixture.nMonomer();
203 const int meshSize = domain.mesh().size();
204
205 const int np = mixture.nPolymer();
206 const int ns = mixture.nSolvent();
207 double phi, mu;
208
209 // Compute polymer ideal gas contributions to lnQ
210 double lnQ = 0.0;
211 if (np > 0) {
212 Polymer<D> const * polymerPtr;
213 double length;
214 for (int i = 0; i < np; ++i) {
215 polymerPtr = &mixture.polymer(i);
216 phi = polymerPtr->phi();
217 mu = polymerPtr->mu();
219 length = polymerPtr->length();
220 } else {
221 length = (double)polymerPtr->nBead();
222 }
223 // Recall: mu = ln(phi/q)
224 if (phi > 1.0E-08) {
225 lnQ += phi*( -mu + 1.0 )/length;
226 }
227 }
228 }
229
230 // Compute solvent ideal gas contributions to lnQ
231 if (ns > 0) {
232 Solvent<D> const * solventPtr;
233 double size;
234 for (int i = 0; i < ns; ++i) {
235 solventPtr = &mixture.solvent(i);
236 phi = solventPtr->phi();
237 mu = solventPtr->mu();
238 size = solventPtr->size();
239 // Recall: mu = ln(phi/q)
240 if (phi > 1.0E-8) {
241 lnQ += phi*( -mu + 1.0 )/size;
242 }
243 }
244 }
245
246 // Subtract average of pressure field wc_[nMonomer-1]
247 RField<D> const & Wc = wc_[nMonomer-1];
248 for (int i = 0; i < meshSize; ++i) {
249 lnQ += Wc[i]/double(meshSize);
250 }
251 // lnQ now contains a value per monomer
252
253 // Initialize field contribution HW
254
255 // Compute quadratic field contribution to HW
256 double HW = 0.0;
257 double prefactor, w, s;
258 int i, j;
259 for (j = 0; j < nMonomer - 1; ++j) {
260 RField<D> const & Wc = wc_[j];
261 prefactor = -0.5*double(nMonomer)/chiEvals_[j];
262 s = sc_[j];
263 for (i = 0; i < meshSize; ++i) {
264 w = Wc[i] - s;
265 HW += prefactor*w*w;
266 }
267 }
268
269 // Normalize HW to equal a value per monomer
270 HW /= double(meshSize);
271
272 // Add constant term K/2 per monomer (K=s=e^{T}chi e/M^2)
273 HW += 0.5*sc_[nMonomer - 1];
274
275 // Compute number of monomers in the system (nMonomerSystem)
276 const double vSystem = domain.unitCell().volume();
277 const double vMonomer = mixture.vMonomer();
278 const double nMonomerSystem = vSystem / vMonomer;
279
280 // Compute final Hamiltonian components
281 fieldHamiltonian_ = nMonomerSystem * HW;
282 idealHamiltonian_ = -1.0 * nMonomerSystem * lnQ;
284
285 if (hasPerturbation()) {
288 } else {
290 }
291
292 hasHamiltonian_ = true;
293 }
294
295 template <int D>
297 {
298 UTIL_CHECK(isAllocated_);
299
300 const int nMonomer = system().mixture().nMonomer();
301 DMatrix<double> const & chi = system().interaction().chi();
302 double d = 1.0/double(nMonomer);
303 int i, j, k;
304
305 // Compute orthogonal projection matrix P
307 P.allocate(nMonomer, nMonomer);
308 for (i = 0; i < nMonomer; ++i) {
309 for (j = 0; j < nMonomer; ++j) {
310 P(i,j) = -d;
311 }
312 P(i,i) += 1.0;
313 }
314
315 // Compute T = chi*P (temporary matrix)
317 T.allocate(nMonomer, nMonomer);
318 for (i = 0; i < nMonomer; ++i) {
319 for (j = 0; j < nMonomer; ++j) {
320 T(i, j) = 0.0;
321 for (k = 0; k < nMonomer; ++k) {
322 T(i,j) += chi(i,k)*P(k,j);
323 }
324 }
325 }
326
327 // Compute chiP = = P*chi*P = P*T
328 DMatrix<double> chiP;
329 chiP.allocate(nMonomer, nMonomer);
330 for (i = 0; i < nMonomer; ++i) {
331 for (j = 0; j < nMonomer; ++j) {
332 chiP(i, j) = 0.0;
333 for (k = 0; k < nMonomer; ++k) {
334 chiP(i,j) += P(i,k)*T(k,j);
335 }
336 }
337 }
338
339 // Eigenvalue calculations use data structures and
340 // functions from the Gnu Scientific Library (GSL)
341
342 // Allocate GSL matrix A that will hold a copy of chiP
343 gsl_matrix* A = gsl_matrix_alloc(nMonomer, nMonomer);
344
345 // Copy DMatrix<double> chiP to gsl_matrix A
346 for (i = 0; i < nMonomer; ++i) {
347 for (j = 0; j < nMonomer; ++j) {
348 gsl_matrix_set(A, i, j, chiP(i, j));
349 }
350 }
351
352 // Compute eigenvalues and eigenvectors of chiP (or A)
353 gsl_eigen_symmv_workspace* work = gsl_eigen_symmv_alloc(nMonomer);
354 gsl_vector* Avals = gsl_vector_alloc(nMonomer);
355 gsl_matrix* Avecs = gsl_matrix_alloc(nMonomer, nMonomer);
356 int error;
357 error = gsl_eigen_symmv(A, Avals, Avecs, work);
358 UTIL_CHECK(error == 0);
359
360 // Requirements:
361 // - A has exactly one zero eigenvalue, with eigenvector (1,...,1)
362 // - All other eigenvalues must be negative.
363
364 // Copy eigenpairs with non-null eigenvalues
365 int iNull = -1; // index for null eigenvalue
366 int nNull = 0; // number of null eigenvalue
367 k = 0; // re-ordered index for non-null eigenvalue
368 double val;
369 for (i = 0; i < nMonomer; ++i) {
370 val = gsl_vector_get(Avals, i);
371 if (std::abs(val) < 1.0E-8) {
372 ++nNull;
373 iNull = i;
374 UTIL_CHECK(nNull <= 1);
375 } else {
376 chiEvals_[k] = val;
377 UTIL_CHECK(val < 0.0);
378 for (j = 0; j < nMonomer; ++j) {
379 chiEvecs_(k, j) = gsl_matrix_get(Avecs, j, i);
380 }
381 if (chiEvecs_(k, 0) < 0.0) {
382 for (j = 0; j < nMonomer; ++j) {
383 chiEvecs_(k, j) = -chiEvecs_(k, j);
384 }
385 }
386 ++k;
387 }
388 }
389 UTIL_CHECK(nNull == 1);
390 UTIL_CHECK(iNull >= 0);
391
392 // Set eigenpair with zero eigenvalue
393 i = nMonomer - 1;
394 chiEvals_[i] = 0.0;
395 for (j = 0; j < nMonomer; ++j) {
396 chiEvecs_(i, j) = gsl_matrix_get(Avecs, j, iNull);
397 }
398 if (chiEvecs_(i, 0) < 0) {
399 for (j = 0; j < nMonomer; ++j) {
400 chiEvecs_(i, j) = -chiEvecs_(i, j);
401 }
402 }
403
404 // Normalize all eigenvectors so that the sum of squares = nMonomer
405 double vec, norm, prefactor;
406 for (i = 0; i < nMonomer; ++i) {
407 norm = 0.0;
408 for (j = 0; j < nMonomer; ++j) {
409 vec = chiEvecs_(i, j);
410 norm += vec*vec;
411 }
412 prefactor = sqrt( double(nMonomer)/norm );
413 for (j = 0; j < nMonomer; ++j) {
414 chiEvecs_(i, j) *= prefactor;
415 }
416 }
417
418 // Check final eigenvector is (1, ..., 1)
419 for (j = 0; j < nMonomer; ++j) {
420 UTIL_CHECK(std::abs(chiEvecs_(nMonomer-1, j) - 1.0) < 1.0E-8);
421 }
422
423 // Compute vector s in monomer basis
425 s.allocate(nMonomer);
426 for (i = 0; i < nMonomer; ++i) {
427 s[i] = 0.0;
428 for (j = 0; j < nMonomer; ++j) {
429 s[i] += chi(i,j);
430 }
431 s[i] = s[i]/double(nMonomer);
432 }
433
434 // Compute components of s in eigenvector basis -> sc_
435 for (i = 0; i < nMonomer; ++i) {
436 sc_[i] = 0.0;
437 for (j = 0; j < nMonomer; ++j) {
438 sc_[i] += chiEvecs_(i,j)*s[j];
439 }
440 sc_[i] = sc_[i]/double(nMonomer);
441 }
442
443 #if 0
444 // Debugging output
445 for (i = 0; i < nMonomer; ++i) {
446 Log::file() << "Eigenpair " << i << "\n";
447 Log::file() << "value = " << chiEvals_[i] << "\n";
448 Log::file() << "vector = [ ";
449 for (j = 0; j < nMonomer; ++j) {
450 Log::file() << chiEvecs_(i, j) << " ";
451 }
452 Log::file() << "]\n";
453 Log::file() << " sc[i] = " << sc_[i] << std::endl;
454 }
455 #endif
456
457 }
458
459 /*
460 * Compute the eigenvector components of the w fields, using the
461 * eigenvectors chiEvecs_ of the projected chi matrix as a basis.
462 */
463 template <int D>
465 {
466 UTIL_CHECK(isAllocated_);
467
468 const int nMonomer = system().mixture().nMonomer();
469 const int meshSize = system().domain().mesh().size();
470 int i, j, k;
471
472 // Loop over eigenvectors (j is an eigenvector index)
473 for (j = 0; j < nMonomer; ++j) {
474
475 // Loop over grid points to zero out field wc_[j]
476 RField<D>& Wc = wc_[j];
477 for (i = 0; i < meshSize; ++i) {
478 Wc[i] = 0.0;
479 }
480
481 // Loop over monomer types (k is a monomer index)
482 for (k = 0; k < nMonomer; ++k) {
483 double vec = chiEvecs_(j, k)/double(nMonomer);
484
485 // Loop over grid points
486 RField<D> const & Wr = system().w().rgrid(k);
487 for (i = 0; i < meshSize; ++i) {
488 Wc[i] += vec*Wr[i];
489 }
490
491 }
492 }
493
494 hasWc_ = true;
495 }
496
497 /*
498 * Compute the eigenvector components of the c-fields, using the
499 * eigenvectors chiEvecs_ of the projected chi matrix as a basis.
500 */
501 template <int D>
503 {
504 // Preconditions
505 UTIL_CHECK(isAllocated_);
506 UTIL_CHECK(system().w().hasData());
507 UTIL_CHECK(system().c().hasData());
508
509 const int nMonomer = system().mixture().nMonomer();
510 const int meshSize = system().domain().mesh().size();
511 int i, j, k;
512
513 // Loop over eigenvectors (i is an eigenvector index)
514 for (i = 0; i < nMonomer; ++i) {
515
516 // Set cc_[i] to zero
517 RField<D>& Cc = cc_[i];
518 for (k = 0; k < meshSize; ++k) {
519 Cc[k] = 0.0;
520 }
521
522 // Loop over monomer types
523 for (j = 0; j < nMonomer; ++j) {
524 RField<D> const & Cr = system().c().rgrid(j);
525 double vec = chiEvecs_(i, j);
526
527 // Loop over grid points
528 for (k = 0; k < meshSize; ++k) {
529 Cc[k] += vec*Cr[k];
530 }
531
532 }
533 }
534
535 hasCc_ = true;
536 }
537
538 /*
539 * Compute d fields, i.e., functional derivatives of H[W].
540 */
541 template <int D>
543 {
544 // Preconditions
545 UTIL_CHECK(isAllocated_);
546 if (!hasWc_) computeWc();
547 if (!hasCc_) computeCc();
548
549 // Local constants and variables
550 const int meshSize = system().domain().mesh().size();
551 const int nMonomer = system().mixture().nMonomer();
552 const double vMonomer = system().mixture().vMonomer();
553 const double a = 1.0/vMonomer;
554 double b, s;
555 int i, k;
556
557 // Compute derivatives for standard Hamiltonian
558 // Loop over composition eigenvectors (exclude the last)
559 for (i = 0; i < nMonomer - 1; ++i) {
560 RField<D>& Dc = dc_[i];
561 RField<D> const & Wc = wc_[i];
562 RField<D> const & Cc = cc_[i];
563 b = -1.0*double(nMonomer)/chiEvals_[i];
564 s = sc_[i];
565 // Loop over grid points
566 for (k = 0; k < meshSize; ++k) {
567 Dc[k] = a*( b*(Wc[k] - s) + Cc[k] );
568 }
569 }
570
571 // Add derivatives arising from a perturbation (if any).
572 if (hasPerturbation()) {
573 perturbation().incrementDc(dc_);
574 }
575
576 hasDc_ = true;
577 }
578
579 /*
580 * Save the current state prior to a next move.
581 *
582 * Invoked before each move.
583 */
584 template <int D>
586 {
587 UTIL_CHECK(system().w().hasData());
588 UTIL_CHECK(hasWc());
589 UTIL_CHECK(state_.isAllocated);
590 UTIL_CHECK(!state_.hasData);
591
592 // Set fields
593 int nMonomer = system().mixture().nMonomer();
594
595 for (int i = 0; i < nMonomer; ++i) {
596 state_.w[i] = system().w().rgrid(i);
597 state_.wc[i] = wc(i);
598 }
599
600 // Save cc based on ccSavePolicy
601 if (state_.needsCc) {
602 UTIL_CHECK(hasCc());
603 UTIL_CHECK(state_.cc.isAllocated());
604 for (int i = 0; i < nMonomer; ++i) {
605 state_.cc[i] = cc(i);
606 }
607 }
608
609 // Save dc based on dcSavePolicy
610 if (state_.needsDc) {
611 UTIL_CHECK(hasDc());
612 UTIL_CHECK(state_.dc.isAllocated());
613 for (int i = 0; i < nMonomer - 1; ++i) {
614 state_.dc[i] = dc(i);
615 }
616 }
617
618 // Save Hamiltonian based on hamiltonianSavePolicy
619 if (state_.needsHamiltonian){
621 state_.hamiltonian = hamiltonian();
622 state_.idealHamiltonian = idealHamiltonian();
623 state_.fieldHamiltonian = fieldHamiltonian();
624 state_.perturbationHamiltonian = perturbationHamiltonian();
625 }
626
627 if (hasPerturbation()) {
628 perturbation().saveState();
629 }
630
631 state_.hasData = true;
632 }
633
634 /*
635 * Restore a saved fts state.
636 *
637 * Invoked after an attempted Monte-Carlo move is rejected
638 * or an fts move fails to converge
639 */
640 template <int D>
642 {
643 UTIL_CHECK(state_.isAllocated);
644 UTIL_CHECK(state_.hasData);
645 const int nMonomer = system().mixture().nMonomer();
646
647 // Restore fields
648 system().w().setRGrid(state_.w);
649
650 // Restore Hamiltonian and components
651 if (state_.needsHamiltonian){
652 hamiltonian_ = state_.hamiltonian;
653 idealHamiltonian_ = state_.idealHamiltonian;
654 fieldHamiltonian_ = state_.fieldHamiltonian;
655 perturbationHamiltonian_ = state_.perturbationHamiltonian;
656 hasHamiltonian_ = true;
657 }
658
659 for (int i = 0; i < nMonomer; ++i) {
660 wc_[i] = state_.wc[i];
661 }
662 hasWc_ = true;
663
664 if (state_.needsCc) {
665 for (int i = 0; i < nMonomer; ++i) {
666 cc_[i] = state_.cc[i];
667 }
668 hasCc_ = true;
669 }
670
671 if (state_.needsDc) {
672 for (int i = 0; i < nMonomer - 1; ++i) {
673 dc_[i] = state_.dc[i];
674 }
675 hasDc_ = true;
676 }
677
678 if (hasPerturbation()) {
679 perturbation().restoreState();
680 }
681
682 state_.hasData = false;
683 }
684
685 /*
686 * Clear the saved Monte-Carlo state.
687 *
688 * Invoked when an attempted Monte-Carlo move is accepted.
689 */
690 template <int D>
692 { state_.hasData = false; }
693
694
695 /*
696 * Output all timer results.
697 */
698 template<int D>
699 void Simulator<D>::outputTimers(std::ostream& out) const
700 {
701 UTIL_CHECK(compressorPtr_);
702 outputMdeCounter(out);
703 compressorPtr_->outputTimers(out);
704 }
705
706 /*
707 * Output modified diffusion equation (MDE) counter.
708 */
709 template<int D>
710 void Simulator<D>::outputMdeCounter(std::ostream& out) const
711 {
712 UTIL_CHECK(compressorPtr_);
713 out << "MDE counter "
714 << compressorPtr_->mdeCounter() << std::endl;
715 out << std::endl;
716 }
717
718 /*
719 * Clear all timers.
720 */
721 template<int D>
723 {
724 UTIL_CHECK(compressorPtr_);
725 compressorPtr_->clearTimers();
726 }
727
728 // Protected Functions
729
730 /*
731 * Optionally read a random number generator seed.
732 */
733 template<int D>
734 void Simulator<D>::readRandomSeed(std::istream& in)
735 {
736 // Optionally read a random number generator seed
737 seed_ = 0;
738 readOptional(in, "seed", seed_);
739
740 // Set random number generator seed
741 // Default value seed_ = 0 uses the clock time.
742 random().setSeed(seed_);
743 }
744
745 /*
746 * Optionally read a Compressor parameter file block.
747 */
748 template<int D>
749 void Simulator<D>::readCompressor(std::istream& in, bool& isEnd)
750 {
751 if (isEnd) return;
752 UTIL_CHECK(compressorFactoryPtr_);
754 std::string className;
755 compressorPtr_ =
756 compressorFactory().readObjectOptional(in, *this,
757 className, isEnd);
758 if (!compressorPtr_ && ParamComponent::echo()) {
759 Log::file() << indent() << " Compressor{ [absent] }\n";
760 }
761 }
762
763 // Functions related to an associated Perturbation
764
765 /*
766 * Optionally read a Perturbation parameter file block.
767 */
768 template<int D>
769 void Simulator<D>::readPerturbation(std::istream& in, bool& isEnd)
770 {
771 if (isEnd) return;
772 UTIL_CHECK(perturbationFactoryPtr_);
774 std::string className;
775 perturbationPtr_ =
776 perturbationFactory().readObjectOptional(in, *this,
777 className, isEnd);
778 if (!perturbationPtr_ && ParamComponent::echo()) {
779 Log::file() << indent() << " Perturbation{ [absent] }\n";
780 }
781 }
782
783 /*
784 * Set the associated Perturbation<D> object.
785 */
786 template<int D>
788 {
789 UTIL_CHECK(ptr);
790 perturbationPtr_ = ptr;
791 }
792
793 // Functions associated with associated Ramp
794
795 /*
796 * Optionally read a Ramp parameter file block.
797 */
798 template<int D>
799 void Simulator<D>::readRamp(std::istream& in, bool& isEnd)
800 {
801 if (isEnd) return;
802 UTIL_CHECK(!rampPtr_);
803
804 std::string className;
805 rampPtr_ =
806 rampFactory().readObjectOptional(in, *this, className, isEnd);
807 if (!rampPtr_ && ParamComponent::echo()) {
808 Log::file() << indent() << " Ramp{ [absent] }\n";
809 }
810 }
811
812 /*
813 * Set the associated Ramp<D> object.
814 */
815 template<int D>
817 {
818 UTIL_CHECK(ptr);
819 rampPtr_ = ptr;
820 }
821
822}
823}
824#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Field of real double precision values on an FFT mesh.
Definition cpu/RField.h:29
SolventT & solvent(int id)
Get a solvent solver object.
PolymerT & polymer(int id)
Get a polymer solver object by non-const reference.
Factory for subclasses of Compressor.
Spatial domain for a periodic structure with real fields, on a CPU.
Mesh< D > & mesh()
Get the Mesh by non-const reference.
UnitCell< D > & unitCell()
Get the UnitCell by non-const reference.
Solver and descriptor for a mixture of polymers and solvents.
int nPolymer() const
Get number of polymer species.
int nMonomer() const
Get number of monomer types.
int nSolvent() const
Get number of solvent (point particle) species.
double vMonomer() const
Get monomer reference volume (set to 1.0 by default).
Factory for subclasses of Perturbation.
Base class for additive perturbations of standard FTS Hamiltonian.
Descriptor and solver for one polymer species.
double phi() const
Get the overall volume fraction for this species.
Definition Species.h:149
int nBead() const
Total number of beads in the polymer (bead model).
double mu() const
Get the chemical potential for this species (units kT=1).
Definition Species.h:155
double length() const
Sum of the lengths of all blocks in the polymer (thread model).
Factory for subclasses of Ramp.
Class that varies parameters during a simulation (abstract).
bool hasCc_
Have eigen-components of the current c fields been computed ?
void readPerturbation(std::istream &in, bool &isEnd)
Optionally read a Perturbation parameter file block.
Perturbation< D > & perturbation()
Get the perturbation factory by non-const reference.
System< D > & system()
Get parent system by reference.
bool hasWc_
Have eigen-components of the current w fields been computed ?
void computeDc()
Compute functional derivatives of the Hamiltonian.
SimState< D > state_
Previous state saved during at the beginning of a step.
bool hasHamiltonian_
Has the Hamiltonian been computed for the current w and c fields?
virtual void analyze(int min, int max, std::string classname, std::string filename)
Read and analyze a trajectory file.
void setClassName(const char *className)
Set class name string.
double perturbationHamiltonian() const
Get the perturbation to the standard Hamiltonian (if any).
void clearState()
Clear the saved copy of the fts state.
PerturbationFactory< D > & perturbationFactory()
Get the perturbation factory by reference.
void computeWc()
Compute eigenvector components of the current w fields.
DArray< RField< D > > const & cc() const
Get all eigenvector components of the current c fields.
void setPerturbation(Perturbation< D > *ptr)
Set the associated Perturbation.
void clearData()
Clear field eigen-components and hamiltonian components.
bool hasDc() const
Are the current d fields valid ?
void analyzeChi()
Perform eigenvalue analysis of projected chi matrix.
double fieldHamiltonian_
Field contribution (H_W) to Hamiltonian.
virtual void outputMdeCounter(std::ostream &out) const
Output MDE counter.
long seed_
Random number generator seed.
virtual void readParameters(std::istream &in)
Read parameters for a simulation.
void allocate()
Allocate required memory.
double idealHamiltonian_
Ideal gas contribution (-lnQ) to Hamiltonian H[W].
virtual void simulate(int nStep)
Perform a field theoretic Monte-Carlo simulation.
void setRamp(Ramp< D > *ptr)
Set the associated ramp.
DArray< RField< D > > wc_
Eigenvector components of w fields on a real space grid.
DArray< RField< D > > dc_
Components of d fields on a real space grid.
bool hasCc() const
Are eigen-components of current c fields valid ?
RampFactory< D > & rampFactory()
Get the ramp factory by reference.
double hamiltonian_
Total field theoretic Hamiltonian H[W] (extensive value).
double perturbationHamiltonian_
Perturbation to the standard Hamiltonian (if any).
virtual void clearTimers()
Clear timers.
bool hasWc() const
Are eigen-components of current w fields valid ?
CompressorFactory< D > & compressorFactory()
Get the compressor factory by reference.
bool hasDc_
Have functional derivatives of H[W] been computed ?
void restoreState()
Restore the saved copy of the fts move state.
void saveState()
Save a copy of the fts move state.
long iTotalStep_
Step counter - total number of attempted BD or MC steps.
double hamiltonian() const
Get the Hamiltonian used in PS-FTS.
bool hasCompressor() const
Does this Simulator have a Compressor?
void readRandomSeed(std::istream &in)
Optionally read a random number generator seed.
bool hasPerturbation() const
Does this Simulator have a Perturbation?
DArray< RField< D > > cc_
Eigenvector components of c fields on a real space grid.
virtual void outputTimers(std::ostream &out) const
Output timing results.
void readCompressor(std::istream &in, bool &isEnd)
Optionally read a Compressor parameter file block.
double fieldHamiltonian() const
Get the quadratic field contribution to the Hamiltonian.
long iStep_
Step counter - attempted steps for which compressor converges.
void readRamp(std::istream &in, bool &isEnd)
Optionally read a Ramp parameter file block.
bool hasHamiltonian() const
Has the Hamiltonian been computed for current w and c fields?
DArray< RField< D > > const & dc() const
Get all of the current d fields.
Random random_
Random number generator.
DArray< RField< D > > const & wc() const
Get all eigenvector components of the current w fields.
void computeHamiltonian()
Compute the Hamiltonian used in PS-FTS.
double idealHamiltonian() const
Get ideal gas contribution to the Hamiltonian.
Random & random()
Get random number generator by reference.
void computeCc()
Compute eigenvector components of the current c fields.
Solver and descriptor for a solvent species.
double phi() const
Get the overall volume fraction for this species.
Definition Species.h:149
double mu() const
Get the chemical potential for this species (units kT=1).
Definition Species.h:155
double size() const
Get the size (number of monomers) in this solvent.
Main class, representing a complete physical system.
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:199
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.
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.
Definition global.h:68
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:49
bool isThread()
Is the thread model in use ?
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.