PSCF v1.3.1
WFieldsTmpl.tpp
1#ifndef PRDC_W_FIELDS_TMPL_TPP
2#define PRDC_W_FIELDS_TMPL_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 "WFieldsTmpl.h"
12#include <prdc/field/fieldIoUtil.h>
13#include <prdc/crystal/Basis.h>
14#include <prdc/crystal/UnitCell.h>
15#include <pscf/mesh/Mesh.h>
16#include <util/signal/Signal.h>
17#include <util/misc/FileMaster.h>
18
19namespace Pscf {
20namespace Prdc {
21
22 using namespace Util;
23
24 // Public member functions
25
26 /*
27 * Constructor.
28 */
29 template <int D, class RFT, class FIT>
31 : basis_(),
32 rgrid_(),
33 meshDimensions_(),
34 meshSize_(0),
35 nBasis_(0),
36 nMonomer_(0),
37 readUnitCellPtr_(nullptr),
38 writeUnitCellPtr_(nullptr),
39 fieldIoPtr_(nullptr),
40 signalPtr_(nullptr),
41 isAllocatedRGrid_(false),
42 isAllocatedBasis_(false),
43 hasData_(false),
44 isSymmetric_(false)
45 {
46 signalPtr_ = new Signal<void>();
47 }
48
49 /*
50 * Destructor.
51 */
52 template <int D, class RFT, class FIT>
54 {
55 delete signalPtr_;
56 }
57
58 /*
59 * Create an association with a FIT object.
60 */
61 template <int D, class RFT, class FIT>
62 void
64 { fieldIoPtr_ = &fieldIo; }
65
66 /*
67 * Set the unit cell that is modified by reading a field file.
68 */
69 template <int D, class RFT, class FIT>
71 {
72 UTIL_CHECK(!readUnitCellPtr_);
73 readUnitCellPtr_ = &cell;
74 }
75
76 /*
77 * Set the unit cell that whose parameters are written to a field header.
78 */
79 template <int D, class RFT, class FIT>
81 {
82 UTIL_CHECK(!writeUnitCellPtr_);
83 writeUnitCellPtr_ = &cell;
84 }
85
86 /*
87 * Set the stored value of nMonomer (this may only be called once).
88 */
89 template <int D, class RFT, class FIT>
91 {
92 UTIL_CHECK(nMonomer_ == 0);
94 nMonomer_ = nMonomer;
95 }
96
97 /*
98 * Allocate memory for fields in r-grid format.
99 */
100 template <int D, class RFT, class FIT>
101 void
103 {
104 UTIL_CHECK(nMonomer_ > 0);
105 UTIL_CHECK(!hasData_);
106 UTIL_CHECK(!isAllocatedRGrid_);
107
108 // Store mesh dimensions
109 meshDimensions_ = meshDimensions;
110 meshSize_ = 1;
111 for (int i = 0; i < D; ++i) {
113 meshSize_ *= meshDimensions[i];
114 }
116 // Allocate arrays
117 rgrid_.allocate(nMonomer_);
118 for (int i = 0; i < nMonomer_; ++i) {
119 rgrid_[i].allocate(meshDimensions);
120 }
121 isAllocatedRGrid_ = true;
122
123 }
124
125 /*
126 * Allocate memory for fields in basis format.
127 */
128 template <int D, class RFT, class FIT>
130 {
131 UTIL_CHECK(nMonomer_ > 0);
132 UTIL_CHECK(nBasis > 0);
133 UTIL_CHECK(!isAllocatedBasis_);
134 UTIL_CHECK(!hasData_);
135
136 nBasis_ = nBasis;
137 basis_.allocate(nMonomer_);
138 for (int i = 0; i < nMonomer_; ++i) {
139 basis_[i].allocate(nBasis);
140 }
141 isAllocatedBasis_ = true;
142 }
143
144 /*
145 * Allocate memory for all fields.
146 */
147 template <int D, class RFT, class FIT>
148 void
150 int nBasis,
152 {
156 }
157
158 // Field Modification Functions
159
160 /*
161 * Set new field values, in basis form.
162 */
163 template <int D, class RFT, class FIT>
164 void
166 {
167 UTIL_CHECK(fields.capacity() == nMonomer_);
168
169 // Allocate fields if needed
170 if (!isAllocatedRGrid_) {
171 Mesh<D> const & mesh = fieldIo().mesh();
172 UTIL_CHECK(mesh.size() > 0);
174 }
175 if (!isAllocatedBasis_) {
176 Basis<D> const & basis = fieldIo().basis();
177 UTIL_CHECK(basis.isInitialized());
178 allocateBasis(basis.nBasis());
179 }
180 UTIL_CHECK(isAllocatedRGrid_);
181 UTIL_CHECK(isAllocatedBasis_);
182
183 // Set components in basis form (array basis_)
184 for (int i = 0; i < nMonomer_; ++i) {
185 DArray<double> const & f = fields[i];
186 DArray<double> & w = basis_[i];
187 UTIL_CHECK(f.capacity() == nBasis_);
188 UTIL_CHECK(w.capacity() == nBasis_);
189 for (int j = 0; j < nBasis_; ++j) {
190 w[j] = f[j];
191 }
192 }
193
194 // Convert to r-grid form (update array rgrid_)
195 fieldIo().convertBasisToRGrid(basis_, rgrid_);
196
197 hasData_ = true;
198 isSymmetric_ = true;
199
200 // Notify signal observers of field modification
201 signal().notify();
202 }
203
204 /*
205 * Set new field values, in r-grid form.
206 */
207 template <int D, class RFT, class FIT>
208 void
210 bool isSymmetric)
212 // Allocate r-grid fields as needed
213 if (!isAllocatedRGrid_) {
214 Mesh<D> const & mesh = fieldIo().mesh();
215 UTIL_CHECK(mesh.size() > 0);
217 }
218 UTIL_CHECK(isAllocatedRGrid_);
219
220 // Update rgrid_ fields
221 UTIL_CHECK(fields.capacity() == nMonomer_);
222 for (int i = 0; i < nMonomer_; ++i) {
223 UTIL_CHECK(fields[i].capacity() == meshSize_);
224 assignRField(rgrid_[i], fields[i]);
225 }
227 // Optionally convert to basis form
228 if (isSymmetric) {
229 if (!isAllocatedBasis_) {
230 Basis<D> const & basis = fieldIo().basis();
231 UTIL_CHECK(basis.isInitialized());
232 allocateBasis(basis.nBasis());
233 }
234 fieldIo().convertRGridToBasis(rgrid_, basis_);
235 }
236
237 hasData_ = true;
238 isSymmetric_ = isSymmetric;
239
240 // Notify signal observers of field modification
241 signal().notify();
242 }
243
244 /*
245 * Read fields from an input stream in basis format.
246 *
247 * This function also computes and stores the corresponding r-grid
248 * representation. On return, hasData and isSymmetric are both true.
249 */
250 template <int D, class RFT, class FIT>
251 void
253 {
254 // Preconditions
255 UTIL_CHECK(nMonomer_ > 0);
256 UTIL_CHECK(readUnitCellPtr_);
257
258 // Read field file header
259 int nMonomerIn;
260 bool isSymmetricIn;
261 fieldIo().readFieldHeader(in, nMonomerIn, *readUnitCellPtr_,
262 isSymmetricIn);
263 // Note: FieldIo::readFieldHeader initializes basis if needed
264 UTIL_CHECK(nMonomerIn == nMonomer_);
265 UTIL_CHECK(isSymmetricIn);
266 int nBasisIn = readNBasis(in);
267
268 // Local references to mesh and basis
269 Mesh<D> const & mesh = fieldIo().mesh();
270 Basis<D> const & basis = fieldIo().basis();
271 UTIL_CHECK(mesh.size() > 0);
272 UTIL_CHECK(basis.isInitialized());
273
274 // If necessary, allocate fields
275 if (!isAllocatedRGrid_) {
277 }
278 if (!isAllocatedBasis_) {
279 allocateBasis(basis.nBasis());
280 }
281 UTIL_CHECK(isAllocatedRGrid_);
282 UTIL_CHECK(isAllocatedBasis_);
283
284 // Read data in basis form (array basis_)
285 Prdc::readBasisData(in, basis_,
286 *readUnitCellPtr_, mesh, basis, nBasisIn);
287
288 // Convert to r-grid form (array rgrid_)
289 fieldIo().convertBasisToRGrid(basis_, rgrid_);
290
291 hasData_ = true;
292 isSymmetric_ = true;
293
294 // Notify signal observers of field modification
295 signal().notify();
296 }
297
298 /*
299 * Read fields from a file in basis format, by filename.
300 *
301 * Calls readBasis(std::ifstream&) internally.
302 */
303 template <int D, class RFT, class FIT>
304 void
306 {
307 std::ifstream file;
308 fieldIo().fileMaster().openInputFile(filename, file);
309 readBasis(file);
310 file.close();
311 }
312
313 /*
314 * Read fields from an input stream in real-space (r-grid) format.
316 * If the isSymmetric parameter is true, this function assumes that
317 * the fields are known to be symmetric and so computes and stores
318 * the corresponding basis components. If isSymmetric is false, it
319 * only sets the values in the r-grid format.
320 *
321 * On return, hasData is true and the bool class member isSymmetric_
322 * is set to the value of the isSymmetric function parameter.
323 */
324 template <int D, class RFT, class FIT>
325 void
327 bool isSymmetric)
328 {
329 // Preconditions
330 UTIL_CHECK(nMonomer_ > 0);
331 UTIL_CHECK(readUnitCellPtr_);
332
333 // If necessary, allocate r-grid fields
334 if (!isAllocatedRGrid_) {
335 Mesh<D> const & mesh = fieldIo().mesh();
337 }
338
339 // Read field file in r-grid format (array rgrid_)
340 fieldIo().readFieldsRGrid(in, rgrid_, *readUnitCellPtr_);
341
342 // Optionally convert to basis form
343 if (isSymmetric) {
344 Basis<D> const & basis = fieldIo().basis();
345 UTIL_CHECK(basis.isInitialized());
346 if (!isAllocatedBasis_) {
347 allocateBasis(basis.nBasis());
348 }
349 fieldIo().convertRGridToBasis(rgrid_, basis_);
350 }
351
352 hasData_ = true;
353 isSymmetric_ = isSymmetric;
354
355 // Notify signal observers of field modification
356 signal().notify();
357 }
358
359 /*
360 * Read fields from a file in r-grid format, by filename.
361 */
362 template <int D, class RFT, class FIT>
363 void
365 bool isSymmetric)
366 {
367 std::ifstream file;
368 fieldIo().fileMaster().openInputFile(filename, file);
369 readRGrid(file, isSymmetric);
370 file.close();
371 }
372
373 /*
374 * Symmetrize r-grid fields, convert to basis format.
375 */
376 template <int D, class RFT, class FIT>
378 {
379 UTIL_CHECK(hasData_);
380 fieldIo().convertRGridToBasis(rgrid_, basis_);
381 fieldIo().convertBasisToRGrid(basis_, rgrid_);
382 isSymmetric_ = true;
383
384 // Notify signal observers of field modification
385 signal().notify();
386 }
387
388 // Field output to file
389
390 /*
391 * Write fields to an output stream in basis format.
392 */
393 template <int D, class RFT, class FIT>
394 void WFieldsTmpl<D,RFT,FIT>::writeBasis(std::ostream& out) const
395 {
396 // Preconditions
397 UTIL_CHECK(nMonomer_ > 0);
398 UTIL_CHECK(fieldIoPtr_);
399 UTIL_CHECK(writeUnitCellPtr_);
400 UTIL_CHECK(isAllocatedBasis_);
401 UTIL_CHECK(hasData_);
402 UTIL_CHECK(isSymmetric_);
403
404 fieldIo().writeFieldsBasis(out, basis_, *writeUnitCellPtr_);
405 }
406
407 /*
408 * Write fields to a file in basis format, by filename.
409 */
410 template <int D, class RFT, class FIT>
411 void WFieldsTmpl<D,RFT,FIT>::writeBasis(std::string filename) const
412 {
413 std::ofstream file;
414 fieldIo().fileMaster().openOutputFile(filename, file);
415 writeBasis(file);
416 file.close();
417 }
418
419 /*
420 * Write fields to an output stream in real-space (r-grid) format.
421 */
422 template <int D, class RFT, class FIT>
423 void WFieldsTmpl<D,RFT,FIT>::writeRGrid(std::ostream& out) const
424 {
425 // Preconditions
426 UTIL_CHECK(nMonomer_ > 0);
427 UTIL_CHECK(writeUnitCellPtr_);
428 UTIL_CHECK(fieldIoPtr_);
429 UTIL_CHECK(isAllocatedRGrid_);
430 UTIL_CHECK(hasData_);
431
432 bool writeHeader = true;
433
434 fieldIo().writeFieldsRGrid(out, rgrid_, *writeUnitCellPtr_, writeHeader,
435 isSymmetric_);
436 }
437
438 /*
439 * Write fields to a file in r-grid format, by filename.
440 */
441 template <int D, class RFT, class FIT>
442 void WFieldsTmpl<D,RFT,FIT>::writeRGrid(std::string filename) const
443 {
444 std::ofstream file;
445 fieldIo().fileMaster().openOutputFile(filename, file);
446 writeRGrid(file);
447 file.close();
448 }
449
450 // Signal accessor
451
452 /*
453 * Get the Signal<void> that is triggered by field modification.
454 */
455 template <int D, class RFT, class FIT>
457 {
458 UTIL_CHECK(signalPtr_);
459 return *signalPtr_;
460 }
461
462 // Private virtual function
463
464 /*
465 * Assignment operation for r-grid fields (RFT objects).
466 *
467 * Unimplemented virtual function - must be overridden by subclasses.
468 */
469 template <int D, class RFT, class FIT>
470 void
471 WFieldsTmpl<D,RFT,FIT>::assignRField(RFT & lhs, RFT const & rhs) const
472 { UTIL_THROW("Unimplemented function WFieldsTmpl::assignRField");
473
474}
475
476} // namespace Prdc
477} // namespace Pscf
478#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Description of a regular grid of points in a periodic domain.
Definition Mesh.h:61
IntVec< D > dimensions() const
Get an IntVec<D> of the grid dimensions.
Definition Mesh.h:217
int size() const
Get total number of grid points.
Definition Mesh.h:229
Symmetry-adapted Fourier basis for pseudo-spectral SCFT.
Definition Basis.h:383
int nBasis() const
Total number of nonzero symmetry-adapted basis functions.
Definition Basis.tpp:936
bool isInitialized() const
Returns true iff this basis is fully initialized.
Definition Basis.h:898
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
IntVec< D > const & meshDimensions() const
Get mesh dimensions in each direction, set on r-grid allocation.
void setBasis(DArray< DArray< double > > const &fields)
Set field component values, in symmetrized Fourier format.
void symmetrize()
Symmetrize r-grid fields, compute corresponding basis components.
FIT const & fieldIo() const
Get associated FIT object (const reference).
void writeRGrid(std::ostream &out) const
Writes fields to an input stream in real-space (r-grid) format.
void readBasis(std::istream &in)
Read fields from an input stream in symmetrized basis format.
Signal< void > & signal()
Get a signal that notifies observers of field modification.
void allocateRGrid(IntVec< D > const &dimensions)
Allocate or re-allocate memory for fields in rgrid format.
void setWriteUnitCell(UnitCell< D > const &cell)
Set unit cell used when writing field files.
bool isSymmetric() const
Are fields symmetric under all elements of the space group?
int nBasis() const
Get number of basis functions, set on basis allocation.
void allocateBasis(int nBasis)
Allocate or re-allocate memory for fields in basis format.
WFieldsTmpl()
Constructor.
void setReadUnitCell(UnitCell< D > &cell)
Set unit cell used when reading field files.
void setFieldIo(FIT const &fieldIo)
Create association with FIT (store pointer).
void setNMonomer(int nMonomer)
Set stored value of nMonomer.
void allocate(int nMonomer, int nBasis, IntVec< D > const &dimensions)
Allocate memory for all fields.
int nMonomer() const
Get number of monomer types.
void writeBasis(std::ostream &out) const
Write fields to an input stream in symmetrized basis format.
void setRGrid(DArray< RFT > const &fields, bool isSymmetric=false)
Set fields values in real-space (r-grid) format.
void readRGrid(std::istream &in, bool isSymmetric=false)
Reads fields from an input stream in real-space (r-grid) format.
int capacity() const
Return allocated size.
Definition Array.h:159
Dynamically allocatable contiguous array template.
Definition DArray.h:32
Notifier (or subject) in the Observer design pattern.
Definition Signal.h:39
#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
int readNBasis(std::istream &in)
Read the number of basis functions from a basis field file header.
void readBasisData(std::istream &in, DArray< DArray< double > > &fields, UnitCell< D > const &unitCell, Mesh< D > const &mesh, Basis< D > const &basis, int nStarIn)
Read an array of fields in basis format, without a header.
Periodic fields and crystallography.
Definition CField.cpp:11
PSCF package top-level namespace.
Definition param_pc.dox:1