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: Ken Esler, kpesler@gmail.com, University of Illinois at Urbana-Champaign
8 //                    Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 //                    Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
10 //                    Jaron T. Krogel, krogeljt@ornl.gov, Oak Ridge National Laboratory
11 //                    Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
12 //
13 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
14 //////////////////////////////////////////////////////////////////////////////////////
15 
16 
17 #include "Particle/DistanceTableData.h"
18 #include "NonLocalECPComponent.h"
19 #include "QMCHamiltonians/NLPPJob.h"
20 
21 namespace qmcplusplus
22 {
NonLocalECPComponent()23 NonLocalECPComponent::NonLocalECPComponent() : lmax(0), nchannel(0), nknot(0), Rmax(-1), VP(nullptr) {}
24 
~NonLocalECPComponent()25 NonLocalECPComponent::~NonLocalECPComponent()
26 {
27   for (int ip = 0; ip < nlpp_m.size(); ip++)
28     delete nlpp_m[ip];
29   if (VP)
30     delete VP;
31 }
32 
makeClone(const ParticleSet & qp)33 NonLocalECPComponent* NonLocalECPComponent::makeClone(const ParticleSet& qp)
34 {
35   NonLocalECPComponent* myclone = new NonLocalECPComponent(*this);
36   for (int i = 0; i < nlpp_m.size(); ++i)
37     myclone->nlpp_m[i] = nlpp_m[i]->makeClone();
38   if (VP)
39     myclone->VP = new VirtualParticleSet(qp, nknot);
40   return myclone;
41 }
42 
initVirtualParticle(const ParticleSet & qp)43 void NonLocalECPComponent::initVirtualParticle(const ParticleSet& qp)
44 {
45   assert(VP == 0);
46   outputManager.pause();
47   VP = new VirtualParticleSet(qp, nknot);
48   outputManager.resume();
49 }
50 
add(int l,RadialPotentialType * pp)51 void NonLocalECPComponent::add(int l, RadialPotentialType* pp)
52 {
53   angpp_m.push_back(l);
54   wgt_angpp_m.push_back(static_cast<RealType>(2 * l + 1));
55   nlpp_m.push_back(pp);
56 }
57 
resize_warrays(int n,int m,int l)58 void NonLocalECPComponent::resize_warrays(int n, int m, int l)
59 {
60   psiratio.resize(n);
61   gradpsiratio.resize(n);
62   deltaV.resize(n);
63   cosgrad.resize(n);
64   wfngrad.resize(n);
65   knot_pots.resize(n);
66   vrad.resize(m);
67   dvrad.resize(m);
68   vgrad.resize(m);
69   wvec.resize(m);
70   Amat.resize(n * m);
71   dAmat.resize(n * m);
72   lpol.resize(l + 1, 1.0);
73   dlpol.resize(l + 1, 0.0);
74   rrotsgrid_m.resize(n);
75   nchannel = nlpp_m.size();
76   nknot    = sgridxyz_m.size();
77   //This is just to check
78   //for(int nl=1; nl<nlpp_m.size(); nl++) nlpp_m[nl]->setGridManager(false);
79   if (lmax)
80   {
81     if (lmax > 7)
82     {
83       APP_ABORT("Increase the maximum angular momentum implemented.");
84     }
85     //Lfactor1.resize(lmax);
86     //Lfactor2.resize(lmax);
87     for (int nl = 0; nl < lmax; nl++)
88     {
89       Lfactor1[nl] = static_cast<RealType>(2 * nl + 1);
90       Lfactor2[nl] = 1.0e0 / static_cast<RealType>(nl + 1);
91     }
92   }
93 }
94 
print(std::ostream & os)95 void NonLocalECPComponent::print(std::ostream& os)
96 {
97   os << "    Maximum angular mementum = " << lmax << std::endl;
98   os << "    Number of non-local channels = " << nchannel << std::endl;
99   for (int l = 0; l < nchannel; l++)
100     os << "       l(" << l << ")=" << angpp_m[l] << std::endl;
101   os << "    Cutoff radius = " << Rmax << std::endl;
102   os << "    Spherical grids and weights: " << std::endl;
103   for (int ik = 0; ik < nknot; ik++)
104     os << "       " << sgridxyz_m[ik] << std::setw(20) << sgridweight_m[ik] << std::endl;
105 }
106 
evaluateOne(ParticleSet & W,int iat,TrialWaveFunction & psi,int iel,RealType r,const PosType & dr,bool use_DLA)107 NonLocalECPComponent::RealType NonLocalECPComponent::evaluateOne(ParticleSet& W,
108                                                                  int iat,
109                                                                  TrialWaveFunction& psi,
110                                                                  int iel,
111                                                                  RealType r,
112                                                                  const PosType& dr,
113                                                                  bool use_DLA)
114 {
115   buildQuadraturePointDeltaPositions(r, dr, deltaV);
116 
117   if (VP)
118   {
119     // Compute ratios with VP
120     VP->makeMoves(iel, W.R[iel], deltaV, true, iat);
121     if (use_DLA)
122       psi.evaluateRatios(*VP, psiratio, TrialWaveFunction::ComputeType::FERMIONIC);
123     else
124       psi.evaluateRatios(*VP, psiratio);
125   }
126   else
127   {
128     // Compute ratio of wave functions
129     for (int j = 0; j < nknot; j++)
130     {
131       W.makeMove(iel, deltaV[j], false);
132       if (use_DLA)
133         psiratio[j] = psi.calcRatio(W, iel, TrialWaveFunction::ComputeType::FERMIONIC);
134       else
135         psiratio[j] = psi.calcRatio(W, iel);
136       W.rejectMove(iel);
137       psi.resetPhaseDiff();
138     }
139   }
140 
141   return calculateProjector(r, dr);
142 }
143 
calculateProjector(RealType r,const PosType & dr)144 NonLocalECPComponent::RealType NonLocalECPComponent::calculateProjector(RealType r, const PosType& dr)
145 {
146   for (int j = 0; j < nknot; j++)
147     psiratio[j] *= sgridweight_m[j];
148 
149   // Compute radial potential, multiplied by (2l+1) factor.
150   for (int ip = 0; ip < nchannel; ip++)
151     vrad[ip] = nlpp_m[ip]->splint(r) * wgt_angpp_m[ip];
152 
153   constexpr RealType czero(0);
154   constexpr RealType cone(1);
155 
156   const RealType rinv = cone / r;
157   RealType pairpot    = czero;
158   // Compute spherical harmonics on grid
159   for (int j = 0; j < nknot; j++)
160   {
161     RealType zz = dot(dr, rrotsgrid_m[j]) * rinv;
162     // Forming the Legendre polynomials
163     lpol[0]           = cone;
164     RealType lpolprev = czero;
165     for (int l = 0; l < lmax; l++)
166     {
167       //Not a big difference
168       //lpol[l+1]=(2*l+1)*zz*lpol[l]-l*lpolprev;
169       //lpol[l+1]/=(l+1);
170       lpol[l + 1] = Lfactor1[l] * zz * lpol[l] - l * lpolprev;
171       lpol[l + 1] *= Lfactor2[l];
172       lpolprev = lpol[l];
173     }
174 
175     ValueType lsum = 0.0;
176     for (int l = 0; l < nchannel; l++)
177       lsum += vrad[l] * lpol[angpp_m[l]];
178     knot_pots[j] = std::real(lsum * psiratio[j]);
179     pairpot += knot_pots[j];
180   }
181 
182   return pairpot;
183 }
184 
mw_evaluateOne(const RefVectorWithLeader<NonLocalECPComponent> & ecp_component_list,const RefVectorWithLeader<ParticleSet> & p_list,const RefVectorWithLeader<TrialWaveFunction> & psi_list,const RefVector<const NLPPJob<RealType>> & joblist,std::vector<RealType> & pairpots,ResourceCollection & collection,bool use_DLA)185 void NonLocalECPComponent::mw_evaluateOne(const RefVectorWithLeader<NonLocalECPComponent>& ecp_component_list,
186                                           const RefVectorWithLeader<ParticleSet>& p_list,
187                                           const RefVectorWithLeader<TrialWaveFunction>& psi_list,
188                                           const RefVector<const NLPPJob<RealType>>& joblist,
189                                           std::vector<RealType>& pairpots,
190                                           ResourceCollection& collection,
191                                           bool use_DLA)
192 {
193   auto& ecp_component_leader = ecp_component_list.getLeader();
194   if (ecp_component_leader.VP)
195   {
196     // Compute ratios with VP
197     RefVectorWithLeader<VirtualParticleSet> vp_list(*ecp_component_leader.VP);
198     RefVector<const VirtualParticleSet> const_vp_list;
199     RefVector<const std::vector<PosType>> deltaV_list;
200     RefVector<std::vector<ValueType>> psiratios_list;
201     vp_list.reserve(ecp_component_list.size());
202     const_vp_list.reserve(ecp_component_list.size());
203     deltaV_list.reserve(ecp_component_list.size());
204     psiratios_list.reserve(ecp_component_list.size());
205 
206     for (size_t i = 0; i < ecp_component_list.size(); i++)
207     {
208       NonLocalECPComponent& component(ecp_component_list[i]);
209       const NLPPJob<RealType>& job = joblist[i];
210 
211       component.buildQuadraturePointDeltaPositions(job.ion_elec_dist, job.ion_elec_displ, component.deltaV);
212 
213       vp_list.push_back(*component.VP);
214       const_vp_list.push_back(*component.VP);
215       deltaV_list.push_back(component.deltaV);
216       psiratios_list.push_back(component.psiratio);
217     }
218 
219     auto vp_to_p_list = VirtualParticleSet::RefVectorWithLeaderParticleSet(vp_list);
220     ResourceCollectionTeamLock<ParticleSet> vp_res_lock(collection, vp_to_p_list);
221 
222     VirtualParticleSet::mw_makeMoves(vp_list, deltaV_list, joblist, true);
223 
224     if (use_DLA)
225       TrialWaveFunction::mw_evaluateRatios(psi_list, const_vp_list, psiratios_list,
226                                            TrialWaveFunction::ComputeType::FERMIONIC);
227     else
228       TrialWaveFunction::mw_evaluateRatios(psi_list, const_vp_list, psiratios_list);
229   }
230   else
231   {
232     // Compute ratios without VP. This is working but very slow code path.
233 #pragma omp parallel for
234     for (size_t i = 0; i < p_list.size(); i++)
235     {
236       NonLocalECPComponent& component(ecp_component_list[i]);
237       auto* VP = component.VP;
238       ParticleSet& W(p_list[i]);
239       TrialWaveFunction& psi(psi_list[i]);
240       const NLPPJob<RealType>& job = joblist[i];
241 
242       component.buildQuadraturePointDeltaPositions(job.ion_elec_dist, job.ion_elec_displ, component.deltaV);
243 
244       // Compute ratio of wave functions
245       for (int j = 0; j < component.getNknot(); j++)
246       {
247         W.makeMove(job.electron_id, component.deltaV[j], false);
248         if (use_DLA)
249           component.psiratio[j] = psi.calcRatio(W, job.electron_id, TrialWaveFunction::ComputeType::FERMIONIC);
250         else
251           component.psiratio[j] = psi.calcRatio(W, job.electron_id);
252         W.rejectMove(job.electron_id);
253         psi.resetPhaseDiff();
254       }
255     }
256   }
257 
258   for (size_t i = 0; i < p_list.size(); i++)
259   {
260     NonLocalECPComponent& component(ecp_component_list[i]);
261     const NLPPJob<RealType>& job = joblist[i];
262     pairpots[i]                  = component.calculateProjector(job.ion_elec_dist, job.ion_elec_displ);
263   }
264 }
265 
evaluateOneWithForces(ParticleSet & W,int iat,TrialWaveFunction & psi,int iel,RealType r,const PosType & dr,PosType & force_iat)266 NonLocalECPComponent::RealType NonLocalECPComponent::evaluateOneWithForces(ParticleSet& W,
267                                                                            int iat,
268                                                                            TrialWaveFunction& psi,
269                                                                            int iel,
270                                                                            RealType r,
271                                                                            const PosType& dr,
272                                                                            PosType& force_iat)
273 {
274   constexpr RealType czero(0);
275   constexpr RealType cone(1);
276 
277   for (int j = 0; j < nknot; j++)
278     deltaV[j] = r * rrotsgrid_m[j] - dr;
279 
280   GradType gradtmp_(0);
281   PosType realgradtmp_(0);
282 
283   //Pseudopotential derivative w.r.t. ions can be split up into 3 contributions:
284   // term coming from the gradient of the radial potential
285   PosType gradpotterm_(0);
286   // term coming from gradient of legendre polynomial
287   PosType gradlpolyterm_(0);
288   // term coming from dependence of quadrature grid on ion position.
289   PosType gradwfnterm_(0);
290 
291   if (VP)
292   {
293     APP_ABORT("NonLocalECPComponent::evaluateOneWithForces(...): Forces not implemented with virtual particle moves\n");
294     // Compute ratios with VP
295     VP->makeMoves(iel, W.R[iel], deltaV, true, iat);
296     psi.evaluateRatios(*VP, psiratio);
297   }
298   else
299   {
300     // Compute ratio of wave functions
301     for (int j = 0; j < nknot; j++)
302     {
303       W.makeMove(iel, deltaV[j], false);
304       psiratio[j] = psi.calcRatioGrad(W, iel, gradtmp_);
305       //QMCPACK spits out $\nabla\Psi(q)/\Psi(q)$.
306       //Multiply times $\Psi(q)/\Psi(r)$ to get
307       // $\nabla\Psi(q)/\Psi(r)
308       gradtmp_ *= psiratio[j];
309 #if defined(QMC_COMPLEX)
310       //And now we take the real part and save it.
311       convert(gradtmp_, gradpsiratio[j]);
312 #else
313       //Real nonlocalpp forces seem to differ from those in the complex build.  Since
314       //complex build has been validated against QE, that indicates there's a bug for the real build.
315       gradpsiratio[j] = gradtmp_;
316 #endif
317       W.rejectMove(iel);
318       psi.resetPhaseDiff();
319       //psi.rejectMove(iel);
320     }
321   }
322 
323   for (int j = 0; j < nknot; j++)
324     psiratio[j] *= sgridweight_m[j];
325 
326   // This is just a temporary variable to dump d2/dr2 into for spline evaluation.
327   RealType secondderiv(0);
328 
329   const RealType rinv = cone / r;
330 
331   // Compute radial potential and its derivative times (2l+1)
332   for (int ip = 0; ip < nchannel; ip++)
333   {
334     //fun fact.  NLPComponent stores v(r) as v(r), and not as r*v(r) like in other places.
335     vrad[ip]  = nlpp_m[ip]->splint(r, dvrad[ip], secondderiv) * wgt_angpp_m[ip];
336     vgrad[ip] = dvrad[ip] * dr * wgt_angpp_m[ip] * rinv;
337   }
338 
339   RealType pairpot = 0;
340   // Compute spherical harmonics on grid
341   for (int j = 0; j < nknot; j++)
342   {
343     RealType zz        = dot(dr, rrotsgrid_m[j]) * rinv;
344     PosType uminusrvec = rrotsgrid_m[j] - zz * dr * rinv;
345 
346     cosgrad[j] = rinv * uminusrvec;
347 
348     RealType udotgradpsi = dot(gradpsiratio[j], rrotsgrid_m[j]);
349     wfngrad[j]           = gradpsiratio[j] - dr * (udotgradpsi * rinv);
350     wfngrad[j] *= sgridweight_m[j];
351 
352     // Forming the Legendre polynomials
353     //P_0(x)=1; P'_0(x)=0.
354     lpol[0]  = cone;
355     dlpol[0] = czero;
356 
357     RealType lpolprev  = czero;
358     RealType dlpolprev = czero;
359 
360     for (int l = 0; l < lmax; l++)
361     {
362       //Legendre polynomial recursion formula.
363       lpol[l + 1] = Lfactor1[l] * zz * lpol[l] - l * lpolprev;
364       lpol[l + 1] *= Lfactor2[l];
365 
366       //and for the derivative...
367       dlpol[l + 1] = Lfactor1[l] * (zz * dlpol[l] + lpol[l]) - l * dlpolprev;
368       dlpol[l + 1] *= Lfactor2[l];
369 
370       lpolprev  = lpol[l];
371       dlpolprev = dlpol[l];
372     }
373 
374     RealType lsum = czero;
375     // Now to compute the forces:
376     gradpotterm_   = 0;
377     gradlpolyterm_ = 0;
378     gradwfnterm_   = 0;
379 
380     for (int l = 0; l < nchannel; l++)
381     {
382       lsum += std::real(vrad[l]) * lpol[angpp_m[l]];
383       gradpotterm_ += vgrad[l] * lpol[angpp_m[l]] * std::real(psiratio[j]);
384       gradlpolyterm_ += std::real(vrad[l]) * dlpol[angpp_m[l]] * cosgrad[j] * std::real(psiratio[j]);
385       gradwfnterm_ += std::real(vrad[l]) * lpol[angpp_m[l]] * wfngrad[j];
386     }
387     knot_pots[j] = std::real(lsum * psiratio[j]);
388     pairpot += knot_pots[j];
389     force_iat += gradpotterm_ + gradlpolyterm_ - gradwfnterm_;
390   }
391 
392   return pairpot;
393 }
394 
evaluateOneWithForces(ParticleSet & W,ParticleSet & ions,int iat,TrialWaveFunction & psi,int iel,RealType r,const PosType & dr,PosType & force_iat,ParticleSet::ParticlePos_t & pulay_terms)395 NonLocalECPComponent::RealType NonLocalECPComponent::evaluateOneWithForces(ParticleSet& W,
396                                                                            ParticleSet& ions,
397                                                                            int iat,
398                                                                            TrialWaveFunction& psi,
399                                                                            int iel,
400                                                                            RealType r,
401                                                                            const PosType& dr,
402                                                                            PosType& force_iat,
403                                                                            ParticleSet::ParticlePos_t& pulay_terms)
404 {
405   constexpr RealType czero(0);
406   constexpr RealType cone(1);
407 
408   for (int j = 0; j < nknot; j++)
409     deltaV[j] = r * rrotsgrid_m[j] - dr;
410 
411   GradType gradtmp_(0);
412   PosType realgradtmp_(0);
413 
414   //Pseudopotential derivative w.r.t. ions can be split up into 3 contributions:
415   // term coming from the gradient of the radial potential
416   PosType gradpotterm_(0);
417   // term coming from gradient of legendre polynomial
418   PosType gradlpolyterm_(0);
419   // term coming from dependence of quadrature grid on ion position.
420   PosType gradwfnterm_(0);
421 
422   //Now for the Pulay specific stuff...
423   // $\nabla_I \Psi(...r...)/\Psi(...r...)$
424   ParticleSet::ParticlePos_t pulay_ref;
425   ParticleSet::ParticlePos_t pulaytmp_;
426   // $\nabla_I \Psi(...q...)/\Psi(...r...)$ for each quadrature point.
427   std::vector<ParticleSet::ParticlePos_t> pulay_quad(nknot);
428 
429   //A working array for pulay stuff.
430   GradType iongradtmp_(0);
431   //resize everything.
432   pulay_ref.resize(ions.getTotalNum());
433   pulaytmp_.resize(ions.getTotalNum());
434   for (size_t j = 0; j < nknot; j++)
435     pulay_quad[j].resize(ions.getTotalNum());
436 
437   if (VP)
438   {
439     APP_ABORT("NonLocalECPComponent::evaluateOneWithForces(...): Forces not implemented with virtual particle moves\n");
440     // Compute ratios with VP
441     VP->makeMoves(iel, W.R[iel], deltaV, true, iat);
442     psi.evaluateRatios(*VP, psiratio);
443   }
444   else
445   {
446     // Compute ratio of wave functions
447     for (int j = 0; j < nknot; j++)
448     {
449       W.makeMove(iel, deltaV[j], false);
450       psiratio[j] = psi.calcRatioGrad(W, iel, gradtmp_);
451       //QMCPACK spits out $\nabla\Psi(q)/\Psi(q)$.
452       //Multiply times $\Psi(q)/\Psi(r)$ to get
453       // $\nabla\Psi(q)/\Psi(r)
454       gradtmp_ *= psiratio[j];
455 #if defined(QMC_COMPLEX)
456       //And now we take the real part and save it.
457       convert(gradtmp_, gradpsiratio[j]);
458 #else
459       //Real nonlocalpp forces seem to differ from those in the complex build.  Since
460       //complex build has been validated against QE, that indicates there's a bug for the real build.
461       gradpsiratio[j] = gradtmp_;
462 #endif
463       W.rejectMove(iel);
464       psi.resetPhaseDiff();
465       //psi.rejectMove(iel);
466     }
467   }
468 
469   for (int j = 0; j < nknot; j++)
470     psiratio[j] *= sgridweight_m[j];
471 
472   // This is just a temporary variable to dump d2/dr2 into for spline evaluation.
473   RealType secondderiv(0);
474 
475   const RealType rinv = cone / r;
476 
477   // Compute radial potential and its derivative times (2l+1)
478   for (int ip = 0; ip < nchannel; ip++)
479   {
480     //fun fact.  NLPComponent stores v(r) as v(r), and not as r*v(r) like in other places.
481     vrad[ip]  = nlpp_m[ip]->splint(r, dvrad[ip], secondderiv) * wgt_angpp_m[ip];
482     vgrad[ip] = dvrad[ip] * dr * wgt_angpp_m[ip] * rinv;
483   }
484 
485   //Now to construct the 3N dimensional ionic wfn derivatives for pulay terms.
486   //This is going to be slow an painful for now.
487   for (size_t jat = 0; jat < ions.getTotalNum(); jat++)
488   {
489     pulay_ref[jat] = psi.evalGradSource(W, ions, jat);
490     gradpotterm_   = 0;
491     for (size_t j = 0; j < nknot; j++)
492     {
493       deltaV[j] = r * rrotsgrid_m[j] - dr;
494       //This sequence is necessary to update the distance tables and make the
495       //inverse matrix available for force computation.  Move the particle to
496       //quadrature point...
497       W.makeMove(iel, deltaV[j]);
498       psi.calcRatio(W, iel);
499       psi.acceptMove(W, iel);
500       W.acceptMove(iel); // it only updates the jel-th row of e-e table
501       //Done with the move.  Ready for force computation.
502 
503       iongradtmp_ = psi.evalGradSource(W, ions, jat);
504       iongradtmp_ *= psiratio[j];
505 #ifdef QMC_COMPLEX
506       convert(iongradtmp_, pulay_quad[j][jat]);
507 #endif
508       pulay_quad[j][jat] = iongradtmp_;
509       //And move the particle back.
510       deltaV[j] = dr - r * rrotsgrid_m[j];
511 
512       // mirror the above in reverse order
513       W.makeMove(iel, deltaV[j]);
514       psi.calcRatio(W, iel);
515       psi.acceptMove(W, iel);
516       W.acceptMove(iel);
517     }
518   }
519 
520   RealType pairpot = 0;
521   // Compute spherical harmonics on grid
522   for (int j = 0; j < nknot; j++)
523   {
524     RealType zz        = dot(dr, rrotsgrid_m[j]) * rinv;
525     PosType uminusrvec = rrotsgrid_m[j] - zz * dr * rinv;
526 
527     cosgrad[j] = rinv * uminusrvec;
528 
529     RealType udotgradpsi = dot(gradpsiratio[j], rrotsgrid_m[j]);
530     wfngrad[j]           = gradpsiratio[j] - dr * (udotgradpsi * rinv);
531     wfngrad[j] *= sgridweight_m[j];
532 
533     // Forming the Legendre polynomials
534     //P_0(x)=1; P'_0(x)=0.
535     lpol[0]  = cone;
536     dlpol[0] = czero;
537 
538     RealType lpolprev  = czero;
539     RealType dlpolprev = czero;
540 
541     for (int l = 0; l < lmax; l++)
542     {
543       //Legendre polynomial recursion formula.
544       lpol[l + 1] = Lfactor1[l] * zz * lpol[l] - l * lpolprev;
545       lpol[l + 1] *= Lfactor2[l];
546 
547       //and for the derivative...
548       dlpol[l + 1] = Lfactor1[l] * (zz * dlpol[l] + lpol[l]) - l * dlpolprev;
549       dlpol[l + 1] *= Lfactor2[l];
550 
551       lpolprev  = lpol[l];
552       dlpolprev = dlpol[l];
553     }
554 
555     RealType lsum = czero;
556     // Now to compute the forces:
557     gradpotterm_   = 0;
558     gradlpolyterm_ = 0;
559     gradwfnterm_   = 0;
560     pulaytmp_      = 0;
561 
562     for (int l = 0; l < nchannel; l++)
563     {
564       //Note.  Because we are computing "forces", there's a -1 difference between this and
565       //direct finite difference calculations.
566       lsum += std::real(vrad[l]) * lpol[angpp_m[l]];
567       gradpotterm_ += vgrad[l] * lpol[angpp_m[l]] * std::real(psiratio[j]);
568       gradlpolyterm_ += std::real(vrad[l]) * dlpol[angpp_m[l]] * cosgrad[j] * std::real(psiratio[j]);
569       gradwfnterm_ += std::real(vrad[l]) * lpol[angpp_m[l]] * wfngrad[j];
570       pulaytmp_ -= std::real(vrad[l]) * lpol[angpp_m[l]] * pulay_quad[j];
571     }
572     knot_pots[j] = std::real(lsum * psiratio[j]);
573     pulaytmp_ += knot_pots[j] * pulay_ref;
574     pairpot += knot_pots[j];
575     force_iat += gradpotterm_ + gradlpolyterm_ - gradwfnterm_;
576     pulay_terms += pulaytmp_;
577   }
578 
579   return pairpot;
580 }
581 
582 ///Randomly rotate sgrid_m
randomize_grid(RandomGenerator_t & myRNG)583 void NonLocalECPComponent::randomize_grid(RandomGenerator_t& myRNG)
584 {
585   RealType phi(TWOPI * myRNG()), psi(TWOPI * myRNG()), cth(myRNG() - 0.5);
586   RealType sph(std::sin(phi)), cph(std::cos(phi)), sth(std::sqrt(1.0 - cth * cth)), sps(std::sin(psi)),
587       cps(std::cos(psi));
588   TensorType rmat(cph * cth * cps - sph * sps, sph * cth * cps + cph * sps, -sth * cps, -cph * cth * sps - sph * cps,
589                   -sph * cth * sps + cph * cps, sth * sps, cph * sth, sph * sth, cth);
590   for (int i = 0; i < sgridxyz_m.size(); i++)
591     rrotsgrid_m[i] = dot(rmat, sgridxyz_m[i]);
592 }
593 
594 template<typename T>
randomize_grid(std::vector<T> & sphere,RandomGenerator_t & myRNG)595 void NonLocalECPComponent::randomize_grid(std::vector<T>& sphere, RandomGenerator_t& myRNG)
596 {
597   RealType phi(TWOPI * myRNG()), psi(TWOPI * myRNG()), cth(myRNG() - 0.5);
598   RealType sph(std::sin(phi)), cph(std::cos(phi)), sth(std::sqrt(1.0 - cth * cth)), sps(std::sin(psi)),
599       cps(std::cos(psi));
600   TensorType rmat(cph * cth * cps - sph * sps, sph * cth * cps + cph * sps, -sth * cps, -cph * cth * sps - sph * cps,
601                   -sph * cth * sps + cph * cps, sth * sps, cph * sth, sph * sth, cth);
602   SpherGridType::iterator it(sgridxyz_m.begin());
603   SpherGridType::iterator it_end(sgridxyz_m.end());
604   SpherGridType::iterator jt(rrotsgrid_m.begin());
605   while (it != it_end)
606   {
607     *jt = dot(rmat, *it);
608     ++it;
609     ++jt;
610   }
611   //copy the randomized grid to sphere
612   for (int i = 0; i < rrotsgrid_m.size(); i++)
613     for (int j = 0; j < OHMMS_DIM; j++)
614       sphere[OHMMS_DIM * i + j] = rrotsgrid_m[i][j];
615 }
616 
buildQuadraturePointDeltaPositions(RealType r,const PosType & dr,std::vector<PosType> & deltaV) const617 void NonLocalECPComponent::buildQuadraturePointDeltaPositions(RealType r,
618                                                               const PosType& dr,
619                                                               std::vector<PosType>& deltaV) const
620 {
621   for (int j = 0; j < nknot; j++)
622     deltaV[j] = r * rrotsgrid_m[j] - dr;
623 }
624 
contributeTxy(int iel,std::vector<NonLocalData> & Txy) const625 void NonLocalECPComponent::contributeTxy(int iel, std::vector<NonLocalData>& Txy) const
626 {
627   for (int j = 0; j < nknot; j++)
628     Txy.push_back(NonLocalData(iel, knot_pots[j], deltaV[j]));
629 }
630 
631 /// \relates NonLocalEcpComponent
632 template void NonLocalECPComponent::randomize_grid(std::vector<float>& sphere, RandomGenerator_t& myRNG);
633 template void NonLocalECPComponent::randomize_grid(std::vector<double>& sphere, RandomGenerator_t& myRNG);
634 
635 
636 } // namespace qmcplusplus
637