QMCPACK
test_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) 2023 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 Nationaln Laboratories
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #include "catch.hpp"
13 
14 #include "Configuration.h"
24 #include "TestListenerFunction.h"
26 
27 namespace qmcplusplus
28 {
29 namespace testing
30 {
32 {
34 
35 public:
37  {
38  so_ecp.ppset_[0]->rrotsgrid_m_ = so_ecp.ppset_[0]->sgridxyz_m_;
39  }
40  static bool didGridChange(SOECPotential& so_ecp)
41  {
42  return so_ecp.ppset_[0]->rrotsgrid_m_ != so_ecp.ppset_[0]->sgridxyz_m_;
43  }
45  {
46  for (size_t iw = 0; iw < o_list.size(); iw++)
47  {
48  auto& sopp = o_list.getCastedElement<SOECPotential>(iw);
49  auto& pset = p_list[iw];
50  for (auto& uptr_comp : sopp.ppset_)
51  uptr_comp.get()->initVirtualParticle(pset);
52  }
53  }
54  static void mw_evaluateImpl(SOECPotential& so_ecp,
58  const std::optional<ListenerOption<Real>> listener_opt,
59  bool keep_grid)
60  {
61  so_ecp.mw_evaluateImpl(o_list, twf_list, p_list, listener_opt, keep_grid);
62  }
63 
64  static void evalFast(SOECPotential& so_ecp, ParticleSet& elec, OperatorBase::Return_t& value)
65  {
67  for (auto& uptr_comp : so_ecp.ppset_)
68  uptr_comp.get()->initVirtualParticle(elec);
69  so_ecp.evaluateImpl(elec, true);
70  value = so_ecp.getValue();
71  }
72 };
73 } // namespace testing
74 
75 void doSOECPotentialTest(bool use_VPs)
76 {
77  using Real = QMCTraits::RealType;
79  using Value = QMCTraits::ValueType;
80  using Pos = QMCTraits::PosType;
82 
84 
85  //Cell definition:
86 
88  lattice.BoxBConds = false; // periodic
89  lattice.R.diagonal(20);
90  lattice.LR_dim_cutoff = 15;
91  lattice.reset();
92 
93  const SimulationCell simulation_cell(lattice);
94  auto ions_uptr = std::make_unique<ParticleSet>(simulation_cell);
95  auto elec_uptr = std::make_unique<ParticleSet>(simulation_cell);
96  ParticleSet& ions(*ions_uptr);
97  ParticleSet& elec(*elec_uptr);
98  ions.setName("ion0");
99  ions.create({1});
100  ions.R[0] = {0.0, 0.0, 0.0};
101 
102  SpeciesSet& ion_species = ions.getSpeciesSet();
103  int pIdx = ion_species.addSpecies("H");
104  int pChargeIdx = ion_species.addAttribute("charge");
105  int iatnumber = ion_species.addAttribute("atomic_number");
106  ion_species(pChargeIdx, pIdx) = 0;
107  ion_species(iatnumber, pIdx) = 1;
108  ions.createSK();
109 
110  elec.setName("e");
111  elec.setSpinor(true);
112  elec.create({2});
113  elec.R[0] = {0.138, -0.24, 0.216};
114  elec.R[1] = {-0.216, 0.24, -0.138};
115  elec.spins = {0.2, 0.51};
116 
117  SpeciesSet& tspecies = elec.getSpeciesSet();
118  int upIdx = tspecies.addSpecies("u");
119  int chargeIdx = tspecies.addAttribute("charge");
120  int massIdx = tspecies.addAttribute("mass");
121  tspecies(chargeIdx, upIdx) = -1;
122  tspecies(massIdx, upIdx) = 1.0;
123 
124  elec.createSK();
125 
126  ions.resetGroups();
127  elec.resetGroups();
128 
129  ParticleSet elec2(elec);
130  elec2.update();
131 
132  RefVector<ParticleSet> ptcls{elec, elec2};
133  RefVectorWithLeader<ParticleSet> p_list(elec, ptcls);
134  ResourceCollection pset_res("test_pset_res");
135  ResourceCollectionTeamLock<ParticleSet> mw_pset_lock(pset_res, p_list);
136 
137  RuntimeOptions runtime_options;
138  TrialWaveFunction psi(runtime_options);
139 
140  std::vector<Pos> kup, kdn;
141  std::vector<Real> k2up, k2dn;
142  QMCTraits::IndexType nelec = elec.getTotalNum();
143  REQUIRE(nelec == 2);
144 
145  kup.resize(nelec);
146  kup[0] = Pos(1, 1, 1);
147  kup[1] = Pos(2, 2, 2);
148 
149  kdn.resize(nelec);
150  kdn[0] = Pos(2, 2, 2);
151  kdn[1] = Pos(1, 1, 1);
152 
153  auto spo_up = std::make_unique<FreeOrbital>("free_orb_up", kup);
154  auto spo_dn = std::make_unique<FreeOrbital>("free_orb_dn", kdn);
155 
156  auto spinor_set = std::make_unique<SpinorSet>("free_orb_spinor");
157  spinor_set->set_spos(std::move(spo_up), std::move(spo_dn));
158  QMCTraits::IndexType norb = spinor_set->getOrbitalSetSize();
159  REQUIRE(norb == 2);
160 
162  QMCTraits::QTFull::ValueType>>(std::move(spinor_set), 0, nelec);
163  std::vector<std::unique_ptr<DiracDeterminantBase>> dirac_dets;
164  dirac_dets.push_back(std::move(dd));
165  auto sd = std::make_unique<SlaterDet>(elec, std::move(dirac_dets));
166  psi.addComponent(std::move(sd));
167 
168  //Add the two body jastrow, parameters from test_J2_bspline
169  //adding jastrow will allow for adding WF parameter derivatives since FreeOrbital doesn't
170  //support that
171  const char* particles = R"(<tmp>
172  <jastrow name="J2" type="Two-Body" function="Bspline" print="yes" gpu="no">
173  <correlation speciesA="u" speciesB="u" rcut="5" size="5">
174  <coefficients id="uu" type="Array"> 0.02904699284 -0.1004179 -0.1752703883 -0.2232576505 -0.2728029201</coefficients>
175  </correlation>
176  </jastrow>
177  </tmp>
178  )";
180  bool okay = doc.parseFromString(particles);
181  REQUIRE(okay);
182  xmlNodePtr root = doc.getRoot();
183  xmlNodePtr jas2 = xmlFirstElementChild(root);
184  RadialJastrowBuilder jastrow(c, elec);
185  psi.addComponent(jastrow.buildComponent(jas2));
186 
187  std::unique_ptr<TrialWaveFunction> psi_clone = psi.makeClone(elec2);
188  RefVectorWithLeader<TrialWaveFunction> twf_list(psi, {psi, *psi_clone});
189  ResourceCollection twf_res("test_twf_res");
190  psi.createResource(twf_res);
191  ResourceCollectionTeamLock<TrialWaveFunction> mw_twf_lock(twf_res, twf_list);
192 
193  //Now we set up the SO ECP component.
194  SOECPotential so_ecp(ions, elec, psi, false);
195  ECPComponentBuilder ecp_comp_builder("test_read_soecp", c);
196  okay = ecp_comp_builder.read_pp_file("so_ecp_test.xml");
197  REQUIRE(okay);
198  UPtr<SOECPComponent> so_ecp_comp = std::move(ecp_comp_builder.pp_so);
199  so_ecp.addComponent(0, std::move(so_ecp_comp));
200  UPtr<OperatorBase> so_ecp2_ptr = so_ecp.makeClone(elec2, *psi_clone);
201  auto& so_ecp2 = dynamic_cast<SOECPotential&>(*so_ecp2_ptr);
202 
203  StdRandom<FullPrecReal> rng(10101);
204  StdRandom<FullPrecReal> rng2(10201);
205  so_ecp.setRandomGenerator(&rng);
206  so_ecp2.setRandomGenerator(&rng2);
207 
208  RefVector<OperatorBase> so_ecps{so_ecp, so_ecp2};
209  RefVectorWithLeader<OperatorBase> o_list(so_ecp, so_ecps);
210  if (use_VPs)
211  testing::TestSOECPotential::addVPs(o_list, p_list);
212  ResourceCollection so_ecp_res("test_so_ecp_res");
213  so_ecp.createResource(so_ecp_res);
214  ResourceCollectionTeamLock<OperatorBase> so_ecp_lock(so_ecp_res, o_list);
215 
218 
221 
222  int num_walkers = 2;
223  int max_values = 10;
224  Matrix<Real> local_pots(num_walkers, max_values);
225  Matrix<Real> local_pots2(num_walkers, max_values);
226  std::vector<ListenerVector<Real>> listeners;
227  listeners.emplace_back("sopotential", getParticularListener(local_pots));
228  listeners.emplace_back("sopotential", getParticularListener(local_pots2));
229 
230  Matrix<Real> ion_pots(num_walkers, max_values);
231  Matrix<Real> ion_pots2(num_walkers, max_values);
232  std::vector<ListenerVector<Real>> ion_listeners;
233  ion_listeners.emplace_back("sopotential", getParticularListener(ion_pots));
234  ion_listeners.emplace_back("sopotential", getParticularListener(ion_pots2));
235 
236  ParticleSet::mw_update(p_list);
237  TrialWaveFunction::mw_evaluateLog(twf_list, p_list);
238 
239  ListenerOption<Real> listener_opt{listeners, ion_listeners};
240  testing::TestSOECPotential::mw_evaluateImpl(so_ecp, o_list, twf_list, p_list, listener_opt, true);
241 
242  //use single walker API to get reference value
243  auto value = o_list[0].evaluateDeterministic(p_list[0]);
244 
245  //also check whether or not reference value from single_walker API is actually correct
246  //this value comes directly from the reference code soecp_eval_reference.cpp
247  CHECK(value == Approx(-3.530511241));
248 
249  CHECK(std::accumulate(local_pots.begin(), local_pots.begin() + local_pots.cols(), 0.0) == Approx(value));
250  CHECK(std::accumulate(local_pots2.begin(), local_pots2.begin() + local_pots2.cols(), 0.0) == Approx(value));
251  CHECK(std::accumulate(ion_pots.begin(), ion_pots.begin() + ion_pots.cols(), 0.0) == Approx(value));
252  CHECK(std::accumulate(ion_pots2.begin(), ion_pots2.begin() + ion_pots2.cols(), 0.0) == Approx(value));
253 
254  //Now lets try out the fast implementation
255  if (use_VPs)
256  {
257  value = 0.0;
258  SOECPotential so_ecp_exact(ions, elec, psi, true);
259  //srule is 0 for exact evaluation
260  ECPComponentBuilder ecp_comp_builder("test_read_soecp", c, -1, -1, 0);
261  okay = ecp_comp_builder.read_pp_file("so_ecp_test.xml");
262  REQUIRE(okay);
263  UPtr<SOECPComponent> so_ecp_comp = std::move(ecp_comp_builder.pp_so);
264  so_ecp_exact.addComponent(0, std::move(so_ecp_comp));
265  testing::TestSOECPotential::evalFast(so_ecp_exact, elec, value);
266  CHECK(value == Approx(-3.530511241));
267  }
268 
271 
272  elec.R[0] = {0.05, 0.0, -0.05};
273  elec.update();
274  testing::TestSOECPotential::mw_evaluateImpl(so_ecp, o_list, twf_list, p_list, listener_opt, true);
275 
278  auto value2 = o_list[0].evaluateDeterministic(elec);
279 
280  CHECK(std::accumulate(local_pots.begin(), local_pots.begin() + local_pots.cols(), 0.0) == Approx(value2));
281  // check the second walker which will be unchanged.
282  CHECK(std::accumulate(local_pots2[1], local_pots2[1] + local_pots2.cols(), 0.0) == Approx(value));
283 }
284 
285 TEST_CASE("SOECPotential", "[hamiltonian]")
286 {
287  //do test using VPs. This uses mw_ APIs for TWF in the mw_ SOECP APIs
288  doSOECPotentialTest(true);
289  //do test without VPs. This uses legacy APIs for TWF in the mw_ SOECP APIs
290  doSOECPotentialTest(false);
291 }
292 
293 } // namespace qmcplusplus
void evaluateImpl(ParticleSet &elec, bool keep_grid=false)
a class that defines a supercell in D-dimensional Euclean space.
static void mw_evaluateImpl(SOECPotential &so_ecp, const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< TrialWaveFunction > &twf_list, const RefVectorWithLeader< ParticleSet > &p_list, const std::optional< ListenerOption< Real >> listener_opt, bool keep_grid)
void setName(const std::string &aname)
Definition: ParticleSet.h:237
std::vector< std::unique_ptr< SOECPComponent > > ppset_
Definition: SOECPotential.h:85
Container_t::iterator begin()
Definition: OhmmsMatrix.h:89
class that handles xmlDoc
Definition: Libxml2Doc.h:76
std::unique_ptr< OperatorBase > makeClone(ParticleSet &qp, TrialWaveFunction &psi) final
int addSpecies(const std::string &aname)
When a name species does not exist, add a new species.
Definition: SpeciesSet.cpp:33
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
ParticleScalar spins
internal spin variables for dynamical spin calculations
Definition: ParticleSet.h:81
void createResource(ResourceCollection &collection) const
initialize a shared resource and hand it to a collection
QTBase::RealType RealType
Definition: Configuration.h:58
void doSOECPotentialTest(bool use_VPs)
size_t getTotalNum() const
Definition: ParticleSet.h:493
static void evalFast(SOECPotential &so_ecp, ParticleSet &elec, OperatorBase::Return_t &value)
const char num_walkers[]
Definition: HDFVersion.h:37
TEST_CASE("complex_helper", "[type_traits]")
std::unique_ptr< WaveFunctionComponent > buildComponent(xmlNodePtr cur) override
process a xml node at cur
RealType ValueType
Definition: QMCTypes.h:42
xmlNodePtr getRoot()
Definition: Libxml2Doc.h:88
JastrowBuilder using an analytic 1d functor Should be able to eventually handle all one and two body ...
static bool didGridChange(SOECPotential &so_ecp)
void update(bool skipSK=false)
update the internal data
void createResource(ResourceCollection &collection) const override
Initialize a shared resource and hand it to a collection.
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
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
static void addVPs(const RefVectorWithLeader< OperatorBase > &o_list, const RefVectorWithLeader< ParticleSet > &p_list)
std::unique_ptr< TrialWaveFunction > makeClone(ParticleSet &tqp) const
ForceBase::Real Real
Definition: ForceBase.cpp:26
size_type cols() const
Definition: OhmmsMatrix.h:78
Wrapping information on parallelism.
Definition: Communicate.h:68
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
std::unique_ptr< SOECPComponent > pp_so
QTBase::ValueType ValueType
Definition: Configuration.h:60
REQUIRE(std::filesystem::exists(filename))
Declaration of a builder class for an ECP component for an ionic type.
CASTTYPE & getCastedElement(size_t i) const
ParticlePos R
Position.
Definition: ParticleSet.h:79
QTBase::PosType PosType
Definition: Configuration.h:61
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)
std::unique_ptr< T > UPtr
auto getParticularListener(Matrix< T > &local_pots)
OHMMS_INDEXTYPE IndexType
define other types
Definition: Configuration.h:65
Return_t getValue() const noexcept
get a copy of value_
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
void create(const std::vector< int > &agroup)
create grouped particles
void setRandomGenerator(RandomBase< FullPrecRealType > *rng) override
Set the Random Generator object TODO: add docs.
Definition: SOECPotential.h:71
bool read_pp_file(const std::string &fname)
FullPrecRealType Return_t
type of return value of evaluate
Definition: OperatorBase.h:64
std::vector< std::reference_wrapper< T > > RefVector
Declaration of DiracDeterminantBatched with a S(ingle)P(article)O(rbital)Set.
Class to represent a many-body trial wave function.
bool parseFromString(const std::string_view data)
Definition: Libxml2Doc.cpp:204
static void mw_update(const RefVectorWithLeader< ParticleSet > &p_list, bool skipSK=false)
batched version of update
CHECK(log_values[0]==ComplexApprox(std::complex< double >{ 5.603777579195571, -6.1586603331188225 }))
void addComponent(int groupID, std::unique_ptr< SOECPComponent > &&pp)
handles acquire/release resource by the consumer (RefVectorWithLeader type).
void createSK()
create Structure Factor with PBCs
QTFull::RealType FullPrecRealType
Definition: Configuration.h:66
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
void setSpinor(bool is_spinor)
Definition: ParticleSet.h:257
DMCRefEnergy::FullPrecReal FullPrecReal
static void copyGridUnrotatedForTest(SOECPotential &so_ecp)
Convenience container for common optional element to mw_eval.._impl.
Definition: Listener.hpp:76
void addComponent(std::unique_ptr< WaveFunctionComponent > &&aterm)
add a WaveFunctionComponent
static void mw_evaluateLog(const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list)
batched version of evaluateLog.