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