PSCF v1.4.0
LrAmCompressor.tpp
1#ifndef RP_LR_AM_COMPRESSOR_TPP
2#define RP_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 <pscf/math/IntVec.h>
13#include <util/global.h>
14
15namespace Pscf {
16namespace Rp {
17
18 using namespace Util;
19
20 // Public member functions
21
22 /*
23 * Constructor.
24 */
25 template <int D, class T, class V>
26 LrAmCompressor<D,T,V>::LrAmCompressor(typename T::System& system)
27 : intra_(system),
28 isIntraCalculated_(false),
29 isAllocated_(false)
30 {
31 CompressorT::setSystem(system);
32 ParamComposite::setClassName("LrAmCompressor");
33 }
34
35 /*
36 * Read body of parameter file block and initialize.
37 */
38 template <int D, class T, class V>
40 {
41 // Default values
42 AmTmpl::maxItr_ = 100;
44 AmTmpl::errorType_ = "rms";
45
46 // Call base class read methods
49 }
50
51 /*
52 * Initialize just before entry to iterative loop.
53 */
54 template <int D, class T, class V>
55 void LrAmCompressor<D,T,V>::setup(bool isContinuation)
56 {
57
58 // Allocate memory required by AM algorithm, if not done earlier
59 AmTmpl::setup(isContinuation);
60
61 const int nMonomer = system().mixture().nMonomer();
62 IntVec<D> const & dimensions = system().domain().mesh().dimensions();
63 FFTT::computeKMesh(dimensions, kMeshDimensions_, kSize_);
64
65 // Allocate memory required by compressor, if not done earlier
66 if (!isAllocated_) {
67 w0_.allocate(nMonomer);
68 wFieldTmp_.allocate(nMonomer);
69 resid_.allocate(dimensions);
70 residK_.allocate(dimensions);
71 intraCorrelationK_.allocate(kMeshDimensions_);
72 for (int i = 0; i < nMonomer; ++i) {
73 w0_[i].allocate(dimensions);
74 wFieldTmp_[i].allocate(dimensions);
75 }
76 isAllocated_ = true;
77 }
78
79 // Compute intraCorrelationK_
80 if (!isIntraCalculated_){
81 intra_.computeOmegaTotal(intraCorrelationK_);
82 isIntraCalculated_ = true;
83 }
84
85 // Store initial values of monomer chemical potential fields
86 for (int i = 0; i < nMonomer; ++i) {
87 VecOp::eqV(w0_[i], system().w().rgrid(i));
88 }
89
90 }
91
92 /*
93 * Main function - iteratively adjust the pressure field.
94 */
95 template <int D, class T, class V>
97 {
98 int solve = AmTmpl::solve();
99 return solve;
100 }
101
102 /*
103 * Output timer results.
104 */
105 template <int D, class T, class V>
106 void LrAmCompressor<D,T,V>::outputTimers(std::ostream& out) const
107 {
108 out << "\n";
109 out << "LrAmCompressor time contributions:\n";
111 }
112
113 /*
114 * Clear timers and the MDE counter.
115 */
116 template <int D, class T, class V>
118 {
120 CompressorT::mdeCounter_ = 0;
121 }
122
123 // Private virtual AM algorithm operation functions
124
125 /*
126 * Compute and return the number of elements in a field vector.
127 */
128 template <int D, class T, class V>
129 int LrAmCompressor<D,T,V>::nElements()
130 { return system().domain().mesh().size(); }
131
132 /*
133 * Does the system have an initial field guess?
134 */
135 template <int D, class T, class V>
136 bool LrAmCompressor<D,T,V>::hasInitialGuess()
137 { return system().w().hasData(); }
138
139 /*
140 * Get the current field variable from the system.
141 *
142 * The field variable is the change in the Lagrange multiplier field
143 * relative to that used in the initial array of monomer fields, w0_.
144 */
145 template <int D, class T, class V>
146 void LrAmCompressor<D,T,V>::getCurrent(VectorT& curr)
147 {
148 /*
149 * The field that we are adjusting is the Langrange multiplier
150 * field. The current value is the difference between w and w0_
151 * for the first monomer type, but any monomer type would give
152 * the same answer.
153 */
154 VecOp::subVV(curr, system().w().rgrid(0), w0_[0]);
155 }
156
157 /*
158 * Perform the main system computation (solve the MDE).
159 */
160 template <int D, class T, class V>
161 void LrAmCompressor<D,T,V>::evaluate()
162 {
163 system().compute();
164 ++(CompressorT::mdeCounter_);
165 }
166
167 /*
168 * Compute the residual vector for the current system state.
169 */
170 template <int D, class T, class V>
171 void LrAmCompressor<D,T,V>::getResidual(VectorT& resid)
172 {
173 // Initialize residual to -1.0
174 VecOp::eqS(resid, -1.0);
175
176 // Add c fields to get SCF residual vector
177 const int nMonomer = system().mixture().nMonomer();
178 for (int i = 0; i < nMonomer; ++i) {
179 VecOp::addEqV(resid, system().c().rgrid(i));
180 }
181 }
182
183 /*
184 * Correction step (second step of Anderson mixing)
185 *
186 * This LrAm algorithm uses a quasi-Newton correction step with an
187 * approximate Jacobian given by the Jacobian in a homogeneous state.
188 */
189 template <int D, class T, class V>
190 void
191 LrAmCompressor<D,T,V>::addCorrection(VectorT& fieldTrial,
192 VectorT const & resTrial)
193 {
194 // Copy resTrial to RField resid_
195 // Allows use of FFT functions that take an RField container
196 VecOp::eqV(resid_, resTrial);
197
198 // Convert residual to Fourier space
199 system().domain().fft().forwardTransform(resid_, residK_);
200
201 // Combine with linear response factor to obtain update step
202 const double vMonomer = system().mixture().vMonomer();
203 VecOp::divEqVc(residK_, intraCorrelationK_, vMonomer);
204
205 // Convert update back to real space (destroys residK_)
206 system().domain().fft().inverseTransformUnsafe(residK_, resid_);
207
208 // Add update resid_ to obtain corrected fieldTrial_
209 VecOp::addEqV(fieldTrial, resid_);
210 }
211
212 /*
213 * Update the w field values stored in the system
214 */
215 template <int D, class T, class V>
216 void LrAmCompressor<D,T,V>::update(VectorT& newGuess)
217 {
218 // New field is w0_ + newGuess for the pressure field
219 const int nMonomer = system().mixture().nMonomer();
220 for (int i = 0; i < nMonomer; ++i) {
221 VecOp::addVV(wFieldTmp_[i], w0_[i], newGuess);
222 }
223
224 // Update system r-grid fields
225 system().w().setRGrid(wFieldTmp_);
226 }
227
228 /*
229 * Output results to log file (do-nothing implementation).
230 */
231 template <int D, class T, class V>
232 void LrAmCompressor<D,T,V>::outputToLog()
233 {}
234
235}
236}
237#endif
virtual void setup(bool isContinuation)
void outputTimers(std::ostream &out) const
virtual void readParameters(std::istream &in)
int solve(bool isContinuation=false)
Iterate to a solution.
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
void setup(bool isContinuation) override
Initialize just before entry to iterative loop.
int compress() override
Compress to obtain partial saddle point field.
void outputTimers(std::ostream &out) const override
Return compressor time contributions.
LrAmCompressor(typename T::System &system)
Constructor.
void clearTimers() override
Clear all timers and MDE solution counter.
void readParameters(std::istream &in) override
Read body of parameter file block and initialize.
void setClassName(const char *className)
Set class name string.
File containing preprocessor macros for error handling.
void addEqV(Array< double > &a, Array< double > const &b)
Vector-vector in-place addition, a[i] += b[i] (real).
Definition VecOp.cpp:198
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 subVV(Array< double > &a, Array< double > const &b, Array< double > const &c)
Vector-vector subtraction, a[i] = b[i] - c[i] (real)
Definition VecOp.cpp:95
void eqS(Array< double > &a, double b)
Vector assignment, a[i] = b (real).
Definition VecOp.cpp:50
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 divEqVc(Array< fftw_complex > &a, Array< double > const &b, double c)
Vector division in-place w/ coeff., a[i] /= (b[i] * c).
Definition VecOpCx.cpp:730
Class templates for real-valued periodic fields.
PSCF package top-level namespace.