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