PSCF v1.3
WFieldsReal.tpp
1#ifndef PRDC_W_FIELDS_REAL_TPP
2#define PRDC_W_FIELDS_REAL_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 "WFieldsReal.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 WFieldsReal<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 WFieldsReal<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 WFieldsReal<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 WFieldsReal<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 WFieldsReal<D,RFT,FIT>::assignRField(RFT & lhs, RFT const & rhs) const
472 { UTIL_THROW("Unimplemented function WFieldsReal::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
void allocateRGrid(IntVec< D > const &dimensions)
Allocate or re-allocate memory for fields in rgrid format.
void allocate(int nMonomer, int nBasis, IntVec< D > const &dimensions)
Allocate memory for all fields.
WFieldsReal()
Constructor.
void readRGrid(std::istream &in, bool isSymmetric=false)
Reads fields from an input stream in real-space (r-grid) format.
void symmetrize()
Symmetrize r-grid fields, compute corresponding basis components.
FIT const & fieldIo() const
Get associated FIT object (const reference).
void setBasis(DArray< DArray< double > > const &fields)
Set field component values, in symmetrized Fourier format.
void setNMonomer(int nMonomer)
Set stored value of nMonomer.
int nBasis() const
Get number of basis functions, set on basis allocation.
void setWriteUnitCell(UnitCell< D > const &cell)
Set unit cell used when writing field files.
void allocateBasis(int nBasis)
Allocate or re-allocate memory for fields in basis format.
void setFieldIo(FIT const &fieldIo)
Create association with FIT (store pointer).
bool isSymmetric() const
Are fields symmetric under all elements of the space group?
void writeBasis(std::ostream &out) const
Write fields to an input stream in symmetrized basis format.
Signal< void > & signal()
Get a signal that notifies observers of field modification.
void setRGrid(DArray< RFT > const &fields, bool isSymmetric=false)
Set fields values in real-space (r-grid) format.
void writeRGrid(std::ostream &out) const
Writes fields to an input stream in real-space (r-grid) format.
void setReadUnitCell(UnitCell< D > &cell)
Set unit cell used when reading field files.
IntVec< D > const & meshDimensions() const
Get mesh dimensions in each direction, set on r-grid allocation.
void readBasis(std::istream &in)
Read fields from an input stream in symmetrized basis format.
int nMonomer() const
Get number of monomer types.
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