PSCF v1.3.3
rpc/fts/compressor/LrAmCompressor.tpp
1#ifndef RPC_LR_AM_COMPRESSOR_TPP
2#define RPC_LR_AM_COMPRESSOR_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 "LrAmCompressor.h"
12#include <rpc/system/System.h>
13#include <rpc/solvers/Mixture.h>
14#include <rpc/field/Domain.h>
15#include <pscf/mesh/MeshIterator.h>
16#include <util/global.h>
17
18namespace Pscf {
19namespace Rpc{
20
21 using namespace Util;
22
23 // Public member functions
24
25 /*
26 * Constructor.
27 */
28 template <int D>
30 : Compressor<D>(system),
31 intra_(system),
32 isIntraCalculated_(false),
33 isAllocated_(false)
34 { ParamComposite::setClassName("LrAmCompressor"); }
35
36 /*
37 * Destructor.
38 */
39 template <int D>
42
43 /*
44 * Read parameters from file.
45 */
46 template <int D>
47 void LrAmCompressor<D>::readParameters(std::istream& in)
48 {
49 // Default values
50 AmTmpl::maxItr_ = 100;
52 AmTmpl::errorType_ = "rms";
53
54 // Call parent read methods
57
58 }
59
60 /*
61 * Initialize just before entry to iterative loop.
62 */
63 template <int D>
64 void LrAmCompressor<D>::setup(bool isContinuation)
65 {
66
67 // Allocate memory required by AM algorithm if not done earlier.
69
70 const int nMonomer = system().mixture().nMonomer();
71 const int meshSize = system().domain().mesh().size();
72 IntVec<D> const & dimensions = system().domain().mesh().dimensions();
73
74 // Compute Fourier space kMeshDimensions_
75 for (int i = 0; i < D; ++i) {
76 if (i < D - 1) {
77 kMeshDimensions_[i] = dimensions[i];
78 } else {
79 kMeshDimensions_[i] = dimensions[i]/2 + 1;
80 }
81 }
82
83 // Allocate memory required by compressor, if not done previously
84 if (!isAllocated_){
85 newBasis_.allocate(meshSize);
86 w0_.allocate(nMonomer);
87 wFieldTmp_.allocate(nMonomer);
88 resid_.allocate(dimensions);
89 residK_.allocate(dimensions);
90 intraCorrelationK_.allocate(kMeshDimensions_);
91 for (int i = 0; i < nMonomer; ++i) {
92 w0_[i].allocate(dimensions);
93 wFieldTmp_[i].allocate(dimensions);
94 }
95
96 isAllocated_ = true;
97 }
98
99 // Compute intraCorrelation
100 if (!isIntraCalculated_){
101 intra_.computeIntraCorrelations(intraCorrelationK_);
102 isIntraCalculated_ = true;
103 }
104
105 // Store initial values of monomer chemical potential fields in w0_
106 for (int i = 0; i < nMonomer; ++i) {
107 for (int j = 0; j< meshSize; ++j){
108 w0_[i][j] = system().w().rgrid(i)[j];
109 }
110 }
111
112 }
113
114 /*
115 * Apply the Anderson-Mixing algorithm (main function).
116 */
117 template <int D>
123
124 /*
125 * Output timing results to an output stream (file)
126 */
127 template<int D>
128 void LrAmCompressor<D>::outputTimers(std::ostream& out) const
129 {
130 out << "\n";
131 out << "LrAmCompressor time contributions:\n";
133 }
134
135 /*
136 * Clear all timers and the MDE counter
137 */
138 template<int D>
144
145 // Private virtual function that interact with parent system
146
147 /*
148 * Correction step (second step of Anderson mixing)
149 *
150 * This LrAM algorithm uses a quasi-Newton correction step with an
151 * approximate Jacobian given by the Jacobian in a homogeneous state.
152 */
153 template <int D>
154 void
155 LrAmCompressor<D>::addCorrection(DArray<double>& fieldTrial,
156 DArray<double> const & resTrial)
157 {
158 // Local constants
159 const int n = fieldTrial.capacity();
160 const double vMonomer = system().mixture().vMonomer();
161
162 // Copy DArray<double> resTrial into RField<D> resid_
163 // Allows use of FFT functions that take an RField container
164 for (int i = 0 ; i < n; ++i) {
165 resid_[i] = resTrial[i];
166 }
167
168 // Fourier transform r-grid residual resid_ to k-grid form residK_
169 system().domain().fft().forwardTransform(resid_, residK_);
170
171 // Compute update on a k-grid, using quasi-Newton algorithm
172 double factor;
173 MeshIterator<D> iter;
174 iter.setDimensions(kMeshDimensions_);
175 for (iter.begin(); !iter.atEnd(); ++iter) {
176 factor = 1.0 / (vMonomer * intraCorrelationK_[iter.rank()]);
177 residK_[iter.rank()][0] *= factor;
178 residK_[iter.rank()][1] *= factor;
179 }
180 // Field residK_ now stores k-grid update rather than residual
181
182 // Convert field update back to r-grid (real space) form
183 // On return, resid_ contains r-grid field update, residK_ is destroyed
184 system().domain().fft().inverseTransformUnsafe(residK_, resid_);
185
186 // Add update to obtain new fieldTrial
187 for (int i = 0; i < n; i++) {
188 fieldTrial[i] += resid_[i];
189 }
190 }
191
192 // Private virtual functions that interact with parent System
193
194 /*
195 * Compute and return the number of elements in a field vector.
196 */
197 template <int D>
198 int LrAmCompressor<D>::nElements()
199 { return system().domain().mesh().size(); }
200
201 /*
202 * Does the associated system have initialized w fields?
203 */
204 template <int D>
205 bool LrAmCompressor<D>::hasInitialGuess()
206 { return system().w().hasData(); }
207
208 /*
209 * Get the current field variable from the system.
210 *
211 * The field variable is the change in the Lagrange multiplier field.
212 * relative to that used in initial array of monomer fields, w0_.
213 */
214 template <int D>
215 void LrAmCompressor<D>::getCurrent(DArray<double>& curr)
216 {
217 // Straighten out fields into linear arrays
218 const int meshSize = system().domain().mesh().size();
219 const DArray< RField<D> > * currSys = &system().w().rgrid();
220
221 /*
222 * The field that we are adjusting is the Langrange multiplier field
223 * with number of grid pts components. The current value is the
224 * difference between w and w0_ for the first monomer (any monomer
225 * should give the same answer)
226 */
227 for (int i = 0; i < meshSize; i++){
228 curr[i] = (*currSys)[0][i] - w0_[0][i];
229 }
230
231 }
232
233 /*
234 * Perform the main system computation (solve the MDE).
235 */
236 template <int D>
237 void LrAmCompressor<D>::evaluate()
238 {
239 system().compute();
241 }
242
243 /*
244 * Compute the residual vector for the current system state
245 */
246 template <int D>
247 void LrAmCompressor<D>::getResidual(DArray<double>& resid)
248 {
249 const int n = nElements();
250 const int nMonomer = system().mixture().nMonomer();
251 const int meshSize = system().domain().mesh().size();
252
253 // Initialize residuals
254 for (int i = 0 ; i < n; ++i) {
255 resid[i] = -1.0;
256 }
257
258 // Compute SCF residual vector elements
259 for (int j = 0; j < nMonomer; ++j) {
260 for (int k = 0; k < meshSize; ++k) {
261 resid[k] += system().c().rgrid(j)[k];
262 }
263 }
264
265 }
266
267 /*
268 * Update the w field values stored in the system
269 */
270 template <int D>
271 void LrAmCompressor<D>::update(DArray<double>& newGuess)
272 {
273 // Local constant values
274 const int nMonomer = system().mixture().nMonomer();
275 const int meshSize = system().domain().mesh().size();
276
277 // Locally update monomer w fields in array wFieldTmp_
278 // Set wFieldTmp = w0_ + newGuess
279 for (int i = 0; i < nMonomer; i++){
280 for (int k = 0; k < meshSize; k++){
281 wFieldTmp_[i][k] = w0_[i][k] + newGuess[k];
282 }
283 }
284
285 // Update w fields in the system WContainer
286 system().w().setRGrid(wFieldTmp_);
287 }
288
289 /*
290 * Output results to log file (do-nothing implementation).
291 */
292 template<int D>
293 void LrAmCompressor<D>::outputToLog()
294 {}
295
296}
297}
298#endif
Template for Anderson mixing iterator algorithm.
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Iterator over points in a Mesh<D>.
int rank() const
Get the rank of current element.
void begin()
Set iterator to the first point in the mesh.
bool atEnd() const
Is this the end (i.e., one past the last point)?
void setDimensions(const IntVec< D > &dimensions)
Set the grid dimensions in all directions.
Base class for iterators that impose incompressibility.
int mdeCounter_
Count how many times MDE has been solved.
void readParameters(std::istream &in) override
Read all parameters and initialize.
LrAmCompressor(System< D > &system)
Constructor.
int compress() override
Compress to obtain partial saddle point w+.
void outputTimers(std::ostream &out) const override
Return compressor times contributions.
void setup(bool isContinuation) override
Initialize just before entry to iterative loop.
void clearTimers() override
Clear all timers (reset accumulated time to zero).
Main class, representing a complete physical system.
int capacity() const
Return allocated size.
Definition Array.h:159
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void setClassName(const char *className)
Set class name string.
File containing preprocessor macros for error handling.
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.