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