PSCF v1.3.2
rpc/scft/sweep/Sweep.tpp
1#ifndef RPC_SWEEP_TPP
2/*
3* PSCF - Polymer Self-Consistent Field
4*
5* Copyright 2015 - 2025, The Regents of the University of Minnesota
6* Distributed under the terms of the GNU General Public License.
7*/
8
9#include "Sweep.h"
10
11#include <rpc/scft/iterator/Iterator.h>
12#include <rpc/scft/ScftThermo.h>
13#include <rpc/system/System.h>
14#include <rpc/field/WFields.h>
15#include <rpc/field/CFields.h>
16#include <prdc/environment/Environment.h>
17#include <pscf/inter/Interaction.h>
18#include <pscf/sweep/SweepTmpl.tpp>
19#include <util/misc/FileMaster.h>
20#include <util/misc/ioUtil.h>
21
22namespace Pscf {
23namespace Rpc {
24
25 using namespace Util;
26
27 // Maximum number of previous states = order of continuation + 1
28 # define RPC_HISTORY_CAPACITY 3
29
30 /*
31 * Default constructor (for unit testing).
32 */
33 template <int D>
35 : SweepTmpl< BasisFieldState<D> >(RPC_HISTORY_CAPACITY),
36 writeCRGrid_(false),
37 writeCBasis_(false),
38 writeWRGrid_(false),
39 systemPtr_(nullptr)
40 {}
41
42 /*
43 * Constructor, creates association with parent system.
44 */
45 template <int D>
47 : SweepTmpl< BasisFieldState<D> >(RPC_HISTORY_CAPACITY),
48 writeCRGrid_(false),
49 writeCBasis_(false),
50 writeWRGrid_(false),
51 systemPtr_(&sys)
52 {
53 // Get specialized sweep parameters from Environment
54 if (system().hasEnvironment()) {
55 addParameterTypes(system().environment().getParameterTypes());
56 }
57 }
58
59 /*
60 * Destructor.
61 */
62 template <int D>
65
66 /*
67 * Set association with a parent system (for unit testing).
68 */
69 template <int D>
71 { systemPtr_ = &system; }
72
73 /*
74 * Read parameters
75 */
76 template <int D>
77 void Sweep<D>::readParameters(std::istream& in)
78 {
79 // Call the base class's readParameters function.
81
82 // Read optional flags indicating which field types to output
83 readOptional(in, "writeCRGrid", writeCRGrid_);
84 readOptional(in, "writeCBasis", writeCBasis_);
85 readOptional(in, "writeWRGrid", writeWRGrid_);
86 }
87
88 /*
89 * Check allocation of one state object, allocate if necessary.
90 */
91 template <int D>
93 {
95 state.setSystem(system());
96 state.allocate();
97 state.unitCell() = system().domain().unitCell();
98 }
99
100 /*
101 * Setup operations at the beginning of a sweep.
102 */
103 template <int D>
105 {
106 initialize();
107 checkAllocation(trial_);
108
109 // Open log summary file
110 std::string fileName = baseFileName_;
111 fileName += "sweep.log";
112 system().fileMaster().openOutputFile(fileName, logFile_);
113 logFile_ << " step ds free_energy pressure"
114 << std::endl;
115 };
116
117 /*
118 * Set non-adjustable system parameters to new values.
119 *
120 * \param s path length coordinate, in range [0,1]
121 */
122 template <int D>
124 {
125 // Empty default implementation allows Sweep<D> to be compiled.
126 UTIL_THROW("Calling unimplemented function Sweep::setParameters");
127 };
128
129 /*
130 * Create guess for adjustable variables by polynomial extrapolation.
131 */
132 template <int D>
133 void Sweep<D>::extrapolate(double sNew)
134 {
135 UTIL_CHECK(historySize() > 0);
136
137 // If historySize() == 1, do nothing: Use previous system state
138 // as trial for the new state.
139
140 if (historySize() > 1) {
142
143 // Does the iterator allow a flexible unit cell ?
144 bool isFlexible = system().iterator().isFlexible();
145
146 // Compute coefficients of polynomial extrapolation to sNew
147 setCoefficients(sNew);
148
149 // Set extrapolated trial w fields
150 double coeff;
151 int nMonomer = system().mixture().nMonomer();
152 int nBasis = system().domain().basis().nBasis();
153 DArray<double>* newFieldPtr;
154 DArray<double>* oldFieldPtr;
155 int i, j, k;
156 for (i=0; i < nMonomer; ++i) {
157 newFieldPtr = &(trial_.field(i));
158
159 // Previous state k = 0 (most recent)
160 oldFieldPtr = &state(0).field(i);
161 coeff = c(0);
162 for (j=0; j < nBasis; ++j) {
163 (*newFieldPtr)[j] = coeff*(*oldFieldPtr)[j];
164 }
165
166 // Previous states k >= 1 (older)
167 for (k = 1; k < historySize(); ++k) {
168 oldFieldPtr = &state(k).field(i);
169 coeff = c(k);
170 for (j=0; j < nBasis; ++j) {
171 (*newFieldPtr)[j] += coeff*(*oldFieldPtr)[j];
172 }
173 }
174 }
175
176 // Make sure unitCellParameters_ is up to date with system
177 // (if we are sweeping in a lattice parameter, then the system
178 // parameters will be up-to-date but unitCellParameters_ wont be)
179 FSArray<double, 6> oldParameters = unitCellParameters_;
180 unitCellParameters_ = system().domain().unitCell().parameters();
181
182 // If isFlexible, extrapolate the flexible unit cell parameters
183 if (isFlexible) {
184
185 double coeff;
186 double parameter;
187
188 const FSArray<bool,6> flexParams =
189 system().iterator().flexibleParams();
190 const int nParameter
191 = system().domain().unitCell().nParameter();
192 UTIL_CHECK(flexParams.size() == nParameter);
193
194 // Add contributions from all previous states
195 for (k = 0; k < historySize(); ++k) {
196 coeff = c(k);
197 for (int i = 0; i < nParameter; ++i) {
198 if (flexParams[i]) {
199 if (k == 0) {
200 unitCellParameters_[i] = 0;
201 }
202 parameter = state(k).unitCell().parameter(i);
203 unitCellParameters_[i] += coeff*parameter;
204 }
205 }
206 }
207 }
208
209 // Reset trial_.unitCell() object
210 trial_.unitCell().setParameters(unitCellParameters_);
211
212 // Check if any unit cell parameters have changed
213 bool newCellParams(true);
214 for (int i = 0; i < oldParameters.size(); i++) {
215 if (fabs(oldParameters[i] - unitCellParameters_[i]) < 1e-10) {
216 newCellParams = false;
217 break;
218 }
219 }
220
221 // Transfer data from trial_ state to parent system
222 trial_.setSystemState(newCellParams);
223 }
224
225
226 };
227
228 /*
229 * Call current iterator to solve SCFT problem.
230 *
231 * Return 0 for sucessful solution, 1 on failure to converge.
232 */
233 template <int D>
234 int Sweep<D>::solve(bool isContinuation)
235 { return system().iterate(isContinuation); };
236
237 /*
238 * Reset system to previous solution after iterature failure.
239 *
240 * The implementation of this function should reset the system state
241 * to correspond to that stored in state(0).
242 */
243 template <int D>
245 {
246 bool isFlexible = system().iterator().isFlexible();
247 state(0).setSystemState(isFlexible);
248 }
249
250 /*
251 * Update state(0) and output data after successful convergence
252 *
253 * The implementation of this function should copy the current
254 * system state into state(0) and output any desired information
255 * about the current converged solution.
256 */
257 template <int D>
259 {
260 state(0).setSystem(system());
261 state(0).getSystemState();
262
263 // Output converged solution to several files
264 outputSolution();
265
266 // Output summary to log file
267 outputSummary(logFile_);
268
269 };
270
271 template <int D>
272 void Sweep<D>::outputSolution()
273 {
274 std::ofstream out;
275 std::string outFileName;
276 std::string indexString = toString(nAccept() - 1);
277
278 // Open parameter file, with thermodynamic properties at end
279 outFileName = baseFileName_;
280 outFileName += indexString;
281 outFileName += ".stt";
282 system().fileMaster().openOutputFile(outFileName, out);
283
284 // Write data file, with thermodynamic properties at end
285 system().writeParamNoSweep(out);
286 out << std::endl;
287 system().scft().write(out);
288 out.close();
289
290 // FieldIo<D> const & fieldIo = system().domain().fieldIo();
291 // UnitCell<D> const & unitCell = system().domain().unitCell();
292
293 // Write w fields
294 UTIL_CHECK(system().w().hasData());
295 outFileName = baseFileName_;
296 outFileName += indexString;
297 outFileName += "_w";
298 if (system().w().isSymmetric()) {
299 outFileName += ".bf";
300 system().w().writeBasis(outFileName);
301 } else {
302 outFileName += ".rf";
303 system().w().writeRGrid(outFileName);
304 }
305
306 // Optionally write c rgrid files
307 if (writeCRGrid_) {
308 UTIL_CHECK(system().c().hasData());
309 outFileName = baseFileName_;
310 outFileName += indexString;
311 outFileName += "_c";
312 outFileName += ".rf";
313 system().c().writeRGrid(outFileName);
314 }
315
316 // Optionally write c basis files
317 if (writeCBasis_ && system().c().isSymmetric()) {
318 UTIL_CHECK(system().c().hasData());
319 outFileName = baseFileName_;
320 outFileName += indexString;
321 outFileName += "_c";
322 outFileName += ".bf";
323 system().c().writeBasis(outFileName);
324 }
325
326 // Optionally write w rgrid files if is symmetric
327 if (writeWRGrid_ && system().c().isSymmetric()) {
328 outFileName = baseFileName_;
329 outFileName += indexString;
330 outFileName += "_w";
331 outFileName += ".rf";
332 system().w().writeRGrid(outFileName);
333 }
334
335 }
336
337 template <int D>
338 void Sweep<D>::outputSummary(std::ostream& out)
339 {
340 int i = nAccept() - 1;
341 double sNew = s(0);
342 if (!system().scft().hasData()) system().scft().compute();
343 out << Int(i,5) << Dbl(sNew)
344 << Dbl(system().scft().fHelmholtz(),16)
345 << Dbl(system().scft().pressure(),16);
346 out << std::endl;
347 }
348
349 template <int D>
351 { logFile_.close(); }
352
353} // namespace Rpc
354} // namespace Pscf
355#endif
FieldState for fields in symmetry-adapted basis format.
virtual int solve(bool isContinuation)
Call current iterator to solve SCFT problem.
virtual void extrapolate(double sNew)
Create a guess for adjustable variables by continuation.
void setSystem(System< D > &system)
Set association with parent System.
Sweep()
Default Constructor.
virtual void getSolution()
Update state(0) and output data after successful convergence.
virtual void checkAllocation(BasisFieldState< D > &state)
Check allocation of fields in one state, allocate if necessary.
System< D > & system()
Return the parent system by reference.
ScalarParam< Type > & readOptional(std::istream &in, const char *label, Type &value)
Add and read a new optional ScalarParam < Type > object.
virtual void reset()
Reset system to previous solution after iterature failure.
bool writeCRGrid_
Should concentration fields be written to file in r-grid format?
virtual void cleanup()
Cleanup operation at the beginning of a sweep.
bool writeCBasis_
Should concentration fields be written to file in basis format?
virtual void readParameters(std::istream &in)
Read parameters from param file.
virtual void setParameters(double sNew)=0
Set system parameters to new values.
bool writeWRGrid_
Should converged w fields be written to file in r-grid format?
bool hasSystem()
Does an association with the parent System exist?
virtual void setup()
Setup operation at the beginning of a sweep.
Main class, representing a complete physical system.
void addParameterTypes(GArray< ParameterType > paramTypes)
BasisFieldState< D > & state(int i)
Definition SweepTmpl.h:127
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
int size() const
Return logical size of this array (i.e., number of elements).
Definition FSArray.h:207
Wrapper for an int, for formatted ostream output.
Definition Int.h:37
#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:49
std::string toString(int n)
Return string representation of an integer.
Definition ioUtil.cpp:52
Real periodic fields, SCFT and PS-FTS (CPU).
Definition param_pc.dox:2
PSCF package top-level namespace.