PSCF v1.4.0
rpg/field/FieldIo.tpp
1#ifndef RPG_FIELD_IO_TPP
2#define RPG_FIELD_IO_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 "FieldIo.h" // class header
12
13#include <prdc/cuda/HostDArrayComplex.h>
14#include <prdc/cuda/RFieldComparison.h>
15#include <prdc/field/fieldCheck.h>
16#include <prdc/crystal/Basis.h>
17#include <prdc/crystal/UnitCell.h>
18
19#include <pscf/cuda/HostDArray.h>
20#include <pscf/cuda/VecOp.h>
21#include <pscf/cuda/complex.h>
22#include <pscf/cuda/cudaTypes.h>
23#include <pscf/mesh/Mesh.h>
24#include <pscf/math/IntVec.h>
25#include <pscf/math/arithmetic.h>
26
27// Templates that require declarations given above to parse
28#include <rp/field/FieldIo.tpp> // base class template implementation
29#include <prdc/field/rFieldIo.h> // function templates for IO operations
30
31namespace Pscf {
32namespace Rpg {
33
34 using namespace Util;
35 using namespace Pscf::Prdc;
36 using namespace Pscf::Prdc::Cuda;
37
38 // Field Io in r-grid format
39
40 /*
41 * Read an array of fields in r-grid format.
42 */
43 template <int D>
45 std::istream &in,
46 DArray<RField<D> >& fields,
47 UnitCell<D>& unitCell) const
48 {
49 // Read header and check fields dimensions
50 int nMonomer;
51 bool isSymmetric;
52 readFieldHeader(in, nMonomer, unitCell, isSymmetric);
53 readMeshDimensions(in, mesh().dimensions());
54 checkAllocateFields(fields, nMonomer, mesh().dimensions());
55
56 // Allocate host arrays
58 allocateArrays(hostFields, nMonomer, mesh().size());
59
60 // Read data
61 Prdc::readRGridData(in, hostFields, nMonomer, mesh().dimensions());
62
63 // Copy device <- host
64 copyArrays(fields, hostFields);
65
66 // Return true iff the header contains a space group declaration
67 return isSymmetric;
68 }
69
70 /*
71 * Read the data section of an array of fields in r-grid format.
72 */
73 template <int D>
75 std::istream& in,
76 DArray< RField<D> >& fields,
77 int nMonomer) const
78 {
79 // Precondition: Check dimensions of fields
80 checkAllocateFields(fields, nMonomer, mesh().dimensions());
81
82 // Allocate host arrays
84 allocateArrays(hostFields, nMonomer, mesh().size());
85
86 // Read data section of file
87 Prdc::readRGridData(in, hostFields, nMonomer, mesh().dimensions());
88
89 // Copy device <- host
90 copyArrays(fields, hostFields);
91 }
92
93 /*
94 * Read a single field in r-grid format.
95 */
96 template <int D>
98 std::istream &in,
99 RField<D> & field,
100 UnitCell<D>& unitCell) const
101 {
102
103 // Read header and check field dimensions
104 int nMonomer;
105 bool isSymmetric;
106 readFieldHeader(in, nMonomer, unitCell, isSymmetric);
107 UTIL_CHECK(nMonomer == 1);
108 readMeshDimensions(in, mesh().dimensions());
109 checkAllocateField(field, mesh().dimensions());
110
111 // Allocate host field
112 HostDArray<cudaReal> hostField;
113 hostField.allocate(mesh().size());
114
115 // Read data section with one field
116 Prdc::readRGridData(in, hostField, mesh().dimensions());
117
118 // Copy device <- host
119 field = hostField;
120
121 // Return true iff the header contains a space group declaration
122 return isSymmetric;
123 }
124
125 /*
126 * Write an array of fields in r-grid format.
127 */
128 template <int D>
130 std::ostream &out,
131 DArray<RField<D> > const & fields,
132 UnitCell<D> const & unitCell,
133 bool writeHeader,
134 bool isSymmetric,
135 bool writeMeshSize) const
136 {
137 // Inspect fields array, check field dimensions
138 int nMonomer;
139 IntVec<D> meshDimensions;
140 inspectFields(fields, nMonomer, meshDimensions);
141 UTIL_CHECK(meshDimensions == mesh().dimensions());
142 int meshSize = mesh().size();
143 UTIL_CHECK(fields[0].capacity() == meshSize);
144
145 // Write header
146 if (writeHeader){
147 writeFieldHeader(out, nMonomer, unitCell, isSymmetric);
148 }
149 if (writeMeshSize){
150 writeMeshDimensions(out, meshDimensions);
151 }
152
153 // Copy field data to host container
154 DArray< HostDArray<cudaReal> > hostFields;
155 allocateArrays(hostFields, nMonomer, meshSize);
156 copyArrays(hostFields, fields);
157
158 // Write data section
159 Prdc::writeRGridData(out, hostFields, nMonomer, meshDimensions);
160 }
161
162 /*
163 * Write a single field in r-grid format.
164 */
165 template <int D>
167 std::ostream &out,
168 RField<D> const & field,
169 UnitCell<D> const & unitCell,
170 bool writeHeader,
171 bool isSymmetric) const
172 {
173 IntVec<D> meshDimensions = field.meshDimensions();
174 int meshSize = field.capacity();
175 UTIL_CHECK(meshDimensions == mesh().dimensions());
176 UTIL_CHECK(meshSize == mesh().size());
177
178 // Write header
179 if (writeHeader) {
180 writeFieldHeader(out, 1, unitCell, isSymmetric);
181 writeMeshDimensions(out, meshDimensions);
182 }
183
184 // Copy field (device) to hostField
185 HostDArray<cudaReal> hostField;
186 hostField.allocate(meshSize);
187 hostField = field;
188
189 // Write data from hostField
190 Prdc::writeRGridData(out, hostField, meshDimensions);
191 }
192
193 // Field IO in k-grid format
194
195 /*
196 * Read an array of fields in k-grid format
197 */
198 template <int D>
200 std::istream &in,
201 DArray<RFieldDft<D> >& fields,
202 UnitCell<D>& unitCell) const
203 {
204 // Read header and validate field mesh dimensions
205 int nMonomer;
206 bool isSymmetric;
207 readFieldHeader(in, nMonomer, unitCell, isSymmetric);
208 readMeshDimensions(in, mesh().dimensions());
209 checkAllocateFields(fields, nMonomer, mesh().dimensions());
210 IntVec<D> dftDimensions = fields[0].dftDimensions();
211 int capacity = fields[0].capacity();
212
213 // Allocate hostFields
215 allocateArrays(hostFields, nMonomer, capacity);
216
217 // Read data into hostFields
218 Prdc::readKGridData(in, hostFields, nMonomer, dftDimensions);
219
220 // Copy device <- host
221 copyArrays(fields, hostFields);
222 }
223
224 /*
225 * Write an array of fields in k-grid format
226 */
227 template <int D>
229 std::ostream &out,
230 DArray<RFieldDft<D> > const & fields,
231 UnitCell<D> const & unitCell,
232 bool isSymmetric) const
233 {
234 // Read header and validate field mesh dimensions
235 int nMonomer;
236 IntVec<D> meshDimensions;
237 inspectFields(fields, nMonomer, meshDimensions);
238 UTIL_CHECK(mesh().dimensions() == meshDimensions);
239 IntVec<D> dftDimensions = fields[0].dftDimensions();
240 int capacity = fields[0].capacity();
241
242 // Write header
243 writeFieldHeader(out, nMonomer, unitCell, isSymmetric);
244 writeMeshDimensions(out, meshDimensions);
245
246 // Copy data from device to hostFields
248 allocateArrays(hostFields, nMonomer, capacity);
249 copyArrays(hostFields, fields);
250
251 // Write data from hostFields
252 Prdc::writeKGridData(out, hostFields, nMonomer, dftDimensions);
253 }
254
255 /*
256 * Convert a single field from basis to k-grid format.
257 */
258 template <int D>
260 DArray<double> const & in,
261 RFieldDft<D>& out) const
262 {
264 UTIL_CHECK(out.isAllocated());
265 UTIL_CHECK(in.capacity() > 0);
266 UTIL_CHECK(out.meshDimensions() == mesh().dimensions());
267
268 // Allocate hostField
269 HostDArrayComplex hostField;
270 hostField.allocate(out.capacity());
271
272 // Convert basis to k-grid on hostField
273 Prdc::convertBasisToKGrid(in, hostField, basis(),
274 out.dftDimensions());
275
276 // Copy out (device) <- host
277 out = hostField;
278 }
279
280 /*
281 * Write an array of fields from k-grid to basis format.
282 */
283 template <int D>
285 RFieldDft<D> const & in,
286 DArray<double>& out,
287 bool checkSymmetry,
288 double epsilon) const
289 {
291 UTIL_CHECK(out.isAllocated());
292 UTIL_CHECK(in.meshDimensions() == mesh().dimensions());
293 UTIL_CHECK(out.capacity() > 0);
294
295 // Copy k-grid input to hostField
296 HostDArrayComplex hostField;
297 hostField.allocate(in.capacity());
298 hostField = in;
299
300 // Convert k-grid host field to basis format
301 Prdc::convertKGridToBasis(hostField, out, basis(),
302 in.dftDimensions(),
303 checkSymmetry, epsilon);
304 }
305
306 /*
307 * Test if an real field DFT has the declared space group symmetry.
308 */
309 template <int D>
311 RFieldDft<D> const & in,
312 double epsilon,
313 bool verbose) const
314 {
316 UTIL_CHECK(in.meshDimensions() == mesh().dimensions());
317
318 // Copy k-grid input to hostField
319 HostDArrayComplex hostField;
320 hostField.allocate(in.capacity());
321 hostField = in;
322
323 // Check symmetry of hostField
324 return Prdc::hasSymmetry(hostField, basis(), in.dftDimensions(),
325 epsilon, verbose);
326 }
327
328 /*
329 * Compare two fields in r-grid format, output report to Log file.
330 */
331 template <int D>
333 DArray< RField<D> > const & field2)
334 const
335 {
336 RFieldComparison<D> comparison;
337 comparison.compare(field1, field2);
338
339 Log::file() << "\n Real-space field comparison results"
340 << std::endl;
341 Log::file() << " Maximum Absolute Difference: "
342 << comparison.maxDiff() << std::endl;
343 Log::file() << " Root-Mean-Square Difference: "
344 << comparison.rmsDiff() << "\n" << std::endl;
345 }
346
347 /*
348 * Multiply a field in r-grid format by a constant factor.
349 */
350 template <int D>
352 RField<D> & field,
353 double factor) const
354 {
355 UTIL_CHECK(field.isAllocated());
356 VecOp::mulEqS(field, factor);
357 }
358
359 /*
360 * Replicate the unit cell for an array of r-grid fields.
361 */
362 template <int D>
364 std::ostream &out,
365 DArray< RField<D> > const & fields,
366 UnitCell<D> const & unitCell,
367 IntVec<D> const & replicas) const
368
369 {
370 // Inspect fields to obtain nMonomer and meshDimensions
371 int nMonomer;
372 IntVec<D> meshDimensions;
373 inspectFields(fields, nMonomer, meshDimensions);
374 UTIL_CHECK(meshDimensions == mesh().dimensions());
375 int capacity = fields[0].capacity();
376
377 // Copy k-grid input to hostField
378 DArray< HostDArray<cudaReal> > hostFields;
379 allocateArrays(hostFields, nMonomer, capacity);
380 copyArrays(hostFields, fields);
381
382 Prdc::replicateUnitCell(out, hostFields, meshDimensions,
383 unitCell, replicas);
384 }
385
386 /*
387 * Expand spatial dimension of an array of r-grid fields.
388 */
389 template <int D>
391 std::ostream &out,
392 DArray< RField<D> > const & fields,
393 UnitCell<D> const & unitCell,
394 int d,
395 DArray<int> const& newGridDimensions) const
396 {
397 // Inspect fields to obtain nMonomer and meshDimensions
398 int nMonomer;
399 IntVec<D> meshDimensions;
400 inspectFields(fields, nMonomer, meshDimensions);
401 UTIL_CHECK(meshDimensions == mesh().dimensions());
402 int capacity = fields[0].capacity();
403
404 // Copy k-grid input fields to hostFields
405 DArray< HostDArray<cudaReal> > hostFields;
406 allocateArrays(hostFields, nMonomer, capacity);
407 copyArrays(hostFields, fields);
408
409 Prdc::expandRGridDimension(out, hostFields, meshDimensions,
410 unitCell, d, newGridDimensions);
411 }
412
413}
414}
415#endif
bool isAllocated() const
Return true if the array has allocated data, false otherwise.
int capacity() const
Return array capacity.
Template for dynamic array stored in host CPU memory.
Definition HostDArray.h:41
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
HostDArray containing cudaComplex elements.
Comparator for fields in real-space (r-grid) format.
double rmsDiff() const
Get precomputed rms difference.
double compare(RField< D > const &a, RField< D > const &b)
Comparator for individual fields.
double maxDiff() const
Get precomputed maximum element-by-element difference.
Discrete Fourier Transform (DFT) of a real field, allocated on a GPU.
IntVec< D > const & dftDimensions() const
Return vector of dft (Fourier) grid dimensions by const reference.
IntVec< D > const & meshDimensions() const
Return vector of real-space mesh dimensions by constant reference.
Field of real values on a regular mesh, allocated on a GPU device.
Definition cuda/RField.h:33
IntVec< D > const & meshDimensions() const
Return mesh dimensions by constant reference.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
Mesh< D > const & mesh() const
Get spatial discretization mesh by const reference.
bool readFieldRGrid(std::istream &in, RField< D > &field, UnitCell< D > &unitCell) const override
Read a single RField (field on an r-space grid) from a stream.
void convertKGridToBasis(RFieldDft< D > const &in, DArray< double > &out, bool checkSymmetry=true, double epsilon=1.0e-8) const override
Convert a field from Fourier (k-grid) to symmetrized basis form.
void convertBasisToKGrid(DArray< double > const &components, RFieldDft< D > &dft) const override
Convert a field from symmetrized basis to Fourier grid (k-grid).
void compareFieldsRGrid(DArray< RField< D > > const &field1, DArray< RField< D > > const &field2) const override
Compare two fields in r-grid format, output a report.
bool hasSymmetry(RFieldDft< D > const &in, double epsilon=1.0e-8, bool verbose=true) const override
Check if a k-grid field has the declared space group symmetry.
Basis< D > const & basis() const
Get the associated Basis by const reference.
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.
void expandRGridDimension(std::ostream &out, DArray< RField< D > > const &fields, UnitCell< D > const &unitCell, int d, DArray< int > const &newGridDimensions) const override
Expand spatial dimension of an array of r-grid fields.
void writeFieldsKGrid(std::ostream &out, DArray< RFieldDft< D > > const &fields, UnitCell< D > const &unitCell, bool isSymmetric=true) const override
Write array of RFieldDft objects (k-space fields) to file.
void readFieldsKGrid(std::istream &in, DArray< RFieldDft< D > > &fields, UnitCell< D > &unitCell) const override
Read array of RFieldDft objects (k-space fields) from a stream.
bool readFieldsRGrid(std::istream &in, DArray< RField< D > > &fields, UnitCell< D > &unitCell) const override
Read array of RField objects (r-grid fields) from a stream.
void readFieldsRGridData(std::istream &in, DArray< RField< D > > &fields, int nMonomer) const override
Read data for an array of r-grid fields, with no header section.
void replicateUnitCell(std::ostream &out, DArray< RField< D > > const &fields, UnitCell< D > const &unitCell, IntVec< D > const &replicas) const override
Write r-grid fields in a replicated unit cell to std::ostream.
void writeFieldRGrid(std::ostream &out, RField< D > const &field, UnitCell< D > const &unitCell, bool writeHeader=true, bool isSymmetric=true) const override
Write a single RField (field on an r-space grid) to a stream.
void scaleFieldRGrid(RField< D > &field, double factor) const override
Rescale a single r-grid field by a scalar factor.
int capacity() const
Return allocated size.
Definition Array.h:144
Dynamically allocatable contiguous array template.
Definition DArray.h:32
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:269
bool isAllocated() const
Return true if this DArray has been allocated, false otherwise.
Definition DArray.h:151
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:59
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition global.h:68
void replicateUnitCell(IntVec< 1 > const &replicas, UnitCell< 1 > const &cellIn, UnitCell< 1 > &cellOut)
Create a replicated UnitCell<1>.
void writeFieldHeader(std::ostream &out, int ver1, int ver2, UnitCell< D > const &cell, std::string const &groupName, int nMonomer)
Write common part of field header (fortran PSCF format).
void readFieldHeader(std::istream &in, int &ver1, int &ver2, UnitCell< D > &cell, std::string &groupName, int &nMonomer)
Read common part of field header (fortran PSCF format).
void writeKGridData(std::ostream &out, DArray< AT > const &fields, int nMonomer, IntVec< D > const &dftDimensions)
Write data for array of k-grid fields, with no header section.
void copyArrays(DArray< OAT > &out, DArray< IAT > const &in)
Copy a DArray of 1D arrays.
bool hasSymmetry(AT const &in, Basis< D > const &basis, IntVec< D > const &dftDimensions, double epsilon=1.0e-8, bool verbose=true)
Check if a k-grid field has the declared space group symmetry.
void inspectFields(DArray< FT > const &fields, int &nMonomer, IntVec< D > &dimensions)
Inspect dimensions of a DArray of fields, each of type FT.
void readKGridData(std::istream &in, DArray< AT > &fields, int nMonomer, IntVec< D > const &dftDimensions)
Read data for array of k-grid fields, with no header section.
void convertBasisToKGrid(DArray< double > const &components, AT &dft, Basis< D > const &basis, IntVec< D > const &dftDimensions)
Convert a real field from symmetrized basis to Fourier grid.
void writeMeshDimensions(std::ostream &out, IntVec< D > const &meshDimensions)
Write mesh dimensions to a field file header.
void expandRGridDimension(std::ostream &out, DArray< AT > const &fields, IntVec< D > const &meshDimensions, UnitCell< D > const &unitCell, int d, DArray< int > newGridDimensions)
Expand the dimensionality of space from D to d.
Definition rFieldIo.tpp:971
void writeRGridData(std::ostream &out, DArray< AT > const &fields, int nMonomer, IntVec< D > const &dimensions)
Write data for array of r-grid fields, with no header section.
Definition rFieldIo.tpp:78
void convertKGridToBasis(AT const &in, DArray< double > &out, Basis< D > const &basis, IntVec< D > const &dftDimensions, bool checkSymmetry=true, double epsilon=1.0e-8)
Convert a real field from Fourier grid to symmetrized basis.
void readRGridData(std::istream &in, DArray< AT > &fields, int nMonomer, IntVec< D > const &dimensions)
Read data for array of r-grid fields, with no header section.
Definition rFieldIo.tpp:38
void readMeshDimensions(std::istream &in, IntVec< D > const &meshDimensions)
Read mesh dimensions from a field file header.
void checkAllocateFields(DArray< FT > &fields, int nMonomer, IntVec< D > const &dimensions)
Check allocation of an array of fields, allocate if necessary.
void checkAllocateField(FT &field, IntVec< D > const &dimensions)
Check allocation of a single field, allocate if necessary.
void mulEqS(Array< double > &a, double b)
Vector-scalar in-place multiplication, a[i] *= b (real).
Definition VecOp.cpp:265
Fields, FFTs, and utilities for periodic boundary conditions (CUDA).
Definition CField.cu:12
Periodic fields and crystallography.
Definition complex.cpp:11
void allocateArrays(DArray< AT > &arrays, int n, int capacity)
Allocate an array of arrays.
SCFT and PS-FTS with real periodic fields (GPU)
PSCF package top-level namespace.