QMCPACK
CoulombPBCAA.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) 2022 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 // Peter W. Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
13 //
14 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
15 //////////////////////////////////////////////////////////////////////////////////////
16 
17 
18 #include "CoulombPBCAA.h"
19 #include <numeric>
20 #include "EwaldRef.h"
21 #include "Particle/DistanceTable.h"
23 #include <ResourceCollection.h>
26 
27 namespace qmcplusplus
28 {
30 {
32 
33  std::unique_ptr<Resource> makeClone() const override
34  {
35  return std::make_unique<CoulombPBCAAMultiWalkerResource>(*this);
36  }
37 
39 
40  /// a walkers worth of per particle coulomb AA potential values
42 
43  /// constant values per particle for coulomb AA potential
45 };
46 
47 CoulombPBCAA::CoulombPBCAA(ParticleSet& ref, bool active, bool computeForces, bool use_offload)
48  : ForceBase(ref, ref),
49  is_active(active),
50  FirstTime(true),
51  myConst(0.0),
52  ComputeForces(computeForces),
53  quasi2d(LRCoulombSingleton::this_lr_type == LRCoulombSingleton::QUASI2D),
54  Ps(ref),
55  use_offload_(active && !computeForces && use_offload),
56  d_aa_ID(ref.addTable(ref, use_offload_ ? DTModes::ALL_OFF : DTModes::NEED_FULL_TABLE_ON_HOST_AFTER_DONEPBYP)),
57  evalLR_timer_(createGlobalTimer("CoulombPBCAA::LongRange", timer_level_fine)),
58  evalSR_timer_(createGlobalTimer("CoulombPBCAA::ShortRange", timer_level_fine)),
59  offload_timer_(createGlobalTimer("CoulombPBCAA::offload", timer_level_fine))
60 {
61  if (use_offload_)
63 
64  ReportEngine PRE("CoulombPBCAA", "CoulombPBCAA");
67  PtclRefName = ref.getDistTable(d_aa_ID).getName();
68  if (ComputeForces || quasi2d)
69  {
70  ref.turnOnPerParticleSK();
71  }
72  initBreakup(ref);
73  if (ComputeForces)
74  {
75  updateSource(ref);
76  }
77 
78  if (!is_active)
79  {
80  ref.update();
81  updateSource(ref);
82 
86 
87  A = Ps.getLattice().R;
88 
89  R.resize(NumCenters);
90  Q.resize(NumCenters);
91  for (int i = 0; i < NumCenters; ++i)
92  {
93  R[i] = Ps.R[i];
94  Q[i] = Zat[i];
95  }
96 
97  RealType Vii_ref = ewaldref::ewaldEnergy(A, R, Q);
98  RealType Vdiff_per_atom = std::abs(value_ - Vii_ref) / NumCenters;
99  app_log() << "Checking ion-ion Ewald energy against reference..." << std::endl;
100  if (Vdiff_per_atom > Ps.getLattice().LR_tol)
101  {
102  std::ostringstream msg;
103  msg << std::setprecision(14);
104  msg << "in ion-ion Ewald energy exceeds " << Ps.getLattice().LR_tol << " Ha/atom tolerance." << std::endl;
105  msg << std::endl;
106  msg << " Reference ion-ion energy: " << Vii_ref << std::endl;
107  msg << " QMCPACK ion-ion energy: " << value_ << std::endl;
108  msg << " ion-ion diff : " << value_ - Vii_ref << std::endl;
109  msg << " diff/atom : " << (value_ - Vii_ref) / NumCenters << std::endl;
110  msg << " tolerance : " << Ps.getLattice().LR_tol << std::endl;
111  msg << std::endl;
112  msg << "Please try increasing the LR_dim_cutoff parameter in the <simulationcell/>" << std::endl;
113  msg << "input. Alternatively, the tolerance can be increased by setting the" << std::endl;
114  msg << "LR_tol parameter in <simulationcell/> to a value greater than " << Ps.getLattice().LR_tol << ". "
115  << std::endl;
116  msg << "If you increase the tolerance, please perform careful checks of energy" << std::endl;
117  msg << "differences to ensure this error is controlled for your application." << std::endl;
118  msg << std::endl;
119 
120  throw UniformCommunicateError(msg.str());
121  }
122  else
123  {
124  app_log() << " Check passed." << std::endl;
125  }
126  }
127  prefix_ = "F_AA";
128  app_log() << " Maximum K shell " << AA->MaxKshell << std::endl;
129  app_log() << " Number of k vectors " << AA->Fk.size() << std::endl;
130  app_log() << " Fixed Coulomb potential for " << ref.getName();
131  app_log() << "\n e-e Madelung Const. =" << std::setprecision(8) << madelung_constant_
132  << "\n Vtot =" << value_ << std::endl;
133 }
134 
135 CoulombPBCAA::~CoulombPBCAA() = default;
136 
138 {
139  addValue(plist);
140  if (ComputeForces)
141  addObservablesF(plist);
142 }
143 
145 {
146  mRealType eL(0.0), eS(0.0);
147  if (ComputeForces)
148  {
149  forces_ = 0.0;
150  eS = evalSRwithForces(s);
151  eL = evalLRwithForces(s);
152  }
153  else
154  {
155  eL = evalLR(s);
156  eS = evalSR(s);
157  }
158  new_value_ = value_ = eL + eS + myConst;
159 }
160 
162 {
163  if (is_active)
164  {
165  PtclRefName = P.getDistTable(d_aa_ID).getName();
166  AA->resetTargetParticleSet(P);
167  }
168 }
169 
170 
171 #if !defined(REMOVE_TRACEMANAGER)
173 
175 {
178  {
180  V_sample = tm.checkout_real<1>(name_, Ps);
181  if (!is_active)
182  evaluate_sp(Ps);
183  }
184 }
185 
187 {
189  delete V_sample;
190 }
191 #endif
192 
194 {
195  // turnOnParticleSK is written so it can be called again and again.
198 }
199 
200 
202 {
203  if (is_active)
204  {
205 #if !defined(REMOVE_TRACEMANAGER)
207  value_ = evaluate_sp(P);
208  else
209 #endif
210  value_ = evalLR(P) + evalSR(P) + myConst;
211  }
212  return value_;
213 }
214 
217  const RefVectorWithLeader<ParticleSet>& p_list) const
218 {
219  auto& o_leader = o_list.getCastedLeader<CoulombPBCAA>();
220  auto& p_leader = p_list.getLeader();
221  assert(this == &o_list.getLeader());
222 
223  if (!o_leader.is_active)
224  return;
225 
226  if (use_offload_)
227  {
228  if (o_leader.streaming_particles_)
229  throw std::runtime_error("Streaming particles is not supported when offloading in CoulombPBCAA");
230 
231  auto short_range_results = mw_evalSR_offload(o_list, p_list);
232 
233  for (int iw = 0; iw < o_list.size(); iw++)
234  {
235  auto& coulomb_aa = o_list.getCastedElement<CoulombPBCAA>(iw);
236  coulomb_aa.value_ = coulomb_aa.evalLR(p_list[iw]) + short_range_results[iw] + myConst;
237  }
238  }
239  else
240  OperatorBase::mw_evaluate(o_list, wf_list, p_list);
241 }
242 
245  const RefVectorWithLeader<ParticleSet>& p_list,
246  const std::vector<ListenerVector<RealType>>& listeners,
247  const std::vector<ListenerVector<RealType>>& listeners_ions) const
248 {
249  auto& o_leader = o_list.getCastedLeader<CoulombPBCAA>();
250  auto& p_leader = p_list.getLeader();
251  assert(this == &o_list.getLeader());
252 
253  if (!o_leader.is_active)
254  return;
255 
256  auto num_centers = p_leader.getTotalNum();
257  auto name(o_leader.getName());
258  Vector<RealType>& v_sample = o_leader.mw_res_handle_.getResource().v_sample;
259  const auto& pp_consts = o_leader.mw_res_handle_.getResource().pp_consts;
260  auto num_species = p_leader.getSpeciesSet().getTotalNum();
261  v_sample.resize(num_centers);
262  // This lambda is mostly about getting a handle on what is being touched by the per particle evaluation.
263  auto evaluate_walker = [num_species, num_centers, name, &v_sample,
264  &pp_consts](const int walker_index, const CoulombPBCAA& cpbcaa, const ParticleSet& pset,
265  const std::vector<ListenerVector<RealType>>& listeners) -> RealType {
266  mRealType Vsr = 0.0;
267  mRealType Vlr = 0.0;
268  mRealType Vc = cpbcaa.myConst;
269  std::fill(v_sample.begin(), v_sample.end(), 0.0);
270  {
271  //SR
272  const auto& d_aa(pset.getDistTableAA(cpbcaa.d_aa_ID));
273  RealType z;
274  for (int ipart = 1; ipart < num_centers; ipart++)
275  {
276  z = .5 * cpbcaa.Zat[ipart];
277  const auto& dist = d_aa.getDistRow(ipart);
278  for (int jpart = 0; jpart < ipart; ++jpart)
279  {
280  RealType pairpot = z * cpbcaa.Zat[jpart] * cpbcaa.rVs->splint(dist[jpart]) / dist[jpart];
281  v_sample[ipart] += pairpot;
282  v_sample[jpart] += pairpot;
283  Vsr += pairpot;
284  }
285  }
286  Vsr *= 2.0;
287  }
288  {
289  //LR
290  const StructFact& PtclRhoK(pset.getSK());
291  if (PtclRhoK.SuperCellEnum == SUPERCELL_SLAB)
292  {
293  APP_ABORT("CoulombPBCAA::evaluate_sp single particle traces have not been implemented for slab geometry");
294  }
295  else
296  {
297  assert(PtclRhoK.isStorePerParticle()); // ensure this so we know eikr_r has been allocated
298  //jtk mark: needs optimizations
299  RealType v1; //single particle energy
300  RealType z;
301  for (int i = 0; i < num_centers; i++)
302  {
303  z = .5 * cpbcaa.Zat[i];
304  v1 = 0.0;
305  for (int s = 0; s < num_species; ++s)
306  v1 += z * cpbcaa.Zspec[s] *
307  cpbcaa.AA->evaluate(pset.getSimulationCell().getKLists().kshell, PtclRhoK.rhok_r[s], PtclRhoK.rhok_i[s],
308  PtclRhoK.eikr_r[i], PtclRhoK.eikr_i[i]);
309  v_sample[i] += v1;
310  Vlr += v1;
311  }
312  }
313  }
314  for (int i = 0; i < v_sample.size(); ++i)
315  v_sample[i] += pp_consts[i];
316  RealType value = Vsr + Vlr + Vc;
317 
318  for (const ListenerVector<RealType>& listener : listeners)
319  listener.report(walker_index, name, v_sample);
320  return value;
321  };
322 
323  for (int iw = 0; iw < o_list.size(); iw++)
324  {
325  auto& coulomb_aa = o_list.getCastedElement<CoulombPBCAA>(iw);
326  coulomb_aa.value_ = evaluate_walker(iw, coulomb_aa, p_list[iw], listeners);
327  }
328 }
329 
331  ParticleSet& ions,
332  TrialWaveFunction& psi,
333  ParticleSet::ParticlePos& hf_terms,
334  ParticleSet::ParticlePos& pulay_terms)
335 {
336  if (ComputeForces and !is_active)
337  hf_terms -= forces_;
338  //No pulay term.
339  return value_;
340 }
341 
342 #if !defined(REMOVE_TRACEMANAGER)
344 {
345  mRealType Vsr = 0.0;
346  mRealType Vlr = 0.0;
347  mRealType& Vc = myConst;
348  Array<RealType, 1>& V_samp = *V_sample;
349  V_samp = 0.0;
350  {
351  //SR
352  const auto& d_aa(P.getDistTableAA(d_aa_ID));
353  RealType z;
354  for (int ipart = 1; ipart < NumCenters; ipart++)
355  {
356  z = .5 * Zat[ipart];
357  const auto& dist = d_aa.getDistRow(ipart);
358  for (int jpart = 0; jpart < ipart; ++jpart)
359  {
360  RealType pairpot = z * Zat[jpart] * rVs->splint(dist[jpart]) / dist[jpart];
361  V_samp(ipart) += pairpot;
362  V_samp(jpart) += pairpot;
363  Vsr += pairpot;
364  }
365  }
366  Vsr *= 2.0;
367  }
368  {
369  //LR
370  const StructFact& PtclRhoK(P.getSK());
371  if (PtclRhoK.SuperCellEnum == SUPERCELL_SLAB)
372  {
373  APP_ABORT("CoulombPBCAA::evaluate_sp single particle traces have not been implemented for slab geometry");
374  }
375  else
376  {
377  assert(PtclRhoK.isStorePerParticle()); // ensure this so we know eikr_r has been allocated
378  //jtk mark: needs optimizations
379  RealType v1; //single particle energy
380  RealType z;
381  for (int i = 0; i < NumCenters; i++)
382  {
383  z = .5 * Zat[i];
384  v1 = 0.0;
385  for (int s = 0; s < NumSpecies; ++s)
386  v1 += z * Zspec[s] *
387  AA->evaluate(P.getSimulationCell().getKLists().kshell, PtclRhoK.rhok_r[s], PtclRhoK.rhok_i[s],
388  PtclRhoK.eikr_r[i], PtclRhoK.eikr_i[i]);
389  V_samp(i) += v1;
390  Vlr += v1;
391  }
392  }
393  }
394  for (int i = 0; i < V_samp.size(); ++i)
395  V_samp(i) += V_const(i);
396  value_ = Vsr + Vlr + Vc;
397 #if defined(TRACE_CHECK)
398  RealType Vlrnow = evalLR(P);
399  RealType Vsrnow = evalSR(P);
400  RealType Vcnow = myConst;
401  RealType Vnow = Vlrnow + Vsrnow + Vcnow;
402  RealType Vsum = V_samp.sum();
403  RealType Vcsum = V_const.sum();
404  if (std::abs(Vsum - Vnow) > TraceManager::trace_tol)
405  {
406  app_log() << "accumtest: CoulombPBCAA::evaluate()" << std::endl;
407  app_log() << "accumtest: tot:" << Vnow << std::endl;
408  app_log() << "accumtest: sum:" << Vsum << std::endl;
409  APP_ABORT("Trace check failed");
410  }
411  if (std::abs(Vcsum - Vcnow) > TraceManager::trace_tol)
412  {
413  app_log() << "accumtest: CoulombPBCAA::evalConsts()" << std::endl;
414  app_log() << "accumtest: tot:" << Vcnow << std::endl;
415  app_log() << "accumtest: sum:" << Vcsum << std::endl;
416  APP_ABORT("Trace check failed");
417  }
418 #endif
419  return value_;
420 }
421 #endif
422 
424 {
425  //SpeciesSet& tspecies(PtclRef->getSpeciesSet());
426  SpeciesSet& tspecies(P.getSpeciesSet());
427  //Things that don't change with lattice are done here instead of InitBreakup()
428  ChargeAttribIndx = tspecies.addAttribute("charge");
429  NumCenters = P.getTotalNum();
430  NumSpecies = tspecies.TotalNum;
431 
432 #if !defined(REMOVE_TRACEMANAGER)
434 #endif
435 
436  Zspec.resize(NumSpecies);
437  NofSpecies.resize(NumSpecies);
438  for (int spec = 0; spec < NumSpecies; spec++)
439  {
440  Zspec[spec] = tspecies(ChargeAttribIndx, spec);
441  NofSpecies[spec] = P.groupsize(spec);
442  }
443 
444  SpeciesID.resize(NumCenters);
445  Zat.resize(NumCenters);
446  Zat_offload = std::make_shared<Vector<RealType, OffloadPinnedAllocator<RealType>>>(NumCenters);
447  auto& Zat_ref(*Zat_offload);
448  for (int iat = 0; iat < NumCenters; iat++)
449  {
450  SpeciesID[iat] = P.GroupID[iat];
451  Zat[iat] = Zspec[P.GroupID[iat]];
452  Zat_ref[iat] = Zat[iat];
453  }
454  Zat_ref.updateTo();
455 
457  //AA->initBreakup(*PtclRef);
458  myConst = evalConsts();
459  myRcut = AA->get_rc(); //Basis.get_rc();
460 
461  auto myGrid = LinearGrid<RealType>();
462  int ng = P.getLattice().num_ewald_grid_points;
463  app_log() << " CoulombPBCAA::initBreakup\n Setting a linear grid=[0,"
464  << myRcut << ") number of grid points =" << ng << std::endl;
465  myGrid.set(0, myRcut, ng);
466 
467  if (rVs == nullptr)
469 
470  rVs_offload = std::make_shared<const OffloadSpline>(*rVs);
471 
472  if (ComputeForces)
473  {
475  if (rVsforce == nullptr)
476  {
478  }
479  }
480 }
481 
482 
484 {
485  // const StructFact& PtclRhoK(P.getSK());
486  std::vector<TinyVector<RealType, DIM>> grad(P.getTotalNum());
487  for (int spec2 = 0; spec2 < NumSpecies; spec2++)
488  {
489  RealType Z2 = Zspec[spec2];
490  for (int iat = 0; iat < grad.size(); iat++)
491  grad[iat] = TinyVector<RealType, DIM>(0.0);
492  //AA->evaluateGrad(P, P, spec2, Zat, grad);
493  dAA->evaluateGrad(P, P, spec2, Zat, grad);
494  for (int iat = 0; iat < grad.size(); iat++)
495  forces_[iat] += Z2 * grad[iat];
496  } //spec2
497  return evalLR(P);
498 }
499 
500 
502 {
503  const auto& d_aa(P.getDistTableAA(d_aa_ID));
504  mRealType SR = 0.0;
505  for (size_t ipart = 1; ipart < (NumCenters / 2 + 1); ipart++)
506  {
507  mRealType esum = 0.0;
508  const auto& dist = d_aa.getDistRow(ipart);
509  const auto& dr = d_aa.getDisplRow(ipart);
510  for (size_t j = 0; j < ipart; ++j)
511  {
512  RealType V, rV, d_rV_dr, d2_rV_dr2;
513  RealType rinv = 1.0 / dist[j];
514  rV = rVsforce->splint(dist[j], d_rV_dr, d2_rV_dr2);
515  V = rV * rinv;
516  esum += Zat[j] * rVs->splint(dist[j]) * rinv;
517 
518  PosType grad = Zat[j] * Zat[ipart] * (d_rV_dr - V) * rinv * rinv * dr[j];
519  forces_[ipart] += grad;
520  forces_[j] -= grad;
521  }
522  SR += Zat[ipart] * esum;
523 
524  const size_t ipart_reverse = NumCenters - ipart;
525  if (ipart == ipart_reverse)
526  continue;
527 
528  esum = 0.0;
529  const auto& dist2 = d_aa.getDistRow(ipart_reverse);
530  const auto& dr2 = d_aa.getDisplRow(ipart_reverse);
531  for (size_t j = 0; j < ipart_reverse; ++j)
532  {
533  RealType V, rV, d_rV_dr, d2_rV_dr2;
534  RealType rinv = 1.0 / dist2[j];
535  rV = rVsforce->splint(dist2[j], d_rV_dr, d2_rV_dr2);
536  V = rV * rinv;
537  esum += Zat[j] * rVs->splint(dist2[j]) * rinv;
538 
539  PosType grad = Zat[j] * Zat[ipart_reverse] * (d_rV_dr - V) * rinv * rinv * dr2[j];
540  forces_[ipart_reverse] += grad;
541  forces_[j] -= grad;
542  }
543  SR += Zat[ipart_reverse] * esum;
544  }
545  return SR;
546 }
547 
548 
549 /** evaluate the constant term that does not depend on the position
550  *
551  * \htmlonly
552  * <ul>
553  * <li> self-energy: \f$ -\frac{1}{2}\sum_{i} v_l(r=0) q_i^2 = -\frac{1}{2}v_l(r=0) \sum_{alpha} N^{\alpha} q^{\alpha}^2\f$
554  * <li> background term \f$ V_{bg} = -\frac{1}{2}\sum_{\alpha}\sum_{\beta} N^{\alpha}q^{\alpha}N^{\beta}q^{\beta} v_s(k=0)\f$
555  * </ul>
556  * \endhtmlonly
557  * CoulombPBCABTemp contributes additional background term which completes the background term
558  * note this calculates the per particle consts even if trace manager is removed.
559  */
561 {
562  mRealType Consts = 0.0; // constant term
563  mRealType v1; //single particle energy
564  mRealType vl_r0 = AA->evaluateLR_r0();
565  mRealType vs_k0 = AA->evaluateSR_k0();
566 
567  if (quasi2d) // background term has z dependence
568  { // just evaluate the Madelung term
569  for (int ispec = 1; ispec < NumSpecies; ispec++)
570  if (Zspec[ispec] != Zspec[0])
571  throw std::runtime_error("quasi2d assumes same charge");
572  if (report)
573  {
574  app_log() << " vlr(r->0) = " << vl_r0 << std::endl;
575  app_log() << " 1/V vsr_k0 = " << vs_k0 << std::endl;
576  }
577  // make sure we can ignore the short-range Madelung sum
578  mRealType Rws = Ps.getLattice().WignerSeitzRadius;
579  mRealType rvsr_at_image = Rws * AA->evaluate(Rws, 1.0 / Rws);
580  if (rvsr_at_image > 1e-6)
581  {
582  std::ostringstream msg;
583  msg << std::setprecision(14);
584  msg << "Ewald alpha = " << rvsr_at_image << " is too small" << std::endl;
585  msg << "Short-range potential r*vsr(r) = " << rvsr_at_image << " at image radius r=" << Rws << std::endl;
586  throw std::runtime_error(msg.str());
587  }
588  // perform long-range Madelung sum
589  const StructFact& PtclRhoK(Ps.getSK());
590  v1 = AA->evaluate_slab(0, Ps.getSimulationCell().getKLists().kshell, PtclRhoK.eikr_r[0], PtclRhoK.eikr_i[0],
591  PtclRhoK.eikr_r[0], PtclRhoK.eikr_i[0]);
592  if (report)
593  app_log() << " LR Madelung = " << v1 << std::endl;
594  madelung_constant_ = 0.5 * (v1 - vl_r0);
595  Consts = NumCenters * madelung_constant_;
596  }
597  else // group background term together with Madelung vsr_k0 part
598  {
599 #if !defined(REMOVE_TRACEMANAGER)
600  V_const = 0.0;
601 #endif
602  for (int ipart = 0; ipart < NumCenters; ipart++)
603  {
604  v1 = -.5 * Zat[ipart] * Zat[ipart] * vl_r0;
605 #if !defined(REMOVE_TRACEMANAGER)
606  V_const(ipart) += v1;
607 #endif
608  Consts += v1;
609  }
610  if (report)
611  app_log() << " PBCAA self-interaction term " << Consts << std::endl;
612  //Compute Madelung constant
613  madelung_constant_ = 0.0;
614  for (int i = 0; i < AA->Fk.size(); i++)
615  madelung_constant_ += AA->Fk[i];
616  madelung_constant_ = 0.5 * (madelung_constant_ - vl_r0 - vs_k0);
617  for (int ipart = 0; ipart < NumCenters; ipart++)
618  {
619  v1 = 0.0;
620  for (int spec = 0; spec < NumSpecies; spec++)
621  v1 += NofSpecies[spec] * Zspec[spec];
622  v1 *= -.5 * Zat[ipart] * vs_k0;
623 #if !defined(REMOVE_TRACEMANAGER)
624  V_const(ipart) += v1;
625 #endif
626  Consts += v1;
627  }
628  if (report)
629  app_log() << " PBCAA total constant " << Consts << std::endl;
630  }
631  return Consts;
632 }
633 
634 
636 {
637  ScopedTimer local_timer(evalSR_timer_);
638  const auto& d_aa(P.getDistTableAA(d_aa_ID));
639  mRealType SR = 0.0;
640 #pragma omp parallel for reduction(+ : SR)
641  for (size_t ipart = 1; ipart < (NumCenters / 2 + 1); ipart++)
642  {
643  mRealType esum = 0.0;
644  const auto& dist = d_aa.getDistRow(ipart);
645  for (size_t j = 0; j < ipart; ++j)
646  esum += Zat[j] * rVs->splint(dist[j]) / dist[j];
647  SR += Zat[ipart] * esum;
648 
649  const size_t ipart_reverse = NumCenters - ipart;
650  if (ipart == ipart_reverse)
651  continue;
652 
653  esum = 0.0;
654  const auto& dist2 = d_aa.getDistRow(ipart_reverse);
655  for (size_t j = 0; j < ipart_reverse; ++j)
656  esum += Zat[j] * rVs->splint(dist2[j]) / dist2[j];
657  SR += Zat[ipart_reverse] * esum;
658  }
659  return SR;
660 }
661 
662 std::vector<CoulombPBCAA::Return_t> CoulombPBCAA::mw_evalSR_offload(const RefVectorWithLeader<OperatorBase>& o_list,
663  const RefVectorWithLeader<ParticleSet>& p_list)
664 {
665  const size_t nw = o_list.size();
666  auto& p_leader = p_list.getLeader();
667  auto& caa_leader = o_list.getCastedLeader<CoulombPBCAA>();
668  ScopedTimer local_timer(caa_leader.evalSR_timer_);
669 
670  RefVectorWithLeader<DistanceTable> dt_list(p_leader.getDistTable(caa_leader.d_aa_ID));
671  dt_list.reserve(p_list.size());
672  for (ParticleSet& p : p_list)
673  dt_list.push_back(p.getDistTable(caa_leader.d_aa_ID));
674 
675  auto& dtaa_leader = dynamic_cast<DistanceTableAA&>(p_leader.getDistTable(caa_leader.d_aa_ID));
676 
677  const size_t chunk_size = dtaa_leader.get_num_particls_stored();
678  if (chunk_size == 0)
679  throw std::runtime_error("bug dtaa_leader.get_num_particls_stored() == 0");
680 
681  auto& values_offload = caa_leader.mw_res_handle_.getResource().values_offload;
682  const size_t total_num = p_leader.getTotalNum();
683  const size_t total_num_half = (total_num + 1) / 2;
684  const size_t num_padded = getAlignedSize<RealType>(total_num);
685  const size_t num_chunks = (total_num_half + chunk_size - 1) / chunk_size;
686 
687  const auto m_Y = caa_leader.rVs_offload->get_m_Y().data();
688  const auto m_Y2 = caa_leader.rVs_offload->get_m_Y2().data();
689  const auto first_deriv = caa_leader.rVs_offload->get_first_deriv();
690  const auto const_value = caa_leader.rVs_offload->get_const_value();
691  const auto r_min = caa_leader.rVs_offload->get_r_min();
692  const auto r_max = caa_leader.rVs_offload->get_r_max();
693  const auto X = caa_leader.rVs_offload->get_X().data();
694  const auto delta_inv = caa_leader.rVs_offload->get_delta_inv();
695  const auto Zat = caa_leader.Zat_offload->data();
696 
697  {
698  values_offload.resize(nw);
699  std::fill_n(values_offload.data(), nw, 0);
700  auto value_ptr = values_offload.data();
701  values_offload.updateTo();
702  for (size_t ichunk = 0; ichunk < num_chunks; ichunk++)
703  {
704  const size_t first = ichunk * chunk_size;
705  const size_t last = std::min(first + chunk_size, total_num_half);
706  const size_t this_chunk_size = last - first;
707 
708  auto* mw_dist = dtaa_leader.mw_evalDistsInRange(dt_list, p_list, first, last);
709 
710  ScopedTimer offload_scope(caa_leader.offload_timer_);
711 
712  PRAGMA_OFFLOAD("omp target teams distribute num_teams(nw)")
713  for (uint32_t iw = 0; iw < nw; iw++)
714  {
715  mRealType SR = 0.0;
716  PRAGMA_OFFLOAD("omp parallel for reduction(+ : SR)")
717  for (uint32_t jcol = 0; jcol < total_num; jcol++)
718  for (uint32_t irow = first; irow < last; irow++)
719  {
720  const RealType dist = mw_dist[num_padded * (irow - first + iw * this_chunk_size) + jcol];
721  if (irow == jcol || (irow * 2 + 1 == total_num && jcol > irow))
722  continue;
723 
724  const size_t i = irow > jcol ? irow : total_num - 1 - irow;
725  const size_t j = irow > jcol ? jcol : total_num - 1 - jcol;
726 
727  SR += Zat[i] * Zat[j] *
728  OffloadSpline::splint(r_min, r_max, X, delta_inv, m_Y, m_Y2, first_deriv, const_value, dist) / dist;
729  }
730  value_ptr[iw] += SR;
731  }
732  }
733 
734  values_offload.updateFrom();
735  }
736  std::vector<Return_t> values(nw);
737  for (int iw = 0; iw < nw; iw++)
738  values[iw] = values_offload[iw];
739  return values;
740 }
741 
743 {
744  ScopedTimer local_timer(evalLR_timer_);
745  mRealType res = 0.0;
746  const StructFact& PtclRhoK(P.getSK());
747  if (quasi2d)
748  {
749  const auto& d_aa(P.getDistTableAA(d_aa_ID));
750  // need 1/2 \sum_{i,j} v_E(r_i - r_j)
751  //distance table handles jat<iat
752  for (int iat = 1; iat < NumCenters; ++iat)
753  {
754  mRealType u = 0;
755  const int slab_dir = OHMMS_DIM - 1;
756  const auto& dr = d_aa.getDisplRow(iat);
757  for (int jat = 0; jat < iat; ++jat)
758  {
759  const RealType z = std::abs(dr[jat][slab_dir]);
760  u += Zat[jat] *
761  AA->evaluate_slab(z, P.getSimulationCell().getKLists().kshell, PtclRhoK.eikr_r[iat], PtclRhoK.eikr_i[iat],
762  PtclRhoK.eikr_r[jat], PtclRhoK.eikr_i[jat]);
763  }
764  res += Zat[iat] * u;
765  }
766  }
767  else
768  {
769  for (int spec1 = 0; spec1 < NumSpecies; spec1++)
770  {
771  mRealType Z1 = Zspec[spec1];
772  for (int spec2 = spec1; spec2 < NumSpecies; spec2++)
773  {
774  mRealType temp = AA->evaluate(P.getSimulationCell().getKLists().kshell, PtclRhoK.rhok_r[spec1],
775  PtclRhoK.rhok_i[spec1], PtclRhoK.rhok_r[spec2], PtclRhoK.rhok_i[spec2]);
776  if (spec2 == spec1)
777  temp *= 0.5;
778  res += Z1 * Zspec[spec2] * temp;
779  } //spec2
780  } //spec1
781  }
782  return res;
783 }
784 
785 void CoulombPBCAA::evalPerParticleConsts(Vector<RealType>& pp_consts) const
786 {
787  mRealType v1; //single particle energy
788  mRealType vl_r0 = AA->evaluateLR_r0();
789  mRealType vs_k0 = AA->evaluateSR_k0();
790 
791  if (quasi2d)
792  throw std::runtime_error("Batched per particle eval is not supported for quasi2d");
793  else
794  {
795  pp_consts.resize(NumCenters, 0.0);
796  for (int ipart = 0; ipart < NumCenters; ipart++)
797  {
798  v1 = -.5 * Zat[ipart] * Zat[ipart] * vl_r0;
799  pp_consts[ipart] += v1;
800  }
801  for (int ipart = 0; ipart < NumCenters; ipart++)
802  {
803  v1 = 0.0;
804  for (int spec = 0; spec < NumSpecies; spec++)
805  v1 += NofSpecies[spec] * Zspec[spec];
806  v1 *= -.5 * Zat[ipart] * vs_k0;
807  pp_consts[ipart] += v1;
808  }
809  }
810 }
811 
812 void CoulombPBCAA::createResource(ResourceCollection& collection) const
813 {
814  auto new_res = std::make_unique<CoulombPBCAAMultiWalkerResource>();
815  if (hasListener())
816  evalPerParticleConsts(new_res->pp_consts);
817  auto resource_index = collection.addResource(std::move(new_res));
818 }
819 
820 void CoulombPBCAA::acquireResource(ResourceCollection& collection,
821  const RefVectorWithLeader<OperatorBase>& o_list) const
822 {
823  auto& o_leader = o_list.getCastedLeader<CoulombPBCAA>();
824  o_leader.mw_res_handle_ = collection.lendResource<CoulombPBCAAMultiWalkerResource>();
825 }
826 
827 void CoulombPBCAA::releaseResource(ResourceCollection& collection,
828  const RefVectorWithLeader<OperatorBase>& o_list) const
829 {
830  auto& o_leader = o_list.getCastedLeader<CoulombPBCAA>();
831  collection.takebackResource(o_leader.mw_res_handle_);
832 }
833 
834 std::unique_ptr<OperatorBase> CoulombPBCAA::makeClone(ParticleSet& qp, TrialWaveFunction& psi)
835 {
836  return std::make_unique<CoulombPBCAA>(*this);
837 }
838 } // namespace qmcplusplus
bool hasListener() const noexcept
virtual void mw_evaluate(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list) const
Evaluate the contribution of this component of multiple walkers.
void twoBodyQuantumDomain(const ParticleSet &P)
set quantum domain for two-body operator
static std::unique_ptr< LRHandlerType > getDerivHandler(ParticleSet &ref)
This returns a force/stress optimized LR handler. If non existent, it creates one.
void resetTargetParticleSet(ParticleSet &P) override
Reset the data with the target ParticleSet.
Vector< RealType > v_sample
a walkers worth of per particle coulomb AA potential values
const std::string & getName() const
return the name
Calculates the AA Coulomb potential using PBCs.
Definition: CoulombPBCAA.h:38
Return_t evaluateWithIonDerivs(ParticleSet &P, ParticleSet &ions, TrialWaveFunction &psi, ParticleSet::ParticlePos &hf_terms, ParticleSet::ParticlePos &pulay_terms) override
Evaluate contribution to local energy and derivatives w.r.t ionic coordinates from OperatorBase...
const bool use_offload_
if true use offload
Definition: CoulombPBCAA.h:191
void set(T ri, T rf, int n) override
Set the grid given the parameters.
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
const DistanceTableAA & getDistTableAA(int table_ID) const
get a distance table by table_ID and dyanmic_cast to DistanceTableAA
std::shared_ptr< Vector< RealType, OffloadPinnedAllocator< RealType > > > Zat_offload
Definition: CoulombPBCAA.h:70
const int d_aa_ID
AA table ID.
Definition: CoulombPBCAA.h:193
Vector< CoulombPBCAA::Return_t, OffloadPinnedAllocator< CoulombPBCAA::Return_t > > values_offload
bool streaming_array(const std::string &name)
Definition: TraceManager.h:249
NewTimer & evalLR_timer_
Timer for long range.
Definition: CoulombPBCAA.h:195
static std::unique_ptr< RadFunctorType > createSpline4RbyVs(const LRHandlerType *aLR, mRealType rcut, const GridType &agrid)
create a linear spline function
ParticleSet::ParticlePos forces_
Definition: ForceBase.h:87
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
size_t getTotalNum() const
Definition: ParticleSet.h:493
void fill_n(T *x, size_t count, const T &value)
Definition: OMPstd.hpp:21
Array< TraceReal, 1 > V_const
Definition: CoulombPBCAA.h:86
std::ostream & app_log()
Definition: OutputManager.h:65
void acquireResource(ResourceCollection &collection, const RefVectorWithLeader< OperatorBase > &o_list) const override
acquire a shared resource from a collection
void releaseResource(ResourceCollection &collection, const RefVectorWithLeader< OperatorBase > &o_list) const override
return a shared resource to a collection
EwaldHandler3D::mRealType mRealType
NewTimer & evalSR_timer_
Timer for long range.
Definition: CoulombPBCAA.h:197
std::shared_ptr< const RadFunctorType > rVs
energy-optimized short range pair potential
Definition: CoulombPBCAA.h:49
std::vector< real_t > ChargeArray
Type for lists of particle charges.
Definition: EwaldRef.h:54
Computes Ewald sums of the potential energy to a given tolerance for arbitrary collections of charges...
Return_t evalSR(ParticleSet &P)
void updateSource(ParticleSet &s) override
Update data associated with a particleset.
void addObservablesF(QMCTraits::PropertySetType &plist)
Definition: ForceBase.cpp:47
An object of this type is a listener expecting a callback to the report function with a vector of val...
Definition: Listener.hpp:38
ScopeGuard< NewTimer > ScopedTimer
Definition: NewTimer.h:257
Vectorized record engine for scalar properties.
std::vector< int > SpeciesID
Definition: CoulombPBCAA.h:73
real_t ewaldEnergy(const RealMat &a, const PosArray &R, const ChargeArray &Q, real_t tol)
Compute the total Ewald potential energy for a collection of charges.
Definition: EwaldRef.cpp:337
LRHandlerType::mRealType mRealType
Definition: CoulombPBCAA.h:43
Return_t evalLR(ParticleSet &P)
std::shared_ptr< const LRHandlerType > dAA
force-optimized long range handle
Definition: CoulombPBCAA.h:53
bool ComputeForces
Flag for whether to compute forces or not.
Definition: CoulombPBCAA.h:79
void update(bool skipSK=false)
update the internal data
Attaches a unit to a Vector for IO.
Calculates the structure-factor for a particle set.
Definition: StructFact.h:39
std::string prefix_
Definition: ForceBase.h:96
void resize(const std::array< SIZET, D > &dims)
Resize the container.
Definition: OhmmsArray.h:65
std::shared_ptr< const RadFunctorType > rVsforce
force-optimized short range pair potential
Definition: CoulombPBCAA.h:55
#define OHMMS_DIM
Definition: config.h:64
std::vector< RealVec > PosArray
Type for lists of particle positions.
Definition: EwaldRef.h:52
TraceRequest request_
whether traces are being collected
Definition: OperatorBase.h:531
T min(T a, T b)
ParticleIndex GroupID
Species ID.
Definition: ParticleSet.h:77
Return_t evalSRwithForces(ParticleSet &P)
for(int i=0;i< size_test;++i) CHECK(Approx(gauss_random_vals[offset_for_rs+i])
void turnOnPerParticleSK()
Turn on per particle storage in Structure Factor.
const auto & getSimulationCell() const
Definition: ParticleSet.h:250
std::string name_
name of this object
Definition: OperatorBase.h:527
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
DynamicCoordinateKind getKind() const
RealType myRcut
cutoff radius of the short-range part
Definition: CoulombPBCAA.h:66
std::shared_ptr< const OffloadSpline > rVs_offload
the same as rVs but can be used inside OpenMP offload regions
Definition: CoulombPBCAA.h:51
Return_t new_value_
a new value for a proposed move
Definition: OperatorBase.h:538
void createResource(ResourceCollection &collection) const override
initialize a shared resource and hand it to a collection
Tensor<T,D> class for D by D tensor.
Definition: OhmmsTinyMeta.h:32
Final class and should not be derived.
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.
This a subclass for runtime errors that will occur on all ranks.
declaration of ProgressReportEngine
void initBreakup(ParticleSet &P)
constructor code factored out
Return_t evalConsts(bool report=true)
CASTTYPE & getCastedElement(size_t i) const
NewTimer & createGlobalTimer(const std::string &myname, timer_levels mylevel)
int groupsize(int igroup) const
return the size of a group
Definition: ParticleSet.h:527
std::unique_ptr< Resource > makeClone() const override
T splint(T r) const
compute the function value at r
size_t size() const
Definition: OhmmsArray.h:57
ParticlePos R
Position.
Definition: ParticleSet.h:79
#define APP_ABORT(msg)
Widely used but deprecated fatal error macros from legacy code.
Definition: AppAbort.h:27
void checkoutParticleQuantities(TraceManager &tm) override
void setEnergyDomain(EnergyDomains edomain)
Set the Energy Domain.
const StructFact & getSK() const
return Structure Factor
Definition: ParticleSet.h:216
void addValue(PropertySetType &plist)
named values to the property list
auto & getDistTable(int table_ID) const
get a distance table by table_ID
Definition: ParticleSet.h:190
const bool quasi2d
Flag for whether to use quasi-2D Ewald.
Definition: CoulombPBCAA.h:81
Vector< RealType > pp_consts
constant values per particle for coulomb AA potential
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
Array< TraceReal, D > * checkout_real(const std::string &name, int n1=1, int n2=0, int n3=0, int n4=0)
FullPrecRealType Return_t
type of return value of evaluate
Definition: OperatorBase.h:64
Type_t sum() const
Definition: OhmmsArray.h:214
const DynamicCoordinates & getCoordinates() const
Definition: ParticleSet.h:246
QMCTraits::RealType RealType
std::shared_ptr< LRHandlerType > AA
energy-optimized long range handle. Should be const LRHandlerType eventually
Definition: CoulombPBCAA.h:47
Class to represent a many-body trial wave function.
void addObservables(PropertySetType &plist, BufferType &collectables) override
named values to the property list Default implementaton uses addValue(plist_)
Return_t value_
current value
Definition: OperatorBase.h:524
std::vector< RealType > Zspec
Definition: CoulombPBCAA.h:69
std::vector< RealType > Zat
Definition: CoulombPBCAA.h:69
static std::unique_ptr< LRHandlerType > getHandler(ParticleSet &ref)
This returns an energy optimized LR handler. If non existent, it creates one.
void contribute_array(const std::string &name, bool default_quantity=false)
Definition: TraceManager.h:198
Array< TraceReal, 1 > * V_sample
Definition: CoulombPBCAA.h:85
virtual void informOfPerParticleListener()
Definition: OperatorBase.h:471
const auto & getLattice() const
Definition: ParticleSet.h:251
static std::vector< Return_t > mw_evalSR_offload(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< ParticleSet > &p_list)
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
void mw_evaluatePerParticle(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list, const std::vector< ListenerVector< RealType >> &listeners, const std::vector< ListenerVector< RealType >> &ion_listeners) const override
Evaluate the contribution of this component of multiple walkers per particle reporting to registered ...
void contributeParticleQuantities() override
Return_t evalLRwithForces(ParticleSet &P)
void informOfPerParticleListener() override
Inform objects associated with this operator of per particle listeners.
whether full table needs to be ready at anytime or not after donePbyP Optimization can be implemented...
std::vector< int > NofSpecies
Definition: CoulombPBCAA.h:72
Return_t evaluate_sp(ParticleSet &P)
CoulombPBCAA(ParticleSet &ref, bool active, bool computeForces, bool use_offload)
constructor
Return_t evaluate(ParticleSet &P) override
Evaluate the local energy contribution of this component.
std::unique_ptr< OperatorBase > makeClone(ParticleSet &qp, TrialWaveFunction &psi) override
void evalPerParticleConsts(Vector< RealType > &pp_consts) const
Compute the const part of the per particle coulomb self interaction potential.
void deleteParticleQuantities() override