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 "NonLocalECPotential.h"
18 #include <DistanceTableData.h>
19 #include <IteratorUtility.h>
20 #include <ResourceCollection.h>
21 #include "NonLocalECPComponent.h"
22 #include "NLPPJob.h"
23 
24 namespace qmcplusplus
25 {
26 struct NonLocalECPotentialMultiWalkerResource : public Resource
27 {
NonLocalECPotentialMultiWalkerResourceqmcplusplus::NonLocalECPotentialMultiWalkerResource28   NonLocalECPotentialMultiWalkerResource() : Resource("NonLocalECPotential"), collection("NLPPcollection") {}
29 
makeCloneqmcplusplus::NonLocalECPotentialMultiWalkerResource30   Resource* makeClone() const override { return new NonLocalECPotentialMultiWalkerResource(*this); }
31 
32   ResourceCollection collection;
33 };
34 
resetTargetParticleSet(ParticleSet & P)35 void NonLocalECPotential::resetTargetParticleSet(ParticleSet& P) {}
36 
37 /** constructor
38  *\param ions the positions of the ions
39  *\param els the positions of the electrons
40  *\param psi trial wavefunction
41  */
NonLocalECPotential(ParticleSet & ions,ParticleSet & els,TrialWaveFunction & psi,bool computeForces,bool enable_DLA)42 NonLocalECPotential::NonLocalECPotential(ParticleSet& ions,
43                                          ParticleSet& els,
44                                          TrialWaveFunction& psi,
45                                          bool computeForces,
46                                          bool enable_DLA)
47     : ForceBase(ions, els),
48       myRNG(nullptr),
49       IonConfig(ions),
50       Psi(psi),
51       ComputeForces(computeForces),
52       use_DLA(enable_DLA),
53       Peln(els),
54       ElecNeighborIons(els),
55       IonNeighborElecs(ions),
56       UseTMove(TMOVE_OFF),
57       nonLocalOps(els.getTotalNum())
58 {
59   set_energy_domain(potential);
60   two_body_quantum_domain(ions, els);
61   myTableIndex = els.addTable(ions);
62   NumIons      = ions.getTotalNum();
63   //els.resizeSphere(NumIons);
64   PP.resize(NumIons, nullptr);
65   prefix = "FNL";
66   PPset.resize(IonConfig.getSpeciesSet().getTotalNum());
67   PulayTerm.resize(NumIons);
68   UpdateMode.set(NONLOCAL, 1);
69   nlpp_jobs.resize(els.groups());
70   for (size_t ig = 0; ig < els.groups(); ig++)
71   {
72     // this should be enough in most calculations assuming that every electron cannot be in more than two pseudo regions.
73     nlpp_jobs[ig].reserve(2 * els.groupsize(ig));
74   }
75 }
76 
77 NonLocalECPotential::~NonLocalECPotential() = default;
78 
79 #if !defined(REMOVE_TRACEMANAGER)
contribute_particle_quantities()80 void NonLocalECPotential::contribute_particle_quantities() { request.contribute_array(myName); }
81 
checkout_particle_quantities(TraceManager & tm)82 void NonLocalECPotential::checkout_particle_quantities(TraceManager& tm)
83 {
84   streaming_particles = request.streaming_array(myName);
85   if (streaming_particles)
86   {
87     Ve_sample = tm.checkout_real<1>(myName, Peln);
88     Vi_sample = tm.checkout_real<1>(myName, IonConfig);
89   }
90 }
91 
delete_particle_quantities()92 void NonLocalECPotential::delete_particle_quantities()
93 {
94   if (streaming_particles)
95   {
96     delete Ve_sample;
97     delete Vi_sample;
98   }
99 }
100 #endif
101 
evaluate(ParticleSet & P)102 NonLocalECPotential::Return_t NonLocalECPotential::evaluate(ParticleSet& P)
103 {
104   evaluateImpl(P, false);
105   return Value;
106 }
107 
evaluateDeterministic(ParticleSet & P)108 NonLocalECPotential::Return_t NonLocalECPotential::evaluateDeterministic(ParticleSet& P)
109 {
110   evaluateImpl(P, false, true);
111   return Value;
112 }
113 
mw_evaluate(const RefVectorWithLeader<OperatorBase> & O_list,const RefVectorWithLeader<ParticleSet> & p_list) const114 void NonLocalECPotential::mw_evaluate(const RefVectorWithLeader<OperatorBase>& O_list,
115                                       const RefVectorWithLeader<ParticleSet>& p_list) const
116 {
117   mw_evaluateImpl(O_list, p_list, false);
118 }
119 
evaluateWithToperator(ParticleSet & P)120 NonLocalECPotential::Return_t NonLocalECPotential::evaluateWithToperator(ParticleSet& P)
121 {
122   if (UseTMove == TMOVE_V0 || UseTMove == TMOVE_V3)
123     evaluateImpl(P, true);
124   else
125     evaluateImpl(P, false);
126   return Value;
127 }
128 
mw_evaluateWithToperator(const RefVectorWithLeader<OperatorBase> & O_list,const RefVectorWithLeader<ParticleSet> & p_list) const129 void NonLocalECPotential::mw_evaluateWithToperator(const RefVectorWithLeader<OperatorBase>& O_list,
130                                                    const RefVectorWithLeader<ParticleSet>& p_list) const
131 {
132   if (UseTMove == TMOVE_V0 || UseTMove == TMOVE_V3)
133     mw_evaluateImpl(O_list, p_list, true);
134   else
135     mw_evaluateImpl(O_list, p_list, false);
136 }
137 
evaluateImpl(ParticleSet & P,bool Tmove,bool keepGrid)138 void NonLocalECPotential::evaluateImpl(ParticleSet& P, bool Tmove, bool keepGrid)
139 {
140   if (Tmove)
141     nonLocalOps.reset();
142   std::vector<NonLocalData>& Txy(nonLocalOps.Txy);
143   Value = 0.0;
144 #if !defined(REMOVE_TRACEMANAGER)
145   auto& Ve_samp = *Ve_sample;
146   auto& Vi_samp = *Vi_sample;
147   if (streaming_particles)
148   {
149     Ve_samp = 0.0;
150     Vi_samp = 0.0;
151   }
152 #endif
153   for (int ipp = 0; ipp < PPset.size(); ipp++)
154     if (PPset[ipp])
155       if (!keepGrid)
156         PPset[ipp]->randomize_grid(*myRNG);
157   //loop over all the ions
158   const auto& myTable = P.getDistTable(myTableIndex);
159   // clear all the electron and ion neighbor lists
160   for (int iat = 0; iat < NumIons; iat++)
161     IonNeighborElecs.getNeighborList(iat).clear();
162   for (int jel = 0; jel < P.getTotalNum(); jel++)
163     ElecNeighborIons.getNeighborList(jel).clear();
164 
165   if (ComputeForces)
166   {
167     forces = 0;
168     for (int ig = 0; ig < P.groups(); ++ig) //loop over species
169     {
170       Psi.prepareGroup(P, ig);
171       for (int jel = P.first(ig); jel < P.last(ig); ++jel)
172       {
173         const auto& dist               = myTable.getDistRow(jel);
174         const auto& displ              = myTable.getDisplRow(jel);
175         std::vector<int>& NeighborIons = ElecNeighborIons.getNeighborList(jel);
176         for (int iat = 0; iat < NumIons; iat++)
177           if (PP[iat] != nullptr && dist[iat] < PP[iat]->getRmax())
178           {
179             RealType pairpot = PP[iat]->evaluateOneWithForces(P, iat, Psi, jel, dist[iat], -displ[iat], forces[iat]);
180             if (Tmove)
181               PP[iat]->contributeTxy(jel, Txy);
182             Value += pairpot;
183             NeighborIons.push_back(iat);
184             IonNeighborElecs.getNeighborList(iat).push_back(jel);
185           }
186       }
187     }
188   }
189   else
190   {
191     for (int ig = 0; ig < P.groups(); ++ig) //loop over species
192     {
193       Psi.prepareGroup(P, ig);
194       for (int jel = P.first(ig); jel < P.last(ig); ++jel)
195       {
196         const auto& dist               = myTable.getDistRow(jel);
197         const auto& displ              = myTable.getDisplRow(jel);
198         std::vector<int>& NeighborIons = ElecNeighborIons.getNeighborList(jel);
199         for (int iat = 0; iat < NumIons; iat++)
200           if (PP[iat] != nullptr && dist[iat] < PP[iat]->getRmax())
201           {
202             RealType pairpot = PP[iat]->evaluateOne(P, iat, Psi, jel, dist[iat], -displ[iat], use_DLA);
203             if (Tmove)
204               PP[iat]->contributeTxy(jel, Txy);
205             Value += pairpot;
206             NeighborIons.push_back(iat);
207             IonNeighborElecs.getNeighborList(iat).push_back(jel);
208             if (streaming_particles)
209             {
210               Ve_samp(jel) += 0.5 * pairpot;
211               Vi_samp(iat) += 0.5 * pairpot;
212             }
213           }
214       }
215     }
216   }
217 
218 #if !defined(TRACE_CHECK)
219   if (streaming_particles)
220   {
221     Return_t Vnow  = Value;
222     RealType Visum = Vi_sample->sum();
223     RealType Vesum = Ve_sample->sum();
224     RealType Vsum  = Vesum + Visum;
225     if (std::abs(Vsum - Vnow) > TraceManager::trace_tol)
226     {
227       app_log() << "accumtest: NonLocalECPotential::evaluate()" << std::endl;
228       app_log() << "accumtest:   tot:" << Vnow << std::endl;
229       app_log() << "accumtest:   sum:" << Vsum << std::endl;
230       APP_ABORT("Trace check failed");
231     }
232     if (std::abs(Vesum - Visum) > TraceManager::trace_tol)
233     {
234       app_log() << "sharetest: NonLocalECPotential::evaluate()" << std::endl;
235       app_log() << "sharetest:   e share:" << Vesum << std::endl;
236       app_log() << "sharetest:   i share:" << Visum << std::endl;
237       APP_ABORT("Trace check failed");
238     }
239   }
240 #endif
241 }
242 
mw_evaluateImpl(const RefVectorWithLeader<OperatorBase> & O_list,const RefVectorWithLeader<ParticleSet> & p_list,bool Tmove)243 void NonLocalECPotential::mw_evaluateImpl(const RefVectorWithLeader<OperatorBase>& O_list,
244                                           const RefVectorWithLeader<ParticleSet>& p_list,
245                                           bool Tmove)
246 {
247   auto& O_leader           = O_list.getCastedLeader<NonLocalECPotential>();
248   ParticleSet& pset_leader = p_list[0];
249   const size_t ngroups     = pset_leader.groups();
250   const size_t nw          = O_list.size();
251   /// maximal number of jobs per spin
252   std::vector<size_t> max_num_jobs(ngroups, 0);
253 
254 #pragma omp parallel for
255   for (size_t iw = 0; iw < nw; iw++)
256   {
257     auto& O = O_list.getCastedElement<NonLocalECPotential>(iw);
258     ParticleSet& P(p_list[iw]);
259 
260     if (Tmove)
261       O.nonLocalOps.reset();
262 
263     for (int ipp = 0; ipp < O.PPset.size(); ipp++)
264       if (O.PPset[ipp])
265         O.PPset[ipp]->randomize_grid(*O.myRNG);
266 
267     //loop over all the ions
268     const auto& myTable = P.getDistTable(O.myTableIndex);
269     // clear all the electron and ion neighbor lists
270     for (int iat = 0; iat < O.NumIons; iat++)
271       O.IonNeighborElecs.getNeighborList(iat).clear();
272     for (int jel = 0; jel < P.getTotalNum(); jel++)
273       O.ElecNeighborIons.getNeighborList(jel).clear();
274 
275     if (O.ComputeForces)
276       APP_ABORT("NonLocalECPotential::mw_evaluateImpl(): Forces not imlpemented\n");
277 
278     for (int ig = 0; ig < P.groups(); ++ig) //loop over species
279     {
280       auto& joblist = O.nlpp_jobs[ig];
281       joblist.clear();
282 
283       for (int jel = P.first(ig); jel < P.last(ig); ++jel)
284       {
285         const auto& dist               = myTable.getDistRow(jel);
286         const auto& displ              = myTable.getDisplRow(jel);
287         std::vector<int>& NeighborIons = O.ElecNeighborIons.getNeighborList(jel);
288         for (int iat = 0; iat < O.NumIons; iat++)
289           if (O.PP[iat] != nullptr && dist[iat] < O.PP[iat]->getRmax())
290           {
291             NeighborIons.push_back(iat);
292             O.IonNeighborElecs.getNeighborList(iat).push_back(jel);
293             joblist.emplace_back(iat, jel, P.R[jel], dist[iat], -displ[iat]);
294           }
295       }
296       // find the max number of jobs of all the walkers
297       max_num_jobs[ig] = std::max(max_num_jobs[ig], joblist.size());
298     }
299 
300     O.Value = 0.0;
301   }
302 
303   // make this class unit tests friendly without the need of setup resources.
304   if (!O_leader.mw_res_)
305   {
306     app_warning() << "NonLocalECPotential: This message should not be seen in production (performance bug) runs "
307                      "but only unit tests (expected)."
308                   << std::endl;
309     O_leader.mw_res_ = std::make_unique<NonLocalECPotentialMultiWalkerResource>();
310     for (int ig = 0; ig < O_leader.PPset.size(); ++ig)
311     if (O_leader.PPset[ig]->getVP())
312     {
313       O_leader.PPset[ig]->getVP()->createResource(O_leader.mw_res_->collection);
314       break;
315     }
316   }
317 
318   auto pp_component = std::find_if(O_leader.PPset.begin(), O_leader.PPset.end(), [](auto& ptr) { return bool(ptr); });
319   assert(pp_component != std::end(O_leader.PPset));
320 
321   RefVector<NonLocalECPotential> ecp_potential_list;
322   RefVectorWithLeader<NonLocalECPComponent> ecp_component_list(**pp_component);
323   RefVectorWithLeader<ParticleSet> pset_list(pset_leader);
324   RefVectorWithLeader<TrialWaveFunction> psi_list(O_leader.Psi);
325   RefVector<const NLPPJob<RealType>> batch_list;
326   std::vector<RealType> pairpots(nw);
327 
328   ecp_potential_list.reserve(nw);
329   ecp_component_list.reserve(nw);
330   pset_list.reserve(nw);
331   psi_list.reserve(nw);
332   batch_list.reserve(nw);
333 
334   for (int ig = 0; ig < ngroups; ++ig) //loop over species
335   {
336     {
337       psi_list.clear();
338       for (size_t iw = 0; iw < nw; iw++)
339         psi_list.push_back(O_list.getCastedElement<NonLocalECPotential>(iw).Psi);
340       TrialWaveFunction::mw_prepareGroup(psi_list, p_list, ig);
341     }
342 
343     for (size_t jobid = 0; jobid < max_num_jobs[ig]; jobid++)
344     {
345       ecp_potential_list.clear();
346       ecp_component_list.clear();
347       pset_list.clear();
348       psi_list.clear();
349       batch_list.clear();
350       for (size_t iw = 0; iw < nw; iw++)
351       {
352         auto& O = O_list.getCastedElement<NonLocalECPotential>(iw);
353         ParticleSet& P(p_list[iw]);
354         if (jobid < O.nlpp_jobs[ig].size())
355         {
356           const auto& job = O.nlpp_jobs[ig][jobid];
357           ecp_potential_list.push_back(O);
358           ecp_component_list.push_back(*O.PP[job.ion_id]);
359           pset_list.push_back(P);
360           psi_list.push_back(O.Psi);
361           batch_list.push_back(job);
362         }
363       }
364 
365       NonLocalECPComponent::mw_evaluateOne(ecp_component_list, pset_list, psi_list, batch_list, pairpots,
366                                            O_leader.mw_res_->collection, O_leader.use_DLA);
367 
368       for (size_t j = 0; j < ecp_potential_list.size(); j++)
369       {
370         if (false)
371         { // code usefully for debugging
372           RealType check_value =
373               ecp_component_list[j].evaluateOne(pset_list[j], batch_list[j].get().ion_id, psi_list[j],
374                                                 batch_list[j].get().electron_id, batch_list[j].get().ion_elec_dist,
375                                                 batch_list[j].get().ion_elec_displ, O_leader.use_DLA);
376           if (std::abs(check_value - pairpots[j]) > 1e-5)
377             std::cout << "check " << check_value << " wrong " << pairpots[j] << " diff "
378                       << std::abs(check_value - pairpots[j]) << std::endl;
379         }
380         ecp_potential_list[j].get().Value += pairpots[j];
381         if (Tmove)
382           ecp_component_list[j].contributeTxy(batch_list[j].get().electron_id,
383                                               ecp_potential_list[j].get().nonLocalOps.Txy);
384       }
385     }
386   }
387 }
388 
evaluateWithIonDerivs(ParticleSet & P,ParticleSet & ions,TrialWaveFunction & psi,ParticleSet::ParticlePos_t & hf_terms,ParticleSet::ParticlePos_t & pulay_terms)389 NonLocalECPotential::Return_t NonLocalECPotential::evaluateWithIonDerivs(ParticleSet& P,
390                                                                          ParticleSet& ions,
391                                                                          TrialWaveFunction& psi,
392                                                                          ParticleSet::ParticlePos_t& hf_terms,
393                                                                          ParticleSet::ParticlePos_t& pulay_terms)
394 {
395   //We're going to ignore psi and use the internal Psi.
396   //
397   //Dummy vector for now.  Tmoves not implemented
398   std::vector<NonLocalData>& Txy(nonLocalOps.Txy);
399   bool Tmove = false;
400 
401   forces    = 0;
402   PulayTerm = 0;
403 
404   Value = 0.0;
405 
406   for (int ipp = 0; ipp < PPset.size(); ipp++)
407     if (PPset[ipp])
408       PPset[ipp]->randomize_grid(*myRNG);
409   //loop over all the ions
410   const auto& myTable = P.getDistTable(myTableIndex);
411   // clear all the electron and ion neighbor lists
412   for (int iat = 0; iat < NumIons; iat++)
413     IonNeighborElecs.getNeighborList(iat).clear();
414   for (int jel = 0; jel < P.getTotalNum(); jel++)
415     ElecNeighborIons.getNeighborList(jel).clear();
416 
417   for (int ig = 0; ig < P.groups(); ++ig) //loop over species
418   {
419     Psi.prepareGroup(P, ig);
420     for (int jel = P.first(ig); jel < P.last(ig); ++jel)
421     {
422       const auto& dist               = myTable.getDistRow(jel);
423       const auto& displ              = myTable.getDisplRow(jel);
424       std::vector<int>& NeighborIons = ElecNeighborIons.getNeighborList(jel);
425       for (int iat = 0; iat < NumIons; iat++)
426         if (PP[iat] != nullptr && dist[iat] < PP[iat]->getRmax())
427         {
428           Value +=
429               PP[iat]->evaluateOneWithForces(P, ions, iat, Psi, jel, dist[iat], -displ[iat], forces[iat], PulayTerm);
430           if (Tmove)
431             PP[iat]->contributeTxy(jel, Txy);
432           NeighborIons.push_back(iat);
433           IonNeighborElecs.getNeighborList(iat).push_back(jel);
434         }
435     }
436   }
437 
438   hf_terms -= forces;
439   pulay_terms -= PulayTerm;
440   return Value;
441 }
442 
computeOneElectronTxy(ParticleSet & P,const int ref_elec)443 void NonLocalECPotential::computeOneElectronTxy(ParticleSet& P, const int ref_elec)
444 {
445   nonLocalOps.reset();
446   std::vector<NonLocalData>& Txy(nonLocalOps.Txy);
447   const auto& myTable                  = P.getDistTable(myTableIndex);
448   const std::vector<int>& NeighborIons = ElecNeighborIons.getNeighborList(ref_elec);
449 
450   const auto& dist  = myTable.getDistRow(ref_elec);
451   const auto& displ = myTable.getDisplRow(ref_elec);
452   for (int atom_index = 0; atom_index < NeighborIons.size(); atom_index++)
453   {
454     const int iat = NeighborIons[atom_index];
455     PP[iat]->evaluateOne(P, iat, Psi, ref_elec, dist[iat], -displ[iat], use_DLA);
456     PP[iat]->contributeTxy(ref_elec, Txy);
457   }
458 }
459 
makeNonLocalMovesPbyP(ParticleSet & P)460 int NonLocalECPotential::makeNonLocalMovesPbyP(ParticleSet& P)
461 {
462   int NonLocalMoveAccepted = 0;
463   RandomGenerator_t& RandomGen(*myRNG);
464   if (UseTMove == TMOVE_V0)
465   {
466     const NonLocalData* oneTMove = nonLocalOps.selectMove(RandomGen());
467     //make a non-local move
468     if (oneTMove)
469     {
470       int iat = oneTMove->PID;
471       Psi.prepareGroup(P, P.getGroupID(iat));
472       if (P.makeMoveAndCheck(iat, oneTMove->Delta))
473       {
474         GradType grad_iat;
475         Psi.calcRatioGrad(P, iat, grad_iat);
476         Psi.acceptMove(P, iat, true);
477         P.acceptMove(iat);
478         NonLocalMoveAccepted++;
479       }
480     }
481   }
482   else if (UseTMove == TMOVE_V1)
483   {
484     GradType grad_iat;
485     //make a non-local move per particle
486     for (int ig = 0; ig < P.groups(); ++ig) //loop over species
487     {
488       Psi.prepareGroup(P, ig);
489       for (int iat = P.first(ig); iat < P.last(ig); ++iat)
490       {
491         computeOneElectronTxy(P, iat);
492         const NonLocalData* oneTMove = nonLocalOps.selectMove(RandomGen());
493         if (oneTMove)
494         {
495           if (P.makeMoveAndCheck(iat, oneTMove->Delta))
496           {
497             Psi.calcRatioGrad(P, iat, grad_iat);
498             Psi.acceptMove(P, iat, true);
499             P.acceptMove(iat);
500             NonLocalMoveAccepted++;
501           }
502         }
503       }
504     }
505   }
506   else if (UseTMove == TMOVE_V3)
507   {
508     elecTMAffected.assign(P.getTotalNum(), false);
509     nonLocalOps.group_by_elec();
510     GradType grad_iat;
511     //make a non-local move per particle
512     for (int ig = 0; ig < P.groups(); ++ig) //loop over species
513     {
514       Psi.prepareGroup(P, ig);
515       for (int iat = P.first(ig); iat < P.last(ig); ++iat)
516       {
517         const NonLocalData* oneTMove;
518         if (elecTMAffected[iat])
519         {
520           // recompute Txy for the given electron effected by Tmoves
521           computeOneElectronTxy(P, iat);
522           oneTMove = nonLocalOps.selectMove(RandomGen());
523         }
524         else
525           oneTMove = nonLocalOps.selectMove(RandomGen(), iat);
526         if (oneTMove)
527         {
528           if (P.makeMoveAndCheck(iat, oneTMove->Delta))
529           {
530             Psi.calcRatioGrad(P, iat, grad_iat);
531             Psi.acceptMove(P, iat, true);
532             // mark all affected electrons
533             markAffectedElecs(P.getDistTable(myTableIndex), iat);
534             P.acceptMove(iat);
535             NonLocalMoveAccepted++;
536           }
537         }
538       }
539     }
540   }
541 
542   if (NonLocalMoveAccepted > 0)
543     Psi.completeUpdates();
544 
545   return NonLocalMoveAccepted;
546 }
547 
markAffectedElecs(const DistanceTableData & myTable,int iel)548 void NonLocalECPotential::markAffectedElecs(const DistanceTableData& myTable, int iel)
549 {
550   std::vector<int>& NeighborIons = ElecNeighborIons.getNeighborList(iel);
551   for (int iat = 0; iat < NumIons; iat++)
552   {
553     if (PP[iat] == nullptr)
554       continue;
555     RealType old_distance = 0.0;
556     RealType new_distance = 0.0;
557     old_distance          = myTable.getDistRow(iel)[iat];
558     new_distance          = myTable.getTempDists()[iat];
559     bool moved            = false;
560     // move out
561     if (old_distance < PP[iat]->getRmax() && new_distance >= PP[iat]->getRmax())
562     {
563       moved                           = true;
564       std::vector<int>& NeighborElecs = IonNeighborElecs.getNeighborList(iat);
565       auto iter_at                    = std::find(NeighborIons.begin(), NeighborIons.end(), iat);
566       auto iter_el                    = std::find(NeighborElecs.begin(), NeighborElecs.end(), iel);
567       *iter_at                        = NeighborIons.back();
568       *iter_el                        = NeighborElecs.back();
569       NeighborIons.pop_back();
570       NeighborElecs.pop_back();
571       elecTMAffected[iel] = true;
572     }
573     // move in
574     if (old_distance >= PP[iat]->getRmax() && new_distance < PP[iat]->getRmax())
575     {
576       moved                           = true;
577       std::vector<int>& NeighborElecs = IonNeighborElecs.getNeighborList(iat);
578       NeighborElecs.push_back(iel);
579       NeighborIons.push_back(iat);
580     }
581     // move around
582     if (moved || (old_distance < PP[iat]->getRmax() && new_distance < PP[iat]->getRmax()))
583     {
584       std::vector<int>& NeighborElecs = IonNeighborElecs.getNeighborList(iat);
585       for (int jel = 0; jel < NeighborElecs.size(); ++jel)
586         elecTMAffected[NeighborElecs[jel]] = true;
587     }
588   }
589 }
590 
addComponent(int groupID,std::unique_ptr<NonLocalECPComponent> && ppot)591 void NonLocalECPotential::addComponent(int groupID, std::unique_ptr<NonLocalECPComponent>&& ppot)
592 {
593   for (int iat = 0; iat < PP.size(); iat++)
594     if (IonConfig.GroupID[iat] == groupID)
595       PP[iat] = ppot.get();
596   PPset[groupID] = std::move(ppot);
597 }
598 
createResource(ResourceCollection & collection) const599 void NonLocalECPotential::createResource(ResourceCollection& collection) const
600 {
601   auto new_res = std::make_unique<NonLocalECPotentialMultiWalkerResource>();
602   for (int ig = 0; ig < PPset.size(); ++ig)
603     if (PPset[ig]->getVP())
604     {
605       PPset[ig]->getVP()->createResource(new_res->collection);
606       break;
607     }
608   auto resource_index = collection.addResource(std::move(new_res));
609 }
610 
acquireResource(ResourceCollection & collection)611 void NonLocalECPotential::acquireResource(ResourceCollection& collection)
612 {
613   auto res_ptr = dynamic_cast<NonLocalECPotentialMultiWalkerResource*>(collection.lendResource().release());
614   if (!res_ptr)
615     throw std::runtime_error("NonLocalECPotential::acquireResource dynamic_cast failed");
616   mw_res_.reset(res_ptr);
617 }
618 
releaseResource(ResourceCollection & collection)619 void NonLocalECPotential::releaseResource(ResourceCollection& collection)
620 {
621   collection.takebackResource(std::move(mw_res_));
622 }
623 
makeClone(ParticleSet & qp,TrialWaveFunction & psi)624 OperatorBase* NonLocalECPotential::makeClone(ParticleSet& qp, TrialWaveFunction& psi)
625 {
626   NonLocalECPotential* myclone = new NonLocalECPotential(IonConfig, qp, psi, ComputeForces, use_DLA);
627   for (int ig = 0; ig < PPset.size(); ++ig)
628     if (PPset[ig])
629       myclone->addComponent(ig, std::unique_ptr<NonLocalECPComponent>(PPset[ig]->makeClone(qp)));
630   return myclone;
631 }
632 
633 
addObservables(PropertySetType & plist,BufferType & collectables)634 void NonLocalECPotential::addObservables(PropertySetType& plist, BufferType& collectables)
635 {
636   OperatorBase::addValue(plist);
637   if (ComputeForces)
638   {
639     if (FirstForceIndex < 0)
640       FirstForceIndex = plist.size();
641     for (int iat = 0; iat < Nnuc; iat++)
642     {
643       for (int x = 0; x < OHMMS_DIM; x++)
644       {
645         std::ostringstream obsName1, obsName2;
646         obsName1 << "FNL"
647                  << "_" << iat << "_" << x;
648         plist.add(obsName1.str());
649         //        obsName2 << "FNL_Pulay" << "_" << iat << "_" << x;
650         //        plist.add(obsName2.str());
651       }
652     }
653   }
654 }
655 
registerObservables(std::vector<observable_helper * > & h5list,hid_t gid) const656 void NonLocalECPotential::registerObservables(std::vector<observable_helper*>& h5list, hid_t gid) const
657 {
658   OperatorBase::registerObservables(h5list, gid);
659   if (ComputeForces)
660   {
661     std::vector<int> ndim(2);
662     ndim[0]                 = Nnuc;
663     ndim[1]                 = OHMMS_DIM;
664     observable_helper* h5o1 = new observable_helper("FNL");
665     h5o1->set_dimensions(ndim, FirstForceIndex);
666     h5o1->open(gid);
667     h5list.push_back(h5o1);
668     //    observable_helper* h5o2 = new observable_helper("FNL_Pulay");
669     //    h5o2->set_dimensions(ndim,FirstForceIndex+Nnuc*OHMMS_DIM);
670     //    h5o2->open(gid);
671     //    h5list.push_back(h5o2);
672   }
673 }
674 
setObservables(QMCTraits::PropertySetType & plist)675 void NonLocalECPotential::setObservables(QMCTraits::PropertySetType& plist)
676 {
677   OperatorBase::setObservables(plist);
678   if (ComputeForces)
679   {
680     int index = FirstForceIndex;
681     for (int iat = 0; iat < Nnuc; iat++)
682     {
683       for (int x = 0; x < OHMMS_DIM; x++)
684       {
685         plist[index++] = forces[iat][x];
686         //    plist[index++] = PulayTerm[iat][x];
687       }
688     }
689   }
690 }
691 
692 
setParticlePropertyList(QMCTraits::PropertySetType & plist,int offset)693 void NonLocalECPotential::setParticlePropertyList(QMCTraits::PropertySetType& plist, int offset)
694 {
695   OperatorBase::setParticlePropertyList(plist, offset);
696   if (ComputeForces)
697   {
698     int index = FirstForceIndex + offset;
699     for (int iat = 0; iat < Nnuc; iat++)
700     {
701       for (int x = 0; x < OHMMS_DIM; x++)
702       {
703         plist[index++] = forces[iat][x];
704         //        plist[index++] = PulayTerm[iat][x];
705       }
706     }
707   }
708 }
709 
710 
711 } // namespace qmcplusplus
712