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:
8 //
9 // File created by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 /** @file SoaLocalizedBasisSet.h
14  * @brief A derived class from BasisSetBase
15  *
16  * This is intended as a replacement for MolecularWaveFunctionComponent and
17  * any other localized basis set.
18  */
19 #ifndef QMCPLUSPLUS_SOA_LOCALIZEDBASISSET_H
20 #define QMCPLUSPLUS_SOA_LOCALIZEDBASISSET_H
21 
22 #include "QMCWaveFunctions/BasisSetBase.h"
23 #include "Particle/DistanceTableData.h"
24 
25 namespace qmcplusplus
26 {
27 /** A localized basis set derived from SoaBasisSetBase<ORBT>
28  *
29  * This class performs the evaluation of the basis functions and their
30  * derivatives for each of the N-particles in a configuration.
31  * The template parameter COT denotes Centered-Orbital-Type which provides
32  * a set of localized orbitals associated with a center.
33  * The template parameter ORBT denotes the orbital value return type
34  */
35 template<class COT, typename ORBT>
36 struct SoaLocalizedBasisSet : public SoaBasisSetBase<ORBT>
37 {
38   typedef typename COT::RealType RealType;
39   typedef SoaBasisSetBase<ORBT> BaseType;
40   typedef typename BaseType::vgl_type vgl_type;
41   typedef typename BaseType::vgh_type vgh_type;
42   typedef typename BaseType::vghgh_type vghgh_type;
43   typedef typename ParticleSet::PosType PosType;
44 
45   using BaseType::BasisSetSize;
46 
47   ///number of centers, e.g., ions
48   size_t NumCenters;
49   ///number of quantum particles
50   size_t NumTargets;
51   ///ion particle set
52   const ParticleSet& ions_;
53   ///number of quantum particles
54   const int myTableIndex;
55   ///Global Coordinate of Supertwist read from HDF5
56   PosType SuperTwist;
57 
58 
59   /** container to store the offsets of the basis functions
60    *
61    * the number of basis states for center J is BasisOffset[J+1]-Basis[J]
62    */
63   aligned_vector<size_t> BasisOffset;
64 
65   /** container of the unique pointers to the Atomic Orbitals
66    *
67    * size of LOBasisSet = number  of unique centers
68    */
69   aligned_vector<COT*> LOBasisSet;
70 
71   /** constructor
72    * @param ions ionic system
73    * @param els electronic system
74    */
SoaLocalizedBasisSetSoaLocalizedBasisSet75   SoaLocalizedBasisSet(ParticleSet& ions, ParticleSet& els)
76       : ions_(ions), myTableIndex(els.addTable(ions, true)), SuperTwist(0.0)
77   {
78     NumCenters = ions.getTotalNum();
79     NumTargets = els.getTotalNum();
80     LOBasisSet.resize(ions.getSpeciesSet().getTotalNum(), 0);
81     BasisOffset.resize(NumCenters + 1);
82     BasisSetSize = 0;
83   }
84 
85   /** copy constructor */
86   SoaLocalizedBasisSet(const SoaLocalizedBasisSet& a) = default;
87 
88   /** makeClone */
89   //SoaLocalizedBasisSet<COT>* makeClone() const
makeCloneSoaLocalizedBasisSet90   BaseType* makeClone() const
91   {
92     SoaLocalizedBasisSet<COT, ORBT>* myclone = new SoaLocalizedBasisSet<COT, ORBT>(*this);
93     for (int i = 0; i < LOBasisSet.size(); ++i)
94       myclone->LOBasisSet[i] = LOBasisSet[i]->makeClone();
95     return myclone;
96   }
97   /** set Number of periodic Images to evaluate the orbitals.
98       Set to 0 for non-PBC, and set manually in the input.
99       Passes the pre-computed phase factor for evaluation of complex wavefunction. If WF is real Phase_factor is real and equals 1 if gamma or -1 if non-Gamma.
100   */
setPBCParamsSoaLocalizedBasisSet101   void setPBCParams(const TinyVector<int, 3>& PBCImages,
102                     const TinyVector<double, 3> Sup_Twist,
103                     const std::vector<QMCTraits::ValueType>& phase_factor)
104   {
105     for (int i = 0; i < LOBasisSet.size(); ++i)
106       LOBasisSet[i]->setPBCParams(PBCImages, Sup_Twist, phase_factor);
107 
108     SuperTwist = Sup_Twist;
109   }
110   /** set BasisSetSize and allocate mVGL container
111    */
setBasisSetSizeSoaLocalizedBasisSet112   void setBasisSetSize(int nbs)
113   {
114     const auto& IonID(ions_.GroupID);
115     if (BasisSetSize > 0 && nbs == BasisSetSize)
116       return;
117 
118     //evaluate the total basis dimension and offset for each center
119     BasisOffset[0] = 0;
120     for (int c = 0; c < NumCenters; c++)
121     {
122       BasisOffset[c + 1] = BasisOffset[c] + LOBasisSet[IonID[c]]->getBasisSetSize();
123     }
124     BasisSetSize = BasisOffset[NumCenters];
125   }
126 
127   /**  Determine which orbitals are S-type.  Used by cusp correction.
128     */
queryOrbitalsForSTypeSoaLocalizedBasisSet129   void queryOrbitalsForSType(const std::vector<bool>& corrCenter, std::vector<bool>& is_s_orbital) const
130   {
131     const auto& IonID(ions_.GroupID);
132     int idx = 0;
133     for (int c = 0; c < NumCenters; c++)
134     {
135       int bss = LOBasisSet[IonID[c]]->BasisSetSize;
136       std::vector<bool> local_is_s_orbital(bss);
137       LOBasisSet[IonID[c]]->queryOrbitalsForSType(local_is_s_orbital);
138       for (int k = 0; k < bss; k++)
139       {
140         if (corrCenter[c])
141         {
142           is_s_orbital[idx++] = local_is_s_orbital[k];
143         }
144         else
145         {
146           is_s_orbital[idx++] = false;
147         }
148       }
149     }
150   }
151 
152   /** compute VGL
153    * @param P quantum particleset
154    * @param iat active particle
155    * @param vgl Matrix(5,BasisSetSize)
156    * @param trialMove if true, use getTempDists()/getTempDispls()
157    */
evaluateVGLSoaLocalizedBasisSet158   inline void evaluateVGL(const ParticleSet& P, int iat, vgl_type& vgl)
159   {
160     const auto& IonID(ions_.GroupID);
161     const auto& coordR  = P.activeR(iat);
162     const auto& d_table = P.getDistTable(myTableIndex);
163     const auto& dist    = (P.activePtcl == iat) ? d_table.getTempDists() : d_table.getDistRow(iat);
164     const auto& displ   = (P.activePtcl == iat) ? d_table.getTempDispls() : d_table.getDisplRow(iat);
165 
166     PosType Tv;
167     for (int c = 0; c < NumCenters; c++)
168     {
169       Tv[0] = (ions_.R[c][0] - coordR[0]) - displ[c][0];
170       Tv[1] = (ions_.R[c][1] - coordR[1]) - displ[c][1];
171       Tv[2] = (ions_.R[c][2] - coordR[2]) - displ[c][2];
172       LOBasisSet[IonID[c]]->evaluateVGL(P.Lattice, dist[c], displ[c], BasisOffset[c], vgl, Tv);
173     }
174   }
175 
176 
177   /** compute VGH
178    * @param P quantum particleset
179    * @param iat active particle
180    * @param vgl Matrix(10,BasisSetSize)
181    * @param trialMove if true, use getTempDists()/getTempDispls()
182    */
evaluateVGHSoaLocalizedBasisSet183   inline void evaluateVGH(const ParticleSet& P, int iat, vgh_type& vgh)
184   {
185     const auto& IonID(ions_.GroupID);
186     const auto& d_table = P.getDistTable(myTableIndex);
187     const auto& dist    = (P.activePtcl == iat) ? d_table.getTempDists() : d_table.getDistRow(iat);
188     const auto& displ   = (P.activePtcl == iat) ? d_table.getTempDispls() : d_table.getDisplRow(iat);
189     for (int c = 0; c < NumCenters; c++)
190     {
191       LOBasisSet[IonID[c]]->evaluateVGH(P.Lattice, dist[c], displ[c], BasisOffset[c], vgh);
192     }
193   }
194 
195   /** compute VGHGH
196    * @param P quantum particleset
197    * @param iat active particle
198    * @param vghgh Matrix(20,BasisSetSize)
199    * @param trialMove if true, use getTempDists()/getTempDispls()
200    */
evaluateVGHGHSoaLocalizedBasisSet201   inline void evaluateVGHGH(const ParticleSet& P, int iat, vghgh_type& vghgh)
202   {
203     // APP_ABORT("SoaLocalizedBasisSet::evaluateVGH() not implemented\n");
204 
205     const auto& IonID(ions_.GroupID);
206     const auto& d_table = P.getDistTable(myTableIndex);
207     const auto& dist    = (P.activePtcl == iat) ? d_table.getTempDists() : d_table.getDistRow(iat);
208     const auto& displ   = (P.activePtcl == iat) ? d_table.getTempDispls() : d_table.getDisplRow(iat);
209     for (int c = 0; c < NumCenters; c++)
210     {
211       LOBasisSet[IonID[c]]->evaluateVGHGH(P.Lattice, dist[c], displ[c], BasisOffset[c], vghgh);
212     }
213   }
214 
215   /** compute values for the iat-paricle move
216    *
217    * Always uses getTempDists() and getTempDispls()
218    * Tv is a translation vector; In PBC, in order to reduce the number
219    * of images that need to be summed over when generating the AO the
220    * nearest image displacement, dr, is used. Tv corresponds to the
221    * translation that takes the 'general displacement' (displacement
222    * between ion position and electron position) to the nearest image
223    * displacement. We need to keep track of Tv because it must be add
224    * as a phase factor, i.e., exp(i*k*Tv).
225    */
evaluateVSoaLocalizedBasisSet226   inline void evaluateV(const ParticleSet& P, int iat, ORBT* restrict vals)
227   {
228     const auto& IonID(ions_.GroupID);
229     const auto& coordR  = P.activeR(iat);
230     const auto& d_table = P.getDistTable(myTableIndex);
231     const auto& dist    = (P.activePtcl == iat) ? d_table.getTempDists() : d_table.getDistRow(iat);
232     const auto& displ   = (P.activePtcl == iat) ? d_table.getTempDispls() : d_table.getDisplRow(iat);
233 
234     PosType Tv;
235     for (int c = 0; c < NumCenters; c++)
236     {
237       Tv[0] = (ions_.R[c][0] - coordR[0]) - displ[c][0];
238       Tv[1] = (ions_.R[c][1] - coordR[1]) - displ[c][1];
239       Tv[2] = (ions_.R[c][2] - coordR[2]) - displ[c][2];
240       LOBasisSet[IonID[c]]->evaluateV(P.Lattice, dist[c], displ[c], vals + BasisOffset[c], Tv);
241     }
242   }
243 
evaluateGradSourceVSoaLocalizedBasisSet244   inline void evaluateGradSourceV(const ParticleSet& P, int iat, const ParticleSet& ions, int jion, vgl_type& vgl)
245   {
246     //We need to zero out the temporary array vgl.
247     auto* restrict gx = vgl.data(1);
248     auto* restrict gy = vgl.data(2);
249     auto* restrict gz = vgl.data(3);
250 
251     for (int ib = 0; ib < BasisSetSize; ib++)
252     {
253       gx[ib] = 0;
254       gy[ib] = 0;
255       gz[ib] = 0;
256     }
257 
258     const auto& IonID(ions_.GroupID);
259     const auto& d_table = P.getDistTable(myTableIndex);
260     const auto& dist    = (P.activePtcl == iat) ? d_table.getTempDists() : d_table.getDistRow(iat);
261     const auto& displ   = (P.activePtcl == iat) ? d_table.getTempDispls() : d_table.getDisplRow(iat);
262 
263 
264     PosType Tv;
265     Tv[0] = Tv[1] = Tv[2] = 0;
266     //Since LCAO's are written only in terms of (r-R), ionic derivatives only exist for the atomic center
267     //that we wish to take derivatives of.  Moreover, we can obtain an ion derivative by multiplying an electron
268     //derivative by -1.0.  Handling this sign is left to LCAOrbitalSet.  For now, just note this is the electron VGL function.
269     LOBasisSet[IonID[jion]]->evaluateVGL(P.Lattice, dist[jion], displ[jion], BasisOffset[jion], vgl, Tv);
270   }
271 
evaluateGradSourceVGLSoaLocalizedBasisSet272   inline void evaluateGradSourceVGL(const ParticleSet& P, int iat, const ParticleSet& ions, int jion, vghgh_type& vghgh)
273   {
274     //We need to zero out the temporary array vghgh.
275     auto* restrict gx = vghgh.data(1);
276     auto* restrict gy = vghgh.data(2);
277     auto* restrict gz = vghgh.data(3);
278 
279     auto* restrict hxx = vghgh.data(4);
280     auto* restrict hxy = vghgh.data(5);
281     auto* restrict hxz = vghgh.data(6);
282     auto* restrict hyy = vghgh.data(7);
283     auto* restrict hyz = vghgh.data(8);
284     auto* restrict hzz = vghgh.data(9);
285 
286     auto* restrict gxxx = vghgh.data(10);
287     auto* restrict gxxy = vghgh.data(11);
288     auto* restrict gxxz = vghgh.data(12);
289     auto* restrict gxyy = vghgh.data(13);
290     auto* restrict gxyz = vghgh.data(14);
291     auto* restrict gxzz = vghgh.data(15);
292     auto* restrict gyyy = vghgh.data(16);
293     auto* restrict gyyz = vghgh.data(17);
294     auto* restrict gyzz = vghgh.data(18);
295     auto* restrict gzzz = vghgh.data(19);
296 
297 
298     for (int ib = 0; ib < BasisSetSize; ib++)
299     {
300       gx[ib] = 0;
301       gy[ib] = 0;
302       gz[ib] = 0;
303 
304       hxx[ib] = 0;
305       hxy[ib] = 0;
306       hxz[ib] = 0;
307       hyy[ib] = 0;
308       hyz[ib] = 0;
309       hzz[ib] = 0;
310 
311       gxxx[ib] = 0;
312       gxxy[ib] = 0;
313       gxxz[ib] = 0;
314       gxyy[ib] = 0;
315       gxyz[ib] = 0;
316       gxzz[ib] = 0;
317       gyyy[ib] = 0;
318       gyyz[ib] = 0;
319       gyzz[ib] = 0;
320       gzzz[ib] = 0;
321     }
322 
323     // Since jion is indexed on the source ions not the ions_ the distinction between
324     // ions_ and ions is extremely important.
325     const auto& IonID(ions.GroupID);
326     const auto& d_table = P.getDistTable(myTableIndex);
327     const auto& dist    = (P.activePtcl == iat) ? d_table.getTempDists() : d_table.getDistRow(iat);
328     const auto& displ   = (P.activePtcl == iat) ? d_table.getTempDispls() : d_table.getDisplRow(iat);
329 
330     //Since LCAO's are written only in terms of (r-R), ionic derivatives only exist for the atomic center
331     //that we wish to take derivatives of.  Moreover, we can obtain an ion derivative by multiplying an electron
332     //derivative by -1.0.  Handling this sign is left to LCAOrbitalSet.  For now, just note this is the electron VGL function.
333 
334     LOBasisSet[IonID[jion]]->evaluateVGHGH(P.Lattice, dist[jion], displ[jion], BasisOffset[jion], vghgh);
335   }
336   /** add a new set of Centered Atomic Orbitals
337    * @param icenter the index of the center
338    * @param aos a set of Centered Atomic Orbitals
339    */
addSoaLocalizedBasisSet340   void add(int icenter, COT* aos) { LOBasisSet[icenter] = aos; }
341 };
342 } // namespace qmcplusplus
343 #endif
344