PSCF v1.4.0
Basis.tpp
1#ifndef PRDC_BASIS_TPP
2#define PRDC_BASIS_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 "Basis.h"
12#include "BWave.h"
13#include "groupFile.h"
14#include <prdc/crystal/UnitCell.h>
15#include <prdc/crystal/SpaceGroup.h>
16#include <prdc/crystal/shiftToMinimum.h>
17#include <pscf/mesh/Mesh.h>
18#include <pscf/mesh/MeshIterator.h>
19#include <util/signal/Signal.h>
20#include <util/format/Dbl.h>
21#include <util/math/Constants.h>
22
23#include <algorithm>
24#include <vector>
25#include <set>
26#include <fstream>
27
28namespace Pscf {
29namespace Prdc {
30
31 /*
32 * Constructor.
33 */
34 template <int D>
36 : waves_(),
37 stars_(),
38 waveIds_(),
39 starIds_(),
40 nWave_(0),
41 nBasisWave_(0),
42 nStar_(0),
43 nBasis_(0),
44 signalPtr_(nullptr),
45 unitCellPtr_(0),
46 meshPtr_(0),
47 isInitialized_(false)
48 {
49 signalPtr_ = new Signal<void>();
50 }
51
52 /*
53 * Destructor.
54 */
55 template <int D>
57 {
58 delete signalPtr_;
59 }
60
61 /*
62 * Construct basis for pseudo-spectral scft.
63 */
64 template <int D>
65 void Basis<D>::makeBasis(Mesh<D> const & mesh,
66 UnitCell<D> const & unitCell,
67 std::string groupName)
68 {
69 SpaceGroup<D> group;
70 readGroup(groupName, group);
71 makeBasis(mesh, unitCell, group);
72 }
73
74 /*
75 * Construct a symmetry-adapted basis for pseudo-spectral scft.
76 */
77 template <int D>
78 void Basis<D>::makeBasis(Mesh<D> const & mesh,
79 UnitCell<D> const & unitCell,
80 SpaceGroup<D> const & group)
81 {
82 // Precondition: Check compatibility of mesh with space group
83 group.checkMeshDimensions(mesh.dimensions());
84
85 // Save pointers to mesh and unit cell
86 meshPtr_ = &mesh;
87 unitCellPtr_ = &unitCell;
88
89 // Allocate arrays
90 nWave_ = mesh.size();
91 waves_.allocate(nWave_);
92 waveIds_.allocate(nWave_);
93
94 // Make sorted array of waves
95 makeWaves();
96
97 // Identify stars of waves that are related by symmetry
98 makeStars(group);
99
100 // Apply validity test suite
101 bool valid = isValid();
102 if (!valid) {
103 UTIL_THROW("Basis failed validity test suite");
104 }
105
106 // Mark as initialized
107 isInitialized_ = true;
108
109 // Notify any observers of successful basis initialization
110 signal().notify();
111 }
112
113 /*
114 * Construct ordered list of waves.
115 *
116 * On exit:
117 * - Member array waves_ contains list of waves ordered by sqNorm.
118 * - Each wave has indicesStd, indicesMin and sqNorm set.
119 * - Member array stars_ is still empty.
120 */
121 template <int D>
122 void Basis<D>::makeWaves()
123 {
124 IntVec<D> meshDimensions = mesh().dimensions();
125 std::vector< BWave<D> > twaves;
126 twaves.reserve(nWave_);
127
128 // Loop over k-grid mesh to generate all waves, add to twaves
129 BWave<D> w;
130 IntVec<D> v;
131 MeshIterator<D> itr(mesh().dimensions());
132 for (itr.begin(); !itr.atEnd(); ++itr) {
133 w.indicesStd = itr.position();
134 v = shiftToMinimum(w.indicesStd, meshDimensions, *unitCellPtr_);
135 w.indicesMin = v;
136 w.sqNorm = unitCell().ksq(v);
137 twaves.push_back(w);
138 }
139
140 // Sort temporary array twaves
141 BWaveNormComp<D> comp;
142 std::sort(twaves.begin(), twaves.end(), comp);
143
144 // Copy temporary array twaves into member variable waves_
145 for (int i = 0; i < nWave_; ++i) {
146 waves_[i].sqNorm = twaves[i].sqNorm;
147 waves_[i].indicesStd = twaves[i].indicesStd;
148 waves_[i].indicesMin = twaves[i].indicesMin;
149 }
150
151 }
152
153 /*
154 * Complete construction of a basis by grouping presorted waves into
155 * stars and completing initialization of all Wave and Star objects.
156 */
157 template <int D>
158 void Basis<D>::makeStars(SpaceGroup<D> const & group)
159 {
160
161 /*
162 * Conceptual definitions:
163 *
164 * - A "bunch" is a set of wavevectors of equal magnitude.
165 * - A "star" is a set of wavevectors that are related by symmetry.
166 *
167 * Each bunch contains one or more complete stars. Bunches are
168 * identified as an intermediate step in identification of stars.
169 *
170 * During initial processing, wavevectors are temporarily stored in
171 * BWave<D> objects. The following local containers of BWave<D>
172 * objects are used:
173 *
174 * bunch - a set of waves of equal norm
175 * star - a set of symmetry-related waves
176 * starList - a sorted star, sorted by descending indicesMin
177 * bunchList - a sorted bunch, with contiguous sorted stars
178 *
179 * The bunch and star containers are std::set< BWave<D> > objects.
180 * The starList container is a std::vector< BWave<D> > objects.
181 * The use of std::set simplifies addition of waves, by allowing
182 * easy identification of duplicates, as well as later removal.
183 * The use of std::vector for the starList allows the use of the
184 * C++ std::sort algorithm to sort stars by standard wavevector
185 * indices.
186 */
187
188 // Local BWave<D> containers and associated iterators
189 std::set< BWave<D>, BWaveStdComp<D> > bunch;
190 std::set< BWave<D>, BWaveStdComp<D> > star;
191 std::vector< BWave<D> > starList;
192 GArray< BWave<D> > bunchList;
193 typename std::set< BWave<D>, BWaveStdComp<D> >::iterator rootItr;
194 typename std::set< BWave<D>, BWaveStdComp<D> >::iterator setItr;
195
196 // Local variables
197 BWave<D> wave;
198 Basis<D>::Star newStar;
199 std::complex<double> coeff;
200 double Gsq;
201 double Gsq_max;
202 double phase_diff;
203 const double twoPi = 2.0*Constants::Pi;
204 const double epsilon = 1.0E-8;
205 IntVec<D> meshDimensions = mesh().dimensions();
206 IntVec<D> rootVecMin; // Min indices for root of this star
207 IntVec<D> rootVecStd; // Std indices for root of this star
208 IntVec<D> vec; // Indices of temporary wavevector
209 IntVec<D> nVec; // Indices of inverse of a wavevector
210 int bunchBegin = 0; // id of first wave in this bunch
211 int bunchEnd = 0; // (id of last wave in this bunch) + 1
212 int bunchSize; // bunchEnd - bunchBegin
213 int starBegin = 0; // id of first wave in this star
214 int i, j, k;
215 bool cancel;
216
217 /*
218 * Overview of algorithm:
219 *
220 * Precondition: Wavevectors in the array waves_ are sorted in
221 * nondecreasing order by wavevector norm.
222 *
223 * Loop over index i of array waves_ {
224 *
225 * Search for end of a "bunch" (i.e., contiguous block of waves
226 * of equal magnitude) by identifying changes in magnitude. The
227 * resulting bunch has indices bunchBegin, ... , bunchEnd-1 .
228 * Set newList true.
229 *
230 * // Each bunch may contain one or more stars.
231 * // Process the newly identified bunch to identify stars.
232 *
233 * If (newList) {
234 *
235 * Copy all waves in the range into std::set bunch
236 *
237 * Set rootItr to the first wave in the bunch
238 *
239 * // Loop over stars within the bunch
240 * while (bunch.size() > 0) {
241 *
242 * // To generate a star from a root wave rootItr,
243 * // loop over symmetry operations of space group.
244 *
245 * For each symmetry operation group[j] {
246 * Compute vec = (rootItr->indicesMin)*group[j]
247 * Set phase = rootItr->indicesMin .dot. (group[j].t)
248 * Check for cancellation of the star, set "cancel" flag
249 * Add wave to std::set<BWave> star if not added before
250 * // Here, use of a std::set simplifies test of uniqueness
251 * }
252 *
253 * Copy all waves from star to std::vector<BWave> starList
254 * Sort starList by indicesMin, in descending order
255 * // Here, use of a std::vector for starList allows sorting
256 *
257 * // Add waves in star to bunchList and remove from bunch
258 * For each wave in starList {
259 * Append the wave to GArray<BWave<D> > bunchList
260 * Erase the wave from std::set<BWave<D> > bunch
261 * // Here, use of a std::set for bunch simplifies erasure
262 * }
263 *
264 * Initialize a Star object named newStar
265 * Assign values to members beginId, endId, size, cancel
266 *
267 * // Assign values of newStar.invertFlag, nextInvert, rootItr
268 * if (nextInvert == -1) {
269 * // This is the second star in pair
270 * newStar.invertFlag = -1;
271 * nextInvert = 1;
272 * Set rootItr to the first wave in remaining bunch
273 * } else {
274 * Search for inverse of rootItr in this star
275 * if inverse is in this star {
276 * // This is a closed star
277 * newStar.invertFlag = 0
278 * nextInvert = 1;
279 * Set rootItr to the first wave in remaining bunch
280 * } else
281 * Search for inverse of rootItr in this remaining bunch
282 * if the inverse is in the remaining bunch {
283 * // This is the first open star in a pair
284 * newStar.invertFlag = 1
285 * nextInvert = -1;
286 * set rootItr to inverse of current root
287 * }
288 * }
289 *
290 * Append newStar object to GArray<Star> stars_
291 *
292 * } // end loop over stars in a single bunch
293 *
294 * // At this point, bunchList contains the contents of the
295 * // waves_ array occupying the range [beginId, endId-1],
296 * // grouped by stars, with waves within each star sorted
297 * // by minimal indices.
298 *
299 * // Overwrite the block of array waves_ with indices in the
300 * // range [beginId, endId-1] with the contents of bunchList.
301 * For each wave in bunchList {
302 * Copy a BWave in bunchList to a Basis:Wave in waves_
303 * Assign a complex coefficient of unit norm to the Wave
304 * }
305 *
306 * // At this point, coefficients of waves have unit magnitude
307 * // and correct relative phases within each star, but not the
308 * // final absolute phases or magnitude.
309 *
310 * } // finish processing of one bunch (waves of equal norm)
311 *
312 * } // End initial processing of all waves and stars
313 *
314 * // Set phases of wave coefficients
315 * For each star in array stars_ {
316 * if star is closed under inversion (star.invertFlag == 0) {
317 * Find the inverse of every wave in this star
318 * if star is cancelled {
319 * Set coefficients of all waves to zero
320 * } else {
321 * Set the root to the first wave in the star
322 * For each wave in star:
323 * Divide coeff by the root coefficient
324 * }
325 * if (coeffs of root & inverse are not complex conjugates){
326 * Divide all coeffs by a common phasor chosen to obtain
327 * complex conjugate coefficients for root and inverse
328 * }
329 * }
330 * } else
331 * if (star.invertFlag == 1) {
332 * Find the inverse of every wave in this star and next star
333 * Set root of this star to the 1st wave in this star
334 * Set partner to the inverse of the root of this star
335 * If this star is cancelled {
336 * Set coefficients in this star and next to zero
337 * } else {
338 * For each wave in this star:
339 * Divide coeff by the root coefficient
340 * }
341 * For each wave in the next star:
342 * Divide coeff by the partner coefficient
343 * }
344 * }
345 * }
346 * // Note: If star.invertFlag = -1, do nothing because properties
347 * // of this star were all set when processing its partner.
348 * }
349 *
350 * // For all waves, normalize coefficients and set starId
351 * For each star in array stars_ {
352 * For each wave in this star {
353 * Set Wave.starId
354 * Divide coefficient by sqrt(double(star.size))
355 * }
356 * }
357 *
358 * // For all waves, set implicit member and add to look up table
359 * For each wave in array waves_ {
360 * Set Wave::implicit attribute
361 * Set waveIds_[rank] = i
362 * }
363 */
364
365 // Loop over all waves (initial processing of waves)
366 nBasis_ = 0;
367 nBasisWave_ = 0;
368 Gsq_max = waves_[0].sqNorm;
369 for (i = 1; i <= nWave_; ++i) {
370
371 // Determine if this wave begins a new bunch
372 bool newList = false;
373 if (i == nWave_) {
374 bunchEnd = i;
375 bunchSize = bunchEnd - bunchBegin;
376 newList = true;
377 } else {
378 Gsq = waves_[i].sqNorm;
379 if (Gsq > Gsq_max + epsilon) {
380 Gsq_max = Gsq;
381 bunchEnd = i;
382 bunchSize = bunchEnd - bunchBegin;
383 newList = true;
384 }
385 }
386
387 // Process completed bunch of wavectors of equal norm
388 if (newList) {
389
390 // Copy waves of equal norm into std::set "bunch"
391 bunch.clear();
392 bunchList.clear();
393 for (j = bunchBegin; j < bunchEnd; ++j) {
394 wave.indicesStd = waves_[j].indicesStd;
395 wave.indicesMin = waves_[j].indicesMin;
396 wave.sqNorm = waves_[j].sqNorm;
397 if (j > bunchBegin) {
398 UTIL_CHECK( std::abs(wave.sqNorm-waves_[j].sqNorm)
399 < 2.0*epsilon );
400 }
401 bunch.insert(wave);
402 }
403
404 // On entry to each iteration of the loop over stars,
405 // rootItr and nextInvert are known. The iterator rootItr
406 // points to the wave in the remaining bunch that will be
407 // used as the root of the next star. The flag nextInvert
408 // is equal to -1 iff the previous star was the first of
409 // a pair that are open under inversion, and is equal
410 // to + 1 otherwise.
411
412 // Initial values for first star in this bunch
413 rootItr = bunch.begin();
414 int nextInvert = 1;
415
416 // Loop over stars with a bunch of waves of equal norm,
417 // removing each star from set bunch as it is identified.
418 // The root of the next star must have been chosen on
419 // entry to each iteration of this loop.
420
421 while (bunch.size() > 0) {
422
423 rootVecMin = rootItr->indicesMin;
424 rootVecStd = rootItr->indicesStd;
425 Gsq = rootItr->sqNorm;
426 cancel = false;
427 star.clear();
428
429 // Construct a star from root vector, by applying every
430 // symmetry operation in the group to the root wavevector.
431 for (j = 0; j < group.size(); ++j) {
432
433 // Apply symmetry (i.e., multiply by rotation matrix)
434 // vec = rotated wavevector.
435 vec = rootVecMin*group[j];
436
437 // Check that rotated vector has same norm as root.
438 UTIL_CHECK(std::abs(Gsq - unitCell().ksq(vec)) < epsilon);
439
440 // Initialize BWave object associated with rotated wave
441 wave.sqNorm = Gsq;
442 wave.indicesMin = shiftToMinimum(vec, meshDimensions,
443 *unitCellPtr_);
444 wave.indicesStd = vec;
445 mesh().shift(wave.indicesStd);
446
447 // Compute phase for coeff. of wave in basis function.
448 // Convention -pi < phase <= pi.
449 wave.phase = 0.0;
450 for (k = 0; k < D; ++k) {
451 wave.phase += rootVecMin[k]*(group[j].t(k));
452 }
453 while (wave.phase > 0.5) {
454 wave.phase -= 1.0;
455 }
456 while (wave.phase <= -0.5) {
457 wave.phase += 1.0;
458 }
459 wave.phase *= twoPi;
460
461 // Check for cancellation of star: The star is
462 // cancelled if application of any symmetry operation
463 // in the group to the root vector yields a rotated
464 // vector equivalent to the root vector but with a
465 // nonzero phase, creating a contradiction.
466
467 if (wave.indicesStd == rootVecStd) {
468 if (std::abs(wave.phase) > 1.0E-6) {
469 cancel = true;
470 }
471 }
472
473 // Search for an equivalent wave already in the star.
474 // Note: Equivalent waves have equal standard indices.
475 setItr = star.find(wave);
476
477 if (setItr == star.end()) {
478
479 // If no equivalent wave is found in the star,
480 // then add this wave to the star
481 star.insert(wave);
482
483 } else {
484
485 // If an equivalent wave is found, check if the
486 // phases are equivalent. If not, the star is
487 // cancelled.
488
489 phase_diff = setItr->phase - wave.phase;
490 while (phase_diff > 0.5) {
491 phase_diff -= 1.0;
492 }
493 while (phase_diff <= -0.5) {
494 phase_diff += 1.0;
495 }
496 if (std::abs(phase_diff) > 1.0E-6) {
497 cancel = true;
498 }
499
500 }
501
502 }
503
504 // Copy waves from std::set star to std::vector starList
505 starList.clear();
506 setItr = star.begin();
507 for ( ; setItr != star.end(); ++setItr) {
508 starList.push_back(*setItr);
509 }
510
511 // Sort starList, in descending order by indicesMin.
512 BWaveMinComp<D> waveMinComp;
513 std::sort(starList.begin(), starList.end(), waveMinComp);
514
515 // Append starList to bunchList, erase from set bunch
516 int starListSize = starList.size();
517 for (j = 0; j < starListSize; ++j) {
518 bunch.erase(starList[j]);
519 bunchList.append(starList[j]);
520 }
521 UTIL_CHECK(int(bunchList.size()+bunch.size())==bunchSize);
522
523 // If this star is not cancelled, increment the number of
524 // basis functions (nBasis_) & waves in basis (nBasisWave_)
525 if (!cancel) {
526 ++nBasis_;
527 nBasisWave_ += star.size();
528 }
529
530 // Initialize a Star object
531 // newStar.eigen = Gsq;
532 newStar.beginId = starBegin;
533 newStar.endId = newStar.beginId + star.size();
534 newStar.size = star.size();
535 newStar.cancel = cancel;
536 // Note: newStar.starInvert is not yet known
537
538 // Determine invertFlag, rootItr and nextInvert
539 if (nextInvert == -1) {
540
541 // If this star is 2nd of a pair related by inversion,
542 // set root for next star to 1st wave of remaining
543 // bunch.
544
545 newStar.invertFlag = -1;
546 rootItr = bunch.begin();
547 nextInvert = 1;
548
549 } else {
550
551 // If this star is not the 2nd of a pair of partners,
552 // then determine if it is closed under inversion.
553
554 // Compute negation nVec of root vector
555 nVec.negate(rootVecMin);
556
557 // Shift nVec to the standard mesh
558 (*meshPtr_).shift(nVec);
559
560 // Search for inverse of root vector within this star
561 bool inverseFound = false;
562 setItr = star.begin();
563 for ( ; setItr != star.end(); ++setItr) {
564 if (nVec == setItr->indicesStd) {
565 inverseFound = true;
566 break;
567 }
568 }
569
570 if (inverseFound) {
571
572 // If this star is closed under inversion, the root
573 // of the next star is the 1st vector of remaining
574 // bunch.
575
576 newStar.invertFlag = 0;
577 rootItr = bunch.begin();
578 nextInvert = 1;
579
580 } else {
581
582 // This star is open under inversion, and is the
583 // first star of a pair related by inversion
584
585 newStar.invertFlag = 1;
586 nextInvert = -1;
587
588 // Find inverse of the root of this star in the
589 // remaining bunch, and use this inverse as the
590 // root of the next star.
591
592 setItr = bunch.begin();
593 for ( ; setItr != bunch.end(); ++setItr) {
594 if (nVec == setItr->indicesStd) {
595 inverseFound = true;
596 rootItr = setItr;
597 break;
598 }
599 }
600 // If inverseFound, then rootVecStd = nVec
601
602 // Failure to find the inverse here is an error:
603 // It must be either in this star or remaining bunch
604
605 if (!inverseFound) {
606 std::cout << "Inverse not found for: " << "\n";
607 std::cout << " vec (std):"
608 << rootVecStd <<"\n";
609 std::cout << " vec (min):"
610 << rootVecMin <<"\n";
611 std::cout << "-vec (std):" << nVec << "\n";
612 UTIL_CHECK(inverseFound);
613 }
614
615 }
616
617 }
618
619 stars_.append(newStar);
620 starBegin = newStar.endId;
621
622 }
623 // End loop over stars within a bunch.
624
625 UTIL_CHECK(bunch.size() == 0);
626 UTIL_CHECK(bunchList.size() == bunchEnd - bunchBegin);
627
628 // Copy bunchList into corresponding section of waves_,
629 // overwriting the section of waves_ used to create the bunch.
630 // Compute a complex coefficient of unit norm for each wave.
631 for (j = 0; j < bunchList.size(); ++j) {
632 k = j + bunchBegin;
633 waves_[k].indicesStd = bunchList[j].indicesStd;
634 waves_[k].indicesMin = bunchList[j].indicesMin;
635 waves_[k].sqNorm = bunchList[j].sqNorm;
636 coeff = std::complex<double>(0.0, bunchList[j].phase);
637 coeff = exp(coeff);
638 if (std::abs(imag(coeff)) < 1.0E-6) {
639 coeff = std::complex<double>(real(coeff), 0.0);
640 }
641 if (std::abs(real(coeff)) < 1.0E-6) {
642 coeff = std::complex<double>(0.0, imag(coeff));
643 }
644 waves_[k].coeff = coeff;
645 }
646
647 // Processing of this bunch is now complete.
648 // Here, waves_[k].coeff has unit absolute magnitude, and
649 // correct relative phases for waves within a star, but
650 // the coeff may not be unity for the first or last wave
651 // in the star.
652
653 bunchBegin = bunchEnd;
654 }
655 // Finished processing a bunch of waves of equal norm
656
657 } // End loop over all waves
658 nStar_ = stars_.size();
659 // Complete initial processing of all bunches and stars
660
661 /*
662 * Conventions for phases of wave coefficients (imposed below):
663 * - Coefficients of the root of each star and its inverse must
664 * be complex conjugates.
665 * - In a closed star (starInvert = 0), the coefficient of the
666 * root must have a non-negative real part. If the root
667 * coefficient is pure imaginary, the imaginary part must
668 * be negative.
669 * - In a pair of open stars that are related by inversion
670 * symmetry, the coefficients of the first wave of the first
671 * star and its inverse must have real coefficients.
672 */
673
674 // Final processing of phases of of waves in stars:
675 std::complex<double> rootCoeff; // Coefficient of root wave
676 std::complex<double> partCoeff; // Coefficient of partner of root
677 std::complex<double> d;
678 int rootId, partId;
679 for (i = 0; i < nStar_; ++i) {
680
681 // Treat open and closed stars differently
682
683 if (stars_[i].invertFlag == 0) {
684
685 // First, assign inverseId for each wave in star
686 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
687 if (waves_[j].inverseId < 0) { // if inverseId is unassigned
688
689 // Compute nVec = inverse of root, shifted to std mesh
690 nVec.negate(waves_[j].indicesMin);
691 (*meshPtr_).shift(nVec);
692
693 // Find inverse
694
695 // Check in the position that the inverse is
696 // expected to be located for a typical star
697 k = stars_[i].endId - 1 - (j - stars_[i].beginId);
698 if (nVec == waves_[k].indicesStd) {
699 waves_[j].inverseId = k;
700 waves_[k].inverseId = j;
701 } else {
702 // Inverse not in expected position, search full star
703 // (this usually occurs for stars on the edge of the
704 // Brillouin zone)
705 for (k = j; k < stars_[i].endId; ++k) {
706 if (nVec == waves_[k].indicesStd) {
707 waves_[j].inverseId = k;
708 waves_[k].inverseId = j;
709 break;
710 }
711 }
712 }
713
714 // For invertFlag == 0, failure to find nVec in this
715 // star is a fatal error
716 if (waves_[j].inverseId < 0) {
717 std::cout << "\n";
718 std::cout << "Inverse not found in closed star"
719 << std::endl;
720 std::cout << "G = " << waves_[j].indicesMin
721 << ", coeff = " << waves_[j].coeff
722 << std::endl;
723 std::cout << "All waves in star " << i
724 << std::endl;
725 for (k=stars_[i].beginId; k < stars_[i].endId; ++k) {
726 std::cout << waves_[k].indicesMin << " "
727 << waves_[k].coeff << std::endl;
728 }
729 UTIL_CHECK(waves_[j].inverseId >= 0);
730 }
731
732 }
733 }
734
735 // Identify root of this star (star i)
736 // Set the root to be the first wave in the star
737
738 rootId = stars_[i].beginId;
739 stars_[i].waveMin = waves_[rootId].indicesMin;
740
741 if (stars_[i].cancel) {
742
743 // If the star is cancelled, set all coefficients to zero
744 std::complex<double> czero(0.0, 0.0);
745 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
746 waves_[j].coeff = czero;
747 }
748
749 } else { // if not cancelled
750
751 // Set partId to index of the inverse of the root
752 partId = waves_[rootId].inverseId;
753
754 // Divide all coefficients by the root coefficient
755 rootCoeff = waves_[rootId].coeff;
756 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
757 waves_[j].coeff /= rootCoeff;
758 }
759 rootCoeff = waves_[rootId].coeff;
760 UTIL_CHECK(std::abs(real(rootCoeff) - 1.0) < 1.0E-9);
761 UTIL_CHECK(std::abs(imag(rootCoeff)) < 1.0E-9);
762
763 // Require coefficients of root and inverse are conjugates
764 if (partId != rootId) {
765
766 partCoeff = waves_[partId].coeff;
767 UTIL_CHECK(std::abs(std::abs(partCoeff) - 1.0) < 1.0E-9);
768 if (std::abs(partCoeff - rootCoeff) > 1.0E-6) {
769 d = sqrt(partCoeff);
770 if (real(d) < -1.0E-4) {
771 d = -d;
772 } else
773 if (std::abs(real(d)) <= 1.0E-4) {
774 if (imag(d) < 0.0) {
775 d = -d;
776 }
777 }
778 for (j=stars_[i].beginId; j < stars_[i].endId; ++j){
779 waves_[j].coeff /= d;
780 }
781 }
782
783 }
784
785 } // end if (cancel) ... else ...
786
787 } // end if (stars_[i].invertFlag == 0)
788 else
789 if (stars_[i].invertFlag == 1) {
790
791 // Process a pair of open stars related by inversion.
792
793 // Preconditions:
794 UTIL_CHECK(stars_[i].size == stars_[i+1].size);
795 UTIL_CHECK(stars_[i].cancel == stars_[i+1].cancel);
796 // UTIL_CHECK(stars_[i+1].invertFlag == -1);
797
798 // First, assign inverseId for each wave in pair of stars
799 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
800 if (waves_[j].inverseId < 0) { // if inverseId is unassigned
801
802 // Compute nVec = inverse of root, shifted to std mesh
803 nVec.negate(waves_[j].indicesMin);
804 (*meshPtr_).shift(nVec);
805
806 // Find inverse
807
808 // Check in the position that the inverse is expected
809 // to be located for a typical pair of stars
810 k = stars_[i+1].endId - 1 - (j - stars_[i].beginId);
811 if (nVec == waves_[k].indicesStd) {
812 waves_[j].inverseId = k;
813 waves_[k].inverseId = j;
814 } else {
815 // Inverse not in expected position, search full star
816 // (this usually occurs for stars on the edge of the
817 // Brillouin zone)
818 k = stars_[i+1].beginId;
819 for ( ; k < stars_[i+1].endId; ++k) {
820 if (nVec == waves_[k].indicesStd) {
821 waves_[j].inverseId = k;
822 waves_[k].inverseId = j;
823 break;
824 }
825 }
826 }
827
828 // For invertFlag = 1, failure to find nVec in the
829 // next star is a fatal error
830 UTIL_CHECK(waves_[j].inverseId >= 0);
831
832 }
833 }
834
835 // Check that inverseId was assigned for all waves in the
836 // next star
837 for (j = stars_[i+1].beginId; j < stars_[i+1].endId; ++j) {
838 UTIL_CHECK(waves_[j].inverseId >= 0);
839 }
840
841 // Identify root of this star (star i)
842 // Set the root to be the first wave in the star
843 rootId = stars_[i].beginId;
844 stars_[i].waveMin = waves_[rootId].indicesMin;
845
846 // Identify root of the next star (star i+1)
847 // Set the root to be the inverse of the root of star i
848 partId = waves_[rootId].inverseId;
849 stars_[i+1].waveMin = waves_[partId].indicesMin;
850
851 if (stars_[i].cancel) {
852
853 std::complex<double> czero(0.0, 0.0);
854 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
855 waves_[j].coeff = czero;
856 }
857 for (j = stars_[i+1].beginId; j < stars_[i+1].endId; ++j) {
858 waves_[j].coeff = czero;
859 }
860
861 } else { // if star is not cancelled
862
863 // Divide all coefficients in this star by root coeff
864 rootCoeff = waves_[rootId].coeff;
865 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
866 waves_[j].coeff /= rootCoeff;
867 }
868
869 // Divide coefficients in next star by a partner coeff.
870 partCoeff = waves_[partId].coeff;
871 for (j = stars_[i+1].beginId; j < stars_[i+1].endId; ++j) {
872 waves_[j].coeff /= partCoeff;
873 }
874
875 } // end if (cancel) ... else ...
876
877 } // end if (invertFlag==0) ... else if (invertFlag==1) ...
878
879 // Note: If invertFlag == -1, do nothing and continue
880 // Related stars with invertFlag == 1 and -1 are treated together
881
882 } // end loop over stars
883
884 // For all waves, normalize coefficients and set starId
885 for (i = 0; i < nStar_; ++i) {
886 double snorm = 1.0/sqrt(double(stars_[i].size));
887 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
888 waves_[j].coeff *= snorm;
889 waves_[j].starId = i;
890 }
891 }
892
893 // Set tiny real and imaginary parts to zero (due to round-off)
894 for (i = 0; i < nWave_; ++i) {
895 if (std::abs(real(waves_[i].coeff)) < 1.0E-8) {
896 waves_[i].coeff
897 = std::complex<double>(0.0, imag(waves_[i].coeff));
898 }
899 if (std::abs(imag(waves_[i].coeff)) < 1.0E-8) {
900 waves_[i].coeff
901 = std::complex<double>(real(waves_[i].coeff), 0.0);
902 }
903 }
904
905 // For each wave, set implicit attribute and add to look-up table
906 for (i = 0; i < nWave_; ++i) {
907 vec = waves_[i].indicesStd;
908
909 // Validity check - check that vec is in standard k-grid mesh
910 for (j = 0; j < D; ++j) {
911 UTIL_CHECK(vec[j] >= 0);
912 UTIL_CHECK(vec[j] < meshDimensions[j]);
913 }
914
915 // Set implicit attribute
916 if ((vec[D-1] + 1) > (meshDimensions[D-1]/2 + 1)) {
917 waves_[i].implicit = true;
918 } else {
919 waves_[i].implicit = false;
920 }
921
922 // Look up table for waves
923 waveIds_[mesh().rank(vec)] = i;
924 }
925
926 // Set Star::starId and Star::basisId, add to look-up table starIds_.
927 starIds_.allocate(nBasis_);
928 j = 0;
929 for (i = 0; i < nStar_; ++i) {
930 stars_[i].starId = i;
931 if (stars_[i].cancel) {
932 stars_[i].basisId = -1;
933 } else {
934 stars_[i].basisId = j;
935 UTIL_CHECK(j < nBasis_);
936 starIds_[j] = i;
937 ++j;
938 }
939 }
940 UTIL_CHECK(j == nBasis_);
941
942 }
943
944 // Return value of nBasis
945 template <int D>
947 { return nBasis_; }
948
949
950 template <int D>
951 void Basis<D>::outputWaves(std::ostream& out, bool outputAll) const
952 {
953 out << "N_wave" << std::endl;
954 if (outputAll) {
955 out << " " << nWave_ << std::endl;
956 } else {
957 out << " " << nBasisWave_ << std::endl;
958 }
959 int i, j, k, starId;
960 k = 0;
961 for (i = 0; i < nWave_; ++i) {
962 starId = waves_[i].starId;
963 if (outputAll || (!stars_[starId].cancel)) {
964 out << Int(k, 8);
965 out << Int(i, 8);
966 for (j = 0; j < D; ++j) {
967 out << Int(waves_[i].indicesMin[j], 5);
968 }
969 out << Int(waves_[i].starId, 6);
970 out << " " << Dbl(waves_[i].coeff.real(), 15);
971 out << " " << Dbl(waves_[i].coeff.imag(), 15);
972 out << std::endl;
973 k++;
974 }
975 }
976 }
977
978
979 template <int D>
980 void Basis<D>::outputStars(std::ostream& out, bool outputAll) const
981 {
982 // Output number of stars in appropriate format
983 if (outputAll) {
984 out << "N_star" << std::endl
985 << " " << nStar_ << std::endl;
986 } else {
987 out << "N_basis" << std::endl
988 << " " << nBasis_ << std::endl;
989 }
990
991 // Loop over stars
992 int i, j;
993 for (i = 0; i < nStar_; ++i) {
994 if (outputAll || (!stars_[i].cancel)) {
995 out << Int(stars_[i].basisId, 6); // basisId
996 out << Int(i, 6); // starId
997 out << Int(stars_[i].size, 5)
998 << Int(stars_[i].beginId, 8)
999 << Int(stars_[i].endId, 8)
1000 << Int(stars_[i].invertFlag, 4);
1001 if (outputAll) {
1002 out << Int(stars_[i].cancel, 4);
1003 }
1004 for (j = 0; j < D; ++j) {
1005 out << Int(stars_[i].waveMin[j], 6);
1006 }
1007 out << std::endl;
1008 }
1009 }
1010 }
1011
1012 template <int D>
1014 {
1015 double Gsq;
1016 IntVec<D> v;
1017 int is, ib, iw, iwp, j;
1018
1019 // Check total number of waves == # of grid points
1020 if (nWave_ != mesh().size()) {
1021 std::cout << "nWave != size of mesh" << std::endl;
1022 return false;
1023 }
1024
1025 // Loop over k-grid mesh to check consistency of waveIds_ and waves_
1026 MeshIterator<D> itr(mesh().dimensions());
1027 for (itr.begin(); !itr.atEnd(); ++itr) {
1028 v = itr.position();
1029 iw = waveId(v);
1030 if (wave(iw).indicesStd != v) {
1031 std::cout << "Inconsistent waveId and Wave::indicesStd"
1032 << std::endl;
1033 return false;
1034 }
1035 }
1036
1037 // Loop over elements of waves_, check consistency of wave data.
1038 for (iw = 0; iw < nWave_; ++iw) {
1039
1040 // Check sqNorm
1041 v = waves_[iw].indicesMin;
1042 Gsq = unitCell().ksq(v);
1043 if (std::abs(Gsq - waves_[iw].sqNorm) > 1.0E-8) {
1044 std::cout << "\n";
1045 std::cout << "Incorrect sqNorm:" << "\n"
1046 << "wave.indicesMin = " << "\n"
1047 << "wave.sqNorm = " << waves_[iw].sqNorm << "\n"
1048 << "|v|^{2} = " << Gsq << "\n";
1049 return false;
1050 }
1051
1052 // Check that wave indicesMin is an image of indicesStd
1053 mesh().shift(v);
1054 if (v != waves_[iw].indicesStd) {
1055 std::cout << "\n";
1056 std::cout << "shift(indicesMin) != indicesStd" << std::endl;
1057 return false;
1058 }
1059
1060 // Compare Wave::starId to Star::beginId and Star::endId
1061 is = waves_[iw].starId;
1062 if (iw < stars_[is].beginId) {
1063 std::cout << "\n";
1064 std::cout << "Wave::starId < Star::beginId" << std::endl;
1065 return false;
1066 }
1067 if (iw >= stars_[is].endId) {
1068 std::cout << "\n";
1069 std::cout << "Wave::starId >= Star::endId" << std::endl;
1070 return false;
1071 }
1072
1073 // Check that inverseId has been assigned
1074 if (waves_[iw].inverseId < 0) {
1075 std::cout << "\n";
1076 std::cout << "Wave::inverseId not assigned\n";
1077 std::cout << "G = " << waves_[iw].indicesMin << std::endl;
1078 return false;
1079 }
1080
1081 // Check that inverseId points to the correct wave
1082 v.negate(waves_[iw].indicesMin);
1083 mesh().shift(v);
1084 iwp = waves_[iw].inverseId;
1085 if (waves_[iwp].indicesStd != v) {
1086 std::cout << "\n";
1087 std::cout << "Wave::inverseId is not inverse" << std::endl;
1088 std::cout << "G = " << waves_[iw].indicesMin << std::endl;
1089 std::cout << "-G (from inverseId) = "
1090 << waves_[iwp].indicesMin << std::endl;
1091 return false;
1092 }
1093
1094 // Check that inverseId of the inverse wave is correct
1095 if (waves_[iwp].inverseId != iw) {
1096 std::cout << "\n";
1097 std::cout << "Wave::inverseId values do not agree\n";
1098 std::cout << "+G = " << waves_[iw].indicesMin << std::endl;
1099 std::cout << "-G = " << waves_[iwp].indicesMin << std::endl;
1100 return false;
1101 }
1102
1103 // Check that either this wave or its inverse is explicit
1104 if (waves_[iw].implicit == true && waves_[iwp].implicit == true)
1105 {
1106 std::cout << "\n";
1107 std::cout << "Wave and its inverse are both implicit";
1108 std::cout << "+G = " << waves_[iw].indicesMin << std::endl;
1109 std::cout << "-G = " << waves_[iwp].indicesMin << std::endl;
1110 return false;
1111 }
1112 }
1113
1114 // Loop over all stars (elements of stars_ array)
1115 int nWave = 0;
1116 for (is = 0; is < nStar_; ++is) {
1117
1118 // Check star size
1119 nWave += stars_[is].size;
1120 if (stars_[is].size != stars_[is].endId - stars_[is].beginId) {
1121 std::cout << "\n";
1122 std::cout << "Inconsistent Star::size:" << std::endl;
1123 std::cout << "Star id " << is << std::endl;
1124 std::cout << "star size " << stars_[is].size << std::endl;
1125 std::cout << "Star begin " << stars_[is].beginId << std::endl;
1126 std::cout << "Star end " << stars_[is].endId << std::endl;
1127 return false;
1128 }
1129 if (is > 0) {
1130 if (stars_[is].beginId != stars_[is-1].endId) {
1131 std::cout << "\n";
1132 std::cout << "Star ranges not consecutive:" << std::endl;
1133 std::cout << "Star id " << is << std::endl;
1134 std::cout << "stars_[" << is << "]" << ".beginId = "
1135 << stars_[is].beginId << std::endl;
1136 std::cout << "stars_[" << is-1 << "]" << ".endId = "
1137 << stars_[is-1].endId << std::endl;
1138 return false;
1139 }
1140 }
1141
1142 // Check waveMin indices of star
1143 if (stars_[is].invertFlag == -1) {
1144 v.negate(stars_[is-1].waveMin);
1145 v = shiftToMinimum(v, mesh().dimensions(), *unitCellPtr_);
1146 if (stars_[is].waveMin != v) {
1147 std::cout << "\n";
1148 std::cout << "waveMin of star is not inverse of waveMin "
1149 << "of previous star" << std::endl;
1150 std::cout << "star id " << is << std::endl;
1151 std::cout << "waveMin " << stars_[is].waveMin << std::endl;
1152 std::cout << "waveMin (previous star) "
1153 << stars_[is-1].waveMin << std::endl;
1154 return false;
1155 }
1156 } else {
1157 v = waves_[stars_[is].beginId].indicesMin;
1158 if (stars_[is].waveMin != v) {
1159 std::cout << "\n";
1160 std::cout << "waveMin of star != first wave of star"
1161 << std::endl;
1162 std::cout << "star id " << is << std::endl;
1163 std::cout << "waveMin " << stars_[is].waveMin
1164 << std::endl;
1165 std::cout << "first wave " << v << std::endl;
1166 return false;
1167 }
1168 }
1169
1170 // Check star ids of waves in star
1171 for (iw = stars_[is].beginId; iw < stars_[is].endId; ++iw) {
1172 if (waves_[iw].starId != is) {
1173 std::cout << "\n";
1174 std::cout << "Inconsistent Wave::starId :" << std::endl;
1175 std::cout << "star id " << is << std::endl;
1176 std::cout << "star beginId " << stars_[is].beginId << "\n";
1177 std::cout << "star endId " << stars_[is].endId << "\n";
1178 std::cout << "wave id " << iw << "\n";
1179 std::cout << "wave starId " << waves_[iw].starId << "\n";
1180 return false;
1181 }
1182 }
1183
1184 // Check Star::starId is equal to array index
1185 if (stars_[is].starId != is) {
1186 std::cout << "\n";
1187 std::cout << "stars_[is].starId != is for "
1188 << "is = " << is << "\n";
1189 return false;
1190 }
1191
1192 // Check Star::basisId and starIds_ look up table
1193 ib = stars_[is].basisId;
1194 if (stars_[is].cancel) {
1195 if (ib != -1) {
1196 std::cout << "\n";
1197 std::cout << "basisId != -1 for cancelled star\n";
1198 std::cout << "star id = " << is << "\n";
1199 return false;
1200 }
1201 } else {
1202 if (starIds_[ib] != is) {
1203 std::cout << "\n";
1204 std::cout << "starIds_[stars_[is].basisId] != is for: \n";
1205 std::cout << "is = " << is << "\n";
1206 std::cout << "ib = stars_[is].basisId = " << ib << "\n";
1207 std::cout << "starIds_[ib] = " << starIds_[ib]
1208 << "\n";
1209 return false;
1210 }
1211 }
1212
1213 // Check ordering of waves in star
1214 for (iw = stars_[is].beginId + 1; iw < stars_[is].endId; ++iw) {
1215 if (waves_[iw].indicesMin > waves_[iw-1].indicesMin) {
1216 std::cout << "\n";
1217 std::cout << "Failure of ordering by indicesB within star"
1218 << std::endl;
1219 return false;
1220 }
1221 if (waves_[iw].indicesMin == waves_[iw-1].indicesMin) {
1222 std::cout << "\n";
1223 std::cout << "Equal values of indicesMin within star"
1224 << std::endl;
1225 return false;
1226 }
1227 }
1228
1229 // Check that all coefficients are zero if star is cancelled
1230 if (stars_[is].cancel) {
1231 for (iw = stars_[is].beginId + 1; iw < stars_[is].endId; ++iw)
1232 {
1233 if (std::abs(waves_[iw].coeff) > 1.0E-8) {
1234 std::cout << "\n";
1235 std::cout << "Nonzero coefficient in a cancelled star"
1236 << "\n";
1237 std::cout << "G = " << waves_[iw].indicesMin
1238 << " coeff = " << waves_[iw].coeff
1239 << "\n";
1240 return false;
1241 }
1242 }
1243 }
1244
1245 } // End do loop over all stars
1246
1247 // Check that all waves in mesh are accounted for in stars
1248 if (stars_[nStar_-1].endId != mesh().size()) {
1249 std::cout << "\n";
1250 std::cout << "Star endId of last star != mesh size" << std::endl;
1251 return false;
1252 }
1253 if (nWave != mesh().size()) {
1254 std::cout << "\n";
1255 std::cout << "Sum of star sizes != mesh size" << std::endl;
1256 return false;
1257 }
1258
1259 // Loop over closed stars and related pairs of stars.
1260 // Test closure under inversion and conjugacy of coefficients.
1261 std::complex<double> cdel;
1262 bool cancel;
1263 is = 0;
1264 while (is < nStar_) {
1265 cancel = stars_[is].cancel;
1266
1267 if (stars_[is].invertFlag == 0) {
1268
1269 // Test that star is closed under inversion and real
1270 int begin = stars_[is].beginId;
1271 int end = stars_[is].endId;
1272 for (iw = begin; iw < end; ++iw) {
1273 iwp = waves_[iw].inverseId;
1274 if (waves_[iwp].starId != is) {
1275 std::cout << "\n";
1276 std::cout << "Inverse not found in closed star"
1277 << std::endl;
1278 std::cout << "G = " << waves_[iw].indicesMin
1279 << "coeff = " << waves_[iw].coeff
1280 << std::endl;
1281 std::cout << "All waves in star " << is << "\n";
1282 for (j=begin; j < end; ++j) {
1283 std::cout << waves_[j].indicesMin << " "
1284 << waves_[j].coeff << "\n";
1285 }
1286 return false;
1287 }
1288 if (!cancel) {
1289 cdel = std::conj(waves_[iwp].coeff);
1290 cdel -= waves_[iw].coeff;
1291 if (std::abs(cdel) > 1.0E-8) {
1292 std::cout << "\n";
1293 std::cout << "Function for closed star is not real:"
1294 << "\n";
1295 std::cout << "+G = " << waves_[iw].indicesMin
1296 << " coeff = " << waves_[iw].coeff
1297 << "\n";
1298 std::cout << "-G = " << waves_[iwp].indicesMin
1299 << " coeff = " << waves_[iwp].coeff
1300 << "\n";
1301 std::cout << "Coefficients are not conjugates."
1302 << "\n";
1303 std::cout << "All waves in star " << is << "\n";
1304 for (j=begin; j < end; ++j) {
1305 std::cout << waves_[j].indicesMin << " "
1306 << waves_[j].coeff << "\n";
1307 }
1308 return false;
1309 }
1310 }
1311 }
1312
1313 // Finished processing a closed star, increment counter is
1314 ++is;
1315
1316 } else {
1317
1318 // Test pairs of open stars
1319
1320 if (stars_[is].invertFlag != 1) {
1321 std::cout << "\n";
1322 std::cout << "Expected invertFlag == 1" << std::endl;
1323 return false;
1324 }
1325 if (stars_[is+1].invertFlag != -1) {
1326 std::cout << "\n";
1327 std::cout << "Expected invertFlag == -1" << std::endl;
1328 return false;
1329 }
1330 if (stars_[is+1].size != stars_[is].size) {
1331 std::cout << "\n";
1332 std::cout << "Partner stars of different size" << std::endl;
1333 return false;
1334 }
1335 if (stars_[is+1].cancel != stars_[is].cancel) {
1336 std::cout << "\n";
1337 std::cout << "Partners stars with different cancel flags"
1338 << std::endl;
1339 return false;
1340 }
1341
1342 // Begin and end wave ids for the first and second stars
1343 int begin1 = stars_[is].beginId;
1344 int end1 = stars_[is].endId;
1345 int begin2 = stars_[is+1].beginId;
1346 int end2 = stars_[is+1].endId;
1347
1348 // Check that inverse is in next star and check for
1349 // conjugate coefficients
1350
1351 // Loop over waves in first star
1352 for (iw = begin1; iw < end1; ++iw) {
1353 iwp = waves_[iw].inverseId;
1354 if (waves_[iwp].starId != is + 1) {
1355 std::cout << "\n";
1356 std::cout << "Inverse not found for G in open star"
1357 << std::endl;
1358 std::cout << "First star id = " << is << std::endl;
1359 std::cout << "+G = " << waves_[iw].indicesMin
1360 << "coeff = " << waves_[iw].coeff
1361 << std::endl;
1362 std::cout << "Waves in star " << is
1363 << " (starInvert ==1):" << "\n";
1364 for (j = begin1; j < end1; ++j) {
1365 std::cout << waves_[j].indicesMin << " "
1366 << waves_[j].coeff << "\n";
1367 }
1368 std::cout << "Waves in star " << is+1
1369 << " (starInvert == -1):" << "\n";
1370 for (j=begin2; j < end2; ++j) {
1371 std::cout << waves_[j].indicesMin << " "
1372 << waves_[j].coeff << "\n";
1373 }
1374 return false;
1375 }
1376 if (!cancel) {
1377 cdel = std::conj(waves_[iwp].coeff);
1378 cdel -= waves_[iw].coeff;
1379 if (std::abs(cdel) > 1.0E-8) {
1380 std::cout << "\n";
1381 std::cout << "Error of coefficients in open stars:"
1382 << "\n";
1383 std::cout << "First star id = " << is << std::endl;
1384 std::cout << "+G = " << waves_[iw].indicesMin
1385 << " coeff = " << waves_[iw].coeff
1386 << "\n";
1387 std::cout << "-G = " << waves_[iwp].indicesMin
1388 << " coeff = " << waves_[iwp].coeff
1389 << "\n";
1390 std::cout << "Coefficients are not conjugates."
1391 << "\n";
1392 std::cout << "Waves in star " << is
1393 << " (starInvert ==1):" << "\n";
1394 for (j = begin1; j < end1; ++j) {
1395 std::cout << waves_[j].indicesMin << " "
1396 << waves_[j].coeff << "\n";
1397 }
1398 std::cout << "Waves in star " << is+1
1399 << " (starInvert == -1):" << "\n";
1400 for (j=begin2; j < end2; ++j) {
1401 std::cout << waves_[j].indicesMin << " "
1402 << waves_[j].coeff << "\n";
1403 }
1404 return false;
1405 }
1406 }
1407 }
1408
1409 // Finished processing a pair, increment star counter by 2
1410 is += 2;
1411
1412 } // end if (stars_[is].invertFlag == 0) ... else ...
1413
1414 } // end while (is < nStar_) loop over stars
1415
1416 // Loop over basis functions
1417 for (ib = 0; ib < nBasis_; ++ib) {
1418 is = starIds_[ib];
1419 if (stars_[is].cancel) {
1420 std::cout << "\n";
1421 std::cout << "Star referred to by starIds_ is cancelled\n";
1422 return false;
1423 }
1424 if (stars_[is].basisId != ib) {
1425 std::cout << "\n";
1426 std::cout << "Error: stars_[starIds_[ib]].basisId != ib\n";
1427 std::cout << "Basis function index ib = " << ib << "\n";
1428 std::cout << "is = starIds_[ib] = " << is << "\n";
1429 std::cout << "stars_[is].basisId = "
1430 << stars_[is].basisId << "\n";
1431 return false;
1432 }
1433 }
1434
1435 // The end of this function is reached iff all tests passed.
1436 return true;
1437 }
1438
1439 /*
1440 * Get the associated signal (notifies observers of basis initialization).
1441 */
1442 template <int D>
1444 {
1445 UTIL_CHECK(signalPtr_);
1446 return *signalPtr_;
1447 }
1448
1449}
1450}
1451#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<D>.
void begin()
Set iterator to the first point in the mesh.
bool atEnd() const
Is this the end (i.e., one past the last point)?
IntVec< D > position() const
Get current position in the grid, as integer vector.
Description of a regular grid of points in a periodic domain.
Definition Mesh.h:61
A list of wavevectors that are related by space-group symmetries.
Definition Basis.h:483
Wave const & wave(int id) const
Get a specific Wave, access by integer index.
Definition Basis.h:877
int nBasis() const
Total number of nonzero symmetry-adapted basis functions.
Definition Basis.tpp:946
int waveId(IntVec< D > vector) const
Get the integer index of a wave, as required by wave(int id).
Definition Basis.h:891
Basis()
Constructor.
Definition Basis.tpp:35
~Basis()
Destructor.
Definition Basis.tpp:56
void makeBasis(Mesh< D > const &mesh, UnitCell< D > const &unitCell, SpaceGroup< D > const &group)
Construct basis for a specific mesh and space group.
Definition Basis.tpp:78
Signal< void > & signal()
Get a Signal that is triggered by basis initialization.
Definition Basis.tpp:1443
void outputWaves(std::ostream &out, bool outputAll=false) const
Print a list of all waves to an output stream.
Definition Basis.tpp:951
int nWave() const
Total number of wavevectors.
Definition Basis.h:864
bool isValid() const
Returns true if this basis is valid, false otherwise.
Definition Basis.tpp:1013
void outputStars(std::ostream &out, bool outputAll=false) const
Print a list of all stars to an output stream.
Definition Basis.tpp:980
Crystallographic space group.
Definition SpaceGroup.h:32
void checkMeshDimensions(IntVec< D > const &dimensions) const
Check if input mesh dimensions are compatible with space group.
Base template for UnitCell<D> classes, D=1, 2 or 3.
Definition UnitCell.h:56
Vec< D, T > & negate(const Vec< D, T > &v)
Return negative of vector v.
Definition Vec.h:520
static const double Pi
Trigonometric constant Pi.
Definition Constants.h:35
Wrapper for a double precision number, for formatted ostream output.
Definition Dbl.h:40
An automatically growable array, analogous to a std::vector.
Definition GArray.h:34
int size() const
Return logical size of this array (i.e., current number of elements).
Definition GArray.h:450
void clear()
Reset to empty state.
Definition GArray.h:296
void append(Data const &data)
Append an element to the end of the sequence.
Definition GArray.h:303
Wrapper for an int, for formatted ostream output.
Definition Int.h:37
Notifier (or subject) in the Observer design pattern.
Definition Signal.h:39
#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
double imag(fftw_complex const &a)
Return the imaginary part of an fftw_complex number.
Definition cpu/complex.h:49
double real(fftw_complex const &a)
Return the real part of an fftw_complex number.
Definition cpu/complex.h:38
Periodic fields and crystallography.
Definition complex.cpp:11
PSCF package top-level namespace.
Comparator for BWave objects, based on BWave::indicesMin.
Definition BWave.h:76
Comparator for BWave objects, based on BWave::indicesStd.
Definition BWave.h:58
Wave struct designed for use within Basis construction.
Definition BWave.h:25