14#include <pscf/crystal/UnitCell.h>
15#include <pscf/crystal/SpaceGroup.h>
16#include <pscf/crystal/shiftToMinimum.h>
17#include <pscf/mesh/Mesh.h>
18#include <pscf/mesh/MeshIterator.h>
57 std::string groupName)
60 readGroup(groupName, group);
61 makeBasis(mesh, unitCell, group);
77 unitCellPtr_ = &unitCell;
81 waves_.allocate(nWave_);
82 waveIds_.allocate(nWave_);
91 bool valid = isValid();
96 isInitialized_ =
true;
110 IntVec<D> meshDimensions = mesh().dimensions();
111 std::vector< TWave<D> > twaves;
112 twaves.reserve(nWave_);
118 for (itr.begin(); !itr.atEnd(); ++itr) {
119 w.indicesDft = itr.position();
120 v = shiftToMinimum(w.indicesDft, meshDimensions, *unitCellPtr_);
122 w.sqNorm = unitCell().ksq(v);
127 TWaveNormComp<D> comp;
128 std::sort(twaves.begin(), twaves.end(), comp);
131 for (
int i = 0; i < nWave_; ++i) {
132 waves_[i].sqNorm = twaves[i].sqNorm;
133 waves_[i].indicesDft = twaves[i].indicesDft;
134 waves_[i].indicesBz = twaves[i].indicesBz;
144 void Basis<D>::makeStars(SpaceGroup<D>
const & group)
165 std::set< TWave<D>, TWaveDftComp<D> > list;
166 std::set< TWave<D>, TWaveDftComp<D> > star;
167 std::vector< TWave<D> > tempStar;
169 typename std::set< TWave<D>, TWaveDftComp<D> >::iterator rootItr;
170 typename std::set< TWave<D>, TWaveDftComp<D> >::iterator setItr;
174 Basis<D>::Star newStar;
175 std::complex<double> coeff;
180 const double epsilon = 1.0E-8;
181 IntVec<D> meshDimensions = mesh().dimensions();
338 Gsq_max = waves_[0].sqNorm;
339 for (i = 1; i <= nWave_; ++i) {
342 bool newList =
false;
345 listSize = listEnd - listBegin;
348 Gsq = waves_[i].sqNorm;
349 if (Gsq > Gsq_max + epsilon) {
352 listSize = listEnd - listBegin;
363 for (j = listBegin; j < listEnd; ++j) {
364 wave.indicesDft = waves_[j].indicesDft;
365 wave.indicesBz = waves_[j].indicesBz;
366 wave.sqNorm = waves_[j].sqNorm;
368 UTIL_CHECK( std::abs(wave.sqNorm-waves_[j].sqNorm)
383 rootItr = list.begin();
391 while (list.size() > 0) {
393 rootVecBz = rootItr->indicesBz;
394 Gsq = rootItr->sqNorm;
400 for (j = 0; j < group.size(); ++j) {
404 vec = rootVecBz*group[j];
407 UTIL_CHECK(std::abs(Gsq - unitCell().ksq(vec)) < epsilon);
411 wave.indicesBz = shiftToMinimum(vec, meshDimensions,
413 wave.indicesDft = vec;
414 mesh().shift(wave.indicesDft);
419 for (k = 0; k < D; ++k) {
420 wave.phase += rootVecBz[k]*(group[j].t(k));
422 while (wave.phase > 0.5) {
425 while (wave.phase <= -0.5) {
436 if (wave.indicesDft == rootItr->indicesDft) {
437 if (std::abs(wave.phase) > 1.0E-6) {
444 setItr = star.find(wave);
446 if (setItr == star.end()) {
458 phase_diff = setItr->phase - wave.phase;
459 while (phase_diff > 0.5) {
462 while (phase_diff <= -0.5) {
465 if (std::abs(phase_diff) > 1.0E-6) {
475 setItr = star.begin();
476 for ( ; setItr != star.end(); ++setItr) {
477 tempStar.push_back(*setItr);
481 TWaveBzComp<D> waveBzComp;
482 std::sort(tempStar.begin(), tempStar.end(), waveBzComp);
485 int tempStarSize = tempStar.size();
486 for (j = 0; j < tempStarSize; ++j) {
487 list.erase(tempStar[j]);
488 tempList.
append(tempStar[j]);
496 nBasisWave_ += star.size();
501 newStar.beginId = starBegin;
502 newStar.endId = newStar.beginId + star.size();
503 newStar.size = star.size();
504 newStar.cancel = cancel;
508 if (nextInvert == -1) {
513 newStar.invertFlag = -1;
514 rootItr = list.begin();
523 nVec.negate(rootVecBz);
526 (*meshPtr_).shift(nVec);
529 bool negationFound =
false;
530 setItr = star.begin();
531 for ( ; setItr != star.end(); ++setItr) {
532 if (nVec == setItr->indicesDft) {
533 negationFound =
true;
543 newStar.invertFlag = 0;
544 rootItr = list.begin();
552 newStar.invertFlag = 1;
559 setItr = list.begin();
560 for ( ; setItr != list.end(); ++setItr) {
561 if (nVec == setItr->indicesDft) {
562 negationFound =
true;
572 if (!negationFound) {
573 std::cout <<
"Negation not found for: " <<
"\n";
574 std::cout <<
" vec (ft):"
575 << rootItr->indicesDft <<
"\n";
576 std::cout <<
" vec (bz):"
577 << rootItr->indicesBz <<
"\n";
578 std::cout <<
"-vec (dft):" << nVec <<
"\n";
586 stars_.append(newStar);
588 starBegin = newStar.endId;
599 for (j = 0; j < tempList.
size(); ++j) {
601 waves_[k].indicesDft = tempList[j].indicesDft;
602 waves_[k].indicesBz = tempList[j].indicesBz;
603 waves_[k].sqNorm = tempList[j].sqNorm;
604 coeff = std::complex<double>(0.0, tempList[j].phase);
606 if (std::abs(imag(coeff)) < 1.0E-6) {
607 coeff = std::complex<double>(real(coeff), 0.0);
609 if (std::abs(real(coeff)) < 1.0E-6) {
610 coeff = std::complex<double>(0.0, imag(coeff));
612 waves_[k].coeff = coeff;
627 nStar_ = stars_.size();
645 std::complex<double> rootCoeff;
646 std::complex<double> partCoeff;
647 std::complex<double> d;
649 for (i = 0; i < nStar_; ++i) {
653 if (stars_[i].invertFlag == 0) {
658 rootId = stars_[i].beginId;
659 stars_[i].waveBz = waves_[rootId].indicesBz;
661 if (stars_[i].cancel) {
664 std::complex<double> czero(0.0, 0.0);
665 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
666 waves_[j].coeff = czero;
672 nVec.negate(waves_[rootId].indicesBz);
673 (*meshPtr_).shift(nVec);
676 bool negationFound =
false;
677 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
678 if (nVec == waves_[j].indicesDft) {
680 negationFound =
true;
690 rootCoeff = waves_[rootId].coeff;
691 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
692 waves_[j].coeff /= rootCoeff;
694 rootCoeff = waves_[rootId].coeff;
695 UTIL_CHECK(std::abs(real(rootCoeff) - 1.0) < 1.0E-9);
696 UTIL_CHECK(std::abs(imag(rootCoeff)) < 1.0E-9);
699 if (partId != rootId) {
701 partCoeff = waves_[partId].coeff;
702 UTIL_CHECK(std::abs(std::abs(partCoeff) - 1.0) < 1.0E-9);
703 if (std::abs(partCoeff - rootCoeff) > 1.0E-6) {
705 if (real(d) < -1.0E-4) {
708 if (std::abs(real(d)) <= 1.0E-4) {
713 for (j=stars_[i].beginId; j < stars_[i].endId; ++j){
714 waves_[j].coeff /= d;
724 if (stars_[i].invertFlag == 1) {
729 UTIL_CHECK(stars_[i].size == stars_[i+1].size);
730 UTIL_CHECK(stars_[i].cancel == stars_[i+1].cancel);
735 rootId = stars_[i].beginId;
736 stars_[i].waveBz = waves_[rootId].indicesBz;
739 nVec.negate(waves_[rootId].indicesBz);
740 (*meshPtr_).shift(nVec);
743 bool negationFound =
false;
744 for (j = stars_[i+1].beginId; j < stars_[i+1].endId; ++j) {
745 if (nVec == waves_[j].indicesDft) {
747 stars_[i+1].waveBz = waves_[j].indicesBz;
748 negationFound =
true;
756 if (stars_[i].cancel) {
758 std::complex<double> czero(0.0, 0.0);
759 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
760 waves_[j].coeff = czero;
762 for (j = stars_[i+1].beginId; j < stars_[i+1].endId; ++j) {
763 waves_[j].coeff = czero;
769 rootCoeff = waves_[rootId].coeff;
770 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
771 waves_[j].coeff /= rootCoeff;
775 partCoeff = waves_[partId].coeff;
776 for (j = stars_[i+1].beginId; j < stars_[i+1].endId; ++j) {
777 waves_[j].coeff /= partCoeff;
790 for (i = 0; i < nStar_; ++i) {
791 double snorm = 1.0/sqrt(
double(stars_[i].size));
792 for (j = stars_[i].beginId; j < stars_[i].endId; ++j) {
793 waves_[j].coeff *= snorm;
794 waves_[j].starId = i;
799 for (i = 0; i < nWave_; ++i) {
800 if (std::abs(real(waves_[i].coeff)) < 1.0E-8) {
802 = std::complex<double>(0.0, imag(waves_[i].coeff));
804 if (std::abs(imag(waves_[i].coeff)) < 1.0E-8) {
806 = std::complex<double>(real(waves_[i].coeff), 0.0);
811 for (i = 0; i < nWave_; ++i) {
812 vec = waves_[i].indicesDft;
815 for (j = 0; j < D; ++j) {
821 if ((vec[D-1] + 1) > (meshDimensions[D-1]/2 + 1)) {
822 waves_[i].implicit =
true;
824 waves_[i].implicit =
false;
828 waveIds_[mesh().rank(vec)] = i;
832 starIds_.allocate(nBasis_);
834 for (i = 0; i < nStar_; ++i) {
835 stars_[i].starId = i;
836 if (stars_[i].cancel) {
837 stars_[i].basisId = -1;
839 stars_[i].basisId = j;
858 out <<
"N_wave" << std::endl;
860 out <<
" " << nWave_ << std::endl;
862 out <<
" " << nBasisWave_ << std::endl;
866 for (i = 0; i < nWave_; ++i) {
867 starId = waves_[i].starId;
868 if (outputAll || (!stars_[starId].cancel)) {
871 for (j = 0; j < D; ++j) {
872 out <<
Int(waves_[i].indicesBz[j], 5);
874 out <<
Int(waves_[i].starId, 6);
875 out <<
" " <<
Dbl(waves_[i].coeff.real(), 15);
876 out <<
" " <<
Dbl(waves_[i].coeff.imag(), 15);
889 out <<
"N_star" << std::endl
890 <<
" " << nStar_ << std::endl;
892 out <<
"N_basis" << std::endl
893 <<
" " << nBasis_ << std::endl;
898 for (i = 0; i < nStar_; ++i) {
899 if (outputAll || (!stars_[i].cancel)) {
900 out <<
Int(stars_[i].basisId, 6);
902 out <<
Int(stars_[i].size, 5)
903 <<
Int(stars_[i].beginId, 8)
904 <<
Int(stars_[i].endId, 8)
905 <<
Int(stars_[i].invertFlag, 4);
907 out <<
Int(stars_[i].cancel, 4);
909 for (j = 0; j < D; ++j) {
910 out <<
Int(stars_[i].waveBz[j], 6);
922 int is, ib, iw, iwp, j;
925 if (nWave_ != mesh().size()) {
926 std::cout <<
"nWave != size of mesh" << std::endl;
935 if (wave(iw).indicesDft != v) {
936 std::cout <<
"Inconsistent waveId and Wave::indicesDft"
943 for (iw = 0; iw < nWave_; ++iw) {
946 v = waves_[iw].indicesBz;
947 Gsq = unitCell().ksq(v);
948 if (std::abs(Gsq - waves_[iw].sqNorm) > 1.0E-8) {
950 std::cout <<
"Incorrect sqNorm:" <<
"\n"
951 <<
"wave.indicesBz = " <<
"\n"
952 <<
"wave.sqNorm = " << waves_[iw].sqNorm <<
"\n"
953 <<
"|v|^{2} = " << Gsq <<
"\n";
959 if (v != waves_[iw].indicesDft) {
961 std::cout <<
"shift(indicesBz) != indicesDft" << std::endl;
966 is = waves_[iw].starId;
967 if (iw < stars_[is].beginId) {
969 std::cout <<
"Wave::starId < Star::beginId" << std::endl;
972 if (iw >= stars_[is].endId) {
974 std::cout <<
" Wave::starId >= Star::endId" << std::endl;
981 for (is = 0; is < nStar_; ++is) {
984 nWave += stars_[is].size;
985 if (stars_[is].size != stars_[is].endId - stars_[is].beginId) {
987 std::cout <<
"Inconsistent Star::size:" << std::endl;
988 std::cout <<
"Star id " << is << std::endl;
989 std::cout <<
"star size " << stars_[is].size << std::endl;
990 std::cout <<
"Star begin " << stars_[is].beginId << std::endl;
991 std::cout <<
"Star end " << stars_[is].endId << std::endl;
995 if (stars_[is].beginId != stars_[is-1].endId) {
997 std::cout <<
"Star ranges not consecutive:" << std::endl;
998 std::cout <<
"Star id " << is << std::endl;
999 std::cout <<
"stars_[" << is <<
"]" <<
".beginId = "
1000 << stars_[is].beginId << std::endl;
1001 std::cout <<
"stars_[" << is-1 <<
"]" <<
".endId = "
1002 << stars_[is-1].endId << std::endl;
1008 for (iw = stars_[is].beginId; iw < stars_[is].endId; ++iw) {
1009 if (waves_[iw].starId != is) {
1011 std::cout <<
"Inconsistent Wave::starId :" << std::endl;
1012 std::cout <<
"star id " << is << std::endl;
1013 std::cout <<
"star beginId " << stars_[is].beginId <<
"\n";
1014 std::cout <<
"star endId " << stars_[is].endId <<
"\n";
1015 std::cout <<
"wave id " << iw <<
"\n";
1016 std::cout <<
"wave starId " << waves_[iw].starId <<
"\n";
1022 if (stars_[is].starId != is) {
1024 std::cout <<
"stars_[is].starId != is for "
1025 <<
"is = " << is <<
"\n";
1030 ib = stars_[is].basisId;
1031 if (stars_[is].cancel) {
1034 std::cout <<
"basisId != -1 for cancelled star\n";
1035 std::cout <<
"star id = " << is <<
"\n";
1039 if (starIds_[ib] != is) {
1041 std::cout <<
"starIds_[stars_[is].basisId] != is for: \n";
1042 std::cout <<
"is = " << is <<
"\n";
1043 std::cout <<
"ib = stars_[is].basisId = " << ib <<
"\n";
1044 std::cout <<
"starIds_[ib] = " << starIds_[ib]
1051 for (iw = stars_[is].beginId + 1; iw < stars_[is].endId; ++iw) {
1052 if (waves_[iw].indicesBz > waves_[iw-1].indicesBz) {
1054 std::cout <<
"Failure of ordering by indicesB within star"
1058 if (waves_[iw].indicesBz == waves_[iw-1].indicesBz) {
1060 std::cout <<
"Equal values of indicesBz within star"
1069 if (stars_[nStar_-1].endId != mesh().size()) {
1071 std::cout <<
"Star endId of last star != mesh size" << std::endl;
1074 if (nWave != mesh().size()) {
1076 std::cout <<
"Sum of star sizes != mesh size" << std::endl;
1082 std::complex<double> cdel;
1083 bool negationFound, cancel;
1085 while (is < nStar_) {
1086 cancel = stars_[is].cancel;
1088 if (stars_[is].invertFlag == 0) {
1091 int begin = stars_[is].beginId;
1092 int end = stars_[is].endId;
1093 for (iw = begin; iw < end; ++iw) {
1094 v.
negate(waves_[iw].indicesBz);
1096 negationFound =
false;
1097 for (iwp = begin; iw < end; ++iwp) {
1098 if (waves_[iwp].indicesDft == v) {
1099 negationFound =
true;
1101 cdel = conj(waves_[iwp].coeff);
1102 cdel -= waves_[iw].coeff;
1107 if (!negationFound) {
1109 std::cout <<
"Negation not found in closed star"
1111 std::cout <<
"G = " << waves_[iw].indicesBz
1112 <<
"coeff = " << waves_[iw].coeff
1114 std::cout <<
"All waves in star " << is <<
"\n";
1115 for (j=begin; j < end; ++j) {
1116 std::cout << waves_[j].indicesBz <<
" "
1117 << waves_[j].coeff <<
"\n";
1121 if (!cancel && std::abs(cdel) > 1.0E-8) {
1123 std::cout <<
"Function for closed star is not real:"
1125 std::cout <<
"+G = " << waves_[iw].indicesBz
1126 <<
" coeff = " << waves_[iw].coeff
1128 std::cout <<
"-G = " << waves_[iwp].indicesBz
1129 <<
" coeff = " << waves_[iwp].coeff
1131 std::cout <<
"Coefficients are not conjugates." <<
"\n";
1132 std::cout <<
"All waves in star " << is <<
"\n";
1133 for (j=begin; j < end; ++j) {
1134 std::cout << waves_[j].indicesBz <<
" "
1135 << waves_[j].coeff <<
"\n";
1139 if (cancel && std::abs(waves_[iw].coeff) > 1.0E-8) {
1141 std::cout <<
"Nonzero coefficient in a cancelled star"
1143 std::cout <<
"G = " << waves_[iw].indicesBz
1144 <<
" coeff = " << waves_[iw].coeff
1157 if (stars_[is].invertFlag != 1) {
1159 std::cout <<
"Expected invertFlag == 1" << std::endl;
1162 if (stars_[is+1].invertFlag != -1) {
1164 std::cout <<
"Expected invertFlag == -1" << std::endl;
1167 if (stars_[is+1].size != stars_[is].size) {
1169 std::cout <<
"Partner stars of different size" << std::endl;
1172 if (stars_[is+1].cancel != stars_[is].cancel) {
1174 std::cout <<
"Partners stars with different cancel flags"
1180 int begin1 = stars_[is].beginId;
1181 int end1 = stars_[is].endId;
1182 int begin2 = stars_[is+1].beginId;
1183 int end2 = stars_[is+1].endId;
1187 for (iw = begin1; iw < end1; ++iw) {
1188 v.
negate(waves_[iw].indicesBz);
1190 negationFound =
false;
1192 for (iwp = begin2; iw < end2; ++iwp) {
1193 if (waves_[iwp].indicesDft == v) {
1194 negationFound =
true;
1196 cdel = conj(waves_[iwp].coeff);
1197 cdel -= waves_[iw].coeff;
1202 if (!negationFound) {
1204 std::cout <<
"Negation not found for G in open star"
1206 std::cout <<
"First star id = " << is << std::endl;
1207 std::cout <<
"+G = " << waves_[iw].indicesBz
1208 <<
"coeff = " << waves_[iw].coeff
1210 std::cout <<
"Waves in star " << is
1211 <<
" (starInvert ==1):" <<
"\n";
1212 for (j = begin1; j < end1; ++j) {
1213 std::cout << waves_[j].indicesBz <<
" "
1214 << waves_[j].coeff <<
"\n";
1216 std::cout <<
"Waves in star " << is+1
1217 <<
" (starInvert == -1):" <<
"\n";
1218 for (j=begin2; j < end2; ++j) {
1219 std::cout << waves_[j].indicesBz <<
" "
1220 << waves_[j].coeff <<
"\n";
1224 if (!cancel && std::abs(cdel) > 1.0E-8) {
1226 std::cout <<
"Error of coefficients in open stars:"
1228 std::cout <<
"First star id = " << is << std::endl;
1229 std::cout <<
"+G = " << waves_[iw].indicesBz
1230 <<
" coeff = " << waves_[iw].coeff
1232 std::cout <<
"-G = " << waves_[iwp].indicesBz
1233 <<
" coeff = " << waves_[iwp].coeff
1235 std::cout <<
"Coefficients are not conjugates."
1237 std::cout <<
"Waves in star " << is
1238 <<
" (starInvert ==1):" <<
"\n";
1239 for (j = begin1; j < end1; ++j) {
1240 std::cout << waves_[j].indicesBz <<
" "
1241 << waves_[j].coeff <<
"\n";
1243 std::cout <<
"Waves in star " << is+1
1244 <<
" (starInvert == -1):" <<
"\n";
1245 for (j=begin2; j < end2; ++j) {
1246 std::cout << waves_[j].indicesBz <<
" "
1247 << waves_[j].coeff <<
"\n";
1261 for (ib = 0; ib < nBasis_; ++ib) {
1263 if (stars_[is].cancel) {
1265 std::cout <<
"Star referred to by starIds_ is cancelled\n";
1268 if (stars_[is].basisId != ib) {
1270 std::cout <<
"Eror: stars_[starIds_[ib]].basisId != ib\n";
1271 std::cout <<
"Basis function index ib = " << ib <<
"\n";
1272 std::cout <<
"is = starIds_[ib] = " << is <<
"\n";
1273 std::cout <<
"stars_[is].basisId = "
1274 << stars_[is].basisId <<
"\n";
Symmetry-adapted Fourier basis for pseudo-spectral scft.
int nBasis() const
Total number of nonzero symmetry-adapted basis functions.
bool isValid() const
Returns true if valid, false otherwise.
void outputStars(std::ostream &out, bool outputAll=false) const
Print a list of all stars to an output stream.
void makeBasis(Mesh< D > const &mesh, UnitCell< D > const &unitCell, SpaceGroup< D > const &group)
Construct basis for a specific mesh and space group.
Basis()
Default constructor.
void outputWaves(std::ostream &out, bool outputAll=false) const
Print a list of all waves to an output stream.
An IntVec<D, T> is a D-component vector of elements of integer type T.
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.
IntVec< D > dimensions() const
Get an IntVec<D> of the grid dimensions.
int size() const
Get total number of grid points.
Crystallographic space group.
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.
Vec< D, T > & negate(const Vec< D, T > &v)
Return negative of vector v.
static const double Pi
Trigonometric constant Pi.
Wrapper for a double precision number, for formatted ostream output.
An automatically growable array, analogous to a std::vector.
int size() const
Return logical size of this array (i.e., current number of elements).
void clear()
Reset to empty state.
void append(Data const &data)
Append an element to the end of the sequence.
Wrapper for an int, for formatted ostream output.
#define UTIL_CHECK(condition)
Assertion macro suitable for serial or parallel production code.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
C++ namespace for polymer self-consistent field theory (PSCF).
Simple wave struct for use within Basis construction.