QMCPACK
test_bare_kinetic.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) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign
8 //
9 // File created by: Mark Dewing, markdewing@gmail.com, University of Illinois at Urbana-Champaign
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 #include "catch.hpp"
14 
15 #include "OhmmsData/Libxml2Doc.h"
16 #include "OhmmsPETE/OhmmsMatrix.h"
17 #include "Particle/ParticleSet.h"
23 
24 #include <functional>
25 #include <stdio.h>
26 #include <string>
27 
28 using std::string;
29 
30 namespace qmcplusplus
31 {
32 
33 using QMCT = QMCTraits;
34 using Real = QMCT::RealType;
35 
36 TEST_CASE("Bare Kinetic Energy", "[hamiltonian]")
37 {
38  const SimulationCell simulation_cell;
39  ParticleSet ions(simulation_cell);
40  ParticleSet elec(simulation_cell);
41 
42  ions.setName("ion");
43  ions.create({1});
44  ions.R[0] = {0.0, 0.0, 0.0};
45  elec.setName("elec");
46  elec.create({2});
47  elec.R[0] = {0.0, 1.0, 0.0};
48  elec.R[1] = {1.0, 1.0, 0.0};
49  SpeciesSet& tspecies = elec.getSpeciesSet();
50  int upIdx = tspecies.addSpecies("u");
51  int massIdx = tspecies.addAttribute("mass");
52  tspecies(massIdx, upIdx) = 1.0;
53 
54  elec.addTable(ions);
55  elec.update();
56 
57  const char* particles = R"(<tmp></tmp>)";
58 
60  bool okay = doc.parseFromString(particles);
61  REQUIRE(okay);
62 
63  xmlNodePtr root = doc.getRoot();
64 
65  xmlNodePtr h1 = xmlFirstElementChild(root);
66 
67  RuntimeOptions runtime_options;
68  TrialWaveFunction psi(runtime_options);
69  BareKineticEnergy bare_ke(elec, psi);
70  bare_ke.put(h1);
71 
72  elec.L[0] = 1.0;
73  elec.L[1] = 0.0;
74  double v = bare_ke.evaluate(elec);
75  REQUIRE(v == -0.5);
76 
77  elec.L[0] = 0.0;
78  elec.L[1] = 0.0;
79  elec.G[0][0] = 1.0;
80  elec.G[0][1] = 0.0;
81  elec.G[0][2] = 0.0;
82  elec.G[1][0] = 0.0;
83  elec.G[1][1] = 0.0;
84  elec.G[1][2] = 0.0;
85  v = bare_ke.evaluate(elec);
86  REQUIRE(v == -0.5);
87 }
88 
89 TEST_CASE("Bare KE Pulay PBC", "[hamiltonian]")
90 {
94 
96 
97  //Cell definition:
98 
100  lattice.BoxBConds = true; // periodic
101  lattice.R.diagonal(20);
102  lattice.LR_dim_cutoff = 15;
103  lattice.reset();
104 
105  const SimulationCell simulation_cell(lattice);
106  ParticleSet ions(simulation_cell);
107  ParticleSet elec(simulation_cell);
108 
109  ions.setName("ion0");
110  ions.create({2});
111  ions.R[0] = {0.0, 0.0, 0.0};
112  ions.R[1] = {6.0, 0.0, 0.0};
113  SpeciesSet& ion_species = ions.getSpeciesSet();
114  int pIdx = ion_species.addSpecies("Na");
115  int pChargeIdx = ion_species.addAttribute("charge");
116  int iatnumber = ion_species.addAttribute("atomic_number");
117  ion_species(pChargeIdx, pIdx) = 1;
118  ion_species(iatnumber, pIdx) = 11;
119  ions.createSK();
120 
121  elec.setName("e");
122  std::vector<int> agroup(2, 1);
123  elec.create(agroup);
124  elec.R[0] = {2.0, 0.0, 0.0};
125  elec.R[1] = {3.0, 0.0, 0.0};
126  SpeciesSet& tspecies = elec.getSpeciesSet();
127  int upIdx = tspecies.addSpecies("u");
128  int downIdx = tspecies.addSpecies("d");
129  int chargeIdx = tspecies.addAttribute("charge");
130  int massIdx = tspecies.addAttribute("mass");
131  tspecies(chargeIdx, upIdx) = -1;
132  tspecies(chargeIdx, downIdx) = -1;
133  tspecies(massIdx, upIdx) = 1.0;
134  tspecies(massIdx, downIdx) = 1.0;
135 
136  elec.createSK();
137 
138  ions.resetGroups();
139 
140  // The call to resetGroups is needed transfer the SpeciesSet
141  // settings to the ParticleSet
142  elec.resetGroups();
143 
144  //Cool. Now to construct a wavefunction with 1 and 2 body jastrow (no determinant)
145  RuntimeOptions runtime_options;
146  TrialWaveFunction psi(runtime_options);
147 
148  //Add the two body jastrow
149  const char* particles = R"(<tmp>
150  <jastrow name="J2" type="Two-Body" function="Bspline" print="yes" gpu="no">
151  <correlation speciesA="u" speciesB="d" rcut="10" size="8">
152  <coefficients id="ud" type="Array"> 2.015599059 1.548994099 1.17959447 0.8769687661 0.6245736507 0.4133517767 0.2333851935 0.1035636904</coefficients>
153  </correlation>
154  </jastrow>
155  </tmp>
156  )";
158  bool okay = doc.parseFromString(particles);
159  REQUIRE(okay);
160 
161  xmlNodePtr root = doc.getRoot();
162 
163  xmlNodePtr jas2 = xmlFirstElementChild(root);
164 
165  RadialJastrowBuilder jastrow(c, elec);
166  psi.addComponent(jastrow.buildComponent(jas2));
167  // Done with two body jastrow.
168 
169  //Add the one body jastrow.
170  const char* particles2 = R"(<tmp>
171  <jastrow name="J1" type="One-Body" function="Bspline" source="ion0" print="yes">
172  <correlation elementType="Na" rcut="10" size="10" cusp="0">
173  <coefficients id="eNa" type="Array"> 1.244201343 -1.188935609 -1.840397253 -1.803849126 -1.612058635 -1.35993202 -1.083353212 -0.8066295188 -0.5319252448 -0.3158819772</coefficients>
174  </correlation>
175  </jastrow>
176  </tmp>
177  )";
178  bool okay3 = doc.parseFromString(particles2);
179  REQUIRE(okay3);
180 
181  root = doc.getRoot();
182 
183  xmlNodePtr jas1 = xmlFirstElementChild(root);
184 
185  RadialJastrowBuilder jastrow1bdy(c, elec, ions);
186  psi.addComponent(jastrow1bdy.buildComponent(jas1));
187 
188  const char* kexml = R"(<tmp></tmp>)";
189 
190  root = doc.getRoot();
191 
192  xmlNodePtr h1 = xmlFirstElementChild(root);
193 
194  BareKineticEnergy bare_ke(elec, psi);
195  bare_ke.put(h1);
196 
197  // update all distance tables
198  ions.update();
199  elec.update();
200 
201  RealType logpsi = psi.evaluateLog(elec);
202 
203  RealType keval = bare_ke.evaluate(elec);
204 
205  //This is validated against an alternate code path (waveefunction tester for local energy).
206  CHECK(keval == Approx(-0.147507745));
207 
208  ParticleSet::ParticlePos HFTerm, PulayTerm;
209  HFTerm.resize(ions.getTotalNum());
210  PulayTerm.resize(ions.getTotalNum());
211 
212  RealType keval2 = bare_ke.evaluateWithIonDerivs(elec, ions, psi, HFTerm, PulayTerm);
213 
214  CHECK(keval2 == Approx(-0.147507745));
215  //These are validated against finite differences (delta=1e-6).
216  CHECK(PulayTerm[0][0] == Approx(-0.13166));
217  CHECK(PulayTerm[0][1] == Approx(0.0));
218  CHECK(PulayTerm[0][2] == Approx(0.0));
219  CHECK(PulayTerm[1][0] == Approx(-0.12145));
220  CHECK(PulayTerm[1][1] == Approx(0.0));
221  CHECK(PulayTerm[1][2] == Approx(0.0));
222 }
223 
224 /** Provide a test scope parameterized on electron species mass that then can run a set of tests using
225  * its objects.
226  * I couldn't see a easier solution to deal with all the setup to get both coverage of this
227  * interesting feature considering various approaches to copy constructors the objects in the testing
228  * scope take.
229  */
230 void testElecCase(double mass_up,
231  double mass_dn,
232  std::function<void(RefVectorWithLeader<OperatorBase>& o_list,
235  Matrix<Real>& kinetic_energies,
236  std::vector<ListenerVector<Real>>& listeners,
237  std::vector<ListenerVector<Real>>& ion_listeners)> tests)
238 {
240 
241  const SimulationCell simulation_cell;
242 
243  ParticleSet ions(simulation_cell);
244 
245  ions.setName("ion");
246  ions.create({1});
247  ions.R[0] = {0.0, 0.0, 0.0};
248  Matrix<Real> kinetic_energies(2);
249 
250  ParticleSet elec(simulation_cell);
251 
252  elec.setName("elec");
253  elec.create({1, 1});
254  elec.R[0] = {0.0, 1.0, 0.0};
255  elec.R[1] = {1.0, 1.0, 0.0};
256  SpeciesSet& tspecies = elec.getSpeciesSet();
257  int upIdx = tspecies.addSpecies("u");
258  int downIdx = tspecies.addSpecies("d");
259  int chargeIdx = tspecies.addAttribute("charge");
260  int massIdx = tspecies.addAttribute("mass");
261  tspecies(chargeIdx, upIdx) = -1;
262  tspecies(chargeIdx, downIdx) = -1;
263  tspecies(massIdx, upIdx) = mass_up;
264  tspecies(massIdx, downIdx) = mass_dn;
265 
266  elec.addTable(ions);
267  elec.update();
268 
269  ParticleSet elec2(elec);
270  elec2.R[1][2] = 1.0;
271  elec2.update();
272 
273  RuntimeOptions runtime_options;
274  TrialWaveFunction psi(runtime_options);
275  TrialWaveFunction psi_clone(runtime_options);
276 
277  RefVector<ParticleSet> ptcls{elec, elec2};
278  RefVectorWithLeader<ParticleSet> p_list(elec, ptcls);
279 
280  BareKineticEnergy bare_ke(elec, psi);
281  BareKineticEnergy bare_ke2(elec, psi_clone);
282 
283  RefVector<OperatorBase> bare_kes{bare_ke, bare_ke2};
284  RefVectorWithLeader<OperatorBase> o_list(bare_ke, bare_kes);
285  elec.L[0] = 1.0;
286  elec.L[1] = 0.0;
287  elec2.L[0] = 1.0;
288  elec2.L[1] = 0.0;
289 
290  RefVectorWithLeader<TrialWaveFunction> twf_list(psi, {psi, psi_clone});
291 
292  ResourceCollection bare_ke_res("test_bare_ke_res");
293  bare_ke.createResource(bare_ke_res);
294  ResourceCollectionTeamLock<OperatorBase> bare_ke_lock(bare_ke_res, o_list);
295 
296  ResourceCollection pset_res("test_pset_res");
297  elec.createResource(pset_res);
298  ResourceCollectionTeamLock<ParticleSet> pset_lock(pset_res, p_list);
299 
300  std::vector<ListenerVector<Real>> listeners;
301  listeners.emplace_back("kinetic", getParticularListener(kinetic_energies));
302 
303  std::vector<ListenerVector<Real>> ion_listeners;
304 
305  tests(o_list, twf_list, p_list, kinetic_energies, listeners, ion_listeners);
306 }
307 
308 /** just set the values to test the electron weights */
309 auto getTestCaseForWeights(Real value1, Real value2, Real value3)
310 {
311  return [value1, value2,
313  RefVectorWithLeader<ParticleSet>& p_list, Matrix<Real>& kinetic_energies,
314  std::vector<ListenerVector<Real>>& listeners, std::vector<ListenerVector<Real>>& ion_listeners) {
315  auto& bare_ke = o_list[0];
316  bare_ke.mw_evaluatePerParticle(o_list, twf_list, p_list, listeners, ion_listeners);
317  CHECK(bare_ke.getValue() == Approx(value1));
318  auto& bare_ke2 = o_list[1];
319  CHECK(bare_ke2.getValue() == Approx(value1));
320  // Check that the sum of the particle energies is consistent with the total.
321  CHECK(std::accumulate(kinetic_energies.begin(), kinetic_energies.begin() + kinetic_energies.cols(), 0.0) ==
322  Approx(bare_ke.getValue()));
323  // check a single particle
324  CHECK(std::accumulate(kinetic_energies[1], kinetic_energies[1] + kinetic_energies.cols(), 0.0) == Approx(value1));
325 
326  auto& elec = p_list[0];
327  elec.L[0] = 2.0;
328  elec.L[1] = 1.0;
329  auto& elec2 = p_list[1];
330  elec2.L[0] = 2.0;
331  elec2.L[1] = 1.0;
332 
333  bare_ke.mw_evaluatePerParticle(o_list, twf_list, p_list, listeners, ion_listeners);
334  CHECK(std::accumulate(kinetic_energies.begin(), kinetic_energies.begin() + kinetic_energies.cols(), 0.0) ==
335  Approx(bare_ke.getValue()));
336  CHECK(std::accumulate(kinetic_energies[1], kinetic_energies[1] + kinetic_energies.cols(), 0.0) == Approx(value2));
337 
338  // test that mw_evaluatePerParticleWithToperator decays to mw_evaluatePerParticle
339  // If mw_evaluatePerParticle follows the standard behavior in OperatorBase the Listner will not receive a report
340  // and tis values will remain as in the previous check.
341  elec.L[0] = 1.0;
342  elec.L[1] = 0.0;
343  elec2.L[0] = 1.0;
344  elec2.L[1] = 0.0;
345 
346  bare_ke.mw_evaluatePerParticleWithToperator(o_list, twf_list, p_list, listeners, ion_listeners);
347  CHECK(std::accumulate(kinetic_energies[1], kinetic_energies[1] + kinetic_energies.cols(), 0.0) == Approx(value3));
348  };
349 }
350 
351 TEST_CASE("BareKineticEnergyListener", "[hamiltonian]")
352 {
354  testElecCase(1.0, 1.0, getTestCaseForWeights(-0.5, -1.5, -0.5));
355  testElecCase(0.5, 1.0, getTestCaseForWeights(-1.0, -2.5, -1.0));
357 }
358 
359 } // namespace qmcplusplus
void resize(size_type n, Type_t val=Type_t())
Resize the container.
Definition: OhmmsVector.h:166
a class that defines a supercell in D-dimensional Euclean space.
RealType evaluateLog(ParticleSet &P)
evalaute the log (internally gradients and laplacian) of the trial wavefunction.
void setName(const std::string &aname)
Definition: ParticleSet.h:237
class that handles xmlDoc
Definition: Libxml2Doc.h:76
void pause()
Pause the summary and log streams.
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
QTBase::RealType RealType
Definition: Configuration.h:58
size_t getTotalNum() const
Definition: ParticleSet.h:493
TEST_CASE("complex_helper", "[type_traits]")
std::unique_ptr< WaveFunctionComponent > buildComponent(xmlNodePtr cur) override
process a xml node at cur
xmlNodePtr getRoot()
Definition: Libxml2Doc.h:88
JastrowBuilder using an analytic 1d functor Should be able to eventually handle all one and two body ...
An object of this type is a listener expecting a callback to the report function with a vector of val...
Definition: Listener.hpp:38
void createResource(ResourceCollection &collection) const
initialize a shared resource and hand it to a collection
Return_t evaluateWithIonDerivs(ParticleSet &P, ParticleSet &ions, TrialWaveFunction &psi, ParticleSet::ParticlePos &hf_terms, ParticleSet::ParticlePos &pulay_terms) override
Function to compute the value, direct ionic gradient terms, and pulay terms for the local kinetic ene...
void update(bool skipSK=false)
update the internal data
Attaches a unit to a Vector for IO.
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
ParticleLaplacian L
laplacians of the particles
Definition: ParticleSet.h:85
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
ForceBase::Real Real
Definition: ForceBase.cpp:26
OutputManagerClass outputManager(Verbosity::HIGH)
Wrapping information on parallelism.
Definition: Communicate.h:68
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
int addTable(const ParticleSet &psrc, DTModes modes=DTModes::ALL_OFF)
add a distance table
void resume()
Resume the summary and log streams.
auto getTestCaseForWeights(Real value1, Real value2, Real value3)
just set the values to test the electron weights
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
void testElecCase(double mass_up, double mass_dn, std::function< void(RefVectorWithLeader< OperatorBase > &o_list, RefVectorWithLeader< TrialWaveFunction > &twf_list, RefVectorWithLeader< ParticleSet > &p_list, Matrix< Real > &kinetic_energies, std::vector< ListenerVector< Real >> &listeners, std::vector< ListenerVector< Real >> &ion_listeners)> tests)
Provide a test scope parameterized on electron species mass that then can run a set of tests using it...
void createResource(ResourceCollection &collection) const override
initialize a shared resource and hand it to a collection
QTBase::ValueType ValueType
Definition: Configuration.h:60
REQUIRE(std::filesystem::exists(filename))
ParticleGradient G
gradients of the particles
Definition: ParticleSet.h:83
ParticlePos R
Position.
Definition: ParticleSet.h:79
QTBase::PosType PosType
Definition: Configuration.h:61
auto getParticularListener(Matrix< T > &local_pots)
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
void create(const std::vector< int > &agroup)
create grouped particles
Declaration of a TrialWaveFunction.
std::vector< std::reference_wrapper< T > > RefVector
Class to represent a many-body trial wave function.
Return_t evaluate(ParticleSet &P) override
Evaluate the local energy contribution of this component.
bool parseFromString(const std::string_view data)
Definition: Libxml2Doc.cpp:204
CHECK(log_values[0]==ComplexApprox(std::complex< double >{ 5.603777579195571, -6.1586603331188225 }))
handles acquire/release resource by the consumer (RefVectorWithLeader type).
LatticeGaussianProduct::ValueType ValueType
bool put(xmlNodePtr) override
implements the virtual function.
void createSK()
create Structure Factor with PBCs
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
traits for QMC variables
Definition: Configuration.h:49
void addComponent(std::unique_ptr< WaveFunctionComponent > &&aterm)
add a WaveFunctionComponent
Evaluate the kinetic energy with a single mass.