PSCF v1.3
rpc/fts/compressor/AmCompressor.tpp
1#ifndef RPC_AM_COMPRESSOR_TPP
2#define RPC_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 "AmCompressor.h"
12#include <rpc/system/System.h>
13#include <util/global.h>
14
15namespace Pscf {
16namespace Rpc{
17
18 using namespace Util;
19
20 // Constructor
21 template <int D>
23 : Compressor<D>(system),
24 isAllocated_(false)
25 { setClassName("AmCompressor"); }
26
27 // Destructor
28 template <int D>
31
32 // Read parameters from file
33 template <int D>
34 void AmCompressor<D>::readParameters(std::istream& in)
35 {
36 // Call parent class readParameters
39 }
40
41 // Initialize just before entry to iterative loop.
42 template <int D>
43 void AmCompressor<D>::setup(bool isContinuation)
44 {
45 const int nMonomer = system().mixture().nMonomer();
46 const int meshSize = system().domain().mesh().size();
47 IntVec<D> const & dimensions = system().domain().mesh().dimensions();
48 // Allocate memory required by AM algorithm if not done earlier.
50
51 // Allocate memory required by compressor if not done earlier.
52 if (!isAllocated_){
53 newBasis_.allocate(meshSize);
54 w0_.allocate(nMonomer);
55 wFieldTmp_.allocate(nMonomer);
56 for (int i = 0; i < nMonomer; ++i) {
57 w0_[i].allocate(dimensions);
58 wFieldTmp_[i].allocate(dimensions);
59 }
60 isAllocated_ = true;
61 }
62
63 // Store value of initial guess chemical potential fields
64 for (int i = 0; i < nMonomer; ++i) {
65 for (int j = 0; j< meshSize; ++j){
66 w0_[i][j] = system().w().rgrid(i)[j];
67 }
68 }
69 }
70
71 template <int D>
73 {
75 //mdeCounter_ = AmIteratorTmpl<Compressor<D>,DArray<double>>::totalItr();
76 return solve;
77 }
78
79 // Assign one array to another
80 template <int D>
81 void AmCompressor<D>::setEqual(DArray<double>& a, DArray<double> const & b)
82 { a = b; }
83
84 // Compute and return inner product of two vectors.
85 template <int D>
86 double AmCompressor<D>::dotProduct(DArray<double> const & a,
87 DArray<double> const & b)
88 {
89 const int n = a.capacity();
90 UTIL_CHECK(b.capacity() == n);
91 double product = 0.0;
92 for (int i = 0; i < n; i++) {
93 // if either value is NaN, throw NanException
94 if (std::isnan(a[i]) || std::isnan(b[i])) {
95 throw NanException("AmCompressor::dotProduct",__FILE__,__LINE__,0);
96 }
97 product += a[i] * b[i];
98 }
99 return product;
100 }
101
102 // Compute and return maximum element of a vector.
103 template <int D>
104 double AmCompressor<D>::maxAbs(DArray<double> const & a)
105 {
106 const int n = a.capacity();
107 double max = 0.0;
108 double value;
109 for (int i = 0; i < n; i++) {
110 value = a[i];
111 if (std::isnan(value)) { // if value is NaN, throw NanException
112 throw NanException("AmCompressor::dotProduct",__FILE__,__LINE__,0);
113 }
114 if (fabs(value) > max) {
115 max = fabs(value);
116 }
117 }
118 return max;
119 }
120
121 // Update basis
122 template <int D>
123 void
124 AmCompressor<D>::updateBasis(RingBuffer< DArray<double> > & basis,
125 RingBuffer< DArray<double> > const & hists)
126 {
127 // Make sure at least two histories are stored
128 UTIL_CHECK(hists.size() >= 2);
129
130 const int n = hists[0].capacity();
131
132 // New basis vector is difference between two most recent states
133 for (int i = 0; i < n; i++) {
134 newBasis_[i] = hists[0][i] - hists[1][i];
135 }
136
137 basis.append(newBasis_);
138 }
139
140 template <int D>
141 void
142 AmCompressor<D>::addHistories(DArray<double>& trial,
143 RingBuffer<DArray<double> > const & basis,
144 DArray<double> coeffs,
145 int nHist)
146 {
147 int n = trial.capacity();
148 for (int i = 0; i < nHist; i++) {
149 for (int j = 0; j < n; j++) {
150 // Not clear on the origin of the -1 factor
151 trial[j] += coeffs[i] * -1 * basis[i][j];
152 }
153 }
154 }
155
156 template <int D>
157 void AmCompressor<D>::addPredictedError(DArray<double>& fieldTrial,
158 DArray<double> const & resTrial,
159 double lambda)
160 {
161 int n = fieldTrial.capacity();
162 for (int i = 0; i < n; i++) {
163 fieldTrial[i] += lambda * resTrial[i];
164 }
165 }
166
167 // Does the system have an initial field guess?
168 template <int D>
169 bool AmCompressor<D>::hasInitialGuess()
170 { return system().w().hasData(); }
171
172 // Compute and return the number of elements in a field vector
173 template <int D>
174 int AmCompressor<D>::nElements()
175 { return system().domain().mesh().size(); }
176
177 // Get the current field from the system
178 template <int D>
179 void AmCompressor<D>::getCurrent(DArray<double>& curr)
180 {
181 // Straighten out fields into linear arrays
182 const int meshSize = system().domain().mesh().size();
183 const DArray< RField<D> > * currSys = &system().w().rgrid();
184
185 /*
186 * The field that we are adjusting is the Langrange multiplier field
187 * with number of grid pts components.The current value is the difference
188 * between w and w0_ for the first monomer (any monomer should give the same answer)
189 */
190 for (int i = 0; i < meshSize; i++){
191 curr[i] = (*currSys)[0][i] - w0_[0][i];
192 }
193
194 }
195
196 // Perform the main system computation (solve the MDE)
197 template <int D>
198 void AmCompressor<D>::evaluate()
199 {
200 system().compute();
201 ++mdeCounter_;
202 }
203
204 // Compute the residual for the current system state
205 template <int D>
206 void AmCompressor<D>::getResidual(DArray<double>& resid)
207 {
208 const int n = nElements();
209 const int nMonomer = system().mixture().nMonomer();
210 const int meshSize = system().domain().mesh().size();
211
212 // Initialize residuals
213 for (int i = 0 ; i < n; ++i) {
214 resid[i] = -1.0;
215 }
216
217 // Compute SCF residual vector elements
218 for (int j = 0; j < nMonomer; ++j) {
219 for (int k = 0; k < meshSize; ++k) {
220 resid[k] += system().c().rgrid(j)[k];
221 }
222 }
223
224 }
225
226 // Update the current system field coordinates
227 template <int D>
228 void AmCompressor<D>::update(DArray<double>& newGuess)
229 {
230 // Convert back to field format
231 const int nMonomer = system().mixture().nMonomer();
232 const int meshSize = system().domain().mesh().size();
233
234 //New field is the w0_ + the newGuess for the Lagrange multiplier field
235 for (int i = 0; i < nMonomer; i++){
236 for (int k = 0; k < meshSize; k++){
237 wFieldTmp_[i][k] = w0_[i][k] + newGuess[k];
238 }
239 }
240 system().w().setRGrid(wFieldTmp_);
241 }
242
243 template<int D>
245 {
246 return 1.0;
247 }
248
249 template<int D>
250 void AmCompressor<D>::outputToLog()
251 {}
252
253 template<int D>
254 void AmCompressor<D>::outputTimers(std::ostream& out) const
255 {
256 // Output timing results, if requested.
257 out << "\n";
258 out << "AmCompressor time contributions:\n";
260 }
261
262 // Clear timers and MDE counter
263 template<int D>
269
270}
271}
272#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Exception thrown when not-a-number (NaN) is encountered.
void setup(bool isContinuation)
Initialize just before entry to iterative loop.
int compress()
Compress to obtain partial saddle point w+.
double computeLambda(double r)
Compute mixing parameter lambda.
AmCompressor(System< D > &system)
Constructor.
void readParameters(std::istream &in)
Read all parameters and initialize.
void outputTimers(std::ostream &out) const
Return compressor times contributions.
void clearTimers()
Clear all timers (reset accumulated time to zero).
Base class for iterators that impose incompressibility.
Main class, representing one complete system.
int capacity() const
Return allocated size.
Definition Array.h:159
Dynamically allocatable contiguous array template.
Definition DArray.h:32
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
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.
Definition param_pc.dox:1
float product(float a, float b)
Product for float Data.
Definition product.h:22