PSCF v1.4.0
rp/field/WFields.tpp
1#ifndef RP_W_FIELDS_TPP
2#define RP_W_FIELDS_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 "WFields.h"
12#include <prdc/field/rFieldIo.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 Rp {
21
22 using namespace Util;
23 using namespace Prdc;
24
25 // Public member functions
26
27 /*
28 * Constructor.
29 */
30 template <int D, class RFT, class FIT>
32 : basis_(),
33 rgrid_(),
34 meshDimensions_(),
35 meshSize_(0),
36 nBasis_(0),
37 nMonomer_(0),
38 readUnitCellPtr_(nullptr),
39 writeUnitCellPtr_(nullptr),
40 fieldIoPtr_(nullptr),
41 signalPtr_(nullptr),
42 isAllocatedRGrid_(false),
43 isAllocatedBasis_(false),
44 hasData_(false),
45 isSymmetric_(false)
46 {
47 signalPtr_ = new Signal<void>();
48 }
49
50 /*
51 * Destructor.
52 */
53 template <int D, class RFT, class FIT>
55 {
56 delete signalPtr_;
57 }
58
59 /*
60 * Create an association with a FIT object.
61 */
62 template <int D, class RFT, class FIT>
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 }
115
116 // Allocate arrays
117 rgrid_.allocate(nMonomer_);
118 for (int i = 0; i < nMonomer_; ++i) {
119 rgrid_[i].allocate(meshDimensions);
120 }
121
122 isAllocatedRGrid_ = true;
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>
156
157 // Field Modification Functions
158
159 /*
160 * Set new field values, in basis form.
161 */
162 template <int D, class RFT, class FIT>
163 void
165 {
166 UTIL_CHECK(fields.capacity() == nMonomer_);
167
168 // Allocate fields if needed
169 if (!isAllocatedRGrid_) {
170 Mesh<D> const & mesh = fieldIo().mesh();
171 UTIL_CHECK(mesh.size() > 0);
173 }
174 if (!isAllocatedBasis_) {
175 Basis<D> const & basis = fieldIo().basis();
176 UTIL_CHECK(basis.isInitialized());
177 allocateBasis(basis.nBasis());
178 }
179 UTIL_CHECK(isAllocatedRGrid_);
180 UTIL_CHECK(isAllocatedBasis_);
181
182 // Set components in basis form (array basis_)
183 for (int i = 0; i < nMonomer_; ++i) {
184 DArray<double> const & f = fields[i];
185 DArray<double> & w = basis_[i];
186 UTIL_CHECK(f.capacity() == nBasis_);
187 UTIL_CHECK(w.capacity() == nBasis_);
188 for (int j = 0; j < nBasis_; ++j) {
189 w[j] = f[j];
190 }
191 }
192
193 // Convert to r-grid form (update array rgrid_)
194 fieldIo().convertBasisToRGrid(basis_, rgrid_);
195
196 hasData_ = true;
197 isSymmetric_ = true;
198
199 // Notify signal observers of field modification
200 signal().notify();
201 }
202
203 /*
204 * Set new field values, in r-grid form.
205 */
206 template <int D, class RFT, class FIT>
207 void
209 bool isSymmetric)
210 {
211 // Allocate r-grid fields as needed
212 if (!isAllocatedRGrid_) {
213 Mesh<D> const & mesh = fieldIo().mesh();
214 UTIL_CHECK(mesh.size() > 0);
216 }
217 UTIL_CHECK(isAllocatedRGrid_);
218
219 // Update rgrid_ fields
220 UTIL_CHECK(fields.capacity() == nMonomer_);
221 for (int i = 0; i < nMonomer_; ++i) {
222 UTIL_CHECK(fields[i].capacity() == meshSize_);
223 VecOp::eqV(rgrid_[i], fields[i]);
224 }
225
226 // Optionally convert to basis form
227 if (isSymmetric) {
228 if (!isAllocatedBasis_) {
229 Basis<D> const & basis = fieldIo().basis();
230 UTIL_CHECK(basis.isInitialized());
231 allocateBasis(basis.nBasis());
232 }
233 fieldIo().convertRGridToBasis(rgrid_, basis_);
234 }
235
236 hasData_ = true;
237 isSymmetric_ = isSymmetric;
238
239 // Notify signal observers of field modification
240 signal().notify();
241 }
242
243 /*
244 * Read fields from an input stream in basis format.
245 *
246 * This function also computes and stores the corresponding r-grid
247 * representation. On return, hasData and isSymmetric are both true.
248 */
249 template <int D, class RFT, class FIT>
250 void
252 {
253 // Preconditions
254 UTIL_CHECK(nMonomer_ > 0);
255 UTIL_CHECK(readUnitCellPtr_);
256
257 // Read field file header
258 int nMonomerIn;
259 bool isSymmetricIn;
260 fieldIo().readFieldHeader(in, nMonomerIn, *readUnitCellPtr_,
261 isSymmetricIn);
262 // Note: FieldIo::readFieldHeader initializes basis if needed
263 UTIL_CHECK(nMonomerIn == nMonomer_);
264 UTIL_CHECK(isSymmetricIn);
265 int nBasisIn = readNBasis(in);
266
267 // Local references to mesh and basis
268 Mesh<D> const & mesh = fieldIo().mesh();
269 Basis<D> const & basis = fieldIo().basis();
270 UTIL_CHECK(mesh.size() > 0);
271 UTIL_CHECK(basis.isInitialized());
272
273 // If necessary, allocate fields
274 if (!isAllocatedRGrid_) {
276 }
277 if (!isAllocatedBasis_) {
278 allocateBasis(basis.nBasis());
279 }
280 UTIL_CHECK(isAllocatedRGrid_);
281 UTIL_CHECK(isAllocatedBasis_);
282
283 // Read data in basis form (array basis_)
284 Prdc::readBasisData(in, basis_,
285 *readUnitCellPtr_, mesh, basis, nBasisIn);
286
287 // Convert to r-grid form (array rgrid_)
288 fieldIo().convertBasisToRGrid(basis_, rgrid_);
289
290 hasData_ = true;
291 isSymmetric_ = true;
292
293 // Notify signal observers of field modification
294 signal().notify();
295 }
296
297 /*
298 * Read fields from a file in basis format, by filename.
299 *
300 * Calls readBasis(std::ifstream&) internally.
301 */
302 template <int D, class RFT, class FIT>
303 void
304 WFields<D,RFT,FIT>::readBasis(std::string filename)
305 {
306 std::ifstream file;
307 fieldIo().fileMaster().openInputFile(filename, file);
308 readBasis(file);
309 file.close();
310 }
311
312 /*
313 * Read fields from an input stream in real-space (r-grid) format.
314 *
315 * If the isSymmetric parameter is true, this function assumes that
316 * the fields are known to be symmetric and so computes and stores
317 * the corresponding basis components. If isSymmetric is false, it
318 * only sets the values in the r-grid format.
319 *
320 * On return, hasData is true and the bool class member isSymmetric_
321 * is set to the value of the isSymmetric function parameter.
322 */
323 template <int D, class RFT, class FIT>
324 void
326 bool isSymmetric)
327 {
328 // Preconditions
329 UTIL_CHECK(nMonomer_ > 0);
330 UTIL_CHECK(readUnitCellPtr_);
331
332 // If necessary, allocate r-grid fields
333 if (!isAllocatedRGrid_) {
334 Mesh<D> const & mesh = fieldIo().mesh();
336 }
337
338 // Read field file in r-grid format (array rgrid_)
339 fieldIo().readFieldsRGrid(in, rgrid_, *readUnitCellPtr_);
340
341 // Optionally convert to basis form
342 if (isSymmetric) {
343 Basis<D> const & basis = fieldIo().basis();
344 UTIL_CHECK(basis.isInitialized());
345 if (!isAllocatedBasis_) {
346 allocateBasis(basis.nBasis());
347 }
348 fieldIo().convertRGridToBasis(rgrid_, basis_);
349 }
350
351 hasData_ = true;
352 isSymmetric_ = isSymmetric;
353
354 // Notify signal observers of field modification
355 signal().notify();
356 }
357
358 /*
359 * Read fields from a file in r-grid format, by filename.
360 */
361 template <int D, class RFT, class FIT>
362 void
363 WFields<D,RFT,FIT>::readRGrid(std::string filename,
364 bool isSymmetric)
365 {
366 std::ifstream file;
367 fieldIo().fileMaster().openInputFile(filename, file);
368 readRGrid(file, isSymmetric);
369 file.close();
370 }
371
372 /*
373 * Symmetrize r-grid fields, convert to basis format.
374 */
375 template <int D, class RFT, class FIT>
377 {
378 UTIL_CHECK(hasData_);
379 fieldIo().convertRGridToBasis(rgrid_, basis_);
380 fieldIo().convertBasisToRGrid(basis_, rgrid_);
381 isSymmetric_ = true;
382
383 // Notify signal observers of field modification
384 signal().notify();
385 }
386
387 // Field output to file
388
389 /*
390 * Write fields to an output stream in basis format.
391 */
392 template <int D, class RFT, class FIT>
393 void WFields<D,RFT,FIT>::writeBasis(std::ostream& out) const
394 {
395 // Preconditions
396 UTIL_CHECK(nMonomer_ > 0);
397 UTIL_CHECK(fieldIoPtr_);
398 UTIL_CHECK(writeUnitCellPtr_);
399 UTIL_CHECK(isAllocatedBasis_);
400 UTIL_CHECK(hasData_);
401 UTIL_CHECK(isSymmetric_);
402
403 fieldIo().writeFieldsBasis(out, basis_, *writeUnitCellPtr_);
404 }
405
406 /*
407 * Write fields to a file in basis format, by filename.
408 */
409 template <int D, class RFT, class FIT>
410 void WFields<D,RFT,FIT>::writeBasis(std::string filename) const
411 {
412 std::ofstream file;
413 fieldIo().fileMaster().openOutputFile(filename, file);
414 writeBasis(file);
415 file.close();
416 }
417
418 /*
419 * Write fields to an output stream in real-space (r-grid) format.
420 */
421 template <int D, class RFT, class FIT>
422 void WFields<D,RFT,FIT>::writeRGrid(std::ostream& out) const
423 {
424 // Preconditions
425 UTIL_CHECK(nMonomer_ > 0);
426 UTIL_CHECK(writeUnitCellPtr_);
427 UTIL_CHECK(fieldIoPtr_);
428 UTIL_CHECK(isAllocatedRGrid_);
429 UTIL_CHECK(hasData_);
430
431 bool writeHeader = true;
432
433 fieldIo().writeFieldsRGrid(out, rgrid_, *writeUnitCellPtr_,
434 writeHeader, isSymmetric_);
435 }
436
437 /*
438 * Write fields to a file in r-grid format, by filename.
439 */
440 template <int D, class RFT, class FIT>
441 void WFields<D,RFT,FIT>::writeRGrid(std::string filename) const
442 {
443 std::ofstream file;
444 fieldIo().fileMaster().openOutputFile(filename, file);
445 writeRGrid(file);
446 file.close();
447 }
448
449 // Signal accessor
450
451 /*
452 * Get the Signal<void> that is triggered by field modification.
453 */
454 template <int D, class RFT, class FIT>
456 {
457 UTIL_CHECK(signalPtr_);
458 return *signalPtr_;
459 }
460
461} // namespace Rp
462} // namespace Pscf
463#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:384
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
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).
void setNMonomer(int nMonomer)
Set stored value of nMonomer.
int nMonomer() const
Get number of monomer types.
void writeRGrid(std::ostream &out) const
Writes fields to an input stream in real-space (r-grid) format.
IntVec< D > const & meshDimensions() const
Get mesh dimensions in each direction, set on r-grid allocation.
DArray< DArray< double > > const & basis() const
Get array of all fields in basis format.
void setRGrid(DArray< RFT > const &fields, bool isSymmetric=false)
Set fields values in real-space (r-grid) format.
void symmetrize()
Symmetrize r-grid fields, compute corresponding basis components.
void readBasis(std::istream &in)
Read fields from an input stream in symmetrized basis format.
int nBasis() const
Get number of basis functions, set on basis allocation.
void setReadUnitCell(UnitCell< D > &cell)
Set unit cell used when reading field files.
bool isSymmetric() const
Are fields symmetric under all elements of the space group?
void setWriteUnitCell(UnitCell< D > const &cell)
Set unit cell used when writing field files.
void readRGrid(std::istream &in, bool isSymmetric=false)
Reads fields from an input stream in real-space (r-grid) format.
FIT const & fieldIo() const
Get associated FIT object (const reference).
void allocate(int nMonomer, int nBasis, IntVec< D > const &dimensions)
Allocate memory for all fields.
void allocateRGrid(IntVec< D > const &dimensions)
Allocate or re-allocate memory for fields in rgrid format.
Signal< void > & signal()
Get a signal that notifies observers of field modification.
void writeBasis(std::ostream &out) const
Write fields to an input stream in symmetrized basis format.
void setBasis(DArray< DArray< double > > const &fields)
Set field component values, in symmetrized Fourier format.
int capacity() const
Return allocated size.
Definition Array.h:144
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
int readNBasis(std::istream &in)
Read the number of basis functions from a basis field file header.
Definition rFieldIo.cpp:16
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.
Definition rFieldIo.tpp:233
void eqV(Array< double > &a, Array< double > const &b, const int beginIdA, const int beginIdB, const int n)
Vector assignment, a[i] = b[i] (real, slice).
Definition VecOp.cpp:21
Periodic fields and crystallography.
Definition complex.cpp:11
Class templates for real-valued periodic fields.
PSCF package top-level namespace.