PSCF v1.4.0
rp/field/FieldIo.tpp
1#ifndef RP_FIELD_IO_TPP
2#define RP_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/rFieldIo.h>
15#include <prdc/crystal/shiftToMinimum.h>
16#include <prdc/crystal/UnitCell.h>
17#include <prdc/crystal/Basis.h>
18#include <prdc/crystal/SpaceGroup.h>
19#include <prdc/crystal/UnitCell.h>
20#include <prdc/crystal/BFieldComparison.h>
21
22#include <pscf/mesh/Mesh.h>
23#include <pscf/mesh/MeshIterator.h>
24#include <pscf/mesh/MeshIteratorFortran.h>
25#include <pscf/math/IntVec.h>
26
27#include <util/containers/DArray.h>
28#include <util/containers/DMatrix.h>
29#include <util/misc/FileMaster.h>
30#include <util/misc/Log.h>
31#include <util/format/Str.h>
32#include <util/format/Int.h>
33#include <util/format/Dbl.h>
34
35#include <iomanip>
36#include <string>
37
38namespace Pscf {
39namespace Rp {
40
41 using namespace Util;
42 using namespace Prdc;
43
44 /*
45 * Constructor.
46 */
47 template <int D, class RFT, class KFT, class FFT>
49 : meshPtr_(nullptr),
50 fftPtr_(nullptr),
51 hasGroupPtr_(nullptr),
52 groupNamePtr_(nullptr),
53 groupPtr_(nullptr),
54 basisPtr_(nullptr),
55 fileMasterPtr_(nullptr),
56 nMonomer_(0),
57 isAllocatedBasis_(false),
58 isAllocatedRGrid_(false),
59 isAllocatedKGrid_(false)
60 {}
61
62 // Initialization functions
63
64 /*
65 * Create associations with other members of a parent Domain<D> object.
66 */
67 template <int D, class RFT, class KFT, class FFT>
68 void
70 Mesh<D> const & mesh,
71 FFT const & fft,
72 typename UnitCell<D>::LatticeSystem const & lattice,
73 bool const & hasGroup,
74 std::string const & groupName,
75 SpaceGroup<D> const & group,
77 {
78 meshPtr_ = &mesh;
79 fftPtr_ = &fft;
80 latticePtr_ = &lattice;
81 hasGroupPtr_ = &hasGroup;
82 groupNamePtr_ = &groupName;
83 groupPtr_ = &group;
84 basisPtr_ = &basis;
85 }
86
87 /*
88 * Create an association with a FileMaster.
89 */
90 template <int D, class RFT, class KFT, class FFT>
92 FileMaster const & fileMaster)
93 { fileMasterPtr_ = &fileMaster; }
94
95 /*
96 * Set nMonomer, the number of monomer types.
97 */
98 template <int D, class RFT, class KFT, class FFT>
100 {
101 // Preconditions - require that function is only called once
102 UTIL_CHECK(nMonomer_ == 0);
103 UTIL_CHECK(nMonomer > 0);
104
105 nMonomer_ = nMonomer;
107
108 // Field File IO - Symmetry-Adapted Basis Format
109
110 /*
111 * Read an array of fields in basis format from an input stream.
112 */
113 template <int D, class RFT, class KFT, class FFT>
115 std::istream& in,
116 DArray< DArray<double> >& fields,
117 UnitCell<D>& unitCell) const
118 {
119 // Precondition
121
122 // Read header (checks compatibility with space group)
123 int nMonomer;
124 bool isSymmetric;
125 readFieldHeader(in, nMonomer, unitCell, isSymmetric);
126 UTIL_CHECK(isSymmetric);
127 UTIL_CHECK(basis().isInitialized());
128 // Note: readFieldHeader can initialize basis if not done previously
129 int nBasisIn = readNBasis(in);
130
131 // Check allocation of fields container
132 if (fields.isAllocated()) {
133 int nMonomerFields, fieldCapacity;
134 inspectArrays(fields, nMonomerFields, fieldCapacity);
135 UTIL_CHECK(nMonomerFields == nMonomer);
136 UTIL_CHECK(fieldCapacity == basis().nBasis());
137 } else {
138 fields.allocate(nMonomer);
139 for (int i = 0; i < nMonomer; ++i) {
140 fields[i].allocate(basis().nBasis());
141 }
142 }
143
144 // Read field data (components in basis)
145 Prdc::readBasisData(in, fields, unitCell, mesh(), basis(), nBasisIn);
146 }
147
148 /*
149 * Read a single field in basis format from an input stream
150 */
151 template <int D, class RFT, class KFT, class FFT>
153 std::istream& in,
154 DArray<double>& field,
155 UnitCell<D>& unitCell) const
156 {
157 // Local array of fields, of type required by readFieldsBasis
158 DArray< DArray<double> > fields;
159
160 // If single field is allocated, allocate local array fields
161 if (field.isAllocated()) {
162 int capacity = field.capacity();
163 UTIL_CHECK(basis().nBasis() == capacity);
164 fields.allocate(1);
165 fields[0].allocate(capacity);
166 }
167 // Otherwise, pass unallocated fields array to readFieldsBasis,
168 // which will allocate it as necessary.
169
170 // Read file containing a single field
171 readFieldsBasis(in, fields, unitCell);
172
173 // Check that only one field was read from file
174 UTIL_CHECK(fields.capacity() == 1);
175
176 // Copy data from local array fields to function parameter field.
177 // The assignment operator will allocate the field if necessary.
178 field = fields[0];
179 }
180
181 /*
182 * Write an array of fields in basis format to an output stream.
183 */
184 template <int D, class RFT, class KFT, class FFT>
186 std::ostream &out,
187 DArray< DArray<double> > const & fields,
188 UnitCell<D> const & unitCell) const
189 {
190 // Inspect fields to obtain nMonomer and fieldCapacity
191 int nMonomer;
192 int fieldCapacity;
193 inspectArrays(fields, nMonomer, fieldCapacity);
194
195 // Preconditions
196 UTIL_CHECK(basis().isInitialized());
197 UTIL_CHECK(fieldCapacity <= basis().nBasis());
198 int nBasis = fieldCapacity;
199
200 // Write header
201 bool isSymmetric = true;
202 writeFieldHeader(out, nMonomer, unitCell, isSymmetric);
203 writeNBasis(out, nBasis);
204
205 // Write data (field components)
206 Prdc::writeBasisData(out, fields, basis());
207 }
208
209 /*
210 * Write a single field in basis format to an output stream.
211 */
212 template <int D, class RFT, class KFT, class FFT>
214 std::ostream& out,
215 DArray<double> const & field,
216 UnitCell<D> const & unitCell) const
217 {
218 // Create local array of type required by writeFieldsBasis
219 DArray<DArray<double> > fields;
220 fields.allocate(1);
221 fields[0].allocate(field.capacity());
222
223 // Copy data from input parameter to local array
224 fields[0] = field;
225
226 writeFieldsBasis(out, fields, unitCell);
227 }
228
229 /*
230 * File IO wrapper functions:
231 *
232 * These functions take a file name as an argument, and simply wrap
233 * file open and close operations around a function of the same name
234 * that takes an io stream argument. These functions can use the same
235 * implementation in Rpc and Rpg.
236 */
237
238 /*
239 * Open-close a file and read a set of fields in basis format.
240 */
241 template <int D, class RFT, class KFT, class FFT>
243 std::string filename,
244 DArray<DArray<double> >& fields,
245 UnitCell<D>& unitCell) const
246 {
247
248 std::ifstream file;
249 fileMaster().openInputFile(filename, file);
250 readFieldsBasis(file, fields, unitCell);
251 file.close();
252 }
253
254 /*
255 * Open-close a file and read a single field in basis format.
256 */
257 template <int D, class RFT, class KFT, class FFT>
259 std::string filename,
260 DArray<double>& field,
261 UnitCell<D>& unitCell) const
262 {
263 std::ifstream file;
264 fileMaster().openInputFile(filename, file);
265 readFieldBasis(file, field, unitCell);
266 file.close();
267 }
268
269 /*
270 * Open-close a file, and write an array of fields in basis format.
271 */
272 template <int D, class RFT, class KFT, class FFT>
274 std::string filename,
275 DArray<DArray<double> > const & fields,
276 UnitCell<D> const & unitCell) const
277 {
278 std::ofstream file;
279 fileMaster().openOutputFile(filename, file);
280 writeFieldsBasis(file, fields, unitCell);
281 file.close();
282 }
283
284 /*
285 * Open-close a file, and write a single field in basis format.
286 */
287 template <int D, class RFT, class KFT, class FFT>
289 std::string filename,
290 DArray<double> const & field,
291 UnitCell<D> const & unitCell) const
292 {
293 std::ofstream file;
294 fileMaster().openOutputFile(filename, file);
295 writeFieldBasis(file, field, unitCell);
296 file.close();
297 }
298
299 /*
300 * Open-close a file, and write an array of fields in r-grid format
301 */
302 template <int D, class RFT, class KFT, class FFT>
304 std::string filename,
305 DArray< RFT >& fields,
306 UnitCell<D>& unitCell) const
307 {
308 std::ifstream file;
309 fileMaster().openInputFile(filename, file);
310 bool isSymmetric;
311 isSymmetric = readFieldsRGrid(file, fields, unitCell);
312 file.close();
313 return isSymmetric;
314 }
315
316 /*
317 * Open-close a file, and read a single field in r-grid format
318 */
319 template <int D, class RFT, class KFT, class FFT>
321 std::string filename,
322 RFT & field,
323 UnitCell<D>& unitCell) const
324 {
325 std::ifstream file;
326 fileMaster().openInputFile(filename, file);
327 bool isSymmetric;
328 isSymmetric = readFieldRGrid(file, field, unitCell);
329 file.close();
330 return isSymmetric;
331 }
332
333 /*
334 * Open-close a file, and write an array of fields in r-grid format
335 */
336 template <int D, class RFT, class KFT, class FFT>
338 std::string filename,
339 DArray< RFT > const & fields,
340 UnitCell<D> const & unitCell,
341 bool isSymmetric) const
342 {
343 std::ofstream file;
344 fileMaster().openOutputFile(filename, file);
345 bool writeHeader = true;
346 bool writeMeshSize = true;
347 writeFieldsRGrid(file, fields, unitCell,
348 writeHeader, isSymmetric, writeMeshSize);
349 file.close();
350 }
351
352 /*
353 * Open-close a file, and write a single field in r-grid format
354 */
355 template <int D, class RFT, class KFT, class FFT>
357 std::string filename,
358 RFT const & field,
359 UnitCell<D> const & unitCell,
360 bool isSymmetric) const
361 {
362 std::ofstream file;
363 fileMaster().openOutputFile(filename, file);
364 writeFieldRGrid(file, field, unitCell, isSymmetric);
365 file.close();
366 }
367
368 /*
369 * Open-close a file, and read an array of fields in k-grid format
370 */
371 template <int D, class RFT, class KFT, class FFT>
373 std::string filename,
374 DArray< KFT >& fields,
375 UnitCell<D>& unitCell) const
376 {
377 std::ifstream file;
378 fileMaster().openInputFile(filename, file);
379 readFieldsKGrid(file, fields, unitCell);
380 file.close();
381 }
382
383 /*
384 * Open-close a file, and read an array of fields in k-grid format
385 */
386 template <int D, class RFT, class KFT, class FFT>
388 std::string filename,
389 DArray< KFT > const & fields,
390 UnitCell<D> const & unitCell,
391 bool isSymmetric) const
392 {
393 std::ofstream file;
394 fileMaster().openOutputFile(filename, file);
395 writeFieldsKGrid(file, fields, unitCell, isSymmetric);
396 file.close();
397 }
398
399 // Field Format Conversion Functions - Basis <-> KGrid
400
401 /*
402 * Convert array of fields from basis to k-grid format.
403 */
404 template <int D, class RFT, class KFT, class FFT>
406 DArray< DArray <double> > const & in,
407 DArray< KFT >& out) const
408 {
409 // Inspect input and output field containers
410 int nMonomer, nMonomerOut, capacity;
411 inspectArrays(in, nMonomer, capacity);
412 IntVec<D> dimensions;
413 inspectFields(out, nMonomerOut, dimensions);
414 UTIL_CHECK(nMonomer == nMonomerOut);
415 UTIL_CHECK(capacity == basis().nBasis());
416 UTIL_CHECK(dimensions == mesh().dimensions());
417
418 // Convert fields for all monomer types
419 for (int i = 0; i < nMonomer; ++i) {
420 convertBasisToKGrid(in[i], out[i]);
421 }
422 }
423
424 /*
425 * Convert array of fields from k-grid format to basis format.
426 */
427 template <int D, class RFT, class KFT, class FFT>
429 DArray< KFT > const & in,
430 DArray< DArray <double> > & out,
431 bool checkSymmetry,
432 double epsilon) const
433 {
434 // Inspect input and output containers
435 int nMonomer, nMonomerOut, capacity;
436 IntVec<D> dimensions;
437 inspectFields(in, nMonomer, dimensions);
438 inspectArrays(out, nMonomerOut, capacity);
439 UTIL_CHECK(nMonomer == nMonomerOut);
440
441 // Convert fields for all monomer types
442 for (int i = 0; i < nMonomer; ++i) {
443 convertKGridToBasis(in[i], out[i], checkSymmetry, epsilon);
444 }
445 }
446
447 /*
448 * Convert a field file from k-grid to basis format.
449 */
450 template <int D, class RFT, class KFT, class FFT>
452 std::string const & inFileName,
453 std::string const & outFileName) const
454 {
456 checkAllocateBasis(inFileName);
457 UnitCell<D> tmpUnitCell;
458 readFieldsKGrid(inFileName, tmpFieldsKGrid_, tmpUnitCell);
459 convertKGridToBasis(tmpFieldsKGrid_, tmpFieldsBasis_);
460 writeFieldsBasis(outFileName, tmpFieldsBasis_, tmpUnitCell);
461 }
462
463 /*
464 * Convert a field file from basis to k-grid format.
465 */
466 template <int D, class RFT, class KFT, class FFT>
468 std::string const & inFileName,
469 std::string const & outFileName) const
470 {
472 checkAllocateBasis(inFileName);
473 UnitCell<D> tmpUnitCell;
474 readFieldsBasis(inFileName, tmpFieldsBasis_, tmpUnitCell);
475 convertBasisToKGrid(tmpFieldsBasis_, tmpFieldsKGrid_);
476 writeFieldsKGrid(outFileName, tmpFieldsKGrid_, tmpUnitCell);
477 }
478
479 // Field Format Conversion Functions - Basis <-> RGrid
480
481 /*
482 * Convert a single field from basis to r-grid format.
483 */
484 template <int D, class RFT, class KFT, class FFT>
486 DArray<double> const & in,
487 RFT& out) const
488 {
490 UTIL_CHECK(out.isAllocated());
491 checkAllocateField(workDft_, mesh().dimensions());
492 convertBasisToKGrid(in, workDft_);
493 fft().inverseTransformUnsafe(workDft_, out);
494 }
495
496 /*
497 * Convert an array of fields from basis to r-grid format.
498 */
499 template <int D, class RFT, class KFT, class FFT>
501 DArray< DArray <double> > const & in,
502 DArray< RFT >& out) const
503 {
504 UTIL_CHECK(in.isAllocated());
505 UTIL_CHECK(out.isAllocated());
506 UTIL_CHECK(in.capacity() == out.capacity());
507 checkAllocateField(workDft_, mesh().dimensions());
508
509 int n = in.capacity();
510 for (int i = 0; i < n; ++i) {
511 convertBasisToKGrid(in[i], workDft_);
512 fft().inverseTransformUnsafe(workDft_, out[i]);
513 }
514 }
515
516 /*
517 * Convert a single field from r-grid to basis format.
518 */
519 template <int D, class RFT, class KFT, class FFT>
521 RFT const & in,
522 DArray<double> & out,
523 bool checkSymmetry,
524 double epsilon) const
525 {
526 checkAllocateField(workDft_, mesh().dimensions());
527 fft().forwardTransform(in, workDft_);
528 convertKGridToBasis(workDft_, out, checkSymmetry, epsilon);
529 }
530
531 /*
532 * Convert an array of fields from r-grid to basis format.
533 */
534 template <int D, class RFT, class KFT, class FFT>
536 DArray< RFT > const & in,
537 DArray< DArray <double> > & out,
538 bool checkSymmetry,
539 double epsilon) const
540 {
541 // Inspect input and output containers
542 int nMonomer, nMonomerOut, capacity;
543 IntVec<D> dimensions;
544 inspectFields(in, nMonomer, dimensions);
545 UTIL_CHECK(mesh().dimensions() == dimensions);
546 inspectArrays(out, nMonomerOut, capacity);
547 UTIL_CHECK(nMonomer == nMonomerOut);
548 checkAllocateField(workDft_, dimensions);
549
550 // Convert RGrid -> KGrid -> Basis for each field
551 for (int i = 0; i < nMonomer; ++i) {
552 fft().forwardTransform(in[i], workDft_);
553 convertKGridToBasis(workDft_, out[i], checkSymmetry, epsilon);
554 }
555 }
556
557 /*
558 * Convert a field file from basis to r-grid format.
559 */
560 template <int D, class RFT, class KFT, class FFT>
562 std::string const & inFileName,
563 std::string const & outFileName) const
564 {
566 checkAllocateBasis(inFileName);
567 UnitCell<D> tmpUnitCell;
568
569 readFieldsBasis(inFileName, tmpFieldsBasis_, tmpUnitCell);
570 convertBasisToRGrid(tmpFieldsBasis_, tmpFieldsRGrid_);
571 writeFieldsRGrid(outFileName, tmpFieldsRGrid_, tmpUnitCell);
572 }
573
574 /*
575 * Convert a field file from r-grid to basis format.
576 */
577 template <int D, class RFT, class KFT, class FFT>
579 std::string const & inFileName,
580 std::string const & outFileName) const
581 {
583 checkAllocateBasis(inFileName);
584 UnitCell<D> tmpUnitCell;
585 readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
586 convertRGridToBasis(tmpFieldsRGrid_, tmpFieldsBasis_);
587 writeFieldsBasis(outFileName, tmpFieldsBasis_, tmpUnitCell);
588 }
589
590 // FFT conversion functions (KGrid <-> RGrid) [Same in Rpc and Rpg]
591
592 /*
593 * Apply inverse FFT to an array of k-grid fields, converting to r-grid.
594 */
595 template <int D, class RFT, class KFT, class FFT>
597 DArray< KFT > const & in,
598 DArray< RFT >& out) const
599 {
600 UTIL_ASSERT(in.capacity() == out.capacity());
601 int n = in.capacity();
602 for (int i = 0; i < n; ++i) {
603 fft().inverseTransformSafe(in[i], out[i]);
604 }
605 }
606
607 /*
608 * Apply inverse FFT to a single k-grid field, converting to r-grid.
609 */
610 template <int D, class RFT, class KFT, class FFT>
612 KFT const & in, RFT& out) const
613 {
614 fft().inverseTransformSafe(in, out);
615 }
617 /*
618 * Apply forward FFT to an array of r-grid fields, converting to k-grid.
619 */
620 template <int D, class RFT, class KFT, class FFT>
622 DArray< RFT > const & in,
623 DArray< KFT >& out) const
624 {
625 UTIL_ASSERT(in.capacity() == out.capacity());
626 int n = in.capacity();
627 for (int i = 0; i < n; ++i) {
628 fft().forwardTransform(in[i], out[i]);
629 }
630 }
631
632 /*
633 * Apply forward FFT to a single r-grid field, converting to k-grid.
634 */
635 template <int D, class RFT, class KFT, class FFT>
637 RFT const & in,
638 KFT& out) const
639 { fft().forwardTransform(in, out); }
640
641 /*
642 * Convert a field file from k-grid to r-grid format.
643 */
644 template <int D, class RFT, class KFT, class FFT>
646 std::string const & inFileName,
647 std::string const & outFileName) const
648 {
651 UnitCell<D> tmpUnitCell;
652 readFieldsKGrid(inFileName, tmpFieldsKGrid_, tmpUnitCell);
653 for (int i = 0; i < nMonomer_; ++i) {
654 fft().inverseTransformUnsafe(tmpFieldsKGrid_[i],
655 tmpFieldsRGrid_[i]);
656 }
657 writeFieldsRGrid(outFileName, tmpFieldsRGrid_, tmpUnitCell);
658 }
659
660 /*
661 * Convert a field file from r-grid to k-grid format.
662 */
663 template <int D, class RFT, class KFT, class FFT>
665 std::string const & inFileName,
666 std::string const & outFileName) const
667 {
670 UnitCell<D> tmpUnitCell;
671 readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
672 convertRGridToKGrid(tmpFieldsRGrid_, tmpFieldsKGrid_);
673 writeFieldsKGrid(outFileName, tmpFieldsKGrid_, tmpUnitCell);
675
676 // Field Inspection
677
678 /*
679 * Test if a single r-grid field has declared space group symmetry.
680 * Return true if symmetric, false otherwise. Print error values
681 * if verbose == true and hasSymmetry == false.
682 */
683 template <int D, class RFT, class KFT, class FFT>
685 RFT const & in,
686 double epsilon,
687 bool verbose) const
688 {
689 checkAllocateField(workDft_, mesh().dimensions());
690 fft().forwardTransform(in, workDft_);
691 return hasSymmetry(workDft_, epsilon, verbose);
692 }
693
694 /*
695 * Check if r-grid fields have declared space group symmetry.
696 */
697 template <int D, class RFT, class KFT, class FFT>
699 std::string const & inFileName,
700 double epsilon) const
701 {
703
704 // Read fields
705 UnitCell<D> tmpUnitCell;
706 readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
707
708 // Check symmetry for all fields
709 for (int i = 0; i < nMonomer_; ++i) {
710 bool symmetric;
711 symmetric = hasSymmetry(tmpFieldsRGrid_[i], epsilon);
712 if (!symmetric) {
713 return false;
714 }
715 }
716 return true;
717 }
718
719 /*
720 * Compare two fields in basis format, write report to Log file.
721 */
722 template <int D, class RFT, class KFT, class FFT>
724 DArray< DArray<double> > const & field1,
725 DArray< DArray<double> > const & field2) const
726 {
727 BFieldComparison comparison(1);
728 comparison.compare(field1, field2);
729
730 Log::file() << "\n Basis expansion field comparison results"
731 << std::endl;
732 Log::file() << " Maximum Absolute Difference: "
733 << comparison.maxDiff() << std::endl;
734 Log::file() << " Root-Mean-Square Difference: "
735 << comparison.rmsDiff() << "\n" << std::endl;
736 }
737
738 template <int D, class RFT, class KFT, class FFT>
740 std::string const & filename1,
741 std::string const & filename2) const
742 {
743 DArray< DArray<double> > fields1, fields2;
744 UnitCell<D> tmpUnitCell;
745 // Unallocated arrays will be allocated in readFieldsBasis
746 readFieldsBasis(filename1, fields1, tmpUnitCell);
747 readFieldsBasis(filename2, fields2, tmpUnitCell);
748 compareFieldsBasis(fields1, fields2);
749 }
750
751 template <int D, class RFT, class KFT, class FFT>
753 std::string const & filename1,
754 std::string const & filename2) const
755 {
756 DArray< RFT > fields1, fields2;
757 UnitCell<D> tmpUnitCell;
758 // Unallocated arrays will be allocated in readFieldsRGrid
759 readFieldsRGrid(filename1, fields1, tmpUnitCell);
760 readFieldsRGrid(filename2, fields2, tmpUnitCell);
761 compareFieldsRGrid(fields1, fields2);
762 }
763
764 // Field Scaling
765
766 /*
767 * Multiply a single field in basis format by a constant factor.
768 */
769 template <int D, class RFT, class KFT, class FFT>
771 DArray<double> & field,
772 double factor) const
773 {
774 UTIL_CHECK(field.isAllocated());
775 int n = field.capacity();
776 for (int i = 0; i < n; ++i) {
777 field[i] *= factor;
778 }
779 }
780
781 /*
782 * Rescale an array of fields in basis format by a constant factor.
783 */
784 template <int D, class RFT, class KFT, class FFT>
786 DArray< DArray<double> >& fields,
787 double factor) const
788 {
789 int n = fields.capacity();
790 UTIL_CHECK(n > 0);
791 int m = fields[0].capacity();
792 for (int i = 0; i < n; ++i) {
793 UTIL_CHECK(fields[i].capacity() == m);
794 scaleFieldBasis(fields[i], factor);
795 }
796 }
797
798 /*
799 * Rescale fields in files by a constant factor.
800 */
801 template <int D, class RFT, class KFT, class FFT>
803 std::string const & inFileName,
804 std::string const & outFileName,
805 double factor) const
806 {
807 checkAllocateBasis(inFileName);
808 UnitCell<D> tmpUnitCell;
809 readFieldsBasis(inFileName, tmpFieldsBasis_, tmpUnitCell);
810 scaleFieldsBasis(tmpFieldsBasis_, factor);
811 writeFieldsBasis(outFileName, tmpFieldsBasis_, tmpUnitCell);
812 }
813
814 /*
815 * Rescale fields in r-grid format by a constant factor.
816 */
817 template <int D, class RFT, class KFT, class FFT>
819 DArray< RFT > & fields,
820 double factor) const
821 {
822 int n = fields.capacity();
823 for (int i = 0; i < n; ++i) {
824 scaleFieldRGrid(fields[i], factor);
825 }
826 }
827
828 /*
829 * Rescale fields by a constant factor, read and write to file.
830 */
831 template <int D, class RFT, class KFT, class FFT>
833 std::string const & inFileName,
834 std::string const & outFileName,
835 double factor) const
836 {
838 UnitCell<D> tmpUnitCell;
839 bool isSymmetric;
840 isSymmetric = readFieldsRGrid(inFileName, tmpFieldsRGrid_,
841 tmpUnitCell);
842 scaleFieldsRGrid(tmpFieldsRGrid_, factor);
843 writeFieldsRGrid(outFileName, tmpFieldsRGrid_, tmpUnitCell,
844 isSymmetric);
845 }
846
847 // Computation of Estimated W Fields
848
849 /*
850 * Convert an array of c fields to estimated w fields, in basis form.
851 */
852 template <int D, class RFT, class KFT, class FFT>
854 DMatrix<double> const & chi,
855 DArray< DArray<double> > & fields) const
856 {
857 // Check dimensions
858 UTIL_CHECK(fields.capacity() == nMonomer_);
859 UTIL_CHECK(chi.capacity1() == nMonomer_);
860 UTIL_CHECK(chi.capacity2() == nMonomer_);
861 const int nb = fields[0].capacity();
862 for (int i = 0; i < nMonomer_; ++i) {
863 UTIL_CHECK(fields[i].capacity() == nb);
864 }
865
866 // Allocate small work array (one element per monomer type)
867 DArray<double> wtmp;
868 wtmp.allocate(nMonomer_);
869
870 // Compute estimated w fields from c fields - convert in place
871 int i, j, k;
872 for (i = 0; i < nb; ++i) {
873 for (j = 0; j < nMonomer_; ++j) {
874 wtmp[j] = 0.0;
875 for (k = 0; k < nMonomer_; ++k) {
876 wtmp[j] += chi(j,k)*fields[k][i];
877 }
878 }
879 for (j = 0; j < nMonomer_; ++j) {
880 fields[j][i] = wtmp[j];
881 }
882 }
883
884 }
885
886 /*
887 * Convert a file of c fields to estimated w fields, in basis format.
888 */
889 template <int D, class RFT, class KFT, class FFT>
891 std::string const & inFileName,
892 std::string const & outFileName,
893 DMatrix<double> const & chi) const
894 {
895 // Preconditions
896 UTIL_CHECK(chi.capacity1() == nMonomer_);;
897 UTIL_CHECK(chi.capacity2() == nMonomer_);;
898
899 // Set and check nb = number of basis functions
900 checkAllocateBasis(inFileName);
901 UTIL_CHECK(basis().isInitialized());
902 const int nb = basis().nBasis();
903 UTIL_CHECK(nb > 0);
904
905 // Open input file
906 std::ifstream in;
907 fileMaster().openInputFile(inFileName, in);
908
909 // Read input file header
910 int nMonomerIn;
911 bool isSymmetric;
912 UnitCell<D> tmpUnitCell;
913 readFieldHeader(in, nMonomerIn, tmpUnitCell, isSymmetric);
914 int nBasisIn = readNBasis(in);
915 UTIL_CHECK(nMonomer_ == nMonomerIn);
916 UTIL_CHECK(isSymmetric);
917
918 // Read c field data into tmpFieldsBasis_
919 Prdc::readBasisData(in, tmpFieldsBasis_,
920 tmpUnitCell, mesh(), basis(), nBasisIn);
921 in.close();
922
923 // Compute estimated w, stored in tmpFilesBasis_
924 estimateWBasis(chi, tmpFieldsBasis_);
925
926 // Open and write output file
927 std::ofstream out;
928 fileMaster().openOutputFile(outFileName, out);
929 writeFieldsBasis(out, tmpFieldsBasis_, tmpUnitCell);
930 }
931
932
933 // Grid manipulation utilities
934
935 /*
936 * Replicate unit cell a specified number of times in each direction.
937 */
938 template <int D, class RFT, class KFT, class FFT>
940 std::string filename,
941 DArray<RFT> const & fields,
942 UnitCell<D> const & unitCell,
943 IntVec<D> const & replicas) const
944 {
945 std::ofstream file;
946 fileMaster().openOutputFile(filename, file);
947 replicateUnitCell(file, fields, unitCell, replicas);
948 file.close();
949 }
950
951 /*
952 * Replicate unit cell a specified number of times in each direction.
953 */
954 template <int D, class RFT, class KFT, class FFT>
956 std::string const & inFileName,
957 std::string const & outFileName,
958 IntVec<D> const & replicas) const
959 {
961 UnitCell<D> tmpUnitCell;
962 readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
963 replicateUnitCell(outFileName, tmpFieldsRGrid_, tmpUnitCell,
964 replicas);
965 }
966
967 /*
968 * Expand the number of spatial dimensions of an RField.
969 */
970 template <int D, class RFT, class KFT, class FFT>
972 std::string filename,
973 DArray<RFT> const & fields,
974 UnitCell<D> const & unitCell, int d,
975 DArray<int> newGridDimensions) const
976 {
977 std::ofstream file;
978 fileMaster().openOutputFile(filename, file);
979 expandRGridDimension(file, fields, unitCell, d, newGridDimensions);
980 file.close();
981 }
982
983 /*
984 * Expand the number of spatial dimensions of an RField.
985 */
986 template <int D, class RFT, class KFT, class FFT>
988 std::string const & inFileName,
989 std::string const & outFileName,
990 int d,
991 DArray<int> newGridDimensions) const
992 {
994 UnitCell<D> tmpUnitCell;
995 readFieldsRGrid(inFileName, tmpFieldsRGrid_, tmpUnitCell);
996 expandRGridDimension(outFileName, tmpFieldsRGrid_, tmpUnitCell,
997 d, newGridDimensions);
998 }
999
1000 // File Header IO Utilities
1001
1002 /*
1003 * Read common part of field header.
1004 *
1005 * Extracts number of monomers (i.e., number of fields) and unitCell
1006 * data (lattice type and parameters) from the file, and returns these
1007 * via non-const reference parameters nMonomer and unitCell.
1008 *
1009 * Also validates lattice type and groupName (if any), and constructs
1010 * a symmetry-adapted basis if there is a group but no basis.
1011 */
1012 template <int D, class RFT, class KFT, class FFT>
1014 std::istream& in,
1015 int& nMonomer,
1016 UnitCell<D>& unitCell,
1017 bool & isSymmetric) const
1018 {
1019 // Preconditions
1020 UTIL_CHECK(latticePtr_);
1021 if (unitCell.lattice() == UnitCell<D>::Null) {
1022 UTIL_CHECK(unitCell.nParameter() == 0);
1023 } else {
1024 UTIL_CHECK(unitCell.nParameter() > 0);
1025 UTIL_CHECK(unitCell.lattice() == lattice());
1026 }
1027
1028 // Read field header to set unitCell, groupNameIn, nMonomer
1029 int ver1, ver2;
1030 std::string groupNameIn;
1031
1032 Pscf::Prdc::readFieldHeader(in, ver1, ver2, unitCell,
1033 groupNameIn, nMonomer);
1034 // Note: Function definition in prdc/field/fieldHeader.tpp
1035
1036 // Checks of data from header
1037 UTIL_CHECK(ver1 == 1);
1038 //UTIL_CHECK(ver2 == 0);
1039 UTIL_CHECK(unitCell.isInitialized());
1040 UTIL_CHECK(unitCell.lattice() != UnitCell<D>::Null);
1041 UTIL_CHECK(unitCell.nParameter() > 0);
1042
1043 // Validate or initialize lattice type
1044 if (lattice() != unitCell.lattice()) {
1045 Log::file() << std::endl
1046 << "Error - Mismatched lattice types "
1047 << "in FieldIo function readFieldHeader:\n"
1048 << " FieldIo::lattice :" << lattice() << "\n"
1049 << " Unit cell lattice :" << unitCell.lattice()
1050 << "\n";
1051 UTIL_THROW("Mismatched lattice types");
1052 }
1053
1054 // Check for presence of group name in the field file header
1055 isSymmetric = false;
1056 if (groupNameIn != "") {
1057 isSymmetric = true;
1058 }
1059
1060 // Process group and basis (if any)
1061 if (hasGroup()) {
1062
1063 // Check consistency of groupName values
1064 if (isSymmetric) {
1065 UTIL_CHECK(groupNamePtr_);
1066 if (groupNameIn != groupName()) {
1067 Log::file() << std::endl
1068 << "Error - Mismatched group names in "
1069 << "FieldIo member function readFieldHeader:\n"
1070 << " FieldIo::groupName :" << groupName() << "\n"
1071 << " Field file header :" << groupNameIn << "\n";
1072 UTIL_THROW("Mismatched group names");
1073 }
1074 }
1075
1076 // If there is a group but no basis, construct a basis
1077 UTIL_CHECK(basisPtr_);
1078 if (!basis().isInitialized()) {
1079 basisPtr_->makeBasis(mesh(), unitCell, group());
1080 }
1081 UTIL_CHECK(basis().isInitialized());
1082
1083 } else {
1084
1085 if (isSymmetric) {
1086 Log::file() << std::endl
1087 << "Warning: Group name found in a field file header"
1088 << "but no group declared in the parameter file.\n";
1089 }
1090
1091 }
1092
1093 }
1094
1095 /*
1096 * Write a field file header.
1097 */
1098 template <int D, class RFT, class KFT, class FFT>
1100 std::ostream &out,
1101 int nMonomer,
1102 UnitCell<D> const & unitCell,
1103 bool isSymmetric) const
1104 {
1105 int v1 = 1;
1106 int v2 = 0;
1107 std::string gName = "";
1108 if (isSymmetric) {
1110 gName = groupName();
1111 }
1112 Pscf::Prdc::writeFieldHeader(out, v1, v2, unitCell,
1113 gName, nMonomer);
1114 // Note: This function is defined in prdc/field/fieldHeader.tpp
1115 }
1116
1117 // Protected functions to check and allocate private workspace arrays
1118
1119 /*
1120 * If necessary, allocate r-grid workspace.
1121 */
1122 template <int D, class RFT, class KFT, class FFT>
1124 {
1125 if (isAllocatedRGrid_) return;
1126
1127 UTIL_CHECK(nMonomer_ > 0);
1128 UTIL_CHECK(mesh().size() > 0);
1129 IntVec<D> const & meshDimensions = mesh().dimensions();
1130 tmpFieldsRGrid_.allocate(nMonomer_);
1131 for (int i = 0; i < nMonomer_; ++i) {
1132 tmpFieldsRGrid_[i].allocate(meshDimensions);
1133 }
1134 isAllocatedRGrid_ = true;
1135 }
1136
1137 /*
1138 * If necessary, allocate k-grid field workspace.
1139 */
1140 template <int D, class RFT, class KFT, class FFT>
1142 {
1143 if (isAllocatedKGrid_) return;
1144
1145 UTIL_CHECK(nMonomer_ > 0);
1146 UTIL_CHECK(mesh().size() > 0);
1147 IntVec<D> const & meshDimensions = mesh().dimensions();
1148 tmpFieldsKGrid_.allocate(nMonomer_);
1149 for (int i = 0; i < nMonomer_; ++i) {
1150 tmpFieldsKGrid_[i].allocate(meshDimensions);
1151 }
1152 isAllocatedKGrid_ = true;
1153 }
1154
1155 /*
1156 * If necessary, allocate basis field workspace.
1157 */
1158 template <int D, class RFT, class KFT, class FFT>
1159 void
1161 std::string const & inFileName) const
1162 {
1163 if (isAllocatedBasis_) return;
1164
1165 UTIL_CHECK(nMonomer_ > 0);
1167 if (!basis().isInitialized()) {
1168 // Peek at field header to initialize basis
1169 std::ifstream file;
1170 fileMaster().openInputFile(inFileName, file);
1171 int nMonomerIn;
1172 bool isSymmetricIn;
1173 UnitCell<D> tmpUnitCell;
1174 readFieldHeader(file, nMonomerIn, tmpUnitCell, isSymmetricIn);
1175 // Note: readFieldHeader can initialize basis if needed
1176 file.close();
1177 }
1178 UTIL_CHECK(basis().isInitialized());
1179 int nBasis = basis().nBasis();
1180 UTIL_CHECK(nBasis > 0);
1181 tmpFieldsBasis_.allocate(nMonomer_);
1182 for (int i = 0; i < nMonomer_; ++i) {
1183 DArray<double>& field = tmpFieldsBasis_[i];
1184 field.allocate(nBasis);
1185 for (int j = 0; j < nBasis; ++j) {
1186 field[j] = 0.0;
1187 }
1188 }
1189 isAllocatedBasis_ = true;
1190 }
1191
1192} // namespace Rp
1193} // namespace Pscf
1194#endif
double rmsDiff() const
Return the precomputed root-mean-squared difference.
double compare(FT const &a, FT const &b)
Compare individual fields.
double maxDiff() const
Return the precomputed maximum element-by-element difference.
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
Comparator for fields in symmetry-adapted basis format.
Symmetry-adapted Fourier basis for pseudo-spectral SCFT.
Definition Basis.h:384
Fourier transform wrapper.
Definition cpu/FFT.h:39
Crystallographic space group.
Definition SpaceGroup.h:32
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
virtual void scaleFieldRGrid(RFT &field, double factor) const =0
Multiply a single field in r-grid format by a scalar.
virtual void writeFieldsRGrid(std::ostream &out, DArray< RFT > const &fields, UnitCell< D > const &unitCell, bool writeHeader=true, bool isSymmetric=true, bool writeMeshSize=true) const =0
Write an array of r-grid fields to an output stream.
virtual void scaleFieldBasis(DArray< double > &field, double factor) const
Multiply a single field in basis form by a real scalar.
virtual void convertKGridToBasis(KFT const &in, DArray< double > &out, bool checkSymmetry=true, double epsilon=1.0e-8) const =0
Convert a single field from Fourier (k-grid) to basis form.
Mesh< D > const & mesh() const
Get spatial discretization mesh by const reference.
virtual bool readFieldRGrid(std::istream &in, RFT &field, UnitCell< D > &unitCell) const =0
Read a single r-grid field from an input stream.
virtual void convertBasisToKGrid(DArray< double > const &components, KFT &dft) const =0
Convert a single field from basis to Fourier (k-grid) form.
virtual void compareFieldsRGrid(DArray< RFT > const &field1, DArray< RFT > const &field2) const =0
Compare two fields in r-grid form, write a report to Log file.
void compareFieldsBasis(DArray< DArray< double > > const &field1, DArray< DArray< double > > const &field2) const
Compare array of fields in basis form, write a report to Log file.
void checkAllocateBasis(std::string const &inFileName) const
Check if basis workspace is allocated, allocate if necessary.
void setNMonomer(int nMonomer)
Set the number of monomer types.
virtual bool hasSymmetry(KFT const &in, double epsilon=1.0e-8, bool verbose=true) const =0
Check if a k-grid field has the declared space group symmetry.
void scaleFieldsBasis(DArray< DArray< double > > &fields, double factor) const
Multiply an array of fields in basis format by a real scalar.
virtual void replicateUnitCell(std::ostream &out, DArray< RFT > const &fields, UnitCell< D > const &unitCell, IntVec< D > const &replicas) const =0
Write r-grid fields in a replicated unit cell to std::ostream.
void readFieldBasis(std::istream &in, DArray< double > &field, UnitCell< D > &unitCell) const
Read a single field in basis format from an input stream.
void checkAllocateRGrid() const
Check if r-grid workspace is allocated, allocate if necessary.
void convertRGridToKGrid(DArray< RFT > const &in, DArray< KFT > &out) const
Convert an array of fields from r-grid to k-grid (Fourier) format.
FileMaster const & fileMaster() const
Get associated FileMaster by const reference.
void convertRGridToBasis(RFT const &in, DArray< double > &out, bool checkSymmetry=true, double epsilon=1.0e-8) const
Convert a single field from r-grid to basis form.
void checkAllocateKGrid() const
Check if k-grid workspace is allocated, allocate if necessary.
void estimateWBasis(DMatrix< double > const &chi, DArray< DArray< double > > &fields) const
Convert c fields to estimated w fields, in basis format.
void convertBasisToRGrid(DArray< double > const &in, RFT &out) const
Convert a single field from basis to r-grid format.
void writeFieldBasis(std::ostream &out, DArray< double > const &field, UnitCell< D > const &unitCell) const
Write a single field in basis format to an output stream.
void writeFieldsBasis(std::ostream &out, DArray< DArray< double > > const &fields, UnitCell< D > const &unitCell) const
Write an array of fields in basis format to an output stream.
void scaleFieldsRGrid(DArray< RFT > &fields, double factor) const
Scale an array of r-grid fields by a scalar.
void writeFieldHeader(std::ostream &out, int nMonomer, UnitCell< D > const &unitCell, bool isSymmetric=true) const
Write header for field file (fortran pscf format).
virtual void readFieldsKGrid(std::istream &in, DArray< KFT > &fields, UnitCell< D > &unitCell) const =0
Read an array of k-grid fields from an input stream.
void readFieldsBasis(std::istream &in, DArray< DArray< double > > &fields, UnitCell< D > &unitCell) const
Read an array of fields in basis format from an input stream.
UnitCell< D >::LatticeSystem const & lattice() const
Get the lattice type enum value by const reference.
virtual void expandRGridDimension(std::ostream &out, DArray< RFT > const &fields, UnitCell< D > const &unitCell, int d, DArray< int > const &newGridDimensions) const =0
Increase D for an array of r-grid fields, write to ostream.
FFT const & fft() const
Get FFT object by const reference.
void associate(Mesh< D > const &mesh, FFT const &fft, typename UnitCell< D >::LatticeSystem const &lattice, bool const &hasGroup, std::string const &groupName, SpaceGroup< D > const &group, Basis< D > &basis)
Create associations with other members of the parent Domain.
std::string const & groupName() const
Get an associated group name string by const reference.
void convertKGridToRGrid(DArray< KFT > const &in, DArray< RFT > &out) const
Convert an array of field from k-grid to r-grid format.
virtual void writeFieldRGrid(std::ostream &out, RFT const &field, UnitCell< D > const &unitCell, bool writeHeader=true, bool isSymmetric=true) const =0
Write a single r-grid field to an an output stream.
bool hasGroup() const
Has a space group been declared externally ?
void readFieldHeader(std::istream &in, int &nMonomer, UnitCell< D > &unitCell, bool &isSymmetric) const
Reader header of field file (fortran PSCF format)
SpaceGroup< D > const & group() const
Get an associated SpaceGroup<D> by const reference.
void setFileMaster(FileMaster const &fileMaster)
Create an association with a FileMaster.
Basis< D > const & basis() const
Get the associated Basis by const reference.
virtual bool readFieldsRGrid(std::istream &in, DArray< RFT > &fields, UnitCell< D > &unitCell) const =0
Read array of r-grid fields from an input stream.
virtual void writeFieldsKGrid(std::ostream &out, DArray< KFT > const &fields, UnitCell< D > const &unitCell, bool isSymmetric=true) const =0
Write an array of k-grid fields to a output stream.
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
Dynamically allocated Matrix.
Definition DMatrix.h:25
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
int capacity2() const
Get number of columns (range of the second array index).
Definition Matrix.h:143
int capacity1() const
Get number of rows (range of the first array index).
Definition Matrix.h:136
#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
#define UTIL_ASSERT(condition)
Assertion macro suitable for debugging serial or parallel code.
Definition global.h:75
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 writeNBasis(std::ostream &out, int nBasis)
Write the number of basis functions to a basis field file header.
Definition rFieldIo.cpp:44
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 inspectArrays(DArray< AT > const &arrays, int &nMonomer, int &capacity)
Inspect dimensions of a DArray of 1D arrays, each of type AT.
void inspectFields(DArray< FT > const &fields, int &nMonomer, IntVec< D > &dimensions)
Inspect dimensions of a DArray of fields, each of type FT.
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 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 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.
int readNBasis(std::istream &in)
Read the number of basis functions from a basis field file header.
Definition rFieldIo.cpp:16
void writeBasisData(std::ostream &out, DArray< DArray< double > > const &fields, Basis< D > const &basis)
Write data section of an array of fields in basis format.
Definition rFieldIo.tpp:511
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 checkAllocateField(FT &field, IntVec< D > const &dimensions)
Check allocation of a single field, allocate if necessary.
Periodic fields and crystallography.
Definition complex.cpp:11
Class templates for real-valued periodic fields.
PSCF package top-level namespace.