QMCPACK
SOECPotential.cpp
Go to the documentation of this file.
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) 2020 QMCPACK developers.
6 //
7 // File developed by: Cody A. Melton, cmelton@sandia.gov, Sandia National Laboratories
8 //
9 // File created by: Cody A. Melton, cmelton@sandia.gov, Sandia National Laboratories
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #include "Particle/DistanceTable.h"
13 #include "SOECPotential.h"
15 #include "NLPPJob.h"
16 #include <ResourceCollection.h>
17 #include <optional>
18 
19 namespace qmcplusplus
20 {
21 
23 {
25 
26  std::unique_ptr<Resource> makeClone() const override
27  {
28  return std::make_unique<SOECPotentialMultiWalkerResource>(*this);
29  }
30 
31 
32  ResourceCollection collection{"SOPPcollection"};
33 
34  //crowds worth of per particle soecp values
37 };
38 
39 /** constructor
40  *\param ionic positions
41  *\param els electronic poitions
42  *\param psi Trial wave function
43 */
45  : my_rng_(nullptr),
46  ion_config_(ions),
47  psi_(psi),
48  peln_(els),
49  elec_neighbor_ions_(els),
50  ion_neighbor_elecs_(ions),
51  use_exact_spin_(use_exact_spin)
52 {
54  twoBodyQuantumDomain(ions, els);
55  my_table_index_ = els.addTable(ions);
56  num_ions_ = ions.getTotalNum();
57  pp_.resize(num_ions_, nullptr);
59  sopp_jobs_.resize(els.groups());
60  for (size_t ig = 0; ig < els.groups(); ig++)
61  sopp_jobs_[ig].reserve(2 * els.groupsize(ig));
62 }
63 
65 
67 
69 {
70  evaluateImpl(P, false);
71  return value_;
72 }
73 
75 {
76  evaluateImpl(P, true);
77  return value_;
78 }
79 
80 void SOECPotential::evaluateImpl(ParticleSet& P, bool keep_grid)
81 {
82  value_ = 0.0;
83  if (!keep_grid)
84  for (int ipp = 0; ipp < ppset_.size(); ipp++)
85  if (ppset_[ipp])
86  ppset_[ipp]->rotateQuadratureGrid(generateRandomRotationMatrix(*my_rng_));
87 
88  const auto& ble = P.getDistTableAB(my_table_index_);
89  for (int iat = 0; iat < num_ions_; iat++)
91  for (int jel = 0; jel < P.getTotalNum(); jel++)
93 
94  for (int jel = 0; jel < P.getTotalNum(); jel++)
95  {
96  const auto& dist = ble.getDistRow(jel);
97  const auto& displ = ble.getDisplRow(jel);
98  std::vector<int>& NeighborIons = elec_neighbor_ions_.getNeighborList(jel);
99  for (int iat = 0; iat < num_ions_; iat++)
100  if (pp_[iat] != nullptr && dist[iat] < pp_[iat]->getRmax())
101  {
102  RealType pairpot = 0;
103  if (use_exact_spin_)
104  pairpot = pp_[iat]->evaluateOneExactSpinIntegration(P, iat, psi_, jel, dist[iat], -displ[iat]);
105  else
106  pairpot = pp_[iat]->evaluateOne(P, iat, psi_, jel, dist[iat], -displ[iat]);
107  value_ += pairpot;
108  NeighborIons.push_back(iat);
109  ion_neighbor_elecs_.getNeighborList(iat).push_back(jel);
110  }
111  }
112 }
113 
115  const opt_variables_type& optvars,
116  const Vector<ValueType>& dlogpsi,
117  Vector<ValueType>& dhpsioverpsi)
118 {
119  value_ = 0.0;
120  for (int ipp = 0; ipp < ppset_.size(); ipp++)
121  if (ppset_[ipp])
122  ppset_[ipp]->rotateQuadratureGrid(generateRandomRotationMatrix(*my_rng_));
123 
124  const auto& ble = P.getDistTableAB(my_table_index_);
125  for (int jel = 0; jel < P.getTotalNum(); jel++)
126  {
127  const auto& dist = ble.getDistRow(jel);
128  const auto& displ = ble.getDisplRow(jel);
129  for (int iat = 0; iat < num_ions_; iat++)
130  if (pp_[iat] != nullptr && dist[iat] < pp_[iat]->getRmax())
131  value_ += pp_[iat]->evaluateValueAndDerivatives(P, iat, psi_, jel, dist[iat], -displ[iat], optvars, dlogpsi,
132  dhpsioverpsi);
133  }
134  return value_;
135 }
136 
139  const RefVectorWithLeader<ParticleSet>& p_list) const
140 {
141  mw_evaluateImpl(o_list, wf_list, p_list, std::nullopt);
142 }
143 
146  const RefVectorWithLeader<ParticleSet>& p_list,
147  const std::vector<ListenerVector<Real>>& listeners,
148  const std::vector<ListenerVector<Real>>& listeners_ions) const
149 {
150  std::optional<ListenerOption<Real>> l_opt(std::in_place, listeners, listeners_ions);
151  mw_evaluateImpl(o_list, wf_list, p_list, l_opt);
152 }
153 
156  const RefVectorWithLeader<ParticleSet>& p_list,
157  const std::optional<ListenerOption<Real>> listeners,
158  bool keep_grid)
159 {
160  auto& O_leader = o_list.getCastedLeader<SOECPotential>();
161  ParticleSet& pset_leader = p_list.getLeader();
162  const size_t nw = o_list.size();
163 
164  for (size_t iw = 0; iw < nw; iw++)
165  {
166  auto& O = o_list.getCastedElement<SOECPotential>(iw);
167  const ParticleSet& P(p_list[iw]);
168 
169  if (!keep_grid)
170  for (size_t ipp = 0; ipp < O.ppset_.size(); ipp++)
171  if (O.ppset_[ipp])
172  O.ppset_[ipp]->rotateQuadratureGrid(generateRandomRotationMatrix(*O.my_rng_));
173 
174  //loop over all the ions
175  const auto& ble = P.getDistTableAB(O.my_table_index_);
176  //clear elec and ion neighbor lists
177  for (size_t iat = 0; iat < O.num_ions_; iat++)
178  O.ion_neighbor_elecs_.getNeighborList(iat).clear();
179  for (size_t jel = 0; jel < P.getTotalNum(); jel++)
180  O.elec_neighbor_ions_.getNeighborList(jel).clear();
181 
182  for (size_t ig = 0; ig < P.groups(); ig++) // loop over species
183  {
184  auto& joblist = O.sopp_jobs_[ig];
185  joblist.clear();
186 
187  for (size_t jel = P.first(ig); jel < P.last(ig); jel++)
188  {
189  const auto& dist = ble.getDistRow(jel);
190  const auto& displ = ble.getDisplRow(jel);
191  std::vector<int>& NeighborIons = O.elec_neighbor_ions_.getNeighborList(jel);
192  for (size_t iat = 0; iat < O.num_ions_; iat++)
193  if (O.pp_[iat] != nullptr && dist[iat] < O.pp_[iat]->getRmax())
194  {
195  NeighborIons.push_back(iat);
196  O.ion_neighbor_elecs_.getNeighborList(iat).push_back(jel);
197  joblist.emplace_back(iat, jel, dist[iat], -displ[iat]);
198  }
199  }
200  }
201  O.value_ = 0.0;
202  }
203 
204  if (listeners)
205  {
206  auto& ve_samples = O_leader.mw_res_handle_.getResource().ve_samples;
207  auto& vi_samples = O_leader.mw_res_handle_.getResource().vi_samples;
208  ve_samples.resize(nw, pset_leader.getTotalNum());
209  vi_samples.resize(nw, O_leader.ion_config_.getTotalNum());
210  }
211 
212  auto pp_component = std::find_if(O_leader.ppset_.begin(), O_leader.ppset_.end(), [](auto& ptr) { return bool(ptr); });
213  assert(pp_component != std::end(O_leader.ppset_));
214 
215  RefVector<SOECPotential> soecp_potential_list;
216  RefVectorWithLeader<SOECPComponent> soecp_component_list(**pp_component);
217  RefVectorWithLeader<ParticleSet> pset_list(pset_leader);
218  RefVectorWithLeader<TrialWaveFunction> psi_list(O_leader.psi_);
219  assert(&O_leader.psi_ == &wf_list.getLeader());
220  for (size_t iw = 0; iw < nw; iw++)
221  assert(&o_list.getCastedElement<SOECPotential>(iw).psi_ == &wf_list[iw]);
222 
224  std::vector<RealType> pairpots(nw);
225 
226  soecp_potential_list.reserve(nw);
227  soecp_component_list.reserve(nw);
228  pset_list.reserve(nw);
229  psi_list.reserve(nw);
230  batch_list.reserve(nw);
231 
232  for (size_t ig = 0; ig < pset_leader.groups(); ig++)
233  {
234  TrialWaveFunction::mw_prepareGroup(wf_list, p_list, ig);
235 
236  size_t max_num_jobs = 0;
237  for (size_t iw = 0; iw < nw; iw++)
238  {
239  const auto& O = o_list.getCastedElement<SOECPotential>(iw);
240  max_num_jobs = std::max(max_num_jobs, O.sopp_jobs_[ig].size());
241  }
242 
243  for (size_t jobid = 0; jobid < max_num_jobs; jobid++)
244  {
245  soecp_potential_list.clear();
246  soecp_component_list.clear();
247  pset_list.clear();
248  psi_list.clear();
249  batch_list.clear();
250  for (size_t iw = 0; iw < nw; iw++)
251  {
252  auto& O = o_list.getCastedElement<SOECPotential>(iw);
253  if (jobid < O.sopp_jobs_[ig].size())
254  {
255  const auto& job = O.sopp_jobs_[ig][jobid];
256  soecp_potential_list.push_back(O);
257  soecp_component_list.push_back(*O.pp_[job.ion_id]);
258  pset_list.push_back(p_list[iw]);
259  psi_list.push_back(wf_list[iw]);
260  batch_list.push_back(job);
261  }
262  }
263 
264  SOECPComponent::mw_evaluateOne(soecp_component_list, pset_list, psi_list, batch_list, pairpots,
265  O_leader.mw_res_handle_.getResource().collection);
266 
267  for (size_t j = 0; j < soecp_potential_list.size(); j++)
268  {
269  soecp_potential_list[j].get().value_ += pairpots[j];
270 
271  if (listeners)
272  {
273  auto& ve_samples = O_leader.mw_res_handle_.getResource().ve_samples;
274  auto& vi_samples = O_leader.mw_res_handle_.getResource().vi_samples;
275  int iw = j;
276  ve_samples(iw, batch_list[j].get().electron_id) += pairpots[j];
277  vi_samples(iw, batch_list[j].get().ion_id) += pairpots[j];
278  }
279  }
280  }
281  }
282 
283  if (listeners)
284  {
285  auto& ve_samples = O_leader.mw_res_handle_.getResource().ve_samples;
286  auto& vi_samples = O_leader.mw_res_handle_.getResource().vi_samples;
287  int num_electrons = pset_leader.getTotalNum();
288  for (int iw = 0; iw < nw; iw++)
289  {
290  Vector<Real> ve_sample(ve_samples.begin(iw), num_electrons);
291  Vector<Real> vi_sample(vi_samples.begin(iw), O_leader.num_ions_);
292  for (const ListenerVector<Real>& listener : listeners->electron_values)
293  listener.report(iw, O_leader.getName(), ve_sample);
294  for (const ListenerVector<Real>& listener : listeners->ion_values)
295  listener.report(iw, O_leader.getName(), vi_sample);
296  }
297  ve_samples = 0.0;
298  vi_samples = 0.0;
299  }
300 }
301 
302 std::unique_ptr<OperatorBase> SOECPotential::makeClone(ParticleSet& qp, TrialWaveFunction& psi)
303 {
304  std::unique_ptr<SOECPotential> myclone = std::make_unique<SOECPotential>(ion_config_, qp, psi, use_exact_spin_);
305  for (int ig = 0; ig < ppset_.size(); ++ig)
306  if (ppset_[ig])
307  myclone->addComponent(ig, std::unique_ptr<SOECPComponent>(ppset_[ig]->makeClone(qp)));
308  return myclone;
309 }
310 
311 void SOECPotential::addComponent(int groupID, std::unique_ptr<SOECPComponent>&& ppot)
312 {
313  for (int iat = 0; iat < pp_.size(); iat++)
314  if (ion_config_.GroupID[iat] == groupID)
315  pp_[iat] = ppot.get();
316  ppset_[groupID] = std::move(ppot);
317 }
318 
320 {
321  auto new_res = std::make_unique<SOECPotentialMultiWalkerResource>();
322  for (int ig = 0; ig < ppset_.size(); ig++)
323  if (ppset_[ig]->getVP())
324  {
325  ppset_[ig]->getVP()->createResource(new_res->collection);
326  break;
327  }
328  auto resource_index = collection.addResource(std::move(new_res));
329 }
330 
332  const RefVectorWithLeader<OperatorBase>& o_list) const
333 {
334  auto& O_leader = o_list.getCastedLeader<SOECPotential>();
336 }
337 
339  const RefVectorWithLeader<OperatorBase>& o_list) const
340 {
341  auto& O_leader = o_list.getCastedLeader<SOECPotential>();
342  collection.takebackResource(O_leader.mw_res_handle_);
343 }
344 
345 } // namespace qmcplusplus
void evaluateImpl(ParticleSet &elec, bool keep_grid=false)
void twoBodyQuantumDomain(const ParticleSet &P)
set quantum domain for two-body operator
std::vector< std::unique_ptr< SOECPComponent > > ppset_
Definition: SOECPotential.h:85
size_t addResource(std::unique_ptr< Resource > &&res, bool noprint=false)
std::unique_ptr< OperatorBase > makeClone(ParticleSet &qp, TrialWaveFunction &psi) final
void takebackResource(ResourceHandle< RS > &res_handle)
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
void mw_evaluate(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list) const override
Evaluate the contribution of this component of multiple walkers.
const DistRow & getDistRow(int iel) const
return a row of distances for a given target particle
size_t getTotalNum() const
Definition: ParticleSet.h:493
static void mw_prepareGroup(const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list, int ig)
batched version of prepareGroup
Return_t evaluateValueAndDerivatives(ParticleSet &P, const opt_variables_type &optvars, const Vector< ValueType > &dlogpsi, Vector< ValueType > &dhpsioverpsi) override
Evaluate value and derivatives wrt the optimizables.
An object of this type is a listener expecting a callback to the report function with a vector of val...
Definition: Listener.hpp:38
std::vector< std::vector< NLPPJob< RealType > > > sopp_jobs_
void releaseResource(ResourceCollection &collection, const RefVectorWithLeader< OperatorBase > &o_list) const override
Return a shared resource to a collection.
std::unique_ptr< Resource > makeClone() const override
NeighborLists ion_neighbor_elecs_
neighborlist of ions
void createResource(ResourceCollection &collection) const override
Initialize a shared resource and hand it to a collection.
int my_table_index_
index of distance table for ion-el pair
Definition: SOECPotential.h:98
Return_t evaluate(ParticleSet &P) override
Evaluate the local energy contribution of this component.
ParticleIndex GroupID
Species ID.
Definition: ParticleSet.h:77
std::vector< SOECPComponent * > pp_
Definition: SOECPotential.h:84
int getTotalNum() const
return the number of species
Definition: SpeciesSet.h:55
const DistanceTableAB & getDistTableAB(int table_ID) const
get a distance table by table_ID and dyanmic_cast to DistanceTableAB
int groups() const
return the number of groups
Definition: ParticleSet.h:511
int addTable(const ParticleSet &psrc, DTModes modes=DTModes::ALL_OFF)
add a distance table
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
ReportingFunction report
Definition: Listener.hpp:55
CASTTYPE & getCastedElement(size_t i) const
int groupsize(int igroup) const
return the size of a group
Definition: ParticleSet.h:527
class to handle a set of variables that can be modified during optimizations
Definition: VariableSet.h:49
NeighborLists elec_neighbor_ions_
neighborlist of electrons
void acquireResource(ResourceCollection &collection, const RefVectorWithLeader< OperatorBase > &o_list) const override
Acquire a shared resource from a collection.
void setEnergyDomain(EnergyDomains edomain)
Set the Energy Domain.
static void mw_evaluateImpl(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list, std::optional< ListenerOption< Real >> listeners, bool keep_grid=false)
ResourceHandle< SOECPotentialMultiWalkerResource > mw_res_handle_
int num_ions_
number of ions
Definition: SOECPotential.h:96
QMCTraits::TensorType generateRandomRotationMatrix(RandomBase< QMCTraits::FullPrecRealType > &rng)
Create a random 3D rotation matrix using a random generator.
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
FullPrecRealType Return_t
type of return value of evaluate
Definition: OperatorBase.h:64
Return_t evaluateDeterministic(ParticleSet &P) override
Evaluate the local energy contribution of this component, deterministically based on current state...
std::vector< std::reference_wrapper< T > > RefVector
Class to represent a many-body trial wave function.
Return_t value_
current value
Definition: OperatorBase.h:524
void addComponent(int groupID, std::unique_ptr< SOECPComponent > &&pp)
TrialWaveFunction & psi_
Definition: SOECPotential.h:87
std::vector< int > & getNeighborList(int source)
get the neighbor list of the source particle
Definition: NeighborLists.h:32
ResourceHandle< RS > lendResource()
RandomBase< FullPrecRealType > * my_rng_
Definition: SOECPotential.h:83
SOECPotential(ParticleSet &ions, ParticleSet &els, TrialWaveFunction &psi, bool use_exact_spin)
constructor
Convenience container for common optional element to mw_eval.._impl.
Definition: Listener.hpp:76
void resetTargetParticleSet(ParticleSet &P) override
Reset the data with the target ParticleSet.
static void mw_evaluateOne(const RefVectorWithLeader< SOECPComponent > &soecp_component_list, const RefVectorWithLeader< ParticleSet > &p_list, const RefVectorWithLeader< TrialWaveFunction > &psi_list, const RefVector< const NLPPJob< RealType >> &joblist, std::vector< RealType > &pairpots, ResourceCollection &collection)
void mw_evaluatePerParticle(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list, const std::vector< ListenerVector< Real >> &listeners, const std::vector< ListenerVector< Real >> &listeners_ions) const override