PSCF v1.4.0
BdSimulator.tpp
1#ifndef RP_BD_SIMULATOR_TPP
2#define RP_BD_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 "BdSimulator.h"
12
13#include <util/param/Factory.h>
14#include <util/param/ParamComposite.h>
15#include <util/random/Random.h>
16#include <util/misc/Timer.h>
17
18namespace Pscf {
19namespace Rp {
20
21 using namespace Util;
22
23 /*
24 * Constructor.
25 */
26 template <int D, class T>
27 BdSimulator<D,T>::BdSimulator(SystemT& system, BdSimulatorT& bdSimulator)
28 : SimulatorT(system),
29 analyzerManagerPtr_(nullptr),
30 bdStepPtr_(nullptr),
31 bdStepFactoryPtr_(nullptr),
32 trajectoryReaderFactoryPtr_(nullptr)
33 {
34 ParamComposite::setClassName("BdSimulator");
35 analyzerManagerPtr_
36 = new typename T::AnalyzerManager(bdSimulator, system),
37 bdStepFactoryPtr_ = new typename T::BdStepFactory(bdSimulator);
38 trajectoryReaderFactoryPtr_
39 = new typename T::TrajectoryReaderFactory(system);
40 AnalyzerT::initStatic();
41 }
42
43 /*
44 * Destructor.
45 */
46 template <int D, class T>
48 {
49 delete analyzerManagerPtr_;
50 if (bdStepFactoryPtr_) {
51 delete bdStepFactoryPtr_;
52 }
53 if (bdStepPtr_) {
54 delete bdStepPtr_;
55 }
56 if (trajectoryReaderFactoryPtr_) {
57 delete trajectoryReaderFactoryPtr_;
58 }
59 }
60
61 /*
62 * Read parameter file block for a BD simulator.
63 */
64 template <int D, class T>
65 void BdSimulator<D,T>::readParameters(std::istream &in)
66 {
67 // Optionally read random seed, initialize random number generators
68 SimulatorT::readRandomSeed(in);
69
70 // Optionally read a BdStep block
71 bool isEnd = false;
72 std::string className;
74 UTIL_CHECK(bdStepFactoryPtr_);
75 bdStepPtr_ =
76 bdStepFactoryPtr_->readObjectOptional(in, *this,
77 className, isEnd);
78 if (!hasBdStep() && ParamComponent::echo()) {
80 << " BdStep{ [absent] }\n";
81 }
82
83 // Compressor is required if a BdStep exists
84 // A Ramp is allowed only if a BdStep exists
85
86 // Optionally read a Compressor block
87 SimulatorT::readCompressor(in, isEnd);
88 if (hasBdStep()) {
89 UTIL_CHECK(SimulatorT::hasCompressor());
90 }
91
92 // Optionally read a Perturbation block
93 SimulatorT::readPerturbation(in, isEnd);
94
95 // Optionally read a Ramp block
96 if (hasBdStep()) {
97 SimulatorT::readRamp(in, isEnd);
98 }
99
100 // Optionally read an AnalyzerManager block
101 AnalyzerT::baseInterval = 0; // default value
102 ParamComposite::readParamCompositeOptional(in, analyzerManager());
103
104 // Figure out what variables need to be saved in stored state()
105 state().needsCc = false;
106 state().needsDc = false;
107 state().needsHamiltonian = false;
108 if (hasBdStep()) {
109 if (bdStep().needsCc()){
110 state().needsCc = true;
111 }
112 if (bdStep().needsDc()){
113 state().needsDc = true;
114 }
115 }
116
117 // Allocate memory for SimulatorT base class
118 SimulatorT::allocate();
119 }
120
121 /*
122 * Setup before main loop of a simulate or analyze command.
123 */
124 template <int D, class T>
125 void BdSimulator<D,T>::setup(int nStep)
126 {
127 UTIL_CHECK(SimulatorT::system().w().hasData());
128
129 // Eigenanalysis of the projected chi matrix.
130 SimulatorT::analyzeChi();
131
132 if (SimulatorT::hasPerturbation()) {
133 SimulatorT::perturbation().setup();
134 }
135
136 if (SimulatorT::hasRamp()) {
137 SimulatorT::ramp().setup(nStep);
138 }
139
140 // Solve MDE and compute c-fields for the intial state
141 SimulatorT::system().compute();
142
143 // Compress the initial state (adjust pressure-like field)
144 if (SimulatorT::hasCompressor()) {
145 SimulatorT::compressor().compress();
146 SimulatorT::compressor().clearTimers();
148
149 // Compute field components and Hamiltonian for initial state.
150 SimulatorT::computeWc();
151 SimulatorT::computeCc();
152 SimulatorT::computeDc();
153 SimulatorT::computeHamiltonian();
154
155 if (hasBdStep()) {
156 bdStep().setup();
157 }
158
159 if (analyzerManager().size() > 0){
160 analyzerManager().setup();
161 }
162
163 }
164
165 /*
166 * Perform a field theoretic MC simulation of nStep steps.
167 */
168 template <int D, class T>
170 {
172 UTIL_CHECK(SimulatorT::hasCompressor());
173 UTIL_CHECK(SimulatorT::system().w().hasData());
174
175 // Initial setup
176 setup(nStep);
177 iStep_ = 0;
178 if (SimulatorT::hasRamp()) {
179 SimulatorT::ramp().setParameters(iStep_);
180 }
181 int analyzerBaseInterval = AnalyzerT::baseInterval;
182
183 // Start timer
184 Timer timer;
185 Timer analyzerTimer;
186 timer.start();
187
188 // Analysis for initial state (if any)
189 analyzerTimer.start();
190 if (analyzerManager().size() > 0) {
191 analyzerManager().sample(iStep_);
192 }
193 analyzerTimer.stop();
194
195 // Main simulation loop
196 for (iTotalStep_ = 0; iTotalStep_ < nStep; ++iTotalStep_) {
197
198 // Take a step (modifies W fields, then applies compressor)
199 bool converged;
200 converged = bdStep().step();
201
202 // Accept step iff compressor converged
203 if (converged){
204 iStep_++;
205
206 if (SimulatorT::hasRamp()) {
207 SimulatorT::ramp().setParameters(iStep_);
208 }
209
210 // Analysis (if any)
211 analyzerTimer.start();
212 if (analyzerBaseInterval != 0) {
213 if (analyzerManager().size() > 0) {
214 if (iStep_ % analyzerBaseInterval == 0) {
215 analyzerManager().sample(iStep_);
216 }
217 }
218 }
219 analyzerTimer.stop();
220
221 } else {
222 Log::file() << "Step: "<< iTotalStep_
223 << " failed to converge" << "\n";
224 }
225
226 }
227 timer.stop();
228 double time = timer.time();
229 double analyzerTime = analyzerTimer.time();
230
231 // Output final analyzer results
232 if (analyzerBaseInterval != 0){
233 analyzerManager().output();
234 }
235
236 // Output results of ramp
237 if (SimulatorT::hasRamp()){
238 Log::file() << std::endl;
239 SimulatorT::ramp().output();
240 }
241
242 // Output times for the simulation run
243 Log::file() << std::endl;
244 Log::file() << "nStep " << nStep << std::endl;
245 if (iStep_ != nStep){
246 Log::file() << "nFail Step " << (nStep - iStep_)
247 << std::endl;
248 }
249 Log::file() << "Total run time " << time
250 << " sec" << std::endl;
251 double rStep = double(nStep);
252 Log::file() << "time / nStep " << time / rStep
253 << " sec" << std::endl;
254 Log::file() << "Analyzer run time " << analyzerTime
255 << " sec" << std::endl;
256 Log::file() << std::endl;
257
258 // Output number of times MDE has been solved for the simulation run
259 Log::file() << "MDE counter "
260 << SimulatorT::compressor().mdeCounter() << std::endl;
261 Log::file() << std::endl;
262
263 }
264
265 /*
266 * Open, read and analyze a trajectory file
267 */
268 template <int D, class T>
270 int max,
271 std::string classname,
272 std::string filename)
273 {
274 // Preconditions
275 UTIL_CHECK(min >= 0);
276 UTIL_CHECK(max >= min);
277 UTIL_CHECK(AnalyzerT::baseInterval > 0);
278 UTIL_CHECK(analyzerManager().size() > 0);
279
280 // Construct TrajectoryReader
281 typename T::TrajectoryReader* trajectoryReaderPtr;
282 trajectoryReaderPtr = trajectoryReaderFactory().factory(classname);
283 if (!trajectoryReaderPtr) {
284 std::string message;
285 message = "Invalid TrajectoryReader class name " + classname;
286 UTIL_THROW(message.c_str());
287 }
288
289 // Open trajectory file
290 trajectoryReaderPtr->open(filename);
291 trajectoryReaderPtr->readHeader();
292
293 // Main loop over trajectory frames
294 Timer timer;
295 timer.start();
296 bool hasFrame = trajectoryReaderPtr->readFrame();
297
298 for (iStep_ = 0; iStep_ <= max && hasFrame; ++iStep_) {
299 if (hasFrame) {
300 SimulatorT::clearData();
301
302 // Initialize analyzers
303 if (iStep_ == min) {
304 setup(iStep_);
305 }
306
307 // Sample property values only for iStep >= min
308 if (iStep_ >= min) {
309 analyzerManager().sample(iStep_);
310 }
311 }
312
313 hasFrame = trajectoryReaderPtr->readFrame();
314 }
315 timer.stop();
316 Log::file() << "end main loop" << std::endl;
317 int nFrames = iStep_ - min;
318 trajectoryReaderPtr->close();
319 delete trajectoryReaderPtr;
320
321 // Output results of all analyzers to output files
322 analyzerManager().output();
323
324 // Output number of frames and times
325 Log::file() << std::endl;
326 Log::file() << "# of frames " << nFrames << std::endl;
327 Log::file() << "run time " << timer.time()
328 << " sec" << std::endl;
329 Log::file() << "time / frame " << timer.time()/double(nFrames)
330 << " sec" << std::endl;
331 Log::file() << std::endl;
332
333 }
334
335 /*
336 * Get the TrajectoryReader factory.
337 */
338 template <int D, class T>
341 {
342 UTIL_CHECK(trajectoryReaderFactoryPtr_);
343 return *trajectoryReaderFactoryPtr_;
344 }
345
346}
347}
348#endif
virtual void readParameters(std::istream &in)
Read parameter file block.
T::BdStep & bdStep()
Get the BdStep by non-const reference.
T::AnalyzerManager & analyzerManager()
Get the AnalyzerManager (const).
typename T::BdSimulator BdSimulatorT
Alias for BdSimulator class in program-level namespace.
Factory< typename T::TrajectoryReader > & trajectoryReaderFactory()
Get the trajectory reader factory by reference.
~BdSimulator()
Destructor.
typename T::System SystemT
Alias for System class in program-level namespace.
virtual void analyze(int min, int max, std::string classname, std::string filename)
Read and analyze a trajectory file.
typename T::Simulator SimulatorT
Alias for Simulator class in program-level namespace.
bool hasBdStep() const
Does this BdSimulator have a BdStep object?
void simulate(int nStep)
Perform a field theoretic Brownian dynamics (BD) simulation.
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.
void readParamCompositeOptional(std::istream &in, ParamComposite &child, bool next=true)
Add and attempt to read an optional child ParamComposite.
Wall clock timer.
Definition Timer.h:35
void start(TimePoint begin)
Start timing from an externally supplied time.
Definition Timer.cpp:49
double time() const
Return the accumulated time, in seconds.
Definition Timer.cpp:37
void stop(TimePoint end)
Stop the clock at an externally supplied time.
Definition Timer.cpp:73
#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
Class templates for real-valued periodic fields.
PSCF package top-level namespace.