PSCF v1.1
AmIteratorGrid.tpp
1#ifndef PSPG_AM_ITERATOR_GRID_TPP
2#define PSPG_AM_ITERATOR_GRID_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 "AmIteratorGrid.h"
12#include <pspg/System.h>
13#include <pscf/inter/Interaction.h>
14#include <pspg/field/RDField.h>
15#include <util/global.h>
16
17namespace Pscf {
18namespace Pspg {
19
20 using namespace Util;
21
22 // Constructor
23 template <int D>
25 : Iterator<D>(system)
26 {}
27
28 // Destructor
29 template <int D>
31 {}
32
33 // Read parameter file block
34 template <int D>
35 void AmIteratorGrid<D>::readParameters(std::istream& in)
36 {
37 // Call parent class readParameters
38 AmIteratorTmpl<Iterator<D>,FieldCUDA>::readParameters(in);
39 AmIteratorTmpl<Iterator<D>,FieldCUDA>::readErrorType(in);
40
41 // Allocate local modified copy of Interaction class
42 interaction_.setNMonomer(system().mixture().nMonomer());
43
44 // Default parameter values
45 isFlexible_ = 1;
46 scaleStress_ = 10.0;
47
48 // Read in additional parameters
49 readOptional(in, "isFlexible", isFlexible_);
50 readOptional(in, "scaleStress", scaleStress_);
51 }
52
53 // Protected virtual function
54
55 // Setup before entering iteration loop
56 template <int D>
57 void AmIteratorGrid<D>::setup(bool isContinuation)
58 {
59 AmIteratorTmpl<Iterator<D>, FieldCUDA>::setup(isContinuation);
60 interaction_.update(system().interaction());
61 }
62
63 // Private virtual functions used to implement AM algorithm
64
65 template <int D>
67 {
68 // GPU resources
69 int nBlocks, nThreads;
70 ThreadGrid::setThreadsLogical(a.capacity(), nBlocks, nThreads);
71
72 UTIL_CHECK(b.capacity() == a.capacity());
73 assignReal<<<nBlocks, nThreads>>>(a.cDField(), b.cDField(), a.capacity());
74 }
75
76 template <int D>
77 double AmIteratorGrid<D>::dotProduct(FieldCUDA const & a,
78 FieldCUDA const& b)
79 {
80 const int n = a.capacity();
81 UTIL_CHECK(b.capacity() == n);
82 double product = (double)gpuInnerProduct(a.cDField(), b.cDField(), n);
83 return product;
84 }
85
86 template <int D>
87 double AmIteratorGrid<D>::maxAbs(FieldCUDA const & a)
88 {
89 int n = a.capacity();
90 cudaReal max = gpuMaxAbs(a.cDField(), n);
91 return (double)max;
92 }
93
94 template <int D>
95 void AmIteratorGrid<D>::updateBasis(RingBuffer<FieldCUDA> & basis,
96 RingBuffer<FieldCUDA> const & hists)
97 {
98 // Make sure at least two histories are stored
99 UTIL_CHECK(hists.size() >= 2);
100
101 const int n = hists[0].capacity();
102 FieldCUDA newbasis;
103 newbasis.allocate(n);
104
105 // GPU resources
106 int nBlocks, nThreads;
107 ThreadGrid::setThreadsLogical(n, nBlocks, nThreads);
108
109 pointWiseBinarySubtract<<<nBlocks,nThreads>>>
110 (hists[0].cDField(),hists[1].cDField(),newbasis.cDField(),n);
111
112 basis.append(newbasis);
113 }
114
115 template <int D>
116 void AmIteratorGrid<D>::addHistories(FieldCUDA& trial,
117 RingBuffer<FieldCUDA> const & basis,
118 DArray<double> coeffs, int nHist)
119 {
120 // GPU resources
121 int nBlocks, nThreads;
122 ThreadGrid::setThreadsLogical(trial.capacity(), nBlocks, nThreads);
123
124 for (int i = 0; i < nHist; i++) {
125 pointWiseAddScale<<<nBlocks, nThreads>>>
126 (trial.cDField(), basis[i].cDField(), -1*coeffs[i], trial.capacity());
127 }
128 }
129
130 template <int D>
131 void AmIteratorGrid<D>::addPredictedError(FieldCUDA& fieldTrial,
132 FieldCUDA const & resTrial, double lambda)
133 {
134 // GPU resources
135 int nBlocks, nThreads;
136 ThreadGrid::setThreadsLogical(fieldTrial.capacity(), nBlocks, nThreads);
137
138 pointWiseAddScale<<<nBlocks, nThreads>>>
139 (fieldTrial.cDField(), resTrial.cDField(), lambda,
140 fieldTrial.capacity());
141 }
142
143 template <int D>
144 bool AmIteratorGrid<D>::hasInitialGuess()
145 { return system().w().hasData(); }
146
147 template <int D>
148 int AmIteratorGrid<D>::nElements()
149 {
150 const int nMonomer = system().mixture().nMonomer();
151 const int nMesh = system().mesh().size();
152
153 int nEle = nMonomer*nMesh;
154
155 if (isFlexible_) {
156 nEle += system().unitCell().nParameter();
157 }
158
159 return nEle;
160 }
161
162 template <int D>
163 void AmIteratorGrid<D>::getCurrent(FieldCUDA& curr)
164 {
165 const int nMonomer = system().mixture().nMonomer();
166 const int nMesh = system().mesh().size();
167 const int n = nElements();
168
169 // GPU resources
170 int nBlocks, nThreads;
171 ThreadGrid::setThreadsLogical(nMesh, nBlocks, nThreads);
172
173 // Pointer to fields on system
174 DArray<RDField<D>> const * currSys = &system().w().rgrid();
175
176 // Loop to unfold the system fields and store them in one long array
177 for (int i = 0; i < nMonomer; i++) {
178 assignReal<<<nBlocks,nThreads>>>(curr.cDField() + i*nMesh,
179 (*currSys)[i].cDField(), nMesh);
180 }
181
182 // If flexible unit cell, also store unit cell parameters
183 if (isFlexible_) {
184 const int nParam = system().unitCell().nParameter();
185 const FSArray<double,6> currParam = system().unitCell().parameters();
186 // convert into a cudaReal array
187 cudaReal* temp = new cudaReal[nParam];
188 for (int k = 0; k < nParam; k++)
189 temp[k] = (cudaReal)scaleStress_*currParam[k];
190
191 // Copy parameters to the end of the curr array
192 cudaMemcpy(curr.cDField() + nMonomer*nMesh, temp,
193 nParam*sizeof(cudaReal), cudaMemcpyHostToDevice);
194 delete[] temp;
195 }
196 }
197
198 template <int D>
199 void AmIteratorGrid<D>::evaluate()
200 {
201 // Solve MDEs for current omega field
202 system().compute();
203 // Compute stress if done
204 if (isFlexible_) {
205 system().mixture().computeStress(system().domain().waveList());
206 }
207 }
208
209 template <int D>
210 void AmIteratorGrid<D>::getResidual(FieldCUDA& resid)
211 {
212 const int n = nElements();
213 const int nMonomer = system().mixture().nMonomer();
214 const int nMesh = system().mesh().size();
215
216 // GPU resources
217 int nBlocks, nThreads;
218 ThreadGrid::setThreadsLogical(nMesh, nBlocks, nThreads);
219
220 // Initialize residuals to zero. Kernel will take care of potential
221 // additional elements (n vs nMesh).
222 assignUniformReal<<<nBlocks, nThreads>>>(resid.cDField(), 0, n);
223
224 // Compute SCF residuals
225 for (int i = 0; i < nMonomer; i++) {
226 int startIdx = i*nMesh;
227 for (int j = 0; j < nMonomer; j++) {
228 pointWiseAddScale<<<nBlocks, nThreads>>>
229 (resid.cDField() + startIdx,
230 system().c().rgrid(j).cDField(),
231 interaction_.chi(i, j),
232 nMesh);
233 pointWiseAddScale<<<nBlocks, nThreads>>>
234 (resid.cDField() + startIdx,
235 system().w().rgrid(j).cDField(),
236 -interaction_.p(i, j),
237 nMesh);
238 }
239 }
240
241 // If ensemble is not canonical, account for incompressibility.
242 if (!system().mixture().isCanonical()) {
243 cudaReal factor = 1/(cudaReal)interaction_.sumChiInverse();
244 for (int i = 0; i < nMonomer; ++i) {
245 subtractUniform<<<nBlocks, nThreads>>>(resid.cDField() + i*nMesh,
246 factor, nMesh);
247 }
248 } else {
249 for (int i = 0; i < nMonomer; i++) {
250 // Find current average
251 cudaReal average = findAverage(resid.cDField()+i*nMesh, nMesh);
252 // subtract out average to set residual average to zero
253 subtractUniform<<<nBlocks, nThreads>>>(resid.cDField() + i*nMesh,
254 average, nMesh);
255 }
256 }
257
258 // If variable unit cell, compute stress residuals
259 if (isFlexible_) {
260 const int nParam = system().unitCell().nParameter();
261 cudaReal* stress = new cudaReal[nParam];
262
263 for (int i = 0; i < nParam; i++) {
264 stress[i] = (cudaReal)(-1*scaleStress_*system().mixture().stress(i));
265 }
266
267 cudaMemcpy(resid.cDField()+nMonomer*nMesh, stress,
268 nParam*sizeof(cudaReal), cudaMemcpyHostToDevice);
269 }
270 }
271
272 template <int D>
273 void AmIteratorGrid<D>::update(FieldCUDA& newGuess)
274 {
275 const int nMonomer = system().mixture().nMonomer();
276 const int nMesh = system().mesh().size();
277
278 // GPU resources
279 int nBlocks, nThreads;
280 ThreadGrid::setThreadsLogical(nMesh, nBlocks, nThreads);
281
282 // If canonical, explicitly set homogeneous field components
283 if (system().mixture().isCanonical()) {
284 cudaReal average, wAverage, cAverage;
285 for (int i = 0; i < nMonomer; i++) {
286 // Find current spatial average
287 average = findAverage(newGuess.cDField() + i*nMesh, nMesh);
288
289 // Subtract average from field, setting average to zero
290 subtractUniform<<<nBlocks, nThreads>>>(newGuess.cDField() + i*nMesh,
291 average, nMesh);
292
293 // Compute the new average omega value, add it to all elements
294 wAverage = 0;
295 for (int j = 0; j < nMonomer; j++) {
296 // Find average concentration for j monomers
297 cAverage = findAverage(system().c().rgrid(j).cDField(), nMesh);
298 wAverage += interaction_.chi(i,j) * cAverage;
299 }
300 addUniform<<<nBlocks, nThreads>>>(newGuess.cDField() + i*nMesh,
301 wAverage, nMesh);
302 }
303 }
304
305 system().setWRGrid(newGuess);
306 system().symmetrizeWFields();
307
308 // If flexible unit cell, update cell parameters
309 if (isFlexible_) {
310 FSArray<double,6> parameters;
311 const int nParam = system().unitCell().nParameter();
312 cudaReal* temp = new cudaReal[nParam];
313
314 cudaMemcpy(temp, newGuess.cDField() + nMonomer*nMesh,
315 nParam*sizeof(cudaReal), cudaMemcpyDeviceToHost);
316 for (int i = 0; i < nParam; i++) {
317 parameters.append(1/scaleStress_ * (double)temp[i]);
318 }
319 system().setUnitCell(parameters);
320
321 delete[] temp;
322 }
323
324 }
325
326 template<int D>
327 void AmIteratorGrid<D>::outputToLog()
328 {
329 if (isFlexible_) {
330 const int nParam = system().unitCell().nParameter();
331 for (int i = 0; i < nParam; i++) {
332 Log::file() << "Parameter " << i << " = "
333 << Dbl(system().unitCell().parameters()[i])
334 << "\n";
335 }
336 }
337 }
338
339 // --- Private member functions that are specific to this implementation ---
340
341 template<int D>
342 cudaReal AmIteratorGrid<D>::findAverage(cudaReal const * field, int n)
343 {
344 cudaReal average = gpuSum(field, n)/n;
345 return average;
346 }
347
348
349
350}
351}
352#endif
Template for Anderson mixing iterator algorithm.
Pspg implementation of the Anderson Mixing iterator.
void readParameters(std::istream &in)
Read all parameters and initialize.
AmIteratorGrid(System< D > &system)
Constructor.
void setup(bool isContinuation)
Setup iterator just before entering iteration loop.
Data * cDField()
Return pointer to underlying C array.
Definition: DField.h:119
void allocate(int capacity)
Allocate the underlying C array on the device.
Definition: DField.tpp:52
int capacity() const
Return allocated size.
Definition: DField.h:112
Base class for iterative solvers for SCF equations.
Main class in SCFT simulation of one system.
Definition: pspg/System.h:71
int capacity() const
Return allocated size.
Definition: Array.h:159
Dynamically allocatable contiguous array template.
Definition: DArray.h:32
Wrapper for a double precision number, for formatted ostream output.
Definition: Dbl.h:40
A fixed capacity (static) contiguous array with a variable logical size.
Definition: FSArray.h:38
void append(Data const &data)
Append data to the end of the array.
Definition: FSArray.h:258
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
int capacity() const
Return the capacity of the buffer.
Definition: RingBuffer.h:333
int size() const
Return number of values currently in the buffer.
Definition: RingBuffer.h:325
void append(Data const &value)
Add a new value to the buffer.
Definition: RingBuffer.h:285
File containing preprocessor macros for error handling.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
int nThreads()
Get the number of threads per block for execution.
Definition: ThreadGrid.cu:173
int nBlocks()
Get the current number of blocks for execution.
Definition: ThreadGrid.cu:170
void setThreadsLogical(int nThreadsLogical)
Set the total number of threads required for execution.
Definition: ThreadGrid.cu:80
C++ namespace for polymer self-consistent field theory (PSCF).
Utility classes for scientific computation.
Definition: accumulators.mod:1
float product(float a, float b)
Product for float Data.
Definition: product.h:22