PSCF v1.2
fieldIoUtil.tpp
1#ifndef PRDC_FIELD_IO_UTIL_TPP
2#define PRDC_FIELD_IO_UTIL_TPP
3
4/*
5* PSCF - Polymer Self-Consistent Field Theory
6*
7* Copyright 2016 - 2024, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include <prdc/crystal/Basis.h>
12#include <prdc/crystal/UnitCell.h>
13#include <prdc/crystal/replicateUnitCell.h>
14#include <prdc/crystal/shiftToMinimum.h>
15#include <prdc/crystal/fieldHeader.h>
16
17#include <pscf/mesh/Mesh.h>
18#include <pscf/mesh/MeshIterator.h>
19#include <pscf/mesh/MeshIteratorFortran.h>
20#include <pscf/math/IntVec.h>
21#include <pscf/math/complex.h>
22
23#include <util/containers/DArray.h>
24#include <util/misc/FileMaster.h>
25#include <util/misc/Log.h>
26#include <util/format/Int.h>
27#include <util/format/Dbl.h>
28
29#include <string>
30
31namespace Pscf {
32namespace Prdc {
33
34 /*
35 * Check allocation of a single field of type FT, allocate if needed.
36 */
37 template <int D, class FT>
38 void checkAllocateField(FT& field,
39 IntVec<D> const& dimensions)
40 {
41 if (field.isAllocated()) {
42 UTIL_CHECK(field.meshDimensions() == dimensions);
43 } else {
44 field.allocate(dimensions);
45 }
46 }
47
48 /*
49 * Check allocation of an array of fields of type FT, allocate if needed.
50 */
51 template <int D, class FT>
53 int nMonomer,
54 IntVec<D> const& dimensions)
55 {
56 if (fields.isAllocated()) {
57 int nMonomerFields = fields.capacity();
58 UTIL_CHECK(nMonomerFields > 0)
59 UTIL_CHECK(nMonomerFields == nMonomer)
60 for (int i = 0; i < nMonomer; ++i) {
61 UTIL_CHECK(fields[i].meshDimensions() == dimensions);
62 }
63 } else {
64 fields.allocate(nMonomer);
65 for (int i = 0; i < nMonomer; ++i) {
66 fields[i].allocate(dimensions);
67 }
68 }
69 }
70
71 /*
72 * Inspect dimensions of a DArray of fields, each of type FT.
73 */
74 template <int D, class FT>
75 void inspectFields(DArray<FT> const& fields,
76 int & nMonomer,
77 IntVec<D> & dimensions)
78 {
79 UTIL_CHECK(fields.isAllocated());
80 nMonomer = fields.capacity();
81 UTIL_CHECK(nMonomer > 0);
82
83 dimensions = fields[0].meshDimensions();
84 for (int i = 0; i < nMonomer; ++i) {
85 UTIL_CHECK(fields[i].meshDimensions() == dimensions);
86 }
87 }
88
89 /*
90 * Check allocation of an array of arrays of type AT, allocate if needed.
91 */
92 template <class AT>
94 int nMonomer,
95 int capacity)
96 {
97 if (arrays.isAllocated()) {
98 int nMonomerArrays = arrays.capacity();
99 UTIL_CHECK(nMonomerArrays > 0)
100 UTIL_CHECK(nMonomerArrays == nMonomer)
101 for (int i = 0; i < nMonomer; ++i) {
102 UTIL_CHECK(arrays[i].capacity() == capacity);
103 }
104 } else {
105 arrays.allocate(nMonomer);
106 for (int i = 0; i < nMonomer; ++i) {
107 arrays[i].allocate(capacity);
108 }
109 }
110 }
111
112 /*
113 * Inspect dimensions of an array of arrays of type AT.
114 */
115 template <class AT>
116 void inspectArrays(DArray<AT> const& arrays,
117 int & nMonomer,
118 int & capacity)
119 {
120 UTIL_CHECK(arrays.isAllocated());
121 nMonomer = arrays.capacity();
122 UTIL_CHECK(nMonomer > 0);
123
124 capacity = arrays[0].capacity();
125 UTIL_CHECK(capacity > 0);
126 for (int i = 0; i < nMonomer; ++i) {
127 UTIL_CHECK(arrays[i].capacity() == capacity);
128 }
129 }
130
131 // RGrid File Io Templates
132
133 template <int D>
134 void readMeshDimensions(std::istream& in,
135 IntVec<D> const& meshDimensions)
136 {
137 // Read and check input stream mesh dimensions
138 std::string label;
139 in >> label;
140 if (label != "mesh" && label != "ngrid") {
141 std::string msg = "\n";
142 msg += "Error reading field file:\n";
143 msg += "Expected mesh or ngrid, but found [";
144 msg += label;
145 msg += "]";
146 UTIL_THROW(msg.c_str());
147 }
148 IntVec<D> meshDimensionsIn;
149 in >> meshDimensionsIn;
150 if (meshDimensionsIn != meshDimensions) {
151 Log::file()
152 << "Inconsistent mesh dimensions:\n"
153 << "meshDimensions (expected) = " << meshDimensions << "\n"
154 << "meshDimensions (from file) = " << meshDimensionsIn << "\n";
155 UTIL_THROW("Unexpected mesh dimensions in field file header");
156 }
157 }
158
159 template <int D>
160 void writeMeshDimensions(std::ostream &out,
161 IntVec<D> const& meshDimensions)
162 {
163 out << "mesh " << std::endl
164 << " " << meshDimensions << std::endl;
165 }
166
167 template <int D, class ART>
168 void readRGridData(std::istream& in,
169 DArray<ART>& fields,
170 int nMonomer,
171 IntVec<D> const& dimensions)
172 {
173 UTIL_CHECK(nMonomer > 0);
174 UTIL_CHECK(fields.capacity() == nMonomer);
175
176 MeshIteratorFortran<D> iter(dimensions);
177 int rank;
178 for (iter.begin(); !iter.atEnd(); ++iter) {
179 rank = iter.rank();
180 for (int k = 0; k < nMonomer; ++k) {
181 in >> fields[k][rank];
182 }
183 }
184 }
185
186 template <int D, class ART>
187 void readRGridData(std::istream& in,
188 ART& field,
189 IntVec<D> const& dimensions)
190 {
191 MeshIteratorFortran<D> iter(dimensions);
192 int rank;
193 for (iter.begin(); !iter.atEnd(); ++iter) {
194 rank = iter.rank();
195 in >> field[rank];
196 }
197 }
198
199 template <int D, class ART>
200 void writeRGridData(std::ostream& out,
201 DArray<ART> const& fields,
202 int nMonomer,
203 IntVec<D> const& dimensions)
204 {
205 UTIL_CHECK(nMonomer > 0);
206 UTIL_CHECK(nMonomer == fields.capacity());
207
208 MeshIteratorFortran<D> iter(dimensions);
209 int rank, j;
210 for (iter.begin(); !iter.atEnd(); ++iter) {
211 rank = iter.rank();
212 for (j = 0; j < nMonomer; ++j) {
213 out << " " << Dbl(fields[j][rank], 21, 13);
214 }
215 out << std::endl;
216 }
217
218 }
219
220 template <int D, class ART>
221 void writeRGridData(std::ostream& out,
222 ART const& field,
223 IntVec<D> const& dimensions)
224 {
225 MeshIteratorFortran<D> iter(dimensions);
226 int rank;
227 for (iter.begin(); !iter.atEnd(); ++iter) {
228 rank = iter.rank();
229 out << " " << Dbl(field[rank], 21, 13);
230 out << std::endl;
231 }
232 }
233
234 // KGrid file IO templates
235
236 template <int D, class ACT>
237 void readKGridData(std::istream& in,
238 DArray<ACT> & fields,
239 int nMonomer,
240 IntVec<D> const& dftDimensions)
241 {
242 typedef typename ACT::Complex CT;
243 typedef typename ACT::Real RT;
244
245 RT x, y;
246 MeshIterator<D> iter(dftDimensions);
247 int rank, i, j, idum;
248 i = 0;
249 for (iter.begin(); !iter.atEnd(); ++iter) {
250 rank = iter.rank();
251 in >> idum;
252 UTIL_CHECK(i == idum);
253 UTIL_CHECK(i == rank);
254 for (j = 0; j < nMonomer; ++j) {
255 in >> x;
256 in >> y;
257 assign<CT, RT>(fields[j][rank], x, y);
258 }
259 ++i;
260 }
261 }
262
263 template <int D, class ACT>
264 void readKGridData(std::istream& in,
265 ACT& field,
266 IntVec<D> const& dftDimensions)
267 {
268 typedef typename ACT::Complex CT;
269 typedef typename ACT::Real RT;
270
271 RT x, y;
272 MeshIterator<D> iter(dftDimensions);
273 int rank, idum;
274 int i = 0;
275 for (iter.begin(); !iter.atEnd(); ++iter) {
276 rank = iter.rank();
277 in >> idum;
278 UTIL_CHECK(i == idum);
279 UTIL_CHECK(i == rank);
280 //in >> field[rank][0];
281 //in >> field[rank][1];
282 in >> x;
283 in >> y;
284 assign<CT, RT>(field[rank], x, y);
285 ++i;
286 }
287 }
288
289 template <int D, class ACT>
290 void writeKGridData(std::ostream& out,
291 DArray<ACT> const& fields,
292 int nMonomer,
293 IntVec<D> const& dftDimensions)
294 {
295 UTIL_CHECK(nMonomer > 0);
296 UTIL_CHECK(nMonomer == fields.capacity());
297
298 typedef typename ACT::Complex CT;
299 typedef typename ACT::Real RT;
300
301 RT x, y;
302 MeshIterator<D> iter(dftDimensions);
303 int rank;
304 int i = 0;
305 for (iter.begin(); !iter.atEnd(); ++iter) {
306 rank = iter.rank();
307 UTIL_CHECK(i == rank);
308 out << Int(rank, 5);
309 for (int j = 0; j < nMonomer; ++j) {
310 x = real<CT, RT>(fields[j][rank]);
311 y = imag<CT, RT>(fields[j][rank]);
312 out << " "
313 << Dbl(x, 21, 13)
314 << Dbl(y, 21, 13);
315 }
316 out << std::endl;
317 ++i;
318 }
319
320 }
321
322 template <int D, class ACT>
323 void writeKGridData(std::ostream& out,
324 ACT const& field,
325 IntVec<D> const& dftDimensions)
326 {
327 typedef typename ACT::Complex CT;
328 typedef typename ACT::Real RT;
329
330 RT x, y;
331 MeshIterator<D> iter(dftDimensions);
332 int rank, i;
333 i = 0;
334 for (iter.begin(); !iter.atEnd(); ++iter) {
335 rank = iter.rank();
336 UTIL_CHECK(i == rank);
337 x = real<CT, RT>(field[rank]);
338 y = imag<CT, RT>(field[rank]);
339 out << Int(rank, 5);
340 out << " "
341 << Dbl(x, 21, 13)
342 << Dbl(y, 21, 13);
343 out << std::endl;
344 ++i;
345 }
346 }
347
348 // Functions for files in symmetry-adapted basis format
349
350 /*
351 * Read the number of basis functions from a field file header.
352 */
353 int readNBasis(std::istream& in)
354 {
355
356 // Read the label, which can be N_star or N_basis
357 std::string label;
358 in >> label;
359 if (label != "N_star" && label != "N_basis") {
360 std::string msg = "\n";
361 msg += "Error reading field file:\n";
362 msg += "Expected N_basis or N_star, but found [";
363 msg += label;
364 msg += "]";
365 UTIL_THROW(msg.c_str());
366 }
367
368 // Read the value of nBasis
369 int nBasis;
370 in >> nBasis;
371 UTIL_CHECK(nBasis > 0);
372
373 return nBasis;
374 }
375
376 /*
377 * Write the number of basis functions to a field file header.
378 */
379 void writeNBasis(std::ostream& out, int nBasis)
380 {
381 out << "N_basis " << std::endl
382 << " " << nBasis << std::endl;
383 }
384
385 /*
386 * Read the data section for an array of fields in basis format.
387 */
388 template <int D>
389 void readBasisData(std::istream& in,
390 DArray< DArray<double> >& fields,
391 UnitCell<D> const& unitCell,
392 Mesh<D> const& mesh,
393 Basis<D> const& basis,
394 int nBasisIn)
395 {
396 UTIL_CHECK(basis.isInitialized());
397 UTIL_CHECK(fields.isAllocated());
398
399 int nMonomer = fields.capacity();
400 UTIL_CHECK(nMonomer > 0);
401
402 // Initialize all field array elements to zero
403 int fieldCapacity = fields[0].capacity();
404 UTIL_CHECK(fieldCapacity > 0);
405 for (int i = 0; i < nMonomer; ++i) {
406 UTIL_CHECK(fields[i].capacity() == fieldCapacity);
407 for (int j = 0; j < fieldCapacity; ++j) {
408 fields[i][j] = 0.0;
409 }
410 }
411
412 // Reset nBasis = min(nBasisIn, fieldCapacity)
413 int nBasis = nBasisIn;
414 if (fieldCapacity < nBasisIn) {
415 nBasis = fieldCapacity;
416 }
417
418 // Allocate temp arrays used to read in components
419 DArray<double> temp, temp2;
420 temp.allocate(nMonomer);
421 temp2.allocate(nMonomer);
422
423 typename Basis<D>::Star const * starPtr;
424 typename Basis<D>::Star const * starPtr2;
425 IntVec<D> waveIn, waveIn2;
426 int sizeIn, sizeIn2;
427 int starId, starId2;
428 int basisId, basisId2;
429 int waveId, waveId2;
430
431 std::complex<double> coeff, phasor;
432 IntVec<D> waveBz, waveDft;
433 int nReversedPair = 0;
434 bool waveExists, sizeMatches;
435
436 // Loop over stars in input file to read field components
437 int i = 0;
438 while (i < nBasis) {
439
440 // Read next line of data
441 for (int j = 0; j < nMonomer; ++j) {
442 in >> temp[j]; // field components
443 }
444 in >> waveIn; // wave of star
445 in >> sizeIn; // # of waves in star
446 ++i;
447
448 sizeMatches = false;
449 waveExists = false;
450
451 // Check if waveIn is in first Brillouin zone (FBZ) for the mesh.
452 waveBz = shiftToMinimum(waveIn, mesh.dimensions(), unitCell);
453 waveExists = (waveIn == waveBz);
454
455 if (waveExists) {
456
457 // Find the star containing waveIn
458 waveDft = waveIn;
459 mesh.shift(waveDft);
460 waveId = basis.waveId(waveDft);
461 starId = basis.wave(waveId).starId;
462 starPtr = &basis.star(starId);
463 UTIL_CHECK(!(starPtr->cancel));
464 basisId = starPtr->basisId;
465
466 if (starPtr->size == sizeIn) {
467 sizeMatches = true;
468 } else {
469 Log::file()
470 << "Warning: Inconsistent star size (line ignored)\n"
471 << "wave from file = " << waveIn << "\n"
472 << "size from file = " << sizeIn << "\n"
473 << "size of star = " << starPtr->size
474 << "\n";
475 sizeMatches = false;
476 }
477
478 }
479
480 if (waveExists && sizeMatches) { // Attempt to process wave
481
482 if (starPtr->invertFlag == 0) {
483
484 if (starPtr->waveBz == waveIn) {
485
486 // Copy components of closed star to fields array
487 for (int j = 0; j < nMonomer; ++j) {
488 fields[j][basisId] = temp[j];
489 }
490
491 } else {
492
493 Log::file()
494 << "Inconsistent wave of closed star on input\n"
495 << "wave from file = " << waveIn << "\n"
496 << "starId of wave = " << starId << "\n"
497 << "waveBz of star = " << starPtr->waveBz
498 << "\n";
499
500 }
501
502 } else {
503
504 // Read the next line
505 for (int j = 0; j < nMonomer; ++j) {
506 in >> temp2[j]; // components of field
507 }
508 in >> waveIn2; // wave of star
509 in >> sizeIn2; // # of wavevectors in star
510 ++i;
511
512 // Check that waveIn2 is also in the 1st BZ
513 waveBz =
514 shiftToMinimum(waveIn2, mesh.dimensions(), unitCell);
515 UTIL_CHECK(waveIn2 == waveBz);
516
517 // Identify the star containing waveIn2
518 waveDft = waveIn2;
519 mesh.shift(waveDft);
520 waveId2 = basis.waveId(waveDft);
521 starId2 = basis.wave(waveId2).starId;
522 starPtr2 = &basis.star(starId2);
523 UTIL_CHECK(!(starPtr2->cancel));
524 basisId2 = starPtr2->basisId;
525 UTIL_CHECK(starPtr2->size == sizeIn2);
526 UTIL_CHECK(sizeIn == sizeIn2);
527
528 if (starPtr->invertFlag == 1) {
529
530 // This is a pair of open stars written in the same
531 // order as in this basis. Check preconditions:
532 UTIL_CHECK(starPtr2->invertFlag == -1);
533 UTIL_CHECK(starId2 = starId + 1);
534 UTIL_CHECK(basisId2 = basisId + 1);
535 UTIL_CHECK(starPtr->waveBz == waveIn);
536 UTIL_CHECK(starPtr2->waveBz == waveIn2);
537
538 // Copy components for both stars into fields array
539 for (int j = 0; j < nMonomer; ++j) {
540 fields[j][basisId] = temp[j];
541 fields[j][basisId2] = temp2[j];
542 }
543
544 } else
545 if (starPtr->invertFlag == -1) {
546
547 // This is a pair of open stars written in opposite
548 // order from in this basis. Check preconditions:
549 UTIL_CHECK(starPtr2->invertFlag == 1);
550 UTIL_CHECK(starId == starId2 + 1);
551 UTIL_CHECK(basisId == basisId2 + 1);
552 UTIL_CHECK(waveId == starPtr->beginId);
553
554 // Check that waveIn2 is negation of waveIn
555 IntVec<D> nVec;
556 nVec.negate(waveIn);
557 nVec =
558 shiftToMinimum(nVec, mesh.dimensions(), unitCell);
559 UTIL_CHECK(waveIn2 == nVec);
560
561 /*
562 * Consider two related stars, C and D, that are listed
563 * in the order (C,D) in the basis used in this code (the
564 * reading program), but that were listed in the opposite
565 * order (D,C) in the program that wrote the file (the
566 * writing program). In the basis of the reading program,
567 * star C has star index starId2, while star D has index
568 * starId = starid2 + 1.
569 *
570 * Let f(r) and f^{*}(r) denote the basis functions used
571 * by the reading program for stars C and D, respectively.
572 * Let u(r) and u^{*}(r) denote the corresponding basis
573 * functions used by the writing program for stars C
574 * and D. Let exp(i phi) denote the unit magnitude
575 * coefficient (i.e., phasor) within f(r) of the wave
576 * with wave index waveId2, which was the characteristic
577 * wave for star C in the writing program. The
578 * coefficient of this wave within the basis function
579 * u(r) used by the writing program must instead be real
580 * and positive. This implies that
581 * u(r) = exp(-i phi) f(r).
582 *
583 * Focus on the contribution to the field for a specific
584 * monomer type j. Let a and b denote the desired
585 * coefficients of stars C and D in the reading program,
586 * for which the total contribution of both stars to the
587 * field is:
588 *
589 * (a - ib) f(r) + (a + ib) f^{*}(r)
590 *
591 * Let A = temp[j] and B = temp2[j] denote the
592 * coefficients read from file in order (A,B). Noting
593 * that the stars were listed in the order (D,C) in the
594 * basis used by the writing program, the contribution
595 * of both stars must be (A-iB)u^{*}(r)+(A+iB)u(r), or:
596 *
597 * (A+iB) exp(-i phi)f(r) + (A-iB) exp(i phi) f^{*}(r)
598 *
599 * Comparing coefficients of f^{*}(r), we find that
600 *
601 * (a + ib) = (A - iB) exp(i phi)
602 *
603 * This equality is implemented below, where the
604 * variable "phasor" is set equal to exp(i phi).
605 */
606 phasor = basis.wave(waveId2).coeff;
607 phasor = phasor/std::abs(phasor);
608 for (int j = 0; j < nMonomer; ++j) {
609 coeff = std::complex<double>(temp[j],-temp2[j]);
610 coeff *= phasor;
611 fields[j][basisId2] = real(coeff);
612 fields[j][basisId ] = imag(coeff);
613 }
614
615 // Increment count of number of reversed open pairs
616 ++nReversedPair;
617
618 } else {
619 UTIL_THROW("Invalid starInvert value");
620 }
621
622 } // if (wavePtr->invertFlag == 0) ... else ...
623
624 } // if (waveExists && sizeMatches)
625
626 } // end while (i < nBasis)
627
628 if (nReversedPair > 0) {
629 Log::file() << "\n";
630 Log::file() << nReversedPair << " reversed pairs of open stars"
631 << " detected in readFieldsBasis\n";
632 }
633
634 }
635
636 /*
637 * Write an array of fields in basis format to an output stream.
638 */
639 template <int D>
640 void writeBasisData(std::ostream &out,
641 DArray< DArray<double> > const & fields,
642 Basis<D> const & basis)
643 {
644 // Preconditions, set nMonomer and fieldCapacity
645 int nMonomer = fields.capacity();
646 UTIL_CHECK(nMonomer > 0);
647 int fieldCapacity = fields[0].capacity();
648 for (int j = 0; j < nMonomer; ++j) {
649 UTIL_CHECK(fieldCapacity == fields[j].capacity());
650 }
651 UTIL_CHECK(basis.isInitialized());
652
653 // Write fields
654 int ib = 0;
655 int nStar = basis.nStar();
656 for (int i = 0; i < nStar; ++i) {
657 if (ib >= fieldCapacity) break;
658 if (!basis.star(i).cancel) {
659 for (int j = 0; j < nMonomer; ++j) {
660 out << Dbl(fields[j][ib], 20, 10);
661 }
662 out << " ";
663 for (int j = 0; j < D; ++j) {
664 out << Int(basis.star(i).waveBz[j], 5);
665 }
666 out << Int(basis.star(i).size, 5) << std::endl;
667 ++ib;
668 }
669 }
670
671 }
672
673 template <int D, class ACT>
674 void convertBasisToKGrid(DArray<double> const & in,
675 ACT& out,
676 Basis<D> const& basis,
677 IntVec<D> const& dftDimensions)
678 {
679 UTIL_CHECK(basis.isInitialized());
680
681 typedef typename ACT::Complex CT;
682 typedef typename ACT::Real RT;
683
684 // Create Mesh<D> with dimensions of DFT Fourier grid.
685 Mesh<D> dftMesh(dftDimensions);
686
687 typename Basis<D>::Star const* starPtr; // pointer to current star
688 typename Basis<D>::Wave const* wavePtr; // pointer to current wave
689 std::complex<double> component; // coefficient for star
690 std::complex<double> coeff; // coefficient for wave
691 IntVec<D> indices; // dft grid indices of wave
692 int rank; // dft grid rank of wave
693 int is; // star index
694 int ib; // basis index
695 int iw; // wave index
696
697 // Initialize all dft coponents to zero
698 for (rank = 0; rank < dftMesh.size(); ++rank) {
699 //out[rank][0] = 0.0;
700 //out[rank][1] = 0.0;
701 assign<CT, RT>(out[rank], 0.0, 0.0);
702 }
703
704 // Loop over stars, skipping cancelled stars
705 is = 0;
706 while (is < basis.nStar()) {
707 starPtr = &(basis.star(is));
708
709 if (starPtr->cancel) {
710 ++is;
711 continue;
712 }
713
714 // Set basisId for uncancelled star
715 ib = starPtr->basisId;
716
717 if (starPtr->invertFlag == 0) {
718
719 // Make complex coefficient for star basis function
720 component = std::complex<double>(in[ib], 0.0);
721
722 // Loop over waves in closed star
723 for (iw = starPtr->beginId; iw < starPtr->endId; ++iw) {
724 wavePtr = &basis.wave(iw);
725 if (!wavePtr->implicit) {
726 coeff = component*(wavePtr->coeff);
727 indices = wavePtr->indicesDft;
728 rank = dftMesh.rank(indices);
729 //out[rank][0] = coeff.real();
730 //out[rank][1] = coeff.imag();
731 assign<CT, RT>(out[rank], coeff);
732 }
733 }
734 ++is;
735
736 } else
737 if (starPtr->invertFlag == 1) {
738
739 // Loop over waves in first star
740 component = std::complex<double>(in[ib], -in[ib+1]);
741 component /= sqrt(2.0);
742 starPtr = &(basis.star(is));
743 for (iw = starPtr->beginId; iw < starPtr->endId; ++iw) {
744 wavePtr = &basis.wave(iw);
745 if (!(wavePtr->implicit)) {
746 coeff = component*(wavePtr->coeff);
747 indices = wavePtr->indicesDft;
748 rank = dftMesh.rank(indices);
749 //out[rank][0] = coeff.real();
750 //out[rank][1] = coeff.imag();
751 assign<CT, RT>(out[rank], coeff);
752 }
753 }
754
755 // Loop over waves in second star
756 starPtr = &(basis.star(is+1));
757 UTIL_CHECK(starPtr->invertFlag == -1);
758 component = std::complex<double>(in[ib], +in[ib+1]);
759 component /= sqrt(2.0);
760 for (iw = starPtr->beginId; iw < starPtr->endId; ++iw) {
761 wavePtr = &basis.wave(iw);
762 if (!(wavePtr->implicit)) {
763 coeff = component*(wavePtr->coeff);
764 indices = wavePtr->indicesDft;
765 rank = dftMesh.rank(indices);
766 //out[rank][0] = coeff.real();
767 //out[rank][1] = coeff.imag();
768 assign<CT, RT>(out[rank], coeff);
769 }
770 }
771
772 // Increment is by 2 (two stars were processed)
773 is += 2;
774
775 } else {
776
777 UTIL_THROW("Invalid invertFlag value");
778
779 }
780
781 }
782
783 }
784
785 template <int D, class ACT>
786 void convertKGridToBasis(ACT const& in,
787 DArray<double>& out,
788 Basis<D> const& basis,
789 IntVec<D> const& dftDimensions,
790 bool checkSymmetry,
791 double epsilon)
792 {
793 UTIL_CHECK(basis.isInitialized());
794
795 typedef typename ACT::Complex CT;
796 typedef typename ACT::Real RT;
797
798 // Check if input field in k-grid format has specified symmetry
799 if (checkSymmetry) {
800 bool symmetric;
801 symmetric = hasSymmetry(in, basis, dftDimensions, epsilon, true);
802 if (!symmetric) {
803 Log::file() << std::endl
804 << "WARNING: Conversion of asymmetric field to"
805 << "symmetry-adapted basis in Prdc::convertKgridToBasis."
806 << std::endl << std::endl;
807 }
808 }
809
810 // Create Mesh<D> with dimensions of DFT Fourier grid.
811 Mesh<D> dftMesh(dftDimensions);
812
813 typename Basis<D>::Star const* starPtr; // pointer to current star
814 typename Basis<D>::Wave const* wavePtr; // pointer to current wave
815 std::complex<double> component; // coefficient for star
816 int rank; // dft grid rank of wave
817 int is; // star index
818 int ib; // basis index
819 int iw; // wave index
820
821 // Initialize all components to zero
822 for (is = 0; is < basis.nBasis(); ++is) {
823 out[is] = 0.0;
824 }
825
826 // Loop over stars
827 is = 0;
828 while (is < basis.nStar()) {
829 starPtr = &(basis.star(is));
830
831 if (starPtr->cancel) {
832 ++is;
833 continue;
834 }
835
836 // Set basis id for uncancelled star
837 ib = starPtr->basisId;
838
839 if (starPtr->invertFlag == 0) {
840
841 // Choose a wave in the star that is not implicit
842 int beginId = starPtr->beginId;
843 int endId = starPtr->endId;
844 iw = 0;
845 bool isImplicit = true;
846 while (isImplicit) {
847 wavePtr = &basis.wave(beginId + iw);
848 if (!wavePtr->implicit) {
849 isImplicit = false;
850 } else {
851 UTIL_CHECK(beginId + iw < endId - 1 - iw);
852 wavePtr = &basis.wave(endId - 1 - iw);
853 if (!wavePtr->implicit) {
854 isImplicit = false;
855 }
856 }
857 ++iw;
858 }
859 UTIL_CHECK(wavePtr->starId == is);
860
861 // Compute component value
862 rank = dftMesh.rank(wavePtr->indicesDft);
863 //component = std::complex<double>(in[rank][0], in[rank][1]);
864 assign<CT,RT>(component, in[rank]);
865 component /= wavePtr->coeff;
866 out[ib] = component.real();
867 ++is;
868
869 } else
870 if (starPtr->invertFlag == 1) {
871
872 // Identify a characteristic wave that is not implicit:
873 // Either the first wave of the 1st star or its inverse
874 // in the second star
875 wavePtr = &basis.wave(starPtr->beginId);
876 UTIL_CHECK(wavePtr->starId == is);
877 if (wavePtr->implicit) {
878 iw = wavePtr->inverseId;
879 starPtr = &(basis.star(is+1));
880 UTIL_CHECK(starPtr->invertFlag == -1);
881 wavePtr = &basis.wave(iw);
882 UTIL_CHECK(!(wavePtr->implicit));
883 UTIL_CHECK(wavePtr->starId == is+1);
884 }
885 rank = dftMesh.rank(wavePtr->indicesDft);
886 //component = std::complex<double>(in[rank][0], in[rank][1]);
887 assign<CT, RT>(component, in[rank]);
888 UTIL_CHECK(std::abs(wavePtr->coeff) > 1.0E-8);
889 component /= wavePtr->coeff;
890 component *= sqrt(2.0);
891
892 // Compute basis function coefficient values
893 if (starPtr->invertFlag == 1) {
894 out[ib] = component.real();
895 out[ib+1] = -component.imag();
896 } else {
897 out[ib] = component.real();
898 out[ib+1] = component.imag();
899 }
900
901 is += 2;
902 } else {
903 UTIL_THROW("Invalid invertFlag value");
904 }
905
906 } // loop over star index is
907 }
908
909 /*
910 * Test if an K-grid array has the declared space group symmetry.
911 * Return true if symmetric, false otherwise. Print error values
912 * if verbose == true and hasSymmetry == false.
913 */
914 template <int D, class ACT>
915 bool hasSymmetry(ACT const & in,
916 Basis<D> const& basis,
917 IntVec<D> const& dftDimensions,
918 double epsilon,
919 bool verbose)
920 {
921 UTIL_CHECK(basis.isInitialized());
922
923 typedef typename ACT::Complex CT;
924 typedef typename ACT::Real RT;
925
926 typename Basis<D>::Star const* starPtr; // pointer to current star
927 typename Basis<D>::Wave const* wavePtr; // pointer to current wave
928 std::complex<double> waveCoeff; // coefficient from wave
929 std::complex<double> rootCoeff; // coefficient from root
930 std::complex<double> diff; // coefficient difference
931 int is; // star index
932 int iw; // wave index
933 int beginId, endId; // star begin, end ids
934 int rank; // dft grid rank of wave
935
936 double cancelledError(0.0); // max error from cancelled stars
937 double uncancelledError(0.0); // max error from uncancelled stars
938
939 // Create Mesh<D> with dimensions of DFT Fourier grid.
940 Mesh<D> dftMesh(dftDimensions);
941
942 // Loop over all stars
943 for (is = 0; is < basis.nStar(); ++is) {
944 starPtr = &(basis.star(is));
945
946 if (starPtr->cancel) {
947
948 // Check that coefficients are zero for all waves in star
949 beginId = starPtr->beginId;
950 endId = starPtr->endId;
951 for (iw = beginId; iw < endId; ++iw) {
952 wavePtr = &basis.wave(iw);
953 if (!wavePtr->implicit) {
954 rank = dftMesh.rank(wavePtr->indicesDft);
955 //waveCoeff
956 // = std::complex<double>(in[rank][0], in[rank][1]);
957 assign<CT, RT>(waveCoeff, in[rank]);
958 if (std::abs(waveCoeff) > cancelledError) {
959 cancelledError = std::abs(waveCoeff);
960 if ((!verbose) && (cancelledError > epsilon)) {
961 return false;
962 }
963 }
964 }
965 }
966
967 } else {
968
969 // Check consistency of coeff values from all waves
970 bool hasRoot = false;
971 beginId = starPtr->beginId;
972 endId = starPtr->endId;
973 for (iw = beginId; iw < endId; ++iw) {
974 wavePtr = &basis.wave(iw);
975 if (!(wavePtr->implicit)) {
976 rank = dftMesh.rank(wavePtr->indicesDft);
977 //waveCoeff
978 // = std::complex<double>(in[rank][0], in[rank][1]);
979 assign<CT, RT>(waveCoeff, in[rank]);
980 waveCoeff /= wavePtr->coeff;
981 if (hasRoot) {
982 diff = waveCoeff - rootCoeff;
983 if (std::abs(diff) > uncancelledError) {
984 uncancelledError = std::abs(diff);
985 if ((!verbose) && (uncancelledError > epsilon)) {
986 return false;
987 }
988 }
989 } else {
990 rootCoeff = waveCoeff;
991 hasRoot = true;
992 }
993 }
994 }
995
996 }
997
998 } // end loop over star index is
999
1000 if ((cancelledError < epsilon) && (uncancelledError < epsilon)) {
1001 return true;
1002 } else if (verbose) {
1003 Log::file()
1004 << std::endl
1005 << "Maximum coefficient of a cancelled star: "
1006 << cancelledError << std::endl
1007 << "Maximum error of coefficient for an uncancelled star: "
1008 << uncancelledError << std::endl;
1009 }
1010 return false;
1011 }
1012
1013 // Field file manipulations
1014
1015 template <int D, class ART>
1016 void replicateUnitCell(std::ostream &out,
1017 DArray<ART> const & fields,
1018 IntVec<D> const & meshDimensions,
1019 UnitCell<D> const & unitCell,
1020 IntVec<D> const & replicas)
1021 {
1022 // Obtain number of monomer types
1023 int nMonomer = fields.capacity();
1024 UTIL_CHECK(nMonomer > 0);
1025
1026 // Compute properties of mesh for replicated fields
1027 IntVec<D> repDimensions; // Dimensions
1028 int repSize = 1; // Total number of grid points
1029 for (int i = 0; i < D; ++i) {
1030 UTIL_CHECK(replicas[i] > 0);
1031 UTIL_CHECK(meshDimensions[i] > 0);
1032 repDimensions[i] = replicas[i] * meshDimensions[i];
1033 repSize *= repDimensions[i];
1034 }
1035
1036 // Allocate arrays for replicated fields
1037 DArray< DArray<double> > repFields;
1038 repFields.allocate(nMonomer);
1039 for (int i = 0; i < nMonomer; ++i) {
1040 repFields[i].allocate(repSize);
1041 }
1042
1043 // Replicate data
1044 Mesh<D> mesh(meshDimensions);
1045 Mesh<D> cellMesh(replicas);
1046 Mesh<D> repMesh(repDimensions);
1047 MeshIterator<D> iter(meshDimensions);
1048 MeshIterator<D> cellIter(replicas);
1049 IntVec<D> position;
1050 IntVec<D> cellPosition;
1051 IntVec<D> repPosition;
1052 double value;
1053 int repRank;
1054 for (int i = 0; i < nMonomer; ++i) {
1055 for (iter.begin(); !iter.atEnd(); ++iter) {
1056 position = iter.position();
1057 value = fields[i][iter.rank()];
1058 for (cellIter.begin(); !cellIter.atEnd(); ++cellIter) {
1059 cellPosition = cellIter.position();
1060 for (int j=0; j < D; ++j) {
1061 repPosition[j] = position[j]
1062 + meshDimensions[j]*cellPosition[j];
1063 }
1064 repRank = repMesh.rank(repPosition);
1065 repFields[i][repRank] = value;
1066 }
1067 }
1068 }
1069
1070 // Create a replicated UnitCell<D> object
1071 // Use function declared in prdc/crystal/replicateUnitCell.h
1072 UnitCell<D> cell;
1073 replicateUnitCell(replicas, unitCell, cell);
1074
1075 // Write header
1076 int v1 = 1;
1077 int v2 = 0;
1078 std::string gName = "";
1079 Pscf::Prdc::writeFieldHeader(out, v1, v2, cell, gName, nMonomer);
1080 writeMeshDimensions(out, repDimensions);
1081
1082 // Write field data
1083 writeRGridData(out, repFields, nMonomer, repDimensions);
1084 }
1085
1086 template <int D, class ART>
1087 void
1088 expandRGridDimension(std::ostream &out,
1089 DArray<ART> const & fields,
1090 IntVec<D> const & meshDimensions,
1091 UnitCell<D> const & unitCell,
1092 int d,
1093 DArray<int> newGridDimensions)
1094 {
1095 UTIL_THROW("Unimplemented base template");
1096 }
1097
1098 template <class ART>
1099 void
1100 expandRGridDimension(std::ostream &out,
1101 DArray<ART> const & fields,
1102 IntVec<1> const & meshDimensions,
1103 UnitCell<1> const & unitCell,
1104 int d,
1105 DArray<int> newGridDimensions)
1106
1107 {
1108 // Check validity of expanded dimension d and newGridDimensions
1109 UTIL_CHECK(d > 1);
1110 UTIL_CHECK(d <= 3);
1111 UTIL_CHECK(newGridDimensions.capacity() == (d - 1));
1112
1113
1114 // Obtain number of monomer types
1115 int nMonomer = fields.capacity();
1116 UTIL_CHECK(nMonomer > 0);
1117
1118 // Set up necessary objects
1119 FSArray<double, 6> cellParameters;
1120 cellParameters.append(unitCell.parameter(0));
1121 int v1 = 1;
1122 int v2 = 0;
1123 std::string gName = "";
1124
1125 if (d == 2) {
1126
1127 // 1D expanded to 2D
1128
1129 // Set dimensions
1130 IntVec<2> dimensions;
1131 dimensions[0] = meshDimensions[0];
1132 dimensions[1] = newGridDimensions[0];
1133
1134 // Assign unit cell
1135 UnitCell<2> cell;
1136 if (dimensions[0] == dimensions[1]) {
1137 cell.set(UnitCell<2>::Square, cellParameters);
1138 } else {
1139 cellParameters.append((double)dimensions[1]/dimensions[0]
1140 * cellParameters[0]);
1141 cell.set(UnitCell<2>::Rectangular, cellParameters);
1142 }
1143
1144 // Write Header
1145 Pscf::Prdc::writeFieldHeader(out, v1, v2, cell, gName, nMonomer);
1146 out << "mesh " << std::endl
1147 << " " << dimensions << std::endl;
1148
1149 } else if (d == 3) {
1150
1151 // 1D expanded to 3D
1152
1153 // Set dimensions
1154 IntVec<3> dimensions;
1155 dimensions[0] = meshDimensions[0];
1156 dimensions[1] = newGridDimensions[0];
1157 dimensions[2] = newGridDimensions[1];
1158
1159 // Assign unit cell
1160 UnitCell<3> cell;
1161 if (dimensions[2] == dimensions[1]) {
1162 if (dimensions[1] == dimensions[0]) {
1163 cell.set(UnitCell<3>::Cubic, cellParameters);
1164 } else {
1165 cellParameters.append((double)dimensions[1]/dimensions[0]
1166 * cellParameters[0]);
1167 cellParameters.append((double)dimensions[2]/dimensions[0]
1168 * cellParameters[0]);
1169 cell.set(UnitCell<3>::Orthorhombic, cellParameters);
1170 }
1171 } else {
1172 if (dimensions[1] == dimensions[0]) {
1173 cellParameters.append((double)dimensions[2]/dimensions[0]
1174 * cellParameters[0]);
1175 cell.set(UnitCell<3>::Tetragonal, cellParameters);
1176 } else {
1177 cellParameters.append((double)dimensions[1]/dimensions[0]
1178 * cellParameters[0]);
1179 cellParameters.append((double)dimensions[2]/dimensions[0]
1180 * cellParameters[0]);
1181 cell.set(UnitCell<3>::Orthorhombic, cellParameters);
1182 }
1183 }
1184
1185 // Write Header
1186 Pscf::Prdc::writeFieldHeader(out, v1, v2, cell, gName, nMonomer);
1187 out << "mesh " << std::endl
1188 << " " << dimensions << std::endl;
1189
1190 } else {
1191
1192 UTIL_THROW("Invalid d value");
1193
1194 }
1195
1196 // Write expanded fields
1197 int nReplica = newGridDimensions[0];
1198 if (d == 3) {
1199 nReplica *= newGridDimensions[1];
1200 }
1201 MeshIteratorFortran<1> iter(meshDimensions);
1202 int rank;
1203 for (int i = 0; i < nReplica; ++i) {
1204 for (iter.begin(); !iter.atEnd(); ++iter) {
1205 rank = iter.rank();
1206 for (int j = 0; j < nMonomer; ++j) {
1207 out << " " << Dbl(fields[j][rank], 21, 13);
1208 }
1209 out << std::endl;
1210 }
1211 }
1212
1213 }
1214
1215 template <class ART>
1216 void expandRGridDimension(std::ostream &out,
1217 DArray<ART> const & fields,
1218 IntVec<2> const & meshDimensions,
1219 UnitCell<2> const & unitCell,
1220 int d,
1221 DArray<int> newGridDimensions)
1222 {
1223 // 2D expanded to 3D
1224
1225 // Check validity of expanded dimension d and newGridDimensions
1226 UTIL_CHECK(d == 3);
1227 UTIL_CHECK(newGridDimensions.capacity() == 1);
1228
1229 // Obtain number of monomer types
1230 int nMonomer = fields.capacity();
1231 UTIL_CHECK(nMonomer > 0);
1232
1233 // Set dimensions of mesh for replicated fields
1234 IntVec<3> dimensions;
1235 dimensions[0] = meshDimensions[0];
1236 dimensions[1] = meshDimensions[1];
1237 dimensions[2] = newGridDimensions[0];
1238
1239 // Set unit cell for replicated fields
1240 UnitCell<3> cell;
1241 FSArray<double, 6> cellParameters;
1242 cellParameters.append(unitCell.parameter(0));
1243 if (unitCell.lattice() == UnitCell<2>::Square) {
1244 if (newGridDimensions[0] == meshDimensions[0]){
1245 cell.set(UnitCell<3>::Cubic, cellParameters);
1246 } else {
1247 cellParameters.append((double)dimensions[2]/dimensions[0]
1248 * cellParameters[0]);
1249 cell.set(UnitCell<3>::Tetragonal, cellParameters);
1250 }
1251 } else if (unitCell.lattice() == UnitCell<2>::Rectangular) {
1252 cellParameters.append(unitCell.parameter(1));
1253 cellParameters.append((double)dimensions[2]/dimensions[0]
1254 * cellParameters[0]);
1255 cell.set(UnitCell<3>::Orthorhombic, cellParameters);
1256 } else if (unitCell.lattice() == UnitCell<2>::Hexagonal){
1257 cellParameters.append((double)dimensions[2]/dimensions[0]
1258 * cellParameters[0]);
1259 cell.set(UnitCell<3>::Hexagonal, cellParameters);
1260 } else if (unitCell.lattice() == UnitCell<2>::Rhombic) {
1261 cellParameters.append(unitCell.parameter(0));
1262 cellParameters.append((double)dimensions[2]/dimensions[0]
1263 * cellParameters[0]);
1264 cellParameters.append(Constants::Pi / 2);
1265 cellParameters.append(0.0);
1266 cellParameters.append(unitCell.parameter(1));
1267 cell.set(UnitCell<3>::Triclinic, cellParameters);
1268 } else if (unitCell.lattice() == UnitCell<2>::Oblique) {
1269 cellParameters.append(unitCell.parameter(1));
1270 cellParameters.append((double)dimensions[2]/dimensions[0]
1271 * cellParameters[0]);
1272 cellParameters.append(Constants::Pi / 2);
1273 cellParameters.append(0.0);
1274 cellParameters.append(unitCell.parameter(2));
1275 cell.set(UnitCell<3>::Triclinic, cellParameters);
1276 } else {
1277 UTIL_THROW("Unrecognized 2D lattice system.");
1278 }
1279
1280 // Write Header
1281 int v1 = 1;
1282 int v2 = 0;
1283 std::string gName = "";
1284 Pscf::Prdc::writeFieldHeader(out, v1, v2, cell, gName, nMonomer);
1285 out << "mesh " << std::endl
1286 << " " << dimensions << std::endl;
1287
1288 // Write expanded fields
1289 int nReplica = newGridDimensions[0];
1290 MeshIteratorFortran<2> iter(meshDimensions);
1291 int rank;
1292 for (int i = 0; i < nReplica; ++i) {
1293 for (iter.begin(); !iter.atEnd(); ++iter) {
1294 rank = iter.rank();
1295 for (int j = 0; j < nMonomer; ++j) {
1296 out << " " << Dbl(fields[j][rank], 21, 13);
1297 }
1298 out << std::endl;
1299 }
1300 }
1301
1302 }
1303
1304 template <class ART>
1305 void expandRGridDimension(std::ostream &out,
1306 DArray<ART> const & fields,
1307 IntVec<3> const & meshDimensions,
1308 UnitCell<3> const & unitCell,
1309 int d,
1310 DArray<int> newGridDimensions)
1311
1312 { UTIL_THROW("expandRGridDimension is invalid when D = 3."); }
1313
1314} // namespace Prdc
1315} // namespace Pscf
1316#endif
An IntVec<D, T> is a D-component vector of elements of integer type T.
Definition IntVec.h:27
Iterator over points in a mesh in "Fortran" order.
Description of a regular grid of points in a periodic domain.
IntVec< D > dimensions() const
Get an IntVec<D> of the grid dimensions.
Definition Mesh.h:217
int shift(int &coordinate, int i) const
Shift a periodic coordinate into range.
Definition Mesh.tpp:131
A list of wavevectors that are related by space-group symmetries.
Definition Basis.h:446
int basisId
Index of basis function associated with this star.
Definition Basis.h:527
IntVec< D > waveBz
Integer indices indicesBz of a characteristic wave of this star.
Definition Basis.h:508
int invertFlag
Index for inversion symmetry of star.
Definition Basis.h:495
int size
Number of wavevectors in this star.
Definition Basis.h:453
int beginId
Wave index of first wavevector in star.
Definition Basis.h:458
bool cancel
Is this star cancelled, i.e., associated with a zero function?
Definition Basis.h:542
std::complex< double > coeff
Coefficient of wave within the associated star basis function.
Definition Basis.h:362
int starId
Index of the star that contains this wavevector.
Definition Basis.h:391
Symmetry-adapted Fourier basis for pseudo-spectral scft.
Definition fieldIoUtil.h:21
Wave const & wave(int id) const
Get a specific Wave, access by integer index.
Definition Basis.h:819
int waveId(IntVec< D > vector) const
Get the integer index of a wave, as required by wave(int id).
Definition Basis.h:833
int nStar() const
Total number of stars.
Definition Basis.h:814
bool isInitialized() const
Returns true iff this basis is fully initialized.
Definition Basis.h:841
Star const & star(int id) const
Get a Star, accessed by integer star index.
Definition Basis.h:824
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition rpg/System.h:34
Vec< D, T > & negate(const Vec< D, T > &v)
Return negative of vector v.
Definition Vec.h:520
int capacity() const
Return allocated size.
Definition Array.h:159
static const double Pi
Trigonometric constant Pi.
Definition Constants.h:35
Dynamically allocatable contiguous array template.
void allocate(int capacity)
Allocate the underlying C array.
Definition DArray.h:199
bool isAllocated() const
Return true if this DArray has been allocated, false otherwise.
Definition DArray.h:247
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
A fixed capacity (static) contiguous array with a variable logical size.
Definition rpg/System.h:28
void append(Data const &data)
Append data to the end of the array.
Definition FSArray.h:258
Wrapper for an int, for formatted ostream output.
Definition Int.h:37
static std::ostream & file()
Get log ostream by reference.
Definition Log.cpp:57
#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:51
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 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 writeNBasis(std::ostream &out, int nBasis)
Write the number of basis functions to a basis field file header.
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 checkAllocateArrays(DArray< AT > &arrays, int nMonomer, int capacity)
Check allocation of a DArray of 1D arrays, allocate if necessary.
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.
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.
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.
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.
void readMeshDimensions(std::istream &in, IntVec< D > const &meshDimensions)
Read mesh dimensions from a field file header.
void writeBasisData(std::ostream &out, DArray< DArray< double > > const &fields, Basis< D > const &basis)
Write array of fields in basis format, without a header.
void readBasisData(std::istream &in, DArray< DArray< double > > &fields, UnitCell< D > const &unitCell, Mesh< D > const &mesh, Basis< D > const &basis, int nStarIn)
Read a set of fields in basis format.
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.
RT imag(CT const &a)
Return the imaginary part of a complex number.
void assign(CT &z, RT const &a, RT const &b)
Create a complex number from real and imaginary parts, z = a + ib.
RT real(CT const &a)
Return the real part of a complex number.
PSCF package top-level namespace.
Definition param_pc.dox:1