PSCF v1.1
fd1d/misc/FieldIo.cpp
1/*
2* PSCF - Polymer Self-Consistent Field Theory
3*
4* Copyright 2016 - 2022, The Regents of the University of Minnesota
5* Distributed under the terms of the GNU General Public License.
6*/
7
8#include "FieldIo.h"
9
10#include <fd1d/domain/Domain.h>
11#include <fd1d/solvers/Mixture.h>
12#include <fd1d/solvers/Polymer.h>
13
14#include <pscf/chem/Vertex.h>
15#include <pscf/homogeneous/Clump.h>
16//#include <pscf/inter/Interaction.h>
17
18#include <util/misc/FileMaster.h>
19#include <util/format/Str.h>
20#include <util/format/Int.h>
21#include <util/format/Dbl.h>
22
23#include <string>
24
25namespace Pscf {
26namespace Fd1d
27{
28
29 using namespace Util;
30
31 /*
32 * Constructor.
33 */
35 {}
36
37 /*
38 * Destructor.
39 */
41 {}
42
43
44 void FieldIo::associate(Domain const & domain,
45 FileMaster const & fileMaster)
46 {
47 domainPtr_ = &domain;
48 fileMasterPtr_ = &fileMaster;
49 }
50
52 std::string const & filename)
53 {
54 std::ifstream in;
55 fileMaster().openInputFile(filename, in);
56 readFields(fields, in);
57 in.close();
58 }
59
60 void FieldIo::readFields(DArray<Field>& fields, std::istream& in)
61 {
62 // Read grid dimensions
63 std::string label;
64 in >> label;
65 UTIL_CHECK(label == "nx");
66 int nx;
67 in >> nx;
68 UTIL_CHECK(nx > 0);
69 UTIL_CHECK(nx == domain().nx());
70 in >> label;
71 UTIL_CHECK (label == "nm");
72 int nm;
73 in >> nm;
74 UTIL_CHECK(nm > 0);
75
76 // Check dimensions of fields array
77 UTIL_CHECK(nm == fields.capacity());
78 for (int i = 0; i < nm; ++i) {
79 UTIL_CHECK(nx == fields[i].capacity());
80 }
81
82 // Read fields
83 int i, j, idum;
84 for (i = 0; i < nx; ++i) {
85 in >> idum;
86 UTIL_CHECK(idum == i);
87 for (j = 0; j < nm; ++j) {
88 in >> fields[j][i];
89 }
90 }
91 }
92
93 void FieldIo::writeField(Field const & field,
94 std::string const & filename, bool writeHeader) const
95 {
96 std::ofstream out;
97 fileMaster().openOutputFile(filename, out);
98 writeField(field, out, writeHeader);
99 out.close();
100 }
101
102 void FieldIo::writeField(Field const & field, std::ostream& out, bool writeHeader) const
103 {
104 int nx = field.capacity();
105 UTIL_CHECK(nx == domain().nx());
106
107 if (writeHeader){
108 out << "nx " << nx << std::endl;
109 }
110 // Write fields
111 int i;
112 for (i = 0; i < nx; ++i) {
113 out << " " << Dbl(field[i], 18, 11);
114 out << std::endl;
115 }
116 }
117
119 std::string const & filename, bool writeHeader)
120 {
121 std::ofstream out;
122 fileMaster().openOutputFile(filename, out);
123 writeFields(fields, out, writeHeader);
124 out.close();
125 }
126
127 void FieldIo::writeFields(DArray<Field> const & fields, std::ostream& out, bool writeHeader)
128 {
129 int nm = fields.capacity();
130 UTIL_CHECK(nm > 0);
131 int nx = fields[0].capacity();
132 UTIL_CHECK(nx == domain().nx());
133 if (nm > 1) {
134 for (int i = 0; i < nm; ++i) {
135 UTIL_CHECK(nx == fields[i].capacity());
136 }
137 }
138 if (writeHeader){
139 out << "nx " << nx << std::endl;
140 out << "nm " << nm << std::endl;
141 }
142 // Write fields
143 int i, j;
144 for (i = 0; i < nx; ++i) {
145 out << Int(i, 5);
146 for (j = 0; j < nm; ++j) {
147 out << " " << Dbl(fields[j][i], 18, 11);
148 }
149 out << std::endl;
150 }
151 }
152
153 void FieldIo::writeBlockCFields(Mixture const & mixture,
154 std::string const & filename)
155 {
156 std::ofstream out;
157 fileMaster().openOutputFile(filename, out);
158 writeBlockCFields(mixture, out);
159 out.close();
160 }
161
162 /*
163 * Write the concentrations associated with all blocks.
164 */
165 void FieldIo::writeBlockCFields(Mixture const & mixture, std::ostream& out)
166 {
167 int nx = domain().nx(); // number grid points
168 int np = mixture.nPolymer(); // number of polymer species
169 int nb_tot = mixture.nBlock(); // number of blocks in all polymers
170 int ns = mixture.nSolvent(); // number of solvents
171
172 out << "nx " << nx << std::endl;
173 out << "n_block " << nb_tot << std::endl;
174 out << "n_solvent " << ns << std::endl;
175
176 int nb; // number of blocks per polymer
177 int i, j, k, l; // loop indices
178 double c;
179 for (i = 0; i < nx; ++i) {
180 out << Int(i, 5);
181 for (j = 0; j < np; ++j) {
182 nb = mixture.polymer(j).nBlock();
183 for (k = 0; k < nb; ++k) {
184 c = mixture.polymer(j).block(k).cField()[i];
185 out << " " << Dbl(c, 15, 8);
186 }
187 }
188 for (l = 0; l < ns; ++l) {
189 c = mixture.solvent(l).cField()[i];
190 out << " " << Dbl(c, 15, 8);
191 }
192 out << std::endl;
193 }
194 }
195
196 /*
197 * Write incoming q fields for a specified vertex.
198 */
199 void FieldIo::writeVertexQ(Mixture const & mixture,
200 int polymerId, int vertexId,
201 std::string const & filename)
202 {
203 std::ofstream out;
204 fileMaster().openOutputFile(filename, out);
205 writeVertexQ(mixture, polymerId, vertexId, out);
206 out.close();
207 }
208
209 /*
210 * Write incoming q fields for a specified vertex.
211 */
212 void FieldIo::writeVertexQ(Mixture const & mixture,
213 int polymerId, int vertexId,
214 std::ostream& out)
215 {
216 UTIL_CHECK(polymerId >= 0);
217 UTIL_CHECK(polymerId < mixture.nPolymer());
218 Polymer const & polymer = mixture.polymer(polymerId);
219 UTIL_CHECK(vertexId >= 0);
220 UTIL_CHECK(vertexId <= polymer.nBlock());
221 Vertex const & vertex = polymer.vertex(vertexId);
222 int nb = vertex.size(); // number of attached blocks
223 int nx = domain().nx(); // number grid points
224
225 Pair<int> pId;
226 int bId;
227 int dId;
228 int i, j;
229 double c, product;
230 for (i = 0; i < nx; ++i) {
231 out << Int(i, 5);
232 product = 1.0;
233 for (j = 0; j < nb; ++j) {
234 pId = vertex.inPropagatorId(j);
235 bId = pId[0]; // blockId
236 UTIL_CHECK(bId >= 0);
237 dId = pId[1]; // directionId
238 UTIL_CHECK(dId >= 0);
239 UTIL_CHECK(dId <= 1);
240 c = polymer.propagator(bId, dId).tail()[i];
241 out << " " << Dbl(c, 15, 8);
242 product *= c;
243 }
244 out << " " << Dbl(product, 15, 8) << std::endl;
245 }
246
247 }
248
249 /*
250 * Interpolate fields onto new mesh, write result to output file
251 */
252 void FieldIo::remesh(DArray<Field> const & fields, int nx,
253 std::string const & filename)
254 {
255 std::ofstream out;
256 fileMaster().openOutputFile(filename, out);
257 remesh(fields, nx, out);
258 out.close();
259 }
260
261 /*
262 * Interpolate fields onto new mesh, write result to outputstream
263 */
264 void
265 FieldIo::remesh(DArray<Field> const & fields, int nx, std::ostream& out)
266 {
267 // Query and check dimensions of fields array
268 int nm = fields.capacity();
269 UTIL_CHECK(nm > 0);
270 for (int i = 0; i < nm; ++i) {
271 UTIL_CHECK(fields[i].capacity() == domain().nx());
272 }
273
274 // Output new grid dimensions
275 out << "nx " << nx << std::endl;
276 out << "nm " << nm << std::endl;
277
278 // Output first grid point
279 int i, j;
280 i = 0;
281 out << Int(i, 5);
282 for (j = 0; j < nm; ++j) {
283 out << " " << Dbl(fields[j][i]);
284 }
285 out << std::endl;
286
287 // Spacing for new grid
288 double dx = (domain().xMax() - domain().xMin())/double(nx-1);
289
290 // Variables used for interpolation
291 double y; // Grid coordinate in old grid
292 double fu; // fractional part of y
293 double fl; // 1.0 - fl
294 double w; // interpolated field value
295 int yi; // Truncated integer part of y
296
297 // Loop over intermediate points
298 for (i = 1; i < nx -1; ++i) {
299 y = dx*double(i)/domain().dx();
300 yi = y;
301 UTIL_CHECK(yi >= 0);
302 UTIL_CHECK(yi + 1 < domain().nx());
303 fu = y - double(yi);
304 fl = 1.0 - fu;
305
306 out << Int(i, 5);
307 for (j = 0; j < nm; ++j) {
308 w = fl*fields[j][yi] + fu*fields[j][yi+1];
309 out << " " << Dbl(w);
310 }
311 out << std::endl;
312 }
313
314 // Output last grid point
315 out << Int(nx - 1, 5);
316 i = domain().nx() - 1;
317 for (j = 0; j < nm; ++j) {
318 out << " " << Dbl(fields[j][i]);
319 }
320 out << std::endl;
321
322 }
323
324 void
325 FieldIo::extend(DArray<Field> const & fields, int m,
326 std::string const & filename)
327 {
328 std::ofstream out;
329 fileMaster().openOutputFile(filename, out);
330 extend(fields, m, out);
331 out.close();
332 }
333
334 /*
335 * Interpolate fields onto new mesh.
336 */
337 void
338 FieldIo::extend(DArray<Field> const & fields, int m, std::ostream& out)
339 {
340 // Query and check dimensions of fields array
341 int nm = fields.capacity();
342 UTIL_CHECK(nm > 0);
343 int nx = fields[0].capacity();
344 UTIL_CHECK(nx == domain().nx());
345 if (nm > 1) {
346 for (int i = 0; i < nm; ++i) {
347 UTIL_CHECK(nx == fields[i].capacity());
348 }
349 }
350
351 // Output new grid dimensions
352 out << "nx " << nx + m << std::endl;
353 out << "nm " << nm << std::endl;
354
355 // Loop over existing points;
356 int i, j;
357 for (i = 0; i < nx; ++i) {
358 out << Int(i, 5);
359 for (j = 0; j < nm; ++j) {
360 out << " " << Dbl(fields[j][i]);
361 }
362 out << std::endl;
363 }
364
365 // Add m new points, assign each the last value
366 for (i = nx; i < nx + m; ++i) {
367 out << Int(i, 5);
368 for (j = 0; j < nm; ++j) {
369 out << " " << Dbl(fields[j][nx-1]);
370 }
371 out << std::endl;
372 }
373
374 }
375
376} // namespace Fd1d
377} // namespace Pscf
One-dimensional spatial domain and discretization grid.
double dx() const
Get spatial grid step size.
double xMin() const
Get minimum spatial coordinate.
double xMax() const
Get maximum spatial coordinate.
int nx() const
Get number of spatial grid points, including both endpoints.
void writeField(Field const &field, std::ostream &out, bool writeHeader=true) const
Write a single field to an output stream.
void writeVertexQ(Mixture const &mixture, int polymerId, int vertexId, std::ostream &out)
Write product of incoming q fields for one vertex to stream.
void remesh(DArray< Field > const &fields, int nx, std::ostream &out)
Interpolate an array of fields onto a new mesh and write to stream.
void associate(Domain const &domain, FileMaster const &fileMaster)
Get and store addresses of associated objects.
void writeFields(DArray< Field > const &fields, std::ostream &out, bool writeHeader=true)
Write a set of fields, one per monomer type, to an output stream.
void extend(DArray< Field > const &fields, int m, std::ostream &out)
Add points to the end of a field mesh and write to stream.
void writeField(Field const &field, std::string const &filename, bool writeHeader=true) const
Write a single field to a file.
void writeBlockCFields(Mixture const &mixture, std::ostream &out)
Write block concentration fields for all blocks to an output stream.
void readFields(DArray< Field > &fields, std::istream &in)
Read a set of fields, one per monomer type.
Mixture of polymers and solvents.
Descriptor and solver for a branched polymer species.
Polymer & polymer(int id)
Get a polymer object.
Definition: MixtureTmpl.h:220
int nBlock() const
Get number of total blocks in the mixture across all polymers.
Definition: MixtureTmpl.h:202
int nSolvent() const
Get number of solvent (point particle) species.
Definition: MixtureTmpl.h:198
Solvent & solvent(int id)
Set a solvent solver object.
Definition: MixtureTmpl.h:234
int nPolymer() const
Get number of polymer species.
Definition: MixtureTmpl.h:194
int nBlock() const
Number of blocks.
Definition: PolymerTmpl.h:241
Propagator & propagator(int blockId, int directionId)
Get propagator for a specific block and direction.
Definition: PolymerTmpl.h:304
const Vertex & vertex(int id) const
Get a specified Vertex by const reference.
Definition: PolymerTmpl.h:269
A junction or chain end in a block polymer.
Definition: Vertex.h:26
int size() const
Get the number of attached blocks.
Definition: Vertex.h:105
Pair< int > const & inPropagatorId(int i) const
Get the block and direction of an incoming propagator.
Definition: Vertex.h:109
int capacity() const
Return allocated size.
Definition: Array.h:159
Dynamically allocatable contiguous array template.
Definition: DArray.h:32
Wrapper for a double precision number, for formatted ostream output.
Definition: Dbl.h:40
A FileMaster manages input and output files for a simulation.
Definition: FileMaster.h:143
void openOutputFile(const std::string &filename, std::ofstream &out, std::ios_base::openmode mode=std::ios_base::out) const
Open an output file.
Definition: FileMaster.cpp:290
void openInputFile(const std::string &filename, std::ifstream &in, std::ios_base::openmode mode=std::ios_base::in) const
Open an input file.
Definition: FileMaster.cpp:273
Wrapper for an int, for formatted ostream output.
Definition: Int.h:37
An array of exactly 2 objects.
Definition: Pair.h:24
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
Definition: global.h:68
C++ namespace for polymer self-consistent field theory (PSCF).
Utility classes for scientific computation.
Definition: accumulators.mod:1
float product(float a, float b)
Product for float Data.
Definition: product.h:22