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