PSCF v1.4.0
cp/field/FieldIo.tpp
1#ifndef RPC_CL_FIELD_IO_TPP
2#define RPC_CL_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"
12
13#include <prdc/field/fieldCheck.h>
14#include <prdc/field/fieldHeader.h>
15#include <prdc/crystal/UnitCell.h>
16
17#include <pscf/mesh/Mesh.h>
18#include <pscf/math/IntVec.h>
19
20#include <util/containers/DArray.h>
21#include <util/containers/DMatrix.h>
22#include <util/misc/FileMaster.h>
23#include <util/misc/Log.h>
24
25#include <iomanip>
26#include <string>
27
28namespace Pscf {
29namespace Cp {
30
31 using namespace Util;
32 using namespace Prdc;
33
34 /*
35 * Constructor.
36 */
37 template <int D, class CFT, class FFT>
39 : meshPtr_(nullptr),
40 fftPtr_(nullptr),
41 fileMasterPtr_(nullptr),
42 nMonomer_(0),
43 isAllocated_(false)
44 {}
45
46 /*
47 * Destructor.
48 */
49 template <int D, class CFT, class FFT>
52
53 // Initialization functions
54
55 /*
56 * Create associations with other members of a parent Domain<D> object.
57 */
58 template <int D, class CFT, class FFT>
59 void
61 Mesh<D> const & mesh,
62 FFT const & fft,
63 typename UnitCell<D>::LatticeSystem const & lattice)
64 {
65 meshPtr_ = &mesh;
66 fftPtr_ = &fft;
67 latticePtr_ = &lattice;
68 }
69
70 /*
71 * Create an association with a FileMaster.
72 */
73 template <int D, class CFT, class FFT>
75 FileMaster const & fileMaster)
76 { fileMasterPtr_ = &fileMaster; }
77
78 /*
79 * Set nMonomer, the number of monomer types.
80 */
81 template <int D, class CFT, class FFT>
83 {
84 // Preconditions - require that function is only called once
85 UTIL_CHECK(nMonomer_ == 0);
86 UTIL_CHECK(nMonomer > 0);
87
88 nMonomer_ = nMonomer;
89 }
90
91 /*
92 * Open-close a file, and write an array of complex fields format.
93 */
94 template <int D, class CFT, class FFT>
96 std::string filename,
97 DArray< CFT >& fields,
98 UnitCell<D>& unitCell) const
99 {
100 std::ifstream file;
101 fileMaster().openInputFile(filename, file);
102 readFields(file, fields, unitCell);
103 file.close();
104 }
105
106 /*
107 * Open-close a file, and read a single complex field.
108 */
109 template <int D, class CFT, class FFT>
111 std::string filename,
112 CFT & field,
113 UnitCell<D>& unitCell) const
114 {
115 std::ifstream file;
116 fileMaster().openInputFile(filename, file);
117 readField(file, field, unitCell);
118 file.close();
119 }
120
121 /*
122 * Open-close a file, and write an array of complex fields.
123 */
124 template <int D, class CFT, class FFT>
126 std::string filename,
127 DArray< CFT > const & fields,
128 UnitCell<D> const & unitCell) const
129 {
130 std::ofstream file;
131 fileMaster().openOutputFile(filename, file);
132 bool writeHeader = true;
133 bool writeMeshSize = true;
134 writeFields(file, fields, unitCell,
135 writeHeader, writeMeshSize);
136 file.close();
137 }
138
139 /*
140 * Open-close a file, and write a single complex field.
141 */
142 template <int D, class CFT, class FFT>
144 std::string filename,
145 CFT const & field,
146 UnitCell<D> const & unitCell) const
147 {
148 std::ofstream file;
149 fileMaster().openOutputFile(filename, file);
150 writeField(file, field, unitCell);
151 file.close();
152 }
153
154 // Fourier transform functions (KGrid <-> RGrid) [Same in Rpc and Rpg]
155
156 /*
157 * Apply forward FFT to an array of r-grid fields, converting to k-grid.
158 */
159 template <int D, class CFT, class FFT>
161 DArray< CFT > const & in,
162 DArray< CFT >& out) const
163 {
164 int n = in.capacity();
165 UTIL_CHECK(n > 0);
166 for (int i = 0; i < n; ++i) {
167 UTIL_CHECK(in[i].meshDimensions() == out[i].meshDimensions());
168 fft().forwardTransform(in[i], out[i]);
169 }
170 }
171
172 /*
173 * Convert a field file from r-grid to k-grid format.
174 */
175 template <int D, class CFT, class FFT>
177 std::string const & inFileName,
178 std::string const & outFileName) const
179 {
181 DArray< CFT > inFields;
182 allocateFields(inFields, nMonomer_, mesh().dimensions());
183 UnitCell<D> tmpUnitCell;
184 readFields(inFileName, inFields, tmpUnitCell);
185 convertRGridToKGrid(inFields, tmpFields_);
186 writeFields(outFileName, tmpFields_, tmpUnitCell);
187 }
188
189 /*
190 * Apply inverse FFT to an array of k-grid fields, converting to r-grid.
191 */
192 template <int D, class CFT, class FFT>
194 DArray< CFT > const & in,
195 DArray< CFT >& out) const
196 {
197 int n = in.capacity();
198 UTIL_CHECK(n > 0);
199 for (int i = 0; i < n; ++i) {
200 UTIL_CHECK(in[i].meshDimensions() == out[i].meshDimensions());
201 fft().inverseTransform(in[i], out[i]);
202 }
203 }
204
205 /*
206 * Convert a field file from k-grid to r-grid format.
207 */
208 template <int D, class CFT, class FFT>
210 std::string const & inFileName,
211 std::string const & outFileName) const
212 {
214 DArray< CFT > inFields;
215 allocateFields(inFields, nMonomer_, mesh().dimensions());
216 UnitCell<D> tmpUnitCell;
217 readFields(inFileName, inFields, tmpUnitCell);
218 convertKGridToRGrid(inFields, tmpFields_);
219 writeFields(outFileName, tmpFields_, tmpUnitCell);
220 }
221
222 #if 0
223 // Field Comparison
224
225 template <int D, class CFT, class FFT>
227 std::string const & filename1,
228 std::string const & filename2) const
229 {
230 checkAllocate();
231 DArray< CFT > fields1;
232 allocateFields(fields1, nMonomer_, mesh().dimensions());
233 UnitCell<D> tmpUnitCell;
234 readFields(filename1, fields1, tmpUnitCell);
235 readFields(filename2, fields2, tmpUnitCell);
236 compareFields(fields1, fields2);
237 }
238 #endif
239
240 // File Header IO Utilities
241
242 /*
243 * Read the common part of field file header.
244 *
245 * Extracts number of monomers (i.e., number of fields) and unitCell
246 * data (lattice type and parameters) from the file, and returns these
247 * via non-const reference parameters nMonomer and unitCell.
248 */
249 template <int D, class CFT, class FFT>
251 std::istream& in,
252 int& nMonomer,
253 UnitCell<D>& unitCell) const
254 {
255 // Preconditions
256 UTIL_CHECK(latticePtr_);
257 if (unitCell.lattice() == UnitCell<D>::Null) {
258 UTIL_CHECK(unitCell.nParameter() == 0);
259 } else {
260 UTIL_CHECK(unitCell.nParameter() > 0);
261 UTIL_CHECK(unitCell.lattice() == lattice());
262 }
263
264 // Read field header to set unitCell, groupNameIn, nMonomer
265 int ver1, ver2;
266 std::string groupNameIn;
267
268 Pscf::Prdc::readFieldHeader(in, ver1, ver2, unitCell,
269 groupNameIn, nMonomer);
270 // Note: Function definition in prdc/field/fieldHeader.tpp
271
272 // Checks of data from header
273 UTIL_CHECK(ver1 == 1);
274 //UTIL_CHECK(ver2 == 0);
275 UTIL_CHECK(unitCell.isInitialized());
276 UTIL_CHECK(unitCell.lattice() != UnitCell<D>::Null);
277 UTIL_CHECK(unitCell.nParameter() > 0);
278
279 // Validate lattice type
280 if (lattice() != unitCell.lattice()) {
281 Log::file() << std::endl
282 << "Error - Mismatched lattice types "
283 << "in Cp::FieldIo::readFieldHeader:\n"
284 << " FieldIo::lattice :" << lattice() << "\n"
285 << " Unit cell lattice :" << unitCell.lattice()
286 << "\n";
287 UTIL_THROW("Mismatched lattice types");
288 }
289
290 }
291
292 /*
293 * Write a field file header.
294 */
295 template <int D, class CFT, class FFT>
297 std::ostream &out,
298 int nMonomer,
299 UnitCell<D> const & unitCell) const
300 {
301 int v1 = 1;
302 int v2 = 0;
303 std::string gName = "";
304 Pscf::Prdc::writeFieldHeader(out, v1, v2, unitCell,
305 gName, nMonomer);
306 // Note: This function is defined in prdc/field/fieldHeader.tpp
307 }
308
309 // Protected functions to check and allocate private workspace arrays
310
311 /*
312 * If necessary, allocate r-grid workspace.
313 */
314 template <int D, class CFT, class FFT>
316 {
317 if (isAllocated_) return;
318
319 UTIL_CHECK(nMonomer_ > 0);
320 UTIL_CHECK(mesh().size() > 0);
321 IntVec<D> const & meshDimensions = mesh().dimensions();
322 tmpFields_.allocate(nMonomer_);
323 for (int i = 0; i < nMonomer_; ++i) {
324 tmpFields_[i].allocate(meshDimensions);
325 }
326 isAllocated_ = true;
327 }
328
329} // namespace Cp
330} // namespace Pscf
331#endif
File IO and other utilities for complex fields.
void readFieldHeader(std::istream &in, int &nMonomer, UnitCell< D > &unitCell) const
Reader header of field file (fortran PSCF format)
void checkAllocate() const
Check if r-grid workspace is allocated, allocate if necessary.
virtual void writeFields(std::ostream &out, DArray< CFT > const &fields, UnitCell< D > const &unitCell, bool writeHeader=true, bool writeMeshSize=true) const =0
Write an array of complex fields to an output stream.
void writeFieldHeader(std::ostream &out, int nMonomer, UnitCell< D > const &unitCell) const
Write header for field file (fortran pscf format).
void convertKGridToRGrid(DArray< CFT > const &in, DArray< CFT > &out) const
Fourier transform an array of fields from k-grid to r-grid format.
FileMaster const & fileMaster() const
Get associated FileMaster by const reference.
FFT const & fft() const
Get FFT object by const reference.
virtual void readFields(std::istream &in, DArray< CFT > &fields, UnitCell< D > &unitCell) const =0
Read array of complex fields from an input stream.
void setNMonomer(int nMonomer)
Set the number of monomer types.
void convertRGridToKGrid(DArray< CFT > const &in, DArray< CFT > &out) const
Fourier transform array of fields from r-grid to k-grid format.
virtual void readField(std::istream &in, CFT &field, UnitCell< D > &unitCell) const =0
Read a single r-grid field from an input stream.
Mesh< D > const & mesh() const
Get spatial discretization mesh by const reference.
UnitCell< D >::LatticeSystem const & lattice() const
Get the lattice type enum value by const reference.
void setFileMaster(FileMaster const &fileMaster)
Create an association with a FileMaster.
virtual ~FieldIo()
Destructor.
void associate(Mesh< D > const &mesh, FFT const &fft, typename UnitCell< D >::LatticeSystem const &lattice)
Create associations with other members of the parent Domain.
virtual void writeField(std::ostream &out, CFT const &field, UnitCell< D > const &unitCell, bool writeHeader=true) const =0
Write a single complex field to an an output stream.
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
Fourier transform wrapper.
Definition cpu/FFT.h:39
bool isInitialized() const
Has this unit cell been initialized?
int nParameter() const
Get the number of parameters in the unit cell.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
int capacity() const
Return allocated size.
Definition Array.h:144
A FileMaster manages input and output files for a simulation.
Definition FileMaster.h:143
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
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition global.h:49
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).
Complex-valued periodic fields (class templates).
Definition cp.mod:6
Periodic fields and crystallography.
Definition complex.cpp:11
void allocateFields(DArray< FT > &fields, int n, IntVec< D > const &dimension)
Allocate a DArray of fields.
PSCF package top-level namespace.