PSCF v1.2
LrAmPreCompressor.tpp
1#ifndef RPG_LR_AM_COMPRESSOR_TPP
2#define RPG_LR_AM_COMPRESSOR_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field Theory
6*
7* Copyright 2016 - 2022, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include "LrAmPreCompressor.h"
12#include <rpg/System.h>
13#include <rpg/fts/compressor/intra/IntraCorrelation.h>
14#include <prdc/crystal/shiftToMinimum.h>
15#include <prdc/cuda/resources.h>
16#include <pscf/chem/Monomer.h>
17#include <pscf/mesh/MeshIterator.h>
18#include <complex>
19#include <util/global.h>
20
21namespace Pscf {
22namespace Rpg {
23
24 using namespace Util;
25
26 // Constructor
27 template <int D>
29 : Compressor<D>(system),
30 intra_(system),
31 isIntraCalculated_(false),
32 isAllocated_(false)
33 { setClassName("LrAmPreCompressor"); }
34
35 // Destructor
36 template <int D>
39
40 // Read parameters from file
41 template <int D>
43 {
44 // Call parent class readParameters
47 }
48
49 // Initialize just before entry to iterative loop.
50 template <int D>
51 void LrAmPreCompressor<D>::setup(bool isContinuation)
52 {
53 const int nMonomer = system().mixture().nMonomer();
54 const int meshSize = system().domain().mesh().size();
55 IntVec<D> const & dimensions = system().mesh().dimensions();
56
57 // Allocate memory required by AM algorithm if not done earlier.
59 DeviceArray<cudaReal> >::setup(isContinuation);
60
61 // Compute Fourier space kMeshDimensions_
62 for (int i = 0; i < D; ++i) {
63 if (i < D - 1) {
64 kMeshDimensions_[i] = dimensions[i];
65 } else {
66 kMeshDimensions_[i] = dimensions[i]/2 + 1;
67 }
68 }
69
70 // Compute number of points in k-space grid
71 kSize_ = 1;
72 for (int i = 0; i < D; ++i) {
73 kSize_ *= kMeshDimensions_[i];
74 }
75
76 // Allocate memory required by compressor if not done earlier.
77 if (!isAllocated_){
78 w0_.allocate(nMonomer);
79 wFieldTmp_.allocate(nMonomer);
80 error_.allocate(dimensions);
81 resid_.allocate(dimensions);
82 residK_.allocate(dimensions);
83 intraCorrelation_.allocate(kMeshDimensions_);
84 for (int i = 0; i < nMonomer; ++i) {
85 w0_[i].allocate(dimensions);
86 wFieldTmp_[i].allocate(dimensions);
87 }
88 isAllocated_ = true;
89 }
90
91 // Compute intraCorrelation
92 if (!isIntraCalculated_){
93 intra_.computeIntraCorrelations(intraCorrelation_);
94 isIntraCalculated_ = true;
95 }
96
97 // Store value of initial guess chemical potential fields
98 for (int i = 0; i < nMonomer; ++i) {
99 VecOp::eqV(w0_[i], system().w().rgrid(i));
100 }
101
102 }
103
104 // Iterative solver (AM algorithm)
105 template <int D>
107 {
108 int solve = AmIteratorTmpl<Compressor<D>,
109 DeviceArray<cudaReal> >::solve();
110 //mdeCounter_ = AmIteratorTmpl<Compressor<D>, DeviceArray<cudaReal>>::totalItr();
111 return solve;
112 }
113
114 // Assign one array to another
115 template <int D>
117 DeviceArray<cudaReal> const & b)
118 {
119 UTIL_CHECK(b.capacity() == a.capacity());
120 VecOp::eqV(a, b);
121 }
122
123 // Compute and return inner product of two vectors.
124 template <int D>
125 double LrAmPreCompressor<D>::dotProduct(DeviceArray<cudaReal> const & a,
126 DeviceArray<cudaReal> const & b)
127 {
128 UTIL_CHECK(a.capacity() == b.capacity());
129 return Reduce::innerProduct(a, b);
130 }
131
132 // Compute and return maximum element of a vector.
133 template <int D>
134 double LrAmPreCompressor<D>::maxAbs(DeviceArray<cudaReal> const & a)
135 {
136 return Reduce::maxAbs(a);
137 }
138
139 // Update basis
140 template <int D>
141 void
142 LrAmPreCompressor<D>::updateBasis(RingBuffer< DeviceArray<cudaReal> > & basis,
143 RingBuffer< DeviceArray<cudaReal> > const & hists)
144 {
145 // Make sure at least two histories are stored
146 UTIL_CHECK(hists.size() >= 2);
147
148 basis.advance();
149 if (basis[0].isAllocated()) {
150 UTIL_CHECK(basis[0].capacity() == hists[0].capacity());
151 } else {
152 basis[0].allocate(hists[0].capacity());
153 }
154
155 VecOp::subVV(basis[0], hists[0], hists[1]);
156 }
157
158 template <int D>
159 void
160 LrAmPreCompressor<D>::addHistories(DeviceArray<cudaReal>& trial,
161 RingBuffer<DeviceArray<cudaReal> > const & basis,
162 DArray<double> coeffs,
163 int nHist)
164 {
165 for (int i = 0; i < nHist; i++) {
166 VecOp::addEqVc(trial, basis[i], -1.0 * coeffs[i]);
167 }
168 }
169
170 template <int D>
171 void
172 LrAmPreCompressor<D>::addPredictedError(DeviceArray<cudaReal>& fieldTrial,
173 DeviceArray<cudaReal> const & resTrial,
174 double lambda)
175 {
176 VecOp::addEqVc(fieldTrial, resTrial, lambda);
177 }
178
179 // Does the system have an initial field guess?
180 template <int D>
181 bool LrAmPreCompressor<D>::hasInitialGuess()
182 { return system().w().hasData(); }
183
184 // Compute and return the number of elements in a field vector
185 template <int D>
186 int LrAmPreCompressor<D>::nElements()
187 { return system().domain().mesh().size(); }
188
189 // Get the current field from the system
190 template <int D>
191 void LrAmPreCompressor<D>::getCurrent(DeviceArray<cudaReal>& curr)
192 {
193 /*
194 * The field that we are adjusting is the Langrange multiplier field
195 * with number of grid pts components.The current value is the difference
196 * between w and w0_ for the first monomer (any monomer should give the
197 * same answer)
198 */
199 VecOp::subVV(curr, system().w().rgrid(0), w0_[0]);
200 }
201
202 // Perform the main system computation (solve the MDE)
203 template <int D>
204 void LrAmPreCompressor<D>::evaluate()
205 {
206 system().compute();
207 ++mdeCounter_;
208 }
209
210 // Compute the residual for the current system state
211 template <int D>
212 void LrAmPreCompressor<D>::getResidual(DeviceArray<cudaReal>& resid)
213 {
214 const int nMonomer = system().mixture().nMonomer();
215 const double vMonomer = system().mixture().vMonomer();
216
217 // Compute incompressibility constraint error vector elements
218 VecOp::subVS(resid_, system().c().rgrid(0), 1.0);
219 for (int i = 1; i < nMonomer; i++) {
220 VecOp::addEqV(resid_, system().c().rgrid(i));
221 }
222
223 // Convert residual to Fourier Space
224 system().fft().forwardTransform(resid_, residK_);
225
226 // Residual combine with Linear response factor
227 VecOp::divEqVc(residK_, intraCorrelation_, vMonomer);
228
229 // Convert back to real Space (destroys residK_)
230 system().fft().inverseTransformUnsafe(residK_, resid_);
231
232 // Assign resid_ to resid
233 VecOp::eqV(resid, resid_);
234
235 }
236
237 // Update the current system field coordinates
238 template <int D>
239 void LrAmPreCompressor<D>::update(DeviceArray<cudaReal>& newGuess)
240 {
241 // Convert back to field format
242 const int nMonomer = system().mixture().nMonomer();
243
244 // New field is the w0_ + the newGuess for the Lagrange multiplier field
245 for (int i = 0; i < nMonomer; i++) {
246 VecOp::addVV(wFieldTmp_[i], w0_[i], newGuess);
247 }
248
249 // Set system r grid
250 system().setWRGrid(wFieldTmp_);
251 }
252
253 template<int D>
254 void LrAmPreCompressor<D>::outputToLog()
255 {}
256
257 template<int D>
259 {
260 // Output timing results, if requested.
261 out << "\n";
262 out << "Compressor times contributions:\n";
264 }
265
266
267 template<int D>
269 {
271 mdeCounter_ = 0;
272 }
273
274 template<int D>
276 {
277 return 1.0;
278 }
279
280 template<int D>
282 DeviceArray<cudaReal>& fieldTrial,
283 std::string errorType,
284 int verbose)
285 {
286 double error = 0.0;
287 const int n = nElements();
288 const int nMonomer = system().mixture().nMonomer();
289
290 // Initialize residuals to sum of all monomer compositions minus 1
291 VecOp::subVS(error_, system().c().rgrid(0), 1.0);
292 for (int i = 1; i < nMonomer; i++) {
293 VecOp::addEqV(error_, system().c().rgrid(i));
294 }
295
296 // Find max residual vector element
297 double maxRes = maxAbs(error_);
298
299 // Find norm of residual vector
300 double normRes = AmIteratorTmpl<Compressor<D>,
301 DeviceArray<cudaReal> >::norm(error_);
302
303 // Find root-mean-squared residual element value
304 double rmsRes = normRes/sqrt(n);
305 if (verbose > 1) {
306 Log::file() << "\n";
307 Log::file() << "Max Residual = " << Dbl(maxRes,15) << "\n";
308 Log::file() << "Residual Norm = " << Dbl(normRes,15) << "\n";
309 Log::file() << "RMS Residual = " << Dbl(rmsRes,15);
310
311 // Check if calculation has diverged (normRes will be NaN)
312 UTIL_CHECK(!std::isnan(normRes));
313 error = normRes;
314 Log::file() <<"\n";
315 // Set error value
316 if (errorType == "maxResid") {
317 error = maxRes;
318 } else if (errorType == "normResid") {
319 error = normRes;
320 } else if (errorType == "rmsResid") {
321 error = rmsRes;
322 } else {
323 UTIL_THROW("Invalid iterator error type in parameter file.");
324 }
325
326 } else {
327 // Set error value
328 if (errorType == "maxResid") {
329 error = maxRes;
330 } else if (errorType == "normResid") {
331 error = normRes;
332 } else if (errorType == "rmsResid") {
333 error = normRes/sqrt(n);
334 } else {
335 UTIL_THROW("Invalid iterator error type in parameter file.");
336 }
337 //Log::file() << ", error = " << Dbl(error, 15) << "\n";
338 }
339
340 return error;
341 }
342
343}
344}
345#endif
Template for Anderson mixing iterator algorithm.
Dynamic array on the GPU device with aligned data.
Definition rpg/System.h:32
int capacity() const
Return allocated capacity.
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Base class for iterators that impose incompressibility.
Anderson Mixing compressor with linear-response preconditioning.
LrAmPreCompressor(System< D > &system)
Constructor.
double computeError(DeviceArray< cudaReal > &residTrial, DeviceArray< cudaReal > &fieldTrial, std::string errorType, int verbose)
Compute and return error used to test for convergence.
void readParameters(std::istream &in)
Read all parameters and initialize.
void setup(bool isContinuation)
Initialize just before entry to iterative loop.
void clearTimers()
Reset / clear all timers.
int compress()
Compress to obtain partial saddle point w+.
void outputTimers(std::ostream &out)
Write a report of time contributions used by this algorithm.
Main class for calculations that represent one system.
Definition rpg/System.h:107
Dynamically allocatable contiguous array template.
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:57
Class for storing history of previous values in an array.
Definition RingBuffer.h:27
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:51
cudaReal innerProduct(DeviceArray< cudaReal > const &a, DeviceArray< cudaReal > const &b)
Compute inner product of two real arrays (GPU kernel wrapper).
Definition Reduce.cu:891
cudaReal maxAbs(DeviceArray< cudaReal > const &in)
Get maximum absolute magnitude of array elements (GPU kernel wrapper).
Definition Reduce.cu:648
void addEqV(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, const int beginIdA, const int beginIdB, const int n)
Vector addition in-place, a[i] += b[i], kernel wrapper (cudaReal).
Definition VecOp.cu:1632
void eqV(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, const int beginIdA, const int beginIdB, const int n)
Vector assignment, a[i] = b[i], kernel wrapper (cudaReal).
Definition VecOp.cu:1020
void subVS(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, cudaReal const c, const int beginIdA, const int beginIdB, const int n)
Vector subtraction, a[i] = b[i] - c, kernel wrapper (cudaReal).
Definition VecOp.cu:1304
void addVV(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, DeviceArray< cudaReal > const &c, const int beginIdA, const int beginIdB, const int beginIdC, const int n)
Vector addition, a[i] = b[i] + c[i], kernel wrapper (cudaReal).
Definition VecOp.cu:1084
void subVV(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, DeviceArray< cudaReal > const &c, const int beginIdA, const int beginIdB, const int beginIdC, const int n)
Vector subtraction, a[i] = b[i] - c[i], kernel wrapper (cudaReal).
Definition VecOp.cu:1228
void divEqVc(DeviceArray< cudaComplex > &a, DeviceArray< cudaReal > const &b, cudaReal const c)
Vector division in-place w/ coeff., a[i] /= (b[i] * c), kernel wrapper.
Definition VecOpMisc.cu:377
void addEqVc(DeviceArray< cudaReal > &a, DeviceArray< cudaReal > const &b, cudaReal const c)
Vector addition in-place w/ coefficient, a[i] += b[i] * c, kernel wrapper.
Definition VecOpMisc.cu:343
PSCF package top-level namespace.
Definition param_pc.dox:1
Utility classes for scientific computation.