QMCPACK
test_QMCHamiltonian.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: Peter Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
8 //
9 // File created by: Peter Doak, doakpw@ornl.gov, Oak Ridge National Laboratory
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 #include "catch.hpp"
14 
20 #include "TestListenerFunction.h"
25 
26 namespace qmcplusplus
27 {
28 using QMCT = QMCTraits;
29 using Real = QMCT::RealType;
31 
32 constexpr bool generate_test_data = false;
33 
34 TEST_CASE("QMCHamiltonian::flex_evaluate", "[hamiltonian]")
35 {
36  RuntimeOptions runtime_options;
39 
43 
44  TrialWaveFunction twf(runtime_options);
45 
46  std::vector<QMCHamiltonian> hamiltonians;
47  //hamiltonians.emplace_back(*(hamiltonian_pool.getPrimary()));
48  //hamiltonians.emplace_back(*(hamiltonian_pool.getPrimary()));
49 
50  std::vector<ParticleSet> elecs;
51  elecs.emplace_back(*(particle_pool.getParticleSet("e")));
52  elecs.emplace_back(*(particle_pool.getParticleSet("e")));
53 
54  // TODO: finish initializing the elecs.
55  //std::vector<QMCHamiltonian::RealType> local_energies(QMCHamiltonian::flex_evaluate(makeRefVector<QMCHamiltonian>(hamiltonians), makeRefVector<ParticleSet>(elecs)));
56 
57  //TODO: Would be nice to check some values but I think the system needs a little more setup
58 }
59 
60 /** QMCHamiltonian + Hamiltonians with listeners integration test
61  */
62 TEST_CASE("integrateListeners", "[hamiltonian]")
63 {
64  RuntimeOptions runtime_options;
66 
70  auto& pset_target = *(particle_pool.getParticleSet("e"));
71  //auto& species_set = pset_target.getSpeciesSet();
72  //auto& spo_map = wavefunction_pool.getWaveFunction("wavefunction")->getSPOMap();
73  auto& trial_wavefunction = *(wavefunction_pool.getPrimary());
74 
77  std::vector<ParticleSet> psets;
78 
79  // This must be done before clones otherwise the clone particle sets do not have the correct state.
80  hamiltonian_pool.getPrimary()->informOperatorsOfListener();
81 
82 
83  int num_walkers = 4;
84  int num_electrons = particle_pool.getParticleSet("e")->getTotalNum();
85  int num_ions = particle_pool.getParticleSet("ion")->getTotalNum();
86 
87  for (int iw = 0; iw < num_walkers; ++iw)
88  {
89  psets.emplace_back(pset_target);
90  psets.back().randomizeFromSource(*particle_pool.getParticleSet("ion"));
91  twfs.emplace_back(trial_wavefunction.makeClone(psets.back()));
92  hams.emplace_back(hamiltonian_pool.getPrimary()->makeClone(psets.back(), *twfs.back()));
93  }
94 
96  RefVectorWithLeader<QMCHamiltonian> ham_list{ham_refs[0], ham_refs};
97 
98  ResourceCollection ham_res("test_ham_res");
99  ham_list.getLeader().createResource(ham_res);
100  ResourceCollectionTeamLock<QMCHamiltonian> ham_lock(ham_res, ham_list);
101 
102  Matrix<Real> kinetic(num_walkers, num_electrons);
103  Matrix<Real> local_pots(num_walkers, num_electrons);
104  Matrix<Real> local_nrg(num_walkers, num_electrons);
105  Matrix<Real> ion_pots(num_walkers, num_ions);
106 
109 
110  ListenerVector<Real> listener_kinetic("kinetic", getSummingListener(kinetic));
111  QMCHamiltonian::mw_registerKineticListener(ham_list.getLeader(), listener_kinetic);
112  ListenerVector<Real> listener_potential("potential", getSummingListener(local_pots));
113  QMCHamiltonian::mw_registerLocalPotentialListener(ham_list.getLeader(), listener_potential);
114  ListenerVector<Real> listener_energy("local_energy", getSummingListener(local_nrg));
115  QMCHamiltonian::mw_registerLocalEnergyListener(ham_list.getLeader(), listener_energy);
116  ListenerVector<Real> listener_ion_potential("ion_potential", getSummingListener(ion_pots));
117  QMCHamiltonian::mw_registerLocalIonPotentialListener(ham_list.getLeader(), listener_ion_potential);
118 
119  auto p_refs = makeRefVector<ParticleSet>(psets);
120  RefVectorWithLeader<ParticleSet> p_list{p_refs[0], p_refs};
121 
122  ResourceCollection pset_res("test_pset_res");
123  p_list.getLeader().createResource(pset_res);
124  ResourceCollectionTeamLock<ParticleSet> pset_lock(pset_res, p_list);
125 
126  auto twf_refs = convertUPtrToRefVector(twfs);
127  RefVectorWithLeader<TrialWaveFunction> twf_list{twf_refs[0], twf_refs};
128 
129  ResourceCollection wfc_res("test_wfc_res");
130  twf_list.getLeader().createResource(wfc_res);
131  ResourceCollectionTeamLock<TrialWaveFunction> mw_wfc_lock(wfc_res, twf_list);
132 
133  // Otherwise we'll get no kinetic energy values
134  p_refs[0].get().L[0] = 1.0;
135  p_refs[1].get().L[1] = 1.0;
136  p_refs[2].get().L[2] = 1.0;
137  p_refs[3].get().L[3] = 1.0;
138 
139  if constexpr (generate_test_data)
140  {
141  std::cout << "QMCHamiltonian-registerListeners initialize psets with:\n{";
142 
143  for (int iw = 0; iw < num_walkers; ++iw)
144  {
145  //psets.emplace_back(pset_target);
146  std::cout << "{";
147  for (auto r : p_refs[iw].get().R)
148  std::cout << NativePrint(r) << ",";
149  std::cout << "},\n";
150  }
151  std::cout << "}\n";
152  }
153  else
154  {
155  std::vector<ParticleSet::ParticlePos> deterministic_rs = {
156  {
157  {0.515677886, 0.9486072745, -1.17423246},
158  {-0.3166678423, 1.376550506, 1.445290031},
159  {1.96071365, 2.47265689, 1.051449486},
160  {0.745853269, 0.5551359072, 4.080774681},
161  {-0.3515016103, -0.5192222523, 0.9941510909},
162  {-0.8354426872, 0.7071638258, -0.3409843552},
163  {0.4386044751, 1.237378731, 2.331874152},
164  {2.125850717, 0.3221067321, 0.5825731561},
165  },
166  {
167  {-0.4633736785, 0.06318772224, -0.8580153742},
168  {-1.174926354, -0.6276503679, 0.07458759314},
169  {1.327618206, 2.085829379, 1.415749862},
170  {0.9114727103, 0.1789183931, -0.08135540251},
171  {-2.267908723, 0.802928773, 0.9522812957},
172  {1.502715257, -1.84493529, 0.2805620469},
173  {3.168934617, 0.1348337978, 1.371092768},
174  {0.8310229518, 1.070827168, 1.18016733},
175  },
176  {
177  {-0.04847732172, -1.201739871, -1.700527771},
178  {0.1589259538, -0.3096047065, -2.066626415},
179  {2.255976232, 1.629132391, -0.8024446773},
180  {2.534792993, 3.121092901, 1.609780703},
181  {-0.2892376071, -0.152022511, -2.727613712},
182  {0.2477154804, 0.5039232765, 2.995702733},
183  {3.679345099, 3.037770313, 2.808899306},
184  {0.6418578532, 1.935944544, 1.515637954},
185  },
186  {
187  {0.91126951, 0.0234699242, 1.442297821},
188  {-0.9240061217, -0.1014997844, 0.9081020061},
189  {1.887794866, 2.210192703, 2.209118551},
190  {2.758945014, -1.21140421, 1.3337907},
191  {0.376540703, 0.3485486555, 0.9056881595},
192  {-0.3512770187, -0.4056820917, -2.068499576},
193  {0.5358460986, 2.720153363, 1.41999706},
194  {2.284020089, 1.173071915, 1.044597715},
195  },
196  };
197  for (int iw = 0; iw < num_walkers; ++iw)
198  {
199  p_refs[iw].get().R = deterministic_rs[iw];
200  }
201  }
202 
203  ParticleSet::mw_update(p_list);
204 
205  auto energies = QMCHamiltonian::mw_evaluate(ham_list, twf_list, p_list);
206 
207  CHECK(ham_list[0].getLocalEnergy() == energies[0]);
208  CHECK(ham_list[1].getLocalEnergy() == energies[1]);
209  CHECK(ham_list[0].getLocalEnergy() == p_list[0].PropertyList[WP::LOCALENERGY]);
210  CHECK(ham_list[1].getLocalEnergy() == p_list[1].PropertyList[WP::LOCALENERGY]);
211 
212  if constexpr (generate_test_data)
213  {
214  std::vector<Real> vector_kinetic;
215  std::copy(kinetic.begin(), kinetic.end(), std::back_inserter(vector_kinetic));
216  std::cout << " size kinetic: " << vector_kinetic.size() << '\n';
217  std::cout << " std::vector<Real> kinetic_ref_vector = " << NativePrint(vector_kinetic) << ";\n";
218 
219  std::vector<Real> vector_pots;
220  std::copy(local_pots.begin(), local_pots.end(), std::back_inserter(vector_pots));
221  std::cout << " size potentials: " << vector_pots.size() << '\n';
222  std::cout << " std::vector<Real> potential_ref_vector = " << NativePrint(vector_pots) << ";\n";
223 
224  std::vector<Real> vector_ions;
225  std::copy(ion_pots.begin(), ion_pots.end(), std::back_inserter(vector_ions));
226  std::cout << " size ion potentials: " << vector_ions.size() << '\n';
227  std::cout << " std::vector<Real> ion_potential_ref_vector = " << NativePrint(vector_ions) << ";\n";
228  }
229  else
230  {
231  std::vector<Real> kinetic_ref_vector = {
232  -0.5, -0, -0, -0, -0, -0, -0, -0, -0, -0.5, -0, -0, -0, -0, -0, -0,
233  -0, -0, -0.5, -0, -0, -0, -0, -0, -0, -0, -0, -0.5, -0, -0, -0, -0,
234  };
235  std::vector<Real> potential_ref_vector = {
236  -0.4304472804, -0.2378402054, -0.9860844016, -0.08201235533, -0.8099648952, -0.9536881447, -0.4498806596,
237  -0.4415832162, -0.9407452345, -0.6449454427, -2.240605593, -1.194514155, 0.04097786546, -0.1860728562,
238  -0.1374063194, -0.8808210492, 0.3020428121, 0.3772183955, -0.112801373, -0.5531326532, 0.4633262753,
239  0.3185032904, 0.3001851439, -0.4555109739, -0.2190704495, -0.7140043378, -1.641614318, 0.1718038917,
240  -0.7621642947, 0.2606962323, -0.1486036181, -1.001747012,
241  };
242  std::vector<Real> ion_potential_ref_vector = {
243  0.04332125187, 0.173753351, -0.9332901239, -1.323815107, 1.695662975, 0.5990064144, 0.1634206772, -1.207304001,
244  };
245 
246  std::size_t num_data = num_electrons * num_walkers;
247  for (std::size_t id = 0; id < num_data; ++id)
248  {
249  INFO("id : " << id);
250  CHECK(kinetic_ref_vector[id] == Approx(kinetic(id)));
251  }
252 
253  for (std::size_t id = 0; id < num_data; ++id)
254  {
255  INFO("id : " << id);
256  CHECK(potential_ref_vector[id] == Approx(local_pots(id)));
257  }
258 
259  std::size_t num_data_ions = num_ions * num_walkers;
260  for (std::size_t id = 0; id < num_data_ions; ++id)
261  {
262  INFO("id : " << id);
263  CHECK(ion_potential_ref_vector[id] == Approx(ion_pots(id)));
264  }
265 
266  // When only EE and EI coulomb potentials the local energy is just the sum of
267  // the local_pots and kinetic
268  auto sum_local_pots = std::accumulate(local_pots.begin(), local_pots.end(), 0.0);
269  auto sum_kinetic = std::accumulate(kinetic.begin(), kinetic.end(), 0.0);
270  auto sum_local_nrg = std::accumulate(local_nrg.begin(), local_nrg.end(), 0.0);
271  CHECK(sum_local_nrg == Approx(sum_local_pots + sum_kinetic));
272 
273  // Here we test consistency between the per particle energies and the per hamiltonian energies
274  typename decltype(energies)::value_type hamiltonian_local_nrg_sum = 0.0;
275  typename decltype(energies)::value_type energies_sum = 0.0;
276  for (int iw = 0; iw < num_walkers; ++iw) {
277  hamiltonian_local_nrg_sum += ham_list[iw].getLocalEnergy();
278  energies_sum += energies[iw];
279  }
280 
281  // the QMCHamiltonian.getLocalEnergy() contains the ion_potential as well.
282  sum_local_nrg += std::accumulate(ion_pots.begin(), ion_pots.end(), 0.0);
283  CHECK(sum_local_nrg == Approx(hamiltonian_local_nrg_sum));
284  CHECK(sum_local_nrg == Approx(energies_sum));
285  }
286 }
287 
288 } // namespace qmcplusplus
Container_t::iterator begin()
Definition: OhmmsMatrix.h:89
The operator<< functions provide output for data structures that can be used to directly initialize t...
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
static HamiltonianPool makeHamWithEEEI(Communicate *comm, ParticleSetPool &particle_pool, WaveFunctionPool &wavefunction_pool)
QTBase::RealType RealType
Definition: Configuration.h:58
static ParticleSetPool make_diamondC_1x1x1(Communicate *c)
const char num_walkers[]
Definition: HDFVersion.h:37
TEST_CASE("complex_helper", "[type_traits]")
static WaveFunctionPool make_diamondC_1x1x1(const RuntimeOptions &runtime_options, Communicate *comm, ParticleSetPool &particle_pool)
An object of this type is a listener expecting a callback to the report function with a vector of val...
Definition: Listener.hpp:38
constexpr bool generate_test_data
set to true to generate new random R for particles.
static void mw_registerLocalEnergyListener(QMCHamiltonian &ham_leader, ListenerVector< RealType > listener)
std::vector< std::unique_ptr< T > > UPtrVector
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
This wrapper is to allow us to leave the user facing operator<< for classes alone.
static RefVector< T > convertUPtrToRefVector(const UPtrVector< T > &ptr_list)
convert a vector of std::unique_ptrs<T> to a refvector<T>
ForceBase::Real Real
Definition: ForceBase.cpp:26
static std::vector< QMCHamiltonian::FullPrecRealType > mw_evaluate(const RefVectorWithLeader< QMCHamiltonian > &ham_list, const RefVectorWithLeader< TrialWaveFunction > &wf_list, const RefVectorWithLeader< ParticleSet > &p_list)
batched version of evaluate for LocalEnergy
void copy(const Array< T1, 3 > &src, Array< T2, 3 > &dest)
Definition: Blitz.h:639
Wrapping information on parallelism.
Definition: Communicate.h:68
static void mw_registerKineticListener(QMCHamiltonian &ham_leader, ListenerVector< RealType > listener)
Listener Registration This must be called on a QMCHamiltonian that has acquired multiwalker resources...
WalkerProperties::Indexes WP
Definition: ParticleSet.cpp:34
static void mw_registerLocalIonPotentialListener(QMCHamiltonian &ham_leader, ListenerVector< RealType > listener)
auto getParticularListener(Matrix< T > &local_pots)
static HamiltonianPool make_hamWithEE(Communicate *comm, ParticleSetPool &particle_pool, WaveFunctionPool &wavefunction_pool)
std::vector< std::reference_wrapper< T > > RefVector
Class to represent a many-body trial wave function.
static void mw_registerLocalPotentialListener(QMCHamiltonian &ham_leader, ListenerVector< RealType > listener)
Indexes
an enum denoting index of physical properties
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 }))
handles acquire/release resource by the consumer (RefVectorWithLeader type).
Container_t::iterator end()
Definition: OhmmsMatrix.h:90
QMCTraits::FullPrecRealType value_type
auto getSummingListener(Matrix< T > &local_pots)
Declaration of QMCHamiltonian.