QMCPACK
CoulombPBCAB.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 #include <ResourceCollection.h>
18 #include "CoulombPBCAB.h"
19 #include "Particle/DistanceTable.h"
20 #include "Message/Communicate.h"
22 
23 namespace qmcplusplus
24 {
26 {
28  std::unique_ptr<Resource> makeClone() const override
29  {
30  return std::make_unique<CoulombPBCABMultiWalkerResource>(*this);
31  }
32 
33  /// a walkers worth of per ion AB potential values
35  /// a walkers worth of per electron AB potential values
37  /// constant values for the source particles aka ions aka A
39  /// constant values for the target particles aka electrons aka B
41 };
42 
43 CoulombPBCAB::CoulombPBCAB(ParticleSet& ions, ParticleSet& elns, bool computeForces)
44  : ForceBase(ions, elns),
45  myTableIndex(elns.addTable(ions)),
46  myConst(0.0),
47  ComputeForces(computeForces),
48  Peln(elns),
49  pset_ions_(ions)
50 {
51  ReportEngine PRE("CoulombPBCAB", "CoulombPBCAB");
53  twoBodyQuantumDomain(ions, elns);
54  if (ComputeForces)
56  initBreakup(elns);
57  prefix_ = "Flocal";
58  app_log() << " Rcut " << myRcut << std::endl;
59  app_log() << " Maximum K shell " << AB->MaxKshell << std::endl;
60  app_log() << " Number of k vectors " << AB->Fk.size() << std::endl;
61 }
62 
63 std::unique_ptr<OperatorBase> CoulombPBCAB::makeClone(ParticleSet& qp, TrialWaveFunction& psi)
64 {
65  return std::make_unique<CoulombPBCAB>(*this);
66 }
67 
68 CoulombPBCAB::~CoulombPBCAB() = default;
69 
71 {
72  int tid = P.addTable(pset_ions_);
73  if (tid != myTableIndex)
74  {
75  APP_ABORT("CoulombPBCAB::resetTargetParticleSet found inconsistent table index");
76  }
77  AB->resetTargetParticleSet(P);
78 }
79 
81 {
82  my_index_ = plist.add(name_.c_str());
83  if (ComputeForces)
84  addObservablesF(plist);
85 }
86 
87 
88 #if !defined(REMOVE_TRACEMANAGER)
90 
92 {
95  {
100  }
101 }
102 
104 {
105  // This is written so it can be called again and again.
109 }
110 
112 {
114  {
115  delete Ve_sample;
116  delete Vi_sample;
117  }
118 }
119 #endif
120 
121 
123 {
124  if (ComputeForces)
125  {
126  forces_ = 0.0;
128  }
129  else
130 #if !defined(REMOVE_TRACEMANAGER)
132  value_ = evaluate_sp(P);
133  else
134 #endif
135  value_ = evalLR(P) + evalSR(P) + myConst;
136  return value_;
137 }
138 
140  ParticleSet& ions,
141  TrialWaveFunction& psi,
142  ParticleSet::ParticlePos& hf_terms,
143  ParticleSet::ParticlePos& pulay_terms)
144 {
145  if (ComputeForces)
146  {
147  forces_ = 0.0;
149  hf_terms -= forces_;
150  //And no Pulay contribution.
151  }
152  else
153  value_ = evalLR(P) + evalSR(P) + myConst;
154  return value_;
155 }
156 
157 #if !defined(REMOVE_TRACEMANAGER)
159 {
160  RealType Vsr = 0.0;
161  RealType Vlr = 0.0;
162  mRealType& Vc = myConst;
163  Array<RealType, 1>& Ve_samp = *Ve_sample;
164  Array<RealType, 1>& Vi_samp = *Vi_sample;
165  Ve_samp = 0.0;
166  Vi_samp = 0.0;
167  {
168  //SR
169  const auto& d_ab(P.getDistTableAB(myTableIndex));
170  RealType z;
171  //Loop over distinct eln-ion pairs
172  for (size_t b = 0; b < NptclB; ++b)
173  {
174  z = 0.5 * Qat[b];
175  const auto& dist = d_ab.getDistRow(b);
176  for (size_t a = 0; a < NptclA; ++a)
177  {
178  Return_t pairpot = z * Zat[a] * Vat[a]->splint(dist[a]) / dist[a];
179  Vi_samp(a) += pairpot;
180  Ve_samp(b) += pairpot;
181  Vsr += pairpot;
182  }
183  }
184  Vsr *= 2.0;
185  }
186  {
187  //LR
188  const StructFact& RhoKA(pset_ions_.getSK());
189  const StructFact& RhoKB(P.getSK());
190  if (RhoKA.SuperCellEnum == SUPERCELL_SLAB)
191  {
192  APP_ABORT("CoulombPBCAB::evaluate_sp single particle traces have not been implemented for slab geometry");
193  }
194  else
195  {
196  assert(RhoKA.isStorePerParticle()); // ensure this so we know eikr_r has been allocated
197  assert(RhoKB.isStorePerParticle());
198  //jtk mark: needs optimizations. will likely require new function definitions
199  RealType v1; //single particle energy
200  RealType q;
201  for (int i = 0; i < P.getTotalNum(); ++i)
202  {
203  q = .5 * Qat[i];
204  v1 = 0.0;
205  for (int s = 0; s < NumSpeciesA; s++)
206  v1 += Zspec[s] * q *
207  AB->evaluate(pset_ions_.getSimulationCell().getKLists().kshell, RhoKA.rhok_r[s], RhoKA.rhok_i[s],
208  RhoKB.eikr_r[i], RhoKB.eikr_i[i]);
209  Ve_samp(i) += v1;
210  Vlr += v1;
211  }
212  for (int i = 0; i < pset_ions_.getTotalNum(); ++i)
213  {
214  q = .5 * Zat[i];
215  v1 = 0.0;
216  for (int s = 0; s < NumSpeciesB; s++)
217  v1 += Qspec[s] * q *
218  AB->evaluate(P.getSimulationCell().getKLists().kshell, RhoKB.rhok_r[s], RhoKB.rhok_i[s], RhoKA.eikr_r[i],
219  RhoKA.eikr_i[i]);
220  Vi_samp(i) += v1;
221  Vlr += v1;
222  }
223  }
224  }
225  for (int i = 0; i < Ve_samp.size(); ++i)
226  Ve_samp(i) += Ve_const(i);
227  for (int i = 0; i < Vi_samp.size(); ++i)
228  Vi_samp(i) += Vi_const(i);
229  value_ = Vsr + Vlr + Vc;
230 #if defined(TRACE_CHECK)
231  RealType Vlrnow = evalLR(P);
232  RealType Vsrnow = evalSR(P);
233  RealType Vcnow = myConst;
234  RealType Vnow = Vlrnow + Vsrnow + Vcnow;
235  RealType Vesum = Ve_samp.sum();
236  RealType Vecsum = Ve_const.sum();
237  RealType Visum = Vi_samp.sum();
238  RealType Vicsum = Vi_const.sum();
239  RealType Vsum = Vesum + Visum;
240  RealType Vcsum = Vecsum + Vicsum;
241  if (std::abs(Vsum - Vnow) > TraceManager::trace_tol)
242  {
243  app_log() << "accumtest: CoulombPBCAA::evaluate()" << std::endl;
244  app_log() << "accumtest: tot:" << Vnow << std::endl;
245  app_log() << "accumtest: sum:" << Vsum << std::endl;
246  APP_ABORT("Trace check failed");
247  }
248  if (std::abs(Vcsum - Vcnow) > TraceManager::trace_tol)
249  {
250  app_log() << "accumtest: CoulombPBCAA::evalConsts()" << std::endl;
251  app_log() << "accumtest: tot:" << Vcnow << std::endl;
252  app_log() << "accumtest: sum:" << Vcsum << std::endl;
253  APP_ABORT("Trace check failed");
254  }
255  if (std::abs(Vesum - Visum) > TraceManager::trace_tol)
256  {
257  app_log() << "sharetest: CoulombPBCAB::evaluate()" << std::endl;
258  app_log() << "sharetest: e share:" << Vesum << std::endl;
259  app_log() << "sharetest: i share:" << Visum << std::endl;
260  }
261  if (std::abs(Vecsum - Vicsum) > TraceManager::trace_tol)
262  {
263  app_log() << "sharetest: CoulombPBCAB::evalConsts()" << std::endl;
264  app_log() << "sharetest: e share:" << Vecsum << std::endl;
265  app_log() << "sharetest: i share:" << Vicsum << std::endl;
266  }
267 
268 #endif
269  return value_;
270 }
271 #endif
272 
275  const RefVectorWithLeader<ParticleSet>& p_list,
276  const std::vector<ListenerVector<RealType>>& listeners,
277  const std::vector<ListenerVector<RealType>>& ion_listeners) const
278 {
279  auto& o_leader = o_list.getCastedLeader<CoulombPBCAB>();
280  auto& p_leader = p_list.getLeader();
281  assert(this == &o_list.getLeader());
282 
283  auto num_centers = p_leader.getTotalNum();
284  auto& name = o_leader.name_;
285  auto& mw_res = o_leader.mw_res_handle_.getResource();
286  Vector<RealType>& ve_sample = mw_res.pp_samples_trg;
287  Vector<RealType>& vi_sample = mw_res.pp_samples_src;
288  const auto& ve_consts = mw_res.pp_consts_trg;
289  const auto& vi_consts = mw_res.pp_consts_src;
290  auto num_species = p_leader.getSpeciesSet().getTotalNum();
291  ve_sample.resize(NptclB);
292  vi_sample.resize(NptclA);
293 
294  // This lambda is mostly about getting a handle on what is being touched by the per particle evaluation.
295  auto evaluate_walker = [name, &ve_sample, &vi_sample, &ve_consts,
296  &vi_consts](const int walker_index, const CoulombPBCAB& cpbcab, const ParticleSet& pset,
297  const std::vector<ListenerVector<RealType>>& listeners,
298  const std::vector<ListenerVector<RealType>>& ion_listeners) -> RealType {
299  RealType Vsr = 0.0;
300  RealType Vlr = 0.0;
301  RealType Vc = cpbcab.myConst;
302  std::fill(ve_sample.begin(), ve_sample.end(), 0.0);
303  std::fill(vi_sample.begin(), vi_sample.end(), 0.0);
304  auto& pset_source = cpbcab.getSourcePSet();
305  {
306  //SR
307  const auto& d_ab(pset.getDistTableAB(cpbcab.myTableIndex));
308  RealType z;
309  //Loop over distinct eln-ion pairs
310  for (size_t b = 0; b < pset.getTotalNum(); ++b)
311  {
312  z = 0.5 * cpbcab.Qat[b];
313  const auto& dist = d_ab.getDistRow(b);
314  for (size_t a = 0; a < pset_source.getTotalNum(); ++a)
315  {
316  Return_t pairpot = z * cpbcab.Zat[a] * cpbcab.Vat[a]->splint(dist[a]) / dist[a];
317  vi_sample[a] += pairpot;
318  ve_sample[b] += pairpot;
319  Vsr += pairpot;
320  }
321  }
322  Vsr *= 2.0;
323  }
324  {
325  //LR
326  // pset_ions_ is a smelly reference to the ion particle set.
327  const StructFact& RhoKA(pset_source.getSK());
328  const StructFact& RhoKB(pset.getSK());
329  if (RhoKA.SuperCellEnum == SUPERCELL_SLAB)
330  {
331  APP_ABORT("CoulombPBCAB::evaluate_sp single particle traces have not been implemented for slab geometry");
332  }
333  else
334  {
335  assert(RhoKA.isStorePerParticle()); // ensure this so we know eikr_r has been allocated
336  assert(RhoKB.isStorePerParticle());
337  //jtk mark: needs optimizations. will likely require new function definitions
338  RealType v1; //single particle energy
339  RealType q;
340  int num_species_source = pset_source.getSpeciesSet().size();
341  for (int i = 0; i < pset.getTotalNum(); ++i)
342  {
343  q = .5 * cpbcab.Qat[i];
344  v1 = 0.0;
345  for (int s = 0; s < num_species_source; s++)
346  v1 += cpbcab.Zspec[s] * q *
347  cpbcab.AB->evaluate(pset_source.getSimulationCell().getKLists().kshell, RhoKA.rhok_r[s],
348  RhoKA.rhok_i[s], RhoKB.eikr_r[i], RhoKB.eikr_i[i]);
349  ve_sample[i] += v1;
350  Vlr += v1;
351  }
352  int num_species_target = pset.getSpeciesSet().size();
353  for (int i = 0; i < pset_source.getTotalNum(); ++i)
354  {
355  q = .5 * cpbcab.Zat[i];
356  v1 = 0.0;
357  for (int s = 0; s < num_species_target; s++)
358  v1 += cpbcab.Qspec[s] * q *
359  cpbcab.AB->evaluate(pset.getSimulationCell().getKLists().kshell, RhoKB.rhok_r[s], RhoKB.rhok_i[s],
360  RhoKA.eikr_r[i], RhoKA.eikr_i[i]);
361  vi_sample[i] += v1;
362  Vlr += v1;
363  }
364  }
365  }
366  for (int i = 0; i < ve_sample.size(); ++i)
367  ve_sample[i] += ve_consts[i];
368  for (int i = 0; i < vi_sample.size(); ++i)
369  vi_sample[i] += vi_consts[i];
370  RealType value = Vsr + Vlr + Vc;
371  for (const ListenerVector<RealType>& listener : listeners)
372  listener.report(walker_index, name, ve_sample);
373  for (const ListenerVector<RealType>& ion_listener : ion_listeners)
374  ion_listener.report(walker_index, name, vi_sample);
375  return value;
376  };
377 
378  for (int iw = 0; iw < o_list.size(); iw++)
379  {
380  auto& coulomb_ab = o_list.getCastedElement<CoulombPBCAB>(iw);
381  coulomb_ab.value_ = evaluate_walker(iw, coulomb_ab, p_list[iw], listeners, ion_listeners);
382  }
383 }
384 
385 /** Evaluate the background term. Other constants are handled by AA potentials.
386  *
387  * \f$V_{bg}^{AB}=-\sum_{\alpha}\sum_{\beta} N^{\alpha} N^{\beta} q^{\alpha} q^{\beta} v_s(k=0) \f$
388  * @todo Here is where the charge system has to be handled.
389  */
391 {
392  int nelns = Peln.getTotalNum();
393  int nions = pset_ions_.getTotalNum();
394 #if !defined(REMOVE_TRACEMANAGER)
395  Ve_const.resize(nelns);
396  Vi_const.resize(nions);
397  Ve_const = 0.0;
398  Vi_const = 0.0;
399 #endif
400  mRealType Consts = 0.0;
401  mRealType vs_k0 = AB->evaluateSR_k0();
402  mRealType v1; //single particle energy
403  for (int i = 0; i < nelns; ++i)
404  {
405  v1 = 0.0;
406  for (int s = 0; s < NumSpeciesA; s++)
407  v1 += NofSpeciesA[s] * Zspec[s];
408  v1 *= -.5 * Qat[i] * vs_k0;
409 #if !defined(REMOVE_TRACEMANAGER)
410  Ve_const(i) = v1;
411 #endif
412  Consts += v1;
413  }
414  for (int i = 0; i < nions; ++i)
415  {
416  v1 = 0.0;
417  for (int s = 0; s < NumSpeciesB; s++)
418  v1 += NofSpeciesB[s] * Qspec[s];
419  v1 *= -.5 * Zat[i] * vs_k0;
420 #if !defined(REMOVE_TRACEMANAGER)
421  Vi_const(i) = v1;
422 #endif
423  Consts += v1;
424  }
425  if (report)
426  app_log() << " Constant of PBCAB " << Consts << std::endl;
427  return Consts;
428 }
429 
430 
432 {
433  constexpr mRealType czero(0);
434  const auto& d_ab(P.getDistTableAB(myTableIndex));
435  mRealType res = czero;
436  //can be optimized but not important enough
437  for (size_t b = 0; b < NptclB; ++b)
438  {
439  const auto& dist = d_ab.getDistRow(b);
440  mRealType esum = czero;
441  for (size_t a = 0; a < NptclA; ++a)
442  esum += Zat[a] * Vat[a]->splint(dist[a]) / dist[a];
443  res += esum * Qat[b];
444  }
445  return res;
446 }
447 
448 
450 {
451  mRealType res = 0.0;
452  const StructFact& RhoKA(pset_ions_.getSK());
453  const StructFact& RhoKB(P.getSK());
454  if (RhoKA.SuperCellEnum == SUPERCELL_SLAB)
455  throw std::runtime_error(
456  "CoulombPBCAB::evalLR RhoKA.SuperCellEnum == SUPERCELL_SLAB case not implemented. There was an implementation "
457  "with complex-valued storage that may be resurrected using real-valued storage.");
458  else
459  {
460  for (int i = 0; i < NumSpeciesA; i++)
461  {
462  mRealType esum = 0.0;
463  for (int j = 0; j < NumSpeciesB; j++)
464  esum += Qspec[j] *
465  AB->evaluate(pset_ions_.getSimulationCell().getKLists().kshell, RhoKA.rhok_r[i], RhoKA.rhok_i[i],
466  RhoKB.rhok_r[j], RhoKB.rhok_i[j]);
467  res += Zspec[i] * esum;
468  }
469  } //specion
470  return res;
471 }
472 
473 
475 {
476  // This is ridiculous so many uneeded convenience variables that also make the object invalid at construction.
477  // Illustraction of the terrible API and convoluted use of species attributes.
478  SpeciesSet& tspeciesA(pset_ions_.getSpeciesSet());
479  SpeciesSet& tspeciesB(P.getSpeciesSet());
480  // Actually finding the index, code further on makes no sense if there wasn't already a charge attribute.
481  int ChargeAttribIndxA = tspeciesA.addAttribute("charge");
482  int ChargeAttribIndxB = tspeciesB.addAttribute("charge");
484  NptclB = P.getTotalNum();
485  NumSpeciesA = tspeciesA.TotalNum;
486  NumSpeciesB = tspeciesB.TotalNum;
487  //Store information about charges and number of each species
488  Zat.resize(NptclA);
489  Zspec.resize(NumSpeciesA);
490  Qat.resize(NptclB);
491  Qspec.resize(NumSpeciesB);
492  NofSpeciesA.resize(NumSpeciesA);
493  NofSpeciesB.resize(NumSpeciesB);
494  for (int spec = 0; spec < NumSpeciesA; spec++)
495  {
496  Zspec[spec] = tspeciesA(ChargeAttribIndxA, spec);
497  NofSpeciesA[spec] = pset_ions_.groupsize(spec);
498  }
499  for (int spec = 0; spec < NumSpeciesB; spec++)
500  {
501  Qspec[spec] = tspeciesB(ChargeAttribIndxB, spec);
502  NofSpeciesB[spec] = P.groupsize(spec);
503  }
504  for (int iat = 0; iat < NptclA; iat++)
505  Zat[iat] = Zspec[pset_ions_.GroupID[iat]];
506  for (int iat = 0; iat < NptclB; iat++)
507  Qat[iat] = Qspec[P.GroupID[iat]];
508  // if(totQ>std::numeric_limits<RealType>::epsilon())
509  // {
510  // LOGMSG("PBCs not yet finished for non-neutral cells");
511  // OHMMS::Controller->abort();
512  // }
513  ////Test if the box sizes are same (=> kcut same for fixed dimcut)
514  kcdifferent =
515  (std::abs(pset_ions_.getLattice().LR_kc - P.getLattice().LR_kc) > std::numeric_limits<RealType>::epsilon());
516  minkc = std::min(pset_ions_.getLattice().LR_kc, P.getLattice().LR_kc);
517  //initBreakup is called only once
519  myConst = evalConsts(P);
520  myRcut = AB->get_rc(); //Basis.get_rc();
521  // create the spline function for the short-range part assuming pure potential
522  auto myGrid = LinearGrid<RealType>();
523  const int ng = P.getLattice().num_ewald_grid_points;
524  app_log() << " CoulombPBCAB::initBreakup\n Setting a linear grid=[0," << myRcut
525  << ") number of grid points =" << ng << std::endl;
526  myGrid.set(0, myRcut, ng);
527  if (V0 == nullptr)
528  {
530  if (Vat.size())
531  {
532  APP_ABORT("CoulombPBCAB::initBreakup. Vat is not empty\n");
533  }
534  Vat.resize(NptclA, V0.get());
535  Vspec.resize(NumSpeciesA); //prepare for PP to overwrite it
536  }
537 
538  //If ComputeForces is true, then we allocate space for the radial derivative functors.
539  if (ComputeForces)
540  {
542  if (fV0 == nullptr)
544  if (dfV0 == nullptr)
546  if (fVat.size())
547  {
548  APP_ABORT("CoulombPBCAB::initBreakup. Vat is not empty\n");
549  }
550  fVat.resize(NptclA, fV0.get());
551  fdVat.resize(NptclA, dfV0.get());
552  fVspec.resize(NumSpeciesA);
553  fdVspec.resize(NumSpeciesA);
554  }
555 }
556 
557 /** add a local pseudo potential
558  * @param groupID species index
559  * @param ppot radial functor for \f$rV_{loc}\f$ on a grid
560  */
561 void CoulombPBCAB::add(int groupID, std::unique_ptr<RadFunctorType>&& ppot)
562 {
563  //FIXME still using magic numbers in the local potential grid.
564  const int MaxGridPoints = 10000;
565  const size_t ng = std::min(MaxGridPoints, static_cast<int>(myRcut / 1e-3) + 1);
566  app_log() << " CoulombPBCAB::add \n Setting a linear grid=[0," << myRcut << ") number of grid =" << ng
567  << std::endl;
568  auto agrid_local = LinearGrid<RealType>();
569  agrid_local.set(0.0, myRcut, ng);
570  RealType dr = agrid_local[1] - agrid_local[0];
571  if (Vspec[groupID] == nullptr)
572  {
573  V0.reset();
574 
575  app_log() << " Creating the short-range pseudopotential for species " << groupID << std::endl;
576  std::vector<RealType> v(ng);
577  for (int ig = 1; ig < ng - 2; ig++)
578  {
579  RealType r = agrid_local[ig];
580  //need to multiply r for the LR
581  v[ig] = -r * AB->evaluateLR(r) + ppot->splint(r);
582  }
583  v[0] = 2.0 * v[1] - v[2];
584  //by construction, v has to go to zero at the boundary
585  v[ng - 2] = 0.0;
586  v[ng - 1] = 0.0;
587  RealType deriv = (v[1] - v[0]) / dr;
588  auto rfunc = std::make_unique<RadFunctorType>(agrid_local.makeClone(), v);
589  rfunc->spline(0, deriv, ng - 1, 0.0);
590  for (int iat = 0; iat < NptclA; iat++)
591  {
592  if (pset_ions_.GroupID[iat] == groupID)
593  Vat[iat] = rfunc.get();
594  }
595  Vspec[groupID] = std::move(rfunc);
596  }
597 
598  if (ComputeForces && fVspec[groupID] == nullptr)
599  {
600  app_log() << " Creating the short-range pseudopotential derivatives for species " << groupID << std::endl;
601  //This is the value coming from optimized breakup for FORCES, not for energy.
602  //Also. Goal of this section is to create and store d/dr(rV), not d/dr(V)!!!
603  std::vector<RealType> v(ng);
604  std::vector<RealType> dv(ng);
605 
606  RealType ppot_val(0), ppot_deriv(0), ppot_2deriv(0);
607  RealType lr_val(0), lr_deriv(0);
608  for (int ig = 1; ig < ng - 2; ig++)
609  {
610  RealType r = agrid_local[ig];
611  ppot_val = ppot->splint(r, ppot_deriv, ppot_2deriv);
612  lr_val = dAB->evaluateLR(r);
613  lr_deriv = dAB->lrDf(r);
614 
615  v[ig] = ppot_val - r * lr_val;
616  dv[ig] = ppot_deriv - (lr_val + lr_deriv * r);
617  }
618  //This is a linear interpolation from v[2] and v[1] to v[0], assuming linear behavior.
619  v[0] = 2.0 * v[1] - v[2];
620  v[ng - 2] = 0.0;
621  v[ng - 1] = 0.0;
622 
623  dv[0] = 2.0 * dv[1] - dv[2];
624  dv[ng - 2] = 0;
625  dv[ng - 1] = 0;
626 
627  auto ffunc = std::make_unique<RadFunctorType>(agrid_local.makeClone(), v);
628  auto fdfunc = std::make_unique<RadFunctorType>(agrid_local.makeClone(), dv);
629 
630  RealType fderiv = (dv[1] - dv[0]) / dr;
631 
632  ffunc->spline(0, dv[0], ng - 1, 0.0);
633  fdfunc->spline(0, fderiv, ng - 1, 0.0);
634 
635  for (int iat = 0; iat < NptclA; iat++)
636  {
637  if (pset_ions_.GroupID[iat] == groupID)
638  {
639  fVat[iat] = ffunc.get();
640  fdVat[iat] = fdfunc.get();
641  }
642  }
643  fVspec[groupID] = std::move(ffunc);
644  fdVspec[groupID] = std::move(fdfunc);
645  //Done
646  }
647 
648  if (ComputeForces)
649  {
650  if (OHMMS::Controller->rank() == 0)
651  {
652  FILE* fout = fopen("Vlocal.dat", "w");
653  for (RealType r = 1.0e-8; r < myRcut; r += 1.0e-2)
654  {
655  RealType d_rV_dr, d2_rV_dr2;
656  RealType Vr = Vat[0]->splint(r, d_rV_dr, d2_rV_dr2);
657  Vr = Vat[0]->splint(r);
658  fprintf(fout, "%1.8e %1.12e %1.12e %1.12e\n", r, Vr, d_rV_dr, d2_rV_dr2);
659  }
660  fclose(fout);
661  }
662  }
663 }
664 
666 {
667  // const StructFact& RhoKA(pset_ions_.getSK());
668  // const StructFact& RhoKB(P.getSK());
669  std::vector<TinyVector<RealType, DIM>> grad(pset_ions_.getTotalNum());
670  for (int j = 0; j < NumSpeciesB; j++)
671  {
672  for (int iat = 0; iat < grad.size(); iat++)
673  grad[iat] = TinyVector<RealType, DIM>(0.0, 0.0, 0.0);
674  dAB->evaluateGrad(pset_ions_, P, j, Zat, grad);
675  for (int iat = 0; iat < grad.size(); iat++)
676  forces_[iat] += Qspec[j] * grad[iat];
677  } // electron species
678  return evalLR(P);
679 }
680 
682 {
683  constexpr mRealType czero(0);
684  const auto& d_ab(P.getDistTableAB(myTableIndex));
685  mRealType res = czero;
686  //Temporary variables for computing energy and forces.
687  mRealType rV(0);
688  mRealType frV(0), fdrV(0);
689  mRealType rinv(1.0);
690  //Magnitude of force.
691  mRealType dvdr(0.0);
692  for (size_t b = 0; b < NptclB; ++b)
693  {
694  const auto& dist = d_ab.getDistRow(b);
695  const auto& dr = d_ab.getDisplRow(b);
696  mRealType esum = czero;
697  for (size_t a = 0; a < NptclA; ++a)
698  {
699  //Low hanging SIMD fruit here. See J1/J2 grad computation.
700  rinv = 1.0 / dist[a];
701  rV = Vat[a]->splint(dist[a]);
702  frV = fVat[a]->splint(dist[a]);
703  fdrV = fdVat[a]->splint(dist[a]);
704  dvdr = Qat[b] * Zat[a] * (fdrV - frV * rinv) * rinv;
705  forces_[a][0] -= dvdr * dr[a][0] * rinv;
706  forces_[a][1] -= dvdr * dr[a][1] * rinv;
707  forces_[a][2] -= dvdr * dr[a][2] * rinv;
708  esum += Zat[a] * rV * rinv; //Total energy accumulation
709  }
710  res += esum * Qat[b];
711  }
712  return res;
713 }
714 
716 {
717  int nelns = Peln.getTotalNum();
718  int nions = pset_ions_.getTotalNum();
719  pp_consts_trg.resize(nelns, 0.0);
720  pp_consts_src.resize(nions, 0.0);
721 
722  RealType vs_k0 = AB->evaluateSR_k0();
723  RealType v1; //single particle energy
724  for (int i = 0; i < nelns; ++i)
725  {
726  v1 = 0.0;
727  for (int s = 0; s < NumSpeciesA; s++)
728  v1 += NofSpeciesA[s] * Zspec[s];
729  v1 *= -.5 * Qat[i] * vs_k0;
730  pp_consts_trg[i] = v1;
731  }
732  for (int i = 0; i < nions; ++i)
733  {
734  v1 = 0.0;
735  for (int s = 0; s < NumSpeciesB; s++)
736  v1 += NofSpeciesB[s] * Qspec[s];
737  v1 *= -.5 * Zat[i] * vs_k0;
738  pp_consts_src[i] = v1;
739  }
740 }
741 
743 {
744  auto new_res = std::make_unique<CoulombPBCABMultiWalkerResource>();
745  evalPerParticleConsts(new_res->pp_consts_src, new_res->pp_consts_trg);
746  auto resource_index = collection.addResource(std::move(new_res));
747 }
748 
750  const RefVectorWithLeader<OperatorBase>& o_list) const
751 {
752  auto& o_leader = o_list.getCastedLeader<CoulombPBCAB>();
754 }
755 
757  const RefVectorWithLeader<OperatorBase>& o_list) const
758 {
759  auto& o_leader = o_list.getCastedLeader<CoulombPBCAB>();
760  collection.takebackResource(o_leader.mw_res_handle_);
761 }
762 
763 } // namespace qmcplusplus
Array< TraceReal, 1 > * Vi_sample
Definition: CoulombPBCAB.h:116
void resize(size_type n, Type_t val=Type_t())
Resize the container.
Definition: OhmmsVector.h:166
void twoBodyQuantumDomain(const ParticleSet &P)
set quantum domain for two-body operator
std::vector< const RadFunctorType * > fdVat
Definition: CoulombPBCAB.h:92
static std::unique_ptr< LRHandlerType > getDerivHandler(ParticleSet &ref)
This returns a force/stress optimized LR handler. If non existent, it creates one.
int NumSpeciesB
number of species of B particle set
Definition: CoulombPBCAB.h:55
void resetTargetParticleSet(ParticleSet &P) override
Reset the data with the target ParticleSet.
Vector< RealType > pp_samples_src
a walkers worth of per ion AB potential values
std::shared_ptr< const RadFunctorType > fV0
Radial functor for bare coulomb, optimized for forces.
Definition: CoulombPBCAB.h:67
Return_t evaluate(ParticleSet &P) override
Evaluate the local energy contribution of this component.
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...
size_t addResource(std::unique_ptr< Resource > &&res, bool noprint=false)
Vector< RealType > pp_consts_src
constant values for the source particles aka ions aka A
void set(T ri, T rf, int n) override
Set the grid given the parameters.
Return_t myConst
const energy after breakup
Definition: CoulombPBCAB.h:61
std::vector< const RadFunctorType * > Vat
Short-range potential for each ion.
Definition: CoulombPBCAB.h:86
void takebackResource(ResourceHandle< RS > &res_handle)
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
Calculates the AA Coulomb potential using PBCs.
Definition: CoulombPBCAB.h:38
bool streaming_array(const std::string &name)
Definition: TraceManager.h:249
Array< TraceReal, 1 > Vi_const
Definition: CoulombPBCAB.h:118
std::shared_ptr< LRHandlerType > AB
long-range Handler. Should be const LRHandlerType eventually
Definition: CoulombPBCAB.h:47
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
int my_index_
starting index of this object
Definition: OperatorBase.h:535
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
constexpr std::complex< float > czero
Definition: BLAS.hpp:51
std::vector< std::shared_ptr< RadFunctorType > > Vspec
Short-range potential for each species.
Definition: CoulombPBCAB.h:88
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
Vector< RealType > pp_consts_trg
constant values for the target particles aka electrons aka B
std::vector< std::shared_ptr< const RadFunctorType > > fVspec
Definition: CoulombPBCAB.h:94
Vectorized record engine for scalar properties.
LRHandlerType::mRealType mRealType
Definition: CoulombPBCAB.h:44
bool ComputeForces
Flag for whether to compute forces or not.
Definition: CoulombPBCAB.h:71
Attaches a unit to a Vector for IO.
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
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
const int myTableIndex
locator of the distance table
Definition: CoulombPBCAB.h:51
int addAttribute(const std::string &aname)
for a new attribute, allocate the data, !More often used to get the index of a species ...
Definition: SpeciesSet.cpp:45
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
for(int i=0;i< size_test;++i) CHECK(Approx(gauss_random_vals[offset_for_rs+i])
std::shared_ptr< const RadFunctorType > V0
Always mave a radial functor for the bare coulomb.
Definition: CoulombPBCAB.h:65
const DistanceTableAB & getDistTableAB(int table_ID) const
get a distance table by table_ID and dyanmic_cast to DistanceTableAB
void turnOnPerParticleSK()
Turn on per particle storage in Structure Factor.
std::shared_ptr< const RadFunctorType > dfV0
Radial functor for derivative of bare coulomb, optimized for forces.
Definition: CoulombPBCAB.h:69
const auto & getSimulationCell() const
Definition: ParticleSet.h:250
std::vector< std::shared_ptr< const RadFunctorType > > fdVspec
Definition: CoulombPBCAB.h:95
int addTable(const ParticleSet &psrc, DTModes modes=DTModes::ALL_OFF)
add a distance table
Array< TraceReal, 1 > * Ve_sample
Definition: CoulombPBCAB.h:115
std::string name_
name of this object
Definition: OperatorBase.h:527
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
int NptclB
number of particles of B
Definition: CoulombPBCAB.h:59
RealType myRcut
cutoff radius of the short-range part
Definition: CoulombPBCAB.h:63
void createResource(ResourceCollection &collection) const override
initialize a shared resource and hand it to a collection
Return_t evaluate_sp(ParticleSet &P)
int add(const std::string &aname)
static std::unique_ptr< RadFunctorType > createSpline4RbyVsDeriv(const LRHandlerType *aLR, mRealType rcut, const GridType &agrid)
create a linear spline of the derivative of short-range potential
Final class and should not be derived.
declaration of ProgressReportEngine
void initBreakup(ParticleSet &P)
Creates the long-range handlers, then splines and stores it by particle and species for quick evaluat...
CASTTYPE & getCastedElement(size_t i) const
int groupsize(int igroup) const
return the size of a group
Definition: ParticleSet.h:527
int NptclA
number of particles of A
Definition: CoulombPBCAB.h:57
size_t size() const
Definition: OhmmsArray.h:57
Array< TraceReal, 1 > Ve_const
Definition: CoulombPBCAB.h:117
#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
Vector< RealType > pp_samples_trg
a walkers worth of per electron AB potential values
int NumSpeciesA
number of species of A particle set
Definition: CoulombPBCAB.h:53
std::vector< RealType > Qspec
Qspec[spec] charge for the spec-th species of B.
Definition: CoulombPBCAB.h:84
ParticleSet & pset_ions_
source particle set
Definition: CoulombPBCAB.h:230
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
void add(int groupID, std::unique_ptr< RadFunctorType > &&ppot)
Adds a local pseudopotential channel "ppot" to all source species of type "groupID".
Array< TraceReal, D > * checkout_real(const std::string &name, int n1=1, int n2=0, int n3=0, int n4=0)
std::vector< int > NofSpeciesA
number of particles per species of A
Definition: CoulombPBCAB.h:74
void evalPerParticleConsts(Vector< RealType > &pp_consts_src, Vector< RealType > &pp_consts_trg) const
Compute the const part of the per particle coulomb AB potential.
CoulombPBCAB(ParticleSet &ions, ParticleSet &elns, bool computeForces=false)
FullPrecRealType Return_t
type of return value of evaluate
Definition: OperatorBase.h:64
Type_t sum() const
Definition: OhmmsArray.h:214
std::vector< const RadFunctorType * > fVat
Short-range potential (r*V) and potential derivative d/dr(rV) derivative for each ion Required for fo...
Definition: CoulombPBCAB.h:91
ResourceHandle< CoulombPBCABMultiWalkerResource > mw_res_handle_
Definition: CoulombPBCAB.h:232
Return_t evalLRwithForces(ParticleSet &P)
Computes the long-range contribution to the coulomb energy and forces.
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 > Qat
Qat[iat] charge for the iat-th particle of B.
Definition: CoulombPBCAB.h:80
std::vector< RealType > Zspec
Zspec[spec] charge for the spec-th species of A.
Definition: CoulombPBCAB.h:82
std::vector< RealType > Zat
Zat[iat] charge for the iat-th particle of A.
Definition: CoulombPBCAB.h:78
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
virtual void informOfPerParticleListener()
Definition: OperatorBase.h:471
std::shared_ptr< const LRHandlerType > dAB
long-range derivative handler
Definition: CoulombPBCAB.h:49
const auto & getLattice() const
Definition: ParticleSet.h:251
std::unique_ptr< Resource > makeClone() const override
ResourceHandle< RS > lendResource()
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 ...
std::unique_ptr< OperatorBase > makeClone(ParticleSet &qp, TrialWaveFunction &psi) override
void contributeParticleQuantities() override
void informOfPerParticleListener() override
Call to inform objects associated with this operator of per particle listeners.
Return_t evalLR(ParticleSet &P)
Computes the long-range contribution to the coulomb energy.
std::vector< int > NofSpeciesB
number of particles per species of B
Definition: CoulombPBCAB.h:76
Return_t evalSR(ParticleSet &P)
Computes the short-range contribution to the coulomb energy.
Return_t evalSRwithForces(ParticleSet &P)
Computes the short-range contribution to the coulomb energy and forces.
void deleteParticleQuantities() override
Return_t evalConsts(const ParticleSet &P, bool report=true)
Evaluates madelung and background contributions to total energy.