PSCF v1.4.0
LMBdStep.tpp
1#ifndef RP_LM_BD_STEP_TPP
2#define RP_LM_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 "LMBdStep.h"
12
13#include <pscf/math/IntVec.h>
14
15namespace Pscf {
16namespace Rp {
17
18 using namespace Util;
19 using namespace Prdc;
20
21 /*
22 * Constructor.
23 */
24 template <int D, class T>
25 LMBdStep<D,T>::LMBdStep(typename T::BdSimulator& simulator)
26 : BdStepT(simulator),
27 w_(),
28 etaA_(),
29 etaB_(),
30 dwc_(),
31 etaNewPtr_(nullptr),
32 etaOldPtr_(nullptr),
33 mobility_(0.0)
34 { ParamComposite::setClassName("LmBdStep"); }
35
36 /*
37 * Read body of parameter file block and allocate memory.
38 */
39 template <int D, class T>
40 void LMBdStep<D,T>::readParameters(std::istream &in)
41 {
42 ParamComposite::read(in, "mobility", mobility_);
43
44 // Allocate memory
45 int nMonomer = system().mixture().nMonomer();
46 IntVec<D> meshDimensions = system().domain().mesh().dimensions();
47 w_.allocate(nMonomer);
48 for (int i=0; i < nMonomer; ++i) {
49 w_[i].allocate(meshDimensions);
50 }
51 etaA_.allocate(nMonomer-1);
52 etaB_.allocate(nMonomer-1);
53 for (int i=0; i < nMonomer - 1; ++i) {
54 etaA_[i].allocate(meshDimensions);
55 etaB_[i].allocate(meshDimensions);
56 }
57 dwc_.allocate(meshDimensions);
58 }
59
60 /*
61 * Generate new random displacement values.
62 */
63 template <int D, class T>
64 void LMBdStep<D,T>::generateEtaNew()
65 {
66 // Constants
67 const int nMonomer = system().mixture().nMonomer();
68 const int meshSize = system().domain().mesh().size();
69 const double vSystem = system().domain().unitCell().volume();
70 const double stddev = sqrt(0.5*mobility_*double(meshSize)/vSystem);
71 const double mean = 0.0;
72
73 for (int j = 0; j < nMonomer - 1; ++j) {
74 vecRandom().normal(etaNew(j), stddev, mean);
75 }
76 }
77
78 /*
79 * Exchange pointers to old and new random fields.
80 */
81 template <int D, class T>
82 void LMBdStep<D,T>::exchangeOldNew()
83 {
85 temp = etaOldPtr_;
86 etaOldPtr_ = etaNewPtr_;
87 etaNewPtr_ = temp;
88 }
89
90 /*
91 * Setup before main simulation loop.
92 */
93 template <int D, class T>
95 {
96 int nMonomer = system().mixture().nMonomer();
97 int meshSize = system().domain().mesh().size();
98
99 // Check array capacities
100 UTIL_CHECK(etaA_.capacity() == nMonomer-1);
101 UTIL_CHECK(etaB_.capacity() == nMonomer-1);
102 for (int i=0; i < nMonomer - 1; ++i) {
103 UTIL_CHECK(etaA_[i].capacity() == meshSize);
104 UTIL_CHECK(etaB_[i].capacity() == meshSize);
105 }
106 UTIL_CHECK(dwc_.capacity() == meshSize);
107
108 // Initialize pointers
109 etaOldPtr_ = &etaA_;
110 etaNewPtr_ = &etaB_;
111
112 generateEtaNew();
113 exchangeOldNew();
114 }
115
116 /*
117 * One step of Leimkuhler-Matthews BD algorithm.
118 */
119 template <int D, class T>
121 {
122 // Save current state
123 simulator().saveState();
124
125 // Copy current W fields from parent system into w_
126 const int nMonomer = system().mixture().nMonomer();
127 for (int i = 0; i < nMonomer; ++i) {
128 VecOp::eqV(w_[i], system().w().rgrid(i));
129 }
130
131 // Generate new random displacement values
132 generateEtaNew();
133
134 // Take LM step
135 const double a = -1.0*mobility_;
136 double evec;
137 // Loop over eigenvectors of projected chi matrix
138 for (int j = 0; j < nMonomer - 1; ++j) {
139 RFieldT const & etaN = etaNew(j);
140 RFieldT const & etaO = etaOld(j);
141 RFieldT const & dc = simulator().dc(j);
142 VecOp::addVV(dwc_, etaN, etaO);
143 VecOp::addEqVc(dwc_, dc, a);
144 // Loop over monomer types
145 for (int i = 0; i < nMonomer; ++i) {
146 evec = simulator().chiEvecs(j,i);
147 VecOp::addEqVc(w_[i], dwc_, evec);
148 }
149 }
150
151 // Set modified fields in parent system
152 system().w().setRGrid(w_);
153
154 // Enforce incompressibility (also solves MDE repeatedly)
155 bool isConverged = false;
156 int compress = simulator().compressor().compress();
157 if (compress != 0){
158 simulator().restoreState();
159 } else {
160 isConverged = true;
161 UTIL_CHECK(system().c().hasData());
162
163 // Compute components and derivatives at wp_
164 simulator().clearState();
165 simulator().clearData();
166 simulator().computeWc();
167 simulator().computeCc();
168 simulator().computeDc();
169
170 // Exchange old and new random fields
171 exchangeOldNew();
172 }
173
174 return isConverged;
175 }
176
177}
178}
179#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
void readParameters(std::istream &in) override
Read body of parameter file block.
Definition LMBdStep.tpp:40
bool step() override
Take a single Brownian dynamics step.
Definition LMBdStep.tpp:120
void setup() override
Setup before simulation loop.
Definition LMBdStep.tpp:94
LMBdStep(typename T::BdSimulator &simulator)
Constructor.
Definition LMBdStep.tpp:25
ScalarParam< Type > & read(std::istream &in, const char *label, Type &value)
Add and read a new required ScalarParam < Type > object.
void setClassName(const char *className)
Set class name string.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
void eqV(Array< double > &a, Array< double > const &b, const int beginIdA, const int beginIdB, const int n)
Vector assignment, a[i] = b[i] (real, slice).
Definition VecOp.cpp:21
void addVV(Array< double > &a, Array< double > const &b, Array< double > const &c)
Vector-vector addition, a[i] = b[i] + c[i] (real)
Definition VecOp.cpp:64
void addEqVc(Array< double > &a, Array< double > const &b, const double c)
Add scaled vector in-place, a[i] += b[i]*c (real).
Definition VecOp.cpp:395
Periodic fields and crystallography.
Definition complex.cpp:11
Class templates for real-valued periodic fields.
PSCF package top-level namespace.