PSCF v1.3.3
rpc/fts/brownian/PredCorrBdStep.tpp
1#ifndef RPC_PRED_CORR_BD_STEP_TPP
2#define RPC_PRED_CORR_BD_STEP_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 "PredCorrBdStep.h"
12#include <rpc/solvers/Mixture.h>
13#include <rpc/field/Domain.h>
14#include <rpc/fts/brownian/BdSimulator.h>
15#include <rpc/fts/compressor/Compressor.h>
16#include <rpc/system/System.h>
17#include <pscf/math/IntVec.h>
18#include <util/random/Random.h>
19
20namespace Pscf {
21namespace Rpc {
22
23 using namespace Util;
24 using namespace Prdc::Cpu;
25
26 /*
27 * Constructor.
28 */
29 template <int D>
31 : BdStep<D>(simulator),
32 wp_(),
33 wf_(),
34 dci_(),
35 eta_(),
36 dwc_(),
37 dwp_(),
38 mobility_(0.0)
39 {}
40
41 /*
42 * Destructor, empty default implementation.
43 */
44 template <int D>
47
48 /*
49 * ReadParameters, empty default implementation.
50 */
51 template <int D>
52 void PredCorrBdStep<D>::readParameters(std::istream &in)
53 {
54 read(in, "mobility", mobility_);
55
56 // Allocate memory for private containers
57 int nMonomer = system().mixture().nMonomer();
58 IntVec<D> meshDimensions = system().domain().mesh().dimensions();
59 wp_.allocate(nMonomer);
60 wf_.allocate(nMonomer);
61 for (int i=0; i < nMonomer; ++i) {
62 wp_[i].allocate(meshDimensions);
63 wf_[i].allocate(meshDimensions);
64 }
65 dci_.allocate(nMonomer-1);
66 eta_.allocate(nMonomer-1);
67 for (int i=0; i < nMonomer - 1; ++i) {
68 dci_[i].allocate(meshDimensions);
69 eta_[i].allocate(meshDimensions);
70 }
71 dwc_.allocate(meshDimensions);
72 dwp_.allocate(meshDimensions);
73 }
74
75 template <int D>
77 {
78 // Check array capacities
79 int meshSize = system().domain().mesh().size();
80 int nMonomer = system().mixture().nMonomer();
81 UTIL_CHECK(wp_.capacity() == nMonomer);
82 UTIL_CHECK(wf_.capacity() == nMonomer);
83 for (int i=0; i < nMonomer; ++i) {
84 UTIL_CHECK(wp_[i].capacity() == meshSize);
85 UTIL_CHECK(wf_[i].capacity() == meshSize);
86 }
87 UTIL_CHECK(dci_.capacity() == nMonomer-1);
88 UTIL_CHECK(eta_.capacity() == nMonomer-1);
89 for (int i=0; i < nMonomer - 1; ++i) {
90 UTIL_CHECK(dci_[i].capacity() == meshSize);
91 UTIL_CHECK(eta_[i].capacity() == meshSize);
92 }
93 UTIL_CHECK(dwc_.capacity() == meshSize);
94 UTIL_CHECK(dwp_.capacity() == meshSize);
95 }
96
97 template <int D>
99 {
100 // Array sizes and indices
101 const int nMonomer = system().mixture().nMonomer();
102 const int meshSize = system().domain().mesh().size();
103 int i, j, k;
104
105 // Save current state
106 simulator().saveState();
107
108 // Copy current W fields from parent system
109 for (i = 0; i < nMonomer; ++i) {
110 wp_[i] = system().w().rgrid(i);
111 wf_[i] = wp_[i];
112 }
113
114 // Store initial value of pressure field at all grid points in dwp_
115 dwp_ = simulator().wc(nMonomer-1);
116
117 // Define constants used for step
118 const double vSystem = system().domain().unitCell().volume();
119 const double a = -1.0*mobility_;
120 const double b = sqrt(2.0*mobility_*double(meshSize)/vSystem);
121
122 // Construct all random displacement (noise) components
123 for (j = 0; j < nMonomer - 1; ++j) {
124 RField<D> & eta = eta_[j];
125 for (k = 0; k < meshSize; ++k) {
126 eta[k] = b*random().gaussian();
127 }
128 }
129
130 // Compute predicted state wp_, and store initial force dci_
131
132 // Loop over eigenvectors of projected chi matrix
133 double evec;
134 for (j = 0; j < nMonomer - 1; ++j) {
135 RField<D> const & dc = simulator().dc(j);
136 RField<D> const & eta = eta_[j];
137 RField<D> & dci = dci_[j];
138 for (k = 0; k < meshSize; ++k) {
139 dwc_[k] = a*dc[k] + eta[k];
140 dci[k] = dc[k];
141 }
142 // Loop over monomer types
143 for (i = 0; i < nMonomer; ++i) {
144 RField<D> & wp = wp_[i];
145 evec = simulator().chiEvecs(j,i);
146 for (k = 0; k < meshSize; ++k) {
147 wp[k] += evec*dwc_[k];
148 }
149 }
150 }
151
152 // Set modified system fields at predicted state wp_
153 system().w().setRGrid(wp_);
154
155 // Set function return value to indicate failure by default
156 bool isConverged = false;
157
158 // Enforce incompressibility at predicted state
159 int compress = simulator().compressor().compress();
160 if (compress != 0){
161 simulator().restoreState();
162 } else {
163 UTIL_CHECK(system().c().hasData());
164
165 // Compute components and derivatives at wp_
166 simulator().clearData();
167 simulator().computeWc();
168 simulator().computeCc();
169 simulator().computeDc();
170
171 // Compute change dwp_ in pressure field
172 // Note: On entry, dwp_ is the old pressure field
173 RField<D> const & wp = simulator().wc(nMonomer-1);
174 for (k = 0; k < meshSize; ++k) {
175 dwp_[k] = wp[k] - dwp_[k];
176 }
177
178 // Adjust predicted pressure field to final monomer fields
179 for (i = 0; i < nMonomer; ++i) {
180 RField<D> & wf = wf_[i];
181 for (k = 0; k < meshSize; ++k) {
182 wf[k] += dwp_[k];
183 }
184 }
185
186 // Full step (corrector) change in exchange fields
187 const double ha = 0.5*a;
188 for (j = 0; j < nMonomer - 1; ++j) {
189 RField<D> const & dcp = simulator().dc(j);
190 RField<D> const & dci = dci_[j];
191 RField<D> const & eta = eta_[j];
192 for (k = 0; k < meshSize; ++k) {
193 dwc_[k] = ha*( dci[k] + dcp[k]) + eta[k];
194 }
195 for (i = 0; i < nMonomer; ++i) {
196 RField<D> & wf = wf_[i];
197 evec = simulator().chiEvecs(j,i);
198 for (k = 0; k < meshSize; ++k) {
199 wf[k] += evec*dwc_[k];
200 }
201 }
202 }
203
204 // Set system fields after predictor step
205 system().w().setRGrid(wf_);
206
207 // Apply compressor to final state
208 int compress2 = simulator().compressor().compress();
209 if (compress2 != 0){
210 simulator().restoreState();
211 } else {
212 isConverged = true;
213 UTIL_CHECK(system().c().hasData());
214
215 // Compute components and derivatives at final point
216 simulator().clearState();
217 simulator().clearData();
218 simulator().computeWc();
219 simulator().computeCc();
220 simulator().computeDc();
221
222 }
223 }
224
225 // True iff compression was successful after predictor and corrector
226 return isConverged;
227 }
228
229}
230}
231#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
Brownian dynamics simulator for PS-FTS.
BdSimulator< D > & simulator()
Get parent BdSimulator object.
System< D > & system()
Get parent System object.
BdStep(BdSimulator< D > &simulator)
Constructor.
Random & random()
Get Random number generator of parent System.
ScalarParam< Type > & read(std::istream &in, const char *label, Type &value)
Add and read a new required ScalarParam < Type > object.
virtual void readParameters(std::istream &in)
Read required parameters from file.
virtual void setup()
Setup before simulation.
virtual bool step()
Take a single Brownian dynamics step.
PredCorrBdStep(BdSimulator< D > &simulator)
Constructor.
#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.