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