PSCF v1.3.2
rpc/fts/montecarlo/McSimulator.tpp
1#ifndef RPC_MC_SIMULATOR_TPP
2#define RPC_MC_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 "McSimulator.h"
12
13#include <rpc/system/System.h>
14#include <rpc/fts/montecarlo/McMoveFactory.h>
15#include <rpc/fts/analyzer/AnalyzerFactory.h>
16#include <rpc/fts/trajectory/TrajectoryReader.h>
17#include <rpc/fts/trajectory/TrajectoryReaderFactory.h>
18#include <rpc/fts/compressor/Compressor.h>
19#include <rpc/fts/perturbation/PerturbationFactory.h>
20#include <rpc/fts/perturbation/Perturbation.h>
21#include <rpc/fts/ramp/RampFactory.h>
22#include <rpc/fts/ramp/Ramp.h>
23
24#include <util/random/Random.h>
25#include <util/misc/Timer.h>
26#include <util/global.h>
27
28#include <gsl/gsl_eigen.h>
29
30namespace Pscf {
31namespace Rpc {
32
33 using namespace Util;
34
35 /*
36 * Constructor.
37 */
38 template <int D>
40 : Simulator<D>(system),
41 mcMoveManager_(*this, system),
42 analyzerManager_(*this, system),
43 trajectoryReaderFactoryPtr_(nullptr)
44 {
45 setClassName("McSimulator");
46 trajectoryReaderFactoryPtr_
48 }
49
50 /*
51 * Destructor.
52 */
53 template <int D>
55 {
56 if (trajectoryReaderFactoryPtr_) {
57 delete trajectoryReaderFactoryPtr_;
58 }
59 }
60
61 /*
62 * Read parameter file block.
63 */
64 template <int D>
65 void McSimulator<D>::readParameters(std::istream &in)
66 {
67 // Read optional random seed value
69
70 // Read optional McMoveManager block
71 readParamCompositeOptional(in, mcMoveManager_);
72
73 bool isEnd = false;
74
75 // Read optionally Compressor block
76 readCompressor(in, isEnd);
77 if (hasMcMoves()) {
79 }
80
81 // Read optional Perturbation and/or Ramp blocks
82 readPerturbation(in, isEnd);
83 if (hasMcMoves()) {
84 readRamp(in, isEnd);
85 }
86
87 // Read optional AnalyzerManager block
88 Analyzer<D>::baseInterval = 0; // default value
89 readParamCompositeOptional(in, analyzerManager_);
90
91 // Figure out what needs to be saved
92 state_.needsCc = false;
93 state_.needsDc = false;
94 state_.needsHamiltonian = true;
95 if (mcMoveManager_.needsCc()){
96 state_.needsCc = true;
97 }
98 if (mcMoveManager_.needsDc()){
99 state_.needsDc = true;
100 }
101
102 // Initialize Simulator<D> base class
104
105 }
106
107 /*
108 * Initialize just prior to a run.
109 */
110 template <int D>
111 void McSimulator<D>::setup(int nStep)
112 {
113 UTIL_CHECK(system().w().hasData());
114
115 // Eigenanalysis of the projected chi matrix.
116 analyzeChi();
117
118 if (hasPerturbation()) {
119 perturbation().setup();
120 }
121
122 if (hasRamp()) {
123 ramp().setup(nStep);
124 }
125
126 // Solve MDE and compute c-fields for the intial state
127 system().compute();
128
129 // Compress the initial state (adjust pressure-like field)
130 if (hasCompressor()) {
131 compressor().compress();
132 compressor().clearTimers();
133 }
134
135 // Compute field components and Hamiltonian
136 computeWc();
137 if (state_.needsCc || state_.needsDc) {
138 computeCc();
139 }
140 if (state_.needsDc) {
141 computeDc();
142 }
143 computeHamiltonian();
144
145 mcMoveManager_.setup();
146 if (analyzerManager_.size() > 0){
147 analyzerManager_.setup();
148 }
149
150 }
151
152 /*
153 * Perform a field theoretic MC simulation of nStep steps.
154 */
155 template <int D>
157 {
160
161 // Initial setup
162 setup(nStep);
163
164 Log::file() << std::endl;
165
166 // Initialize timer, iStep_, and ramp (if any)
167 Timer timer;
168 Timer analyzerTimer;
169 timer.start();
170 iStep_ = 0;
171 if (hasRamp()) {
172 ramp().setParameters(iStep_);
173 }
174
175 // Analysis initial step (if any)
176 analyzerTimer.start();
177 analyzerManager_.sample(iStep_);
178 analyzerTimer.stop();
179
180 // Main Monte Carlo loop
181 for (iTotalStep_ = 0; iTotalStep_ < nStep; ++iTotalStep_) {
182
183 // Choose and attempt an McMove
184 bool converged;
185 converged = mcMoveManager_.chooseMove().move();
186
187 if (converged){
188 iStep_++;
189
190 if (hasRamp()) {
191 ramp().setParameters(iStep_);
192 }
193
194 // Analysis (if any)
195 analyzerTimer.start();
196 if (Analyzer<D>::baseInterval != 0) {
198 if (analyzerManager_.size() > 0) {
199 analyzerManager_.sample(iStep_);
200 }
201 }
202 }
203 analyzerTimer.stop();
204
205 } else{
206 Log::file() << "Step: "<< iTotalStep_
207 << " failed to converge" << "\n";
208 }
209 }
210
211 timer.stop();
212 double time = timer.time();
213 double analyzerTime = analyzerTimer.time();
214
215 // Output results of move statistics to files
216 mcMoveManager_.output();
218 analyzerManager_.output();
219 }
220
221 // Output results of ramp
222 if (hasRamp()){
223 ramp().output();
224 }
225
226 // Output times for the simulation run
227 Log::file() << std::endl;
228 Log::file() << "nStep " << nStep << std::endl;
229 if (iStep_ != nStep){
230 Log::file() << "nFail Step " << (nStep - iStep_) << std::endl;
231 }
232 Log::file() << "Total run time " << time
233 << " sec" << std::endl;
234 double rStep = double(nStep);
235 Log::file() << "time / nStep " << time / rStep
236 << " sec" << std::endl;
237 Log::file() << "Analyzer run time " << analyzerTime
238 << " sec" << std::endl;
239 Log::file() << std::endl;
240
241 // Output number of times MDE has been solved for the simulation run
243
244 // Print McMove acceptance statistics
245 long attempt;
246 long accept;
247 long fail;
248 using namespace std;
249 Log::file() << "Move Statistics:" << endl << endl;
250 Log::file() << setw(20) << left << "Move Name"
251 << setw(10) << right << "Attempted"
252 << setw(10) << right << "Accepted"
253 << setw(13) << right << "AcceptRate"
254 << setw(10) << right << "Failed"
255 << setw(13) << right << "FailRate"
256 << endl;
257 int nMove = mcMoveManager_.size();
258 for (int iMove = 0; iMove < nMove; ++iMove) {
259 attempt = mcMoveManager_[iMove].nAttempt();
260 accept = mcMoveManager_[iMove].nAccept();
261 fail = mcMoveManager_[iMove].nFail();
262 Log::file() << setw(20) << left
263 << mcMoveManager_[iMove].className()
264 << setw(10) << right << attempt
265 << setw(10) << accept
266 << setw(13) << fixed << setprecision(5)
267 << ( attempt == 0 ? 0.0 : double(accept)/double(attempt) )
268 << setw(10) << fail
269 << setw(13) << fixed << setprecision(5)
270 << ( attempt == 0 ? 0.0 : double(fail)/double(attempt) )
271 << endl;
272 }
273 Log::file() << endl;
274
275 }
276
277 /*
278 * Open, read and analyze a trajectory file
279 */
280 template <int D>
281 void McSimulator<D>::analyze(int min, int max,
282 std::string classname,
283 std::string filename)
284 {
285 // Preconditions
286 UTIL_CHECK(min >= 0);
287 UTIL_CHECK(max >= min);
289 UTIL_CHECK(analyzerManager_.size() > 0);
290
291 // Construct TrajectoryReader
292 TrajectoryReader<D>* trajectoryReaderPtr;
293 trajectoryReaderPtr = trajectoryReaderFactory().factory(classname);
294 if (!trajectoryReaderPtr) {
295 std::string message;
296 message = "Invalid TrajectoryReader class name " + classname;
297 UTIL_THROW(message.c_str());
298 }
299
300 // Open trajectory file
301 trajectoryReaderPtr->open(filename);
302 trajectoryReaderPtr->readHeader();
303
304 // Main loop over trajectory frames
305 Timer timer;
306 bool hasFrame;
307 timer.start();
308 hasFrame = trajectoryReaderPtr->readFrame();
309
310 for (iStep_ = 0; iStep_ <= max && hasFrame; ++iStep_) {
311 if (hasFrame) {
312 clearData();
313
314 // Initialize analyzers
315 if (iStep_ == min) {
316 setup(iStep_);
317 }
318
319 // Sample property values only for iStep >= min
320 if (iStep_ >= min) {
321 analyzerManager_.sample(iStep_);
322 }
323 }
324
325 hasFrame = trajectoryReaderPtr->readFrame();
326 }
327 timer.stop();
328 Log::file() << "end main loop" << std::endl;
329 int nFrames = iStep_ - min;
330 trajectoryReaderPtr->close();
331 delete trajectoryReaderPtr;
332
333 // Output results of all analyzers to output files
334 analyzerManager_.output();
335
336 // Output number of frames and times
337 Log::file() << std::endl;
338 Log::file() << "# of frames " << nFrames << std::endl;
339 Log::file() << "run time " << timer.time()
340 << " sec" << std::endl;
341 Log::file() << "time / frame " << timer.time()/double(nFrames)
342 << " sec" << std::endl;
343 Log::file() << std::endl;
344
345 }
346
347 /*
348 * Output McMoveManager timer results.
349 */
350 template<int D>
351 void McSimulator<D>::outputTimers(std::ostream& out) const
352 {
353 compressor().outputTimers(out);
354 out << "\n";
355 out << "MC move time contributions:\n";
356 mcMoveManager_.outputTimers(out);
357 out << "\n";
358 }
359
360 /*
361 * Clear all McMoveManager timers.
362 */
363 template<int D>
365 { mcMoveManager_.clearTimers(); }
366
367}
368}
369#endif
static long baseInterval
The interval for an Analyzer must be a multiple of baseInterval.
Factory< TrajectoryReader< D > > & trajectoryReaderFactory()
Get the trajectory reader factory by reference.
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.
bool hasMcMoves() const
Have any McMove algorithms been defined?
virtual void readParameters(std::istream &in)
Read parameters file block for an MC simulation.
virtual void outputTimers(std::ostream &out) const
Output timing results.
virtual void clearTimers()
Clear timers.
void simulate(int nStep)
Perform a field theoretic Monte-Carlo simulation.
McSimulator(System< D > &system)
Constructor.
void readParamCompositeOptional(std::istream &in, ParamComposite &child, bool next=true)
Add and attempt to read an optional child ParamComposite.
Ramp< D > const & ramp() const
Get the associated Ramp by const reference.
void readPerturbation(std::istream &in, bool &isEnd)
Optionally read a Perturbation parameter file block.
System< D > & system()
Get parent system by reference.
SimState< D > state_
Previous state saved during at the beginning of a step.
bool hasRamp() const
Does this Simulator have a Ramp?
void clearData()
Clear field eigen-components and hamiltonian components.
Compressor< D > & compressor()
Get the compressor by non-const reference.
virtual void outputMdeCounter(std::ostream &out) const
Output MDE counter.
void allocate()
Allocate required memory.
long iTotalStep_
Step counter - total number of attempted BD or MC steps.
bool hasCompressor() const
Does this Simulator have a Compressor?
void readRandomSeed(std::istream &in)
Optionally read a random number generator seed.
void readCompressor(std::istream &in, bool &isEnd)
Optionally read a Compressor parameter file block.
long iStep_
Step counter - attempted steps for which compressor converges.
void readRamp(std::istream &in, bool &isEnd)
Optionally read a Ramp parameter file block.
Main class, representing a complete physical system.
Factory for subclasses of TrajectoryReader.
Trajectory file reader (base class).
virtual bool readFrame()=0
Read a single frame.
virtual void close()=0
Close the trajectory file.
virtual void open(std::string filename)=0
Open trajectory file and read header, if any.
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:59
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
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
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.