1 ////////////////////////////////////////////////////////////////////////////////////// 2 // This file is distributed under the University of Illinois/NCSA Open Source License. 3 // See LICENSE file in top directory for details. 4 // 5 // Copyright (c) 2016 Jeongnim Kim and QMCPACK developers. 6 // 7 // File developed by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign 8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign 9 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory 10 // 11 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign 12 ////////////////////////////////////////////////////////////////////////////////////// 13 14 15 /** @file PWBasis.h 16 * @brief Declaration of Plane-wave basis set 17 */ 18 #ifndef QMCPLUSPLUS_PLANEWAVEBASIS_BLAS_H 19 #define QMCPLUSPLUS_PLANEWAVEBASIS_BLAS_H 20 21 #include "Configuration.h" 22 #include "Particle/ParticleSet.h" 23 #include "Numerics/HDFSTLAttrib.h" 24 #include "Numerics/HDFNumericAttrib.h" 25 #include "Message/Communicate.h" 26 #include "CPU/e2iphi.h" 27 28 /** If defined, use recursive method to build the basis set for each position 29 * 30 * performance improvement is questionable: load vs sin/cos 31 */ 32 //#define PWBASIS_USE_RECURSIVE 33 34 namespace qmcplusplus 35 { 36 /** Plane-wave basis set 37 * 38 * Rewrite of PlaneWaveBasis to utilize blas II or III 39 * Support more general input tags 40 */ 41 class PWBasis : public QMCTraits 42 { 43 public: 44 typedef ParticleSet::ParticleLayout_t ParticleLayout_t; 45 typedef TinyVector<IndexType, 3> GIndex_t; 46 47 private: 48 ///max of maxg[i] 49 int maxmaxg; 50 //Need to store the maximum translation in each dimension to use recursive PW generation. 51 GIndex_t maxg; 52 //The PlaneWave data - keep all of these strictly private to prevent inconsistencies. 53 RealType ecut; 54 ///twist angle in reduced 55 PosType twist; 56 ///twist angle in cartesian 57 PosType twist_cart; //Twist angle in reduced and Cartesian. 58 59 ///gvecs in reduced coordiates 60 std::vector<GIndex_t> gvecs; 61 ///Reduced coordinates with offset gvecs_shifted[][idim]=gvecs[][idim]+maxg[idim] 62 std::vector<GIndex_t> gvecs_shifted; 63 64 std::vector<RealType> minusModKplusG2; 65 std::vector<PosType> kplusgvecs_cart; //Cartesian. 66 67 Matrix<ComplexType> C; 68 //Real wavefunctions here. Now the basis states are cos(Gr) or sin(Gr), not exp(iGr) 69 //We need a way of switching between them for G -> -G, otherwise the 70 //determinant will have multiple rows that are equal (to within a constant factor) 71 //of others, giving a zero determinant. For this, we build a vector (negative) which 72 //stores whether a vector is "+" or "-" (with some criterion, to be defined). We 73 //the switch from cos() to sin() based on the value of this input. 74 std::vector<int> negative; 75 76 public: 77 //enumeration for the value, laplacian, gradients and size 78 enum 79 { 80 PW_VALUE, 81 PW_LAP, 82 PW_GRADX, 83 PW_GRADY, 84 PW_GRADZ, 85 PW_MAXINDEX 86 }; 87 88 Matrix<ComplexType> Z; 89 90 Vector<ComplexType> Zv; 91 /* inputmap is used for a memory efficient way of 92 * 93 * importing the basis-set and coefficients when the desired energy cutoff may be 94 * lower than that represented by all data in the wavefunction input file. 95 * The steps taken are: 96 * - Read all basis data. 97 * - Create map. inputmap[i] = j; j is correct PW index, i is input coef index. 98 * For basis elements outside cutoff, inputmap[i] = gvecs.size(); 99 * - Coefficients are in same order as PWs in inputfile => simply file into 100 * storage matrix using the map as the input. All excess coefficients are 101 * put into [gvecs.size()] and not used. i.e. coefs need to be allocated 1 higher. 102 * Such an approach is not needed for Gamma-point only calculations because the 103 * basis is spherically ordered. However, when a twist-angle is used, the "sphere" 104 * of allowed planewaves is shifted. 105 */ 106 107 Vector<RealType> phi; 108 109 std::vector<int> inputmap; 110 111 ///total number of basis functions 112 int NumPlaneWaves; 113 114 ///local copy of Lattice 115 ParticleLayout_t Lattice; 116 117 ///default constructor PWBasis()118 PWBasis() : maxmaxg(0), NumPlaneWaves(0) {} 119 120 ///constructor PWBasis(const PosType & twistangle)121 PWBasis(const PosType& twistangle) : maxmaxg(0), twist(twistangle), NumPlaneWaves(0) {} 122 ~PWBasis()123 ~PWBasis() {} 124 125 ///basis size getBasisSetSize()126 inline IndexType getBasisSetSize() const { return NumPlaneWaves; } 127 128 ///set the twist angle 129 void setTwistAngle(const PosType& tang); 130 131 ///reset 132 void reset(); 133 134 /** Read basisset from hdf5 file. Apply ecut. 135 * @param h5basisgroup h5 node where basis is located 136 * @param ecutoff cutoff energy 137 * @param lat CrystalLattice 138 * @param resizeContainer if true, resize internal storage. 139 * @return the number of plane waves 140 */ 141 int readbasis(hid_t h5basisgroup, 142 RealType ecutoff, 143 ParticleLayout_t& lat, 144 const std::string& pwname = "planewaves", 145 const std::string& pwmultname = "multipliers", 146 bool resizeContainer = true); 147 148 /** Remove basis elements if kinetic energy > ecut. 149 * 150 * Keep and indexmap so we know how to match coefficients on read. 151 */ 152 void trimforecut(); 153 154 #if defined(PWBASIS_USE_RECURSIVE) 155 /** Fill the recursion coefficients matrix. 156 * 157 * @todo Generalize to non-orthorohmbic cells 158 */ BuildRecursionCoefs(const PosType & pos)159 inline void BuildRecursionCoefs(const PosType& pos) 160 { 161 PosType tau_red(Lattice.toUnit(pos)); 162 // RealType phi=TWOPI*tau_red[0]; 163 // RealType nphi=maxg0*phi; 164 // ComplexType ct0(std::cos(phi),std::sin(phi)); 165 // ComplexType t(std::cos(nphi),-std::sin(nphi)); 166 // C0[0]=t; 167 // for(int n=1; n<=2*maxg0; n++) C0[n] = (t *= ct0); 168 // 169 // phi=TWOPI*tau_red[1]; 170 // nphi=maxg1*phi; 171 // ct0=ComplexType(std::cos(phi),std::sin(phi)); 172 // t=ComplexType(std::cos(nphi),-std::sin(nphi)); 173 // C1[0]=t; 174 // for(int n=1; n<=2*maxg1; n++) C1[n] = (t *= ct0); 175 // 176 // phi=TWOPI*tau_red[2]; 177 // nphi=maxg2*phi; 178 // ct0=ComplexType(std::cos(phi),std::sin(phi)); 179 // t=ComplexType(std::cos(nphi),-std::sin(nphi)); 180 // C2[0]=t; 181 // for(int n=1; n<=2*maxg2; n++) C2[n] = (t *= ct0); 182 #pragma ivdep 183 for (int idim = 0; idim < 3; idim++) 184 { 185 int ng = maxg[idim]; 186 RealType phi = TWOPI * tau_red[idim]; 187 RealType nphi = ng * phi; 188 ComplexType Ctemp(std::cos(phi), std::sin(phi)); 189 ComplexType t(std::cos(nphi), -std::sin(nphi)); 190 ComplexType* restrict cp_ptr = C[idim]; 191 *cp_ptr++ = t; 192 for (int n = 1; n <= 2 * ng; n++) 193 { 194 *cp_ptr++ = (t *= Ctemp); 195 } 196 } 197 //Base version 198 //#pragma ivdep 199 // for(int idim=0; idim<3; idim++){ 200 // RealType phi=TWOPI*tau_red[idim]; 201 // ComplexType Ctemp(std::cos(phi),std::sin(phi)); 202 // int ng=maxg[idim]; 203 // ComplexType* restrict cp_ptr=C[idim]+ng; 204 // ComplexType* restrict cn_ptr=C[idim]+ng-1; 205 // *cp_ptr=1.0; 206 // for(int n=1; n<=ng; n++,cn_ptr--){ 207 // ComplexType t(Ctemp*(*cp_ptr++)); 208 // *cp_ptr = t; 209 // *cn_ptr = conj(t); 210 // } 211 // } 212 //Not valid for general supercell 213 // // Cartesian of twist for 1,1,1 (reduced coordinates) 214 // PosType G111(1.0,1.0,1.0); 215 // G111 = Lattice.k_cart(G111); 216 // 217 // //Precompute a small number of complex factors (PWs along b1,b2,b3 lines) 218 // //using a fast recursion algorithm 219 //#pragma ivdep 220 // for(int idim=0; idim<3; idim++){ 221 // //start the recursion with the 111 vector. 222 // RealType phi = pos[idim] * G111[idim]; 223 // register ComplexType Ctemp(std::cos(phi), std::sin(phi)); 224 // int ng=maxg[idim]; 225 // ComplexType* restrict cp_ptr=C[idim]+ng; 226 // ComplexType* restrict cn_ptr=C[idim]+ng-1; 227 // *cp_ptr=1.0; 228 // for(int n=1; n<=ng; n++,cn_ptr--){ 229 // ComplexType t(Ctemp*(*cp_ptr++)); 230 // *cp_ptr = t; 231 // *cn_ptr = conj(t); 232 // } 233 // } 234 } 235 evaluate(const PosType & pos)236 inline void evaluate(const PosType& pos) 237 { 238 BuildRecursionCoefs(pos); 239 RealType twistdotr = dot(twist_cart, pos); 240 ComplexType pw0(std::cos(twistdotr), std::sin(twistdotr)); 241 //Evaluate the planewaves for particle iat. 242 for (int ig = 0; ig < NumPlaneWaves; ig++) 243 { 244 //PW is initialized as exp(i*twist.r) so that the final basis evaluations are for (twist+G).r 245 ComplexType pw(pw0); //std::cos(twistdotr),std::sin(twistdotr)); 246 for (int idim = 0; idim < 3; idim++) 247 pw *= C(idim, gvecs_shifted[ig][idim]); 248 //pw *= C0[gvecs_shifted[ig][0]]; 249 //pw *= C1[gvecs_shifted[ig][1]]; 250 //pw *= C2[gvecs_shifted[ig][2]]; 251 Zv[ig] = pw; 252 } 253 } 254 /** Evaluate all planewaves and derivatives for the iat-th particle 255 * 256 * The basis functions are evaluated for particles iat: first <= iat < last 257 * Evaluate the plane-waves at current particle coordinates using a fast 258 * recursion algorithm. Order of Y,dY and d2Y is kept correct. 259 * These can be "dotted" with coefficients later to complete orbital evaluations. 260 */ evaluateAll(const ParticleSet & P,int iat)261 inline void evaluateAll(const ParticleSet& P, int iat) 262 { 263 const PosType& r(P.activeR(iat)); 264 BuildRecursionCoefs(r); 265 RealType twistdotr = dot(twist_cart, r); 266 ComplexType pw0(std::cos(twistdotr), std::sin(twistdotr)); 267 //Evaluate the planewaves and derivatives. 268 ComplexType* restrict zptr = Z.data(); 269 for (int ig = 0; ig < NumPlaneWaves; ig++, zptr += 5) 270 { 271 //PW is initialized as exp(i*twist.r) so that the final basis evaluations 272 //are for (twist+G).r 273 ComplexType pw(pw0); 274 // THE INDEX ORDER OF C DOESN'T LOOK TOO GOOD: this could be fixed 275 for (int idim = 0; idim < 3; idim++) 276 pw *= C(idim, gvecs_shifted[ig][idim]); 277 //pw *= C0[gvecs_shifted[ig][0]]; 278 //pw *= C1[gvecs_shifted[ig][1]]; 279 //pw *= C2[gvecs_shifted[ig][2]]; 280 zptr[0] = pw; 281 zptr[1] = minusModKplusG2[ig] * pw; 282 zptr[2] = kplusgvecs_cart[ig][0] * ComplexType(-pw.imag(), pw.real()); 283 zptr[3] = kplusgvecs_cart[ig][1] * ComplexType(-pw.imag(), pw.real()); 284 zptr[4] = kplusgvecs_cart[ig][2] * ComplexType(-pw.imag(), pw.real()); 285 } 286 } 287 #else evaluate(const PosType & pos)288 inline void evaluate(const PosType& pos) 289 { 290 //Evaluate the planewaves for particle iat. 291 for (int ig = 0; ig < NumPlaneWaves; ig++) 292 phi[ig] = dot(kplusgvecs_cart[ig], pos); 293 eval_e2iphi(NumPlaneWaves, phi.data(), Zv.data()); 294 } evaluateAll(const ParticleSet & P,int iat)295 inline void evaluateAll(const ParticleSet& P, int iat) 296 { 297 const PosType& r(P.activeR(iat)); 298 evaluate(r); 299 ComplexType* restrict zptr = Z.data(); 300 for (int ig = 0; ig < NumPlaneWaves; ig++, zptr += 5) 301 { 302 //PW is initialized as exp(i*twist.r) so that the final basis evaluations 303 //are for (twist+G).r 304 ComplexType& pw = Zv[ig]; 305 zptr[0] = pw; 306 zptr[1] = minusModKplusG2[ig] * pw; 307 zptr[2] = kplusgvecs_cart[ig][0] * ComplexType(-pw.imag(), pw.real()); 308 zptr[3] = kplusgvecs_cart[ig][1] * ComplexType(-pw.imag(), pw.real()); 309 zptr[4] = kplusgvecs_cart[ig][2] * ComplexType(-pw.imag(), pw.real()); 310 } 311 } 312 #endif 313 // /** Fill the recursion coefficients matrix. 314 // * 315 // * @todo Generalize to non-orthorohmbic cells 316 // */ 317 // void BuildRecursionCoefsByAdd(const PosType& pos) 318 // { 319 // // Cartesian of twist for 1,1,1 (reduced coordinates) 320 // PosType G111(1.0,1.0,1.0); 321 // G111 = Lattice.k_cart(G111); 322 // //PosType redP=P.Lattice.toUnit(P.R[iat]); 323 // //Precompute a small number of complex factors (PWs along b1,b2,b3 lines) 324 // for(int idim=0; idim<3; idim++){ 325 // //start the recursion with the 111 vector. 326 // RealType phi = pos[idim] * G111[idim]; 327 // int ng(maxg[idim]); 328 // RealType* restrict cp_ptr=logC[idim]+ng; 329 // RealType* restrict cn_ptr=logC[idim]+ng-1; 330 // *cp_ptr=0.0; 331 // //add INTEL vectorization 332 // for(int n=1; n<=ng; n++,cn_ptr--){ 333 // RealType t(phi+*cp_ptr++); 334 // *cp_ptr = t; 335 // *cn_ptr = -t; 336 // } 337 // } 338 // } 339 }; 340 } // namespace qmcplusplus 341 #endif 342