PSCF v1.3.3
rpc/fts/montecarlo/ForceBiasMove.tpp
1#ifndef RPC_FORCE_BIAS_MOVE_TPP
2#define RPC_FORCE_BIAS_MOVE_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 "ForceBiasMove.h"
12#include "McMove.h"
13#include <rpc/solvers/Mixture.h>
14#include <rpc/field/Domain.h>
15#include <rpc/fts/montecarlo/McSimulator.h>
16#include <rpc/fts/compressor/Compressor.h>
17#include <rpc/system/System.h>
18#include <util/param/ParamComposite.h>
19#include <util/random/Random.h>
20
21
22namespace Pscf {
23namespace Rpc {
24
25 using namespace Util;
26
27 /*
28 * Constructor.
29 */
30 template <int D>
32 : McMove<D>(simulator),
33 w_(),
34 dwc_(),
35 mobility_(0.0)
36 { setClassName("ForceBiasMove"); }
37
38 /*
39 * Destructor, empty default implementation.
40 */
41 template <int D>
44
45 /*
46 * ReadParameters, empty default implementation.
47 */
48 template <int D>
49 void ForceBiasMove<D>::readParameters(std::istream &in)
50 {
51 //Read the probability
53
54 // Read Brownian dynamics mobility parameter
55 read(in, "mobility", mobility_);
56
57 // Allocate memory for private containers
58 int nMonomer = system().mixture().nMonomer();
59 IntVec<D> meshDimensions = system().domain().mesh().dimensions();
60 w_.allocate(nMonomer);
61 for (int i=0; i < nMonomer; ++i) {
62 w_[i].allocate(meshDimensions);
63 }
64 dc_.allocate(nMonomer-1);
65 dwc_.allocate(nMonomer-1);
66 for (int i=0; i < nMonomer - 1; ++i) {
67 dc_[i].allocate(meshDimensions);
68 dwc_[i].allocate(meshDimensions);
69 }
70
71 }
72
73 template <int D>
75 {
76 // Check array capacities
77 int meshSize = system().domain().mesh().size();
78 int nMonomer = system().mixture().nMonomer();
79 UTIL_CHECK(w_.capacity() == nMonomer);
80 for (int i=0; i < nMonomer; ++i) {
81 UTIL_CHECK(w_[i].capacity() == meshSize);
82 }
83 UTIL_CHECK(dc_.capacity() == nMonomer-1);
84 UTIL_CHECK(dwc_.capacity() == nMonomer-1);
85 for (int i=0; i < nMonomer - 1; ++i) {
86 UTIL_CHECK(dc_[i].capacity() == meshSize);
87 UTIL_CHECK(dwc_[i].capacity() == meshSize);
88 }
89
91 }
92
93 /*
94 * Attempt unconstrained move
95 */
96 template <int D>
98 {
99 totalTimer_.start();
101
102 // Preconditions
103 UTIL_CHECK(simulator().hasWc());
104 UTIL_CHECK(simulator().hasDc());
105 UTIL_CHECK(simulator().hasHamiltonian());
106
107 // Array sizes and indices
108 const int nMonomer = system().mixture().nMonomer();
109 const int meshSize = system().domain().mesh().size();
110 int i, j, k;
111
112 // Get current Hamiltonian
113 double oldHamiltonian = simulator().hamiltonian();
114
115 // Save current state
116 simulator().saveState();
117
118 // Clear both eigen-components of the fields and hamiltonian
119 simulator().clearData();
120
121 attemptMoveTimer_.start();
122
123 // Copy current W fields from parent system into wc_
124 for (i = 0; i < nMonomer; ++i) {
125 w_[i] = system().w().rgrid(i);
126 }
127
128 // Copy current derivative fields from into member variable dc_
129 for (i = 0; i < nMonomer - 1; ++i) {
130 dc_[i] = simulator().dc(i);
131 }
132
133 // Constants for dynamics
134 const double vSystem = system().domain().unitCell().volume();
135 const double vNode = vSystem/double(meshSize);
136 const double a = -1.0*mobility_;
137 const double b = sqrt(2.0*mobility_/vNode);
138
139 // Modify local variables dwc_ and wc_
140 // Loop over eigenvectors of projected chi matrix
141 double dwd, dwr, evec;
142 for (j = 0; j < nMonomer - 1; ++j) {
143 RField<D> const & dc = dc_[j];
144 RField<D> & dwc = dwc_[j];
145 for (k = 0; k < meshSize; ++k) {
146 dwd = a*dc[k];
147 dwr = b*random().gaussian();
148 dwc[k] = dwd + dwr;
149 }
150
151 // Loop over monomer types
152 for (i = 0; i < nMonomer; ++i) {
153 RField<D> const & dwc = dwc_[j];
154 RField<D> & wn = w_[i];
155 evec = simulator().chiEvecs(j,i);
156 for (k = 0; k < meshSize; ++k) {
157 wn[k] += evec*dwc[k];
158 }
159 }
160
161 }
162
163 // Set modified fields in parent system
164 system().w().setRGrid(w_);
165 simulator().clearData();
166
167 attemptMoveTimer_.stop();
168
169 // Call compressor
170 compressorTimer_.start();
171 int compress = simulator().compressor().compress();
172 compressorTimer_.stop();
173
174 bool isConverged = false;
175 if (compress != 0){
177 simulator().restoreState();
178 } else {
179 isConverged = true;
180
181 // Compute eigenvector components of current fields
182 componentTimer_.start();
183 simulator().computeWc();
184 simulator().computeCc();
185 simulator().computeDc();
186 componentTimer_.stop();
187
188 // Evaluate new Hamiltonian
189 hamiltonianTimer_.start();
190 simulator().computeHamiltonian();
191 double newHamiltonian = simulator().hamiltonian();
192 double dH = newHamiltonian - oldHamiltonian;
193
194 // Compute force bias
195 double dp, dm;
196 double bias = 0.0;
197 for (j = 0; j < nMonomer - 1; ++j) {
198 RField<D> const & di = dc_[j];
199 RField<D> const & df = simulator().dc(j);
200 RField<D> const & dwc = dwc_[j];
201 for (k=0; k < meshSize; ++k) {
202 dp = 0.5*(di[k] + df[k]);
203 dm = 0.5*(di[k] - df[k]);
204 bias += dp*( dwc[k] + mobility_*dm );
205 }
206 }
207 bias *= vNode;
208 hamiltonianTimer_.stop();
209
210 // Accept or reject move
211 bool accept = false;
212 decisionTimer_.start();
213 double weight = exp(bias - dH);
214 accept = random().metropolis(weight);
215 if (accept) {
217 simulator().clearState();
218 } else {
219 simulator().restoreState();
220 }
221 decisionTimer_.stop();
222
223 }
224
225 totalTimer_.stop();
226 return isConverged;
227 }
228
229 /*
230 * Trivial default implementation - do nothing
231 */
232 template <int D>
235
236 template<int D>
237 void ForceBiasMove<D>::outputTimers(std::ostream& out)
238 {
239 out << "\n";
240 out << "ForceBiasMove time contributions:\n";
242 }
243
244}
245}
246#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
ForceBiasMove(McSimulator< D > &simulator)
Constructor.
void readParameters(std::istream &in)
Read required parameters from file.
ScalarParam< Type > & read(std::istream &in, const char *label, Type &value)
Add and read a new required ScalarParam < Type > object.
bool move()
Attempt and accept or reject force bias Monte-Carlo move.
void setClassName(const char *className)
Set class name string.
void outputTimers(std::ostream &out)
Return real move times contributions.
void setup()
Setup before the beginning of each simulation run.
void output()
Output statistics for this move (at the end of simulation)
void incrementNAccept()
Increment the number of accepted moves.
Timer attemptMoveTimer_
Timers for McMove.
Random & random()
Get Random number generator of parent System.
McMove(McSimulator< D > &simulator)
Constructor.
System< D > & system()
Get parent System object.
McSimulator< D > & simulator()
Get parent McSimulator object.
void incrementNAttempt()
Increment the number of attempted moves.
virtual void outputTimers(std::ostream &out)
Log output timing results.
void readProbability(std::istream &in)
Read the probability from file.
void incrementNFail()
Increment the number of failed moves.
virtual void setup()
Setup before the beginning of each simulation run.
Monte-Carlo simulation coordinator.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.