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