QMCPACK
test_MO_spinor.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: Cody A. Melton, cmelton@sandia.gov, Sandia National Laboratories
8 //
9 // File created by: Cody A. Melton, cmelton@sandia.gov, Sandia National Laboratories
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 #include "catch.hpp"
14 
15 #include "Configuration.h"
16 #include "Message/Communicate.h"
17 #include "Particle/ParticleSet.h"
19 #include "Particle/DistanceTable.h"
23 
24 namespace qmcplusplus
25 {
27 {
28  app_log() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
29  app_log() << "!!!!!!! LCAO SpinorSet from HDF !!!!!!!\n";
30  app_log() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
31 
33  using RealType = SPOSet::RealType;
35 
37  auto ions_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
38  auto elec_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
39  ParticleSet& ions_(*ions_uptr);
40  ParticleSet& elec_(*elec_uptr);
41 
42  ions_.setName("ion");
43  ptcl.addParticleSet(std::move(ions_uptr));
44  ions_.create({1});
45 
46  ions_.R[0] = {0.00000000, 0.00000000, 0.00000000};
47  SpeciesSet& ispecies = ions_.getSpeciesSet();
48  int hIdx = ispecies.addSpecies("H");
49  ions_.update();
50 
51  elec_.setName("elec");
52  ptcl.addParticleSet(std::move(elec_uptr));
53  elec_.create({1});
54  elec_.R[0] = {0.1, -0.3, 1.7};
55  elec_.spins[0] = 0.6;
56  elec_.setSpinor(true);
57 
58  SpeciesSet& tspecies = elec_.getSpeciesSet();
59  int upIdx = tspecies.addSpecies("u");
60  int chargeIdx = tspecies.addAttribute("charge");
61  tspecies(chargeIdx, upIdx) = -1;
62 
63 
64  elec_.addTable(ions_);
65  elec_.update();
66 
67  const char* particles = R"XML(<tmp>
68  <sposet_builder name="spinorbuilder" type="molecularorbital" href="lcao_spinor.h5" source="ion" precision="float">
69  <basisset transform="yes"/>
70  <sposet name="myspo" size="2"/>
71  </sposet_builder>
72  </tmp>)XML";
73 
75  bool okay = doc.parseFromString(particles);
76  REQUIRE(okay);
77 
78  xmlNodePtr root = doc.getRoot();
79 
80  xmlNodePtr bnode = xmlFirstElementChild(root);
81  SPOSetBuilderFactory fac(c, elec_, ptcl.getPool());
82  const auto spo_builder_ptr = fac.createSPOSetBuilder(bnode);
83  auto& bb = *spo_builder_ptr;
84 
85  // only pick up the last sposet
86  std::unique_ptr<SPOSet> spo;
87  processChildren(bnode, [&](const std::string& cname, const xmlNodePtr element) {
88  if (cname == "sposet")
89  spo = bb.createSPOSet(element);
90  });
91  REQUIRE(spo);
92 
93  //For this test, we are making the number of total orbitals in the SPOSet larger
94  //than what is requested for all SPOSet calls.
95  //That will allow us to check the behavior of SpinorSet doing the right thing if
96  //OrbitalSetSize > norbs_requested. This is necessary for things like orb opt with single determinants
97  SPOSet::ValueMatrix psiM(elec_.R.size(), elec_.R.size());
98  SPOSet::GradMatrix dpsiM(elec_.R.size(), elec_.R.size());
99  SPOSet::ValueMatrix dspsiM(elec_.R.size(), elec_.R.size()); //spin gradient
100  SPOSet::ValueMatrix d2psiM(elec_.R.size(), elec_.R.size());
101 
102  spo->evaluate_notranspose(elec_, 0, elec_.R.size(), psiM, dpsiM, d2psiM);
103 
104  ValueType val(5.584596565578567e-05, 0.0012321335483993093);
105  ValueType vdx(-2.7922982853738495e-05, -0.0006160667747698895);
106  ValueType vdy(8.376894847079449e-05, 0.0018482003223147029);
107  ValueType vdz(-0.00047469070804637896, -0.010473135160780798);
108  ValueType vlp(0.0033369958606517744, 0.07362437917398082);
109  ValueType vds(1.0474021389417806e-05, -0.00040482519442528657);
110  const RealType eps = 1e-4;
111 
112  for (unsigned int iat = 0; iat < 1; iat++)
113  {
114  CHECK(psiM[iat][0] == ComplexApprox(val).epsilon(eps));
115  CHECK(dpsiM[iat][0][0] == ComplexApprox(vdx).epsilon(eps));
116  CHECK(dpsiM[iat][0][1] == ComplexApprox(vdy).epsilon(eps));
117  CHECK(dpsiM[iat][0][2] == ComplexApprox(vdz).epsilon(eps));
118  CHECK(d2psiM[iat][0] == ComplexApprox(vlp).epsilon(eps));
119  }
120 
121  /** this is a somewhat simple example. We have an ion at the origin
122  * and a gaussian basis function centered on the ion as a orbital.
123  * In this case, the ion derivative is actually just the negative of
124  * the electron gradient.
125  */
126  SPOSet::GradMatrix gradIon(elec_.R.size(), elec_.R.size());
127  spo->evaluateGradSource(elec_, 0, elec_.R.size(), ions_, 0, gradIon);
128  for (int iat = 0; iat < 1; iat++)
129  {
130  CHECK(gradIon[iat][0][0] == ComplexApprox(-vdx).epsilon(eps));
131  CHECK(gradIon[iat][0][1] == ComplexApprox(-vdy).epsilon(eps));
132  CHECK(gradIon[iat][0][2] == ComplexApprox(-vdz).epsilon(eps));
133  }
134 
135  //temporary arrays for holding the values of the up and down channels respectively.
136  SPOSet::ValueVector psi_work;
137 
138  //temporary arrays for holding the gradients of the up and down channels respectively.
139  SPOSet::GradVector dpsi_work;
140 
141  //temporary arrays for holding the laplacians of the up and down channels respectively.
142  SPOSet::ValueVector d2psi_work;
143 
144  //temporary arrays for holding spin gradient
145  SPOSet::ValueVector dspsi_work;
146 
147  psi_work.resize(elec_.R.size());
148  dpsi_work.resize(elec_.R.size());
149  d2psi_work.resize(elec_.R.size());
150  dspsi_work.resize(elec_.R.size());
151 
152  //We worked hard to generate nice reference data above. Let's generate a test for evaluateV
153  //and evaluateVGL by perturbing the electronic configuration by dR, and then make
154  //single particle moves that bring it back to our original R reference values.
155 
156  //Our perturbation vector.
158  dR.resize(1);
159  dR[0][0] = 0.1;
160  dR[0][1] = 0.2;
161  dR[0][2] = 0.1;
162 
163  //The new R of our perturbed particle set. Ma
165  Rnew.resize(1);
166  Rnew = elec_.R + dR;
167  elec_.R = Rnew;
168  elec_.update();
169 
170  //Now we test evaluateValue()
171  for (unsigned int iat = 0; iat < 1; iat++)
172  {
173  psi_work = 0.0;
174  elec_.makeMove(iat, -dR[iat], false);
175  spo->evaluateValue(elec_, iat, psi_work);
176 
177  CHECK(psi_work[0] == ComplexApprox(val));
178  elec_.rejectMove(iat);
179  }
180 
181  //Now we test evaluateVGL()
182  for (unsigned int iat = 0; iat < 1; iat++)
183  {
184  psi_work = 0.0;
185  dpsi_work = 0.0;
186  d2psi_work = 0.0;
187  dspsi_work = 0.0;
188 
189  elec_.makeMove(iat, -dR[iat], false);
190  spo->evaluateVGL_spin(elec_, iat, psi_work, dpsi_work, d2psi_work, dspsi_work);
191 
192  CHECK(psi_work[0] == ComplexApprox(val).epsilon(eps));
193  CHECK(dpsi_work[0][0] == ComplexApprox(vdx).epsilon(eps));
194  CHECK(dpsi_work[0][1] == ComplexApprox(vdy).epsilon(eps));
195  CHECK(dpsi_work[0][2] == ComplexApprox(vdz).epsilon(eps));
196  CHECK(d2psi_work[0] == ComplexApprox(vlp).epsilon(eps));
197  CHECK(dspsi_work[0] == ComplexApprox(vds).epsilon(eps));
198  elec_.rejectMove(iat);
199  }
200 
201  //Now we test evaluateSpin:
202 
203  for (unsigned int iat = 0; iat < 1; iat++)
204  {
205  psi_work = 0.0;
206  dspsi_work = 0.0;
207 
208  elec_.makeMove(iat, -dR[iat], false);
209  spo->evaluate_spin(elec_, iat, psi_work, dspsi_work);
210 
211  CHECK(psi_work[0] == ComplexApprox(val).epsilon(eps));
212  CHECK(dspsi_work[0] == ComplexApprox(vds).epsilon(eps));
213 
214  elec_.rejectMove(iat);
215  }
216 
217  // test batched interface
218  // first move elec_ back to original positions for reference
219  Rnew = elec_.R - dR;
220  elec_.R = Rnew;
221  elec_.update();
222 
223  //make a spin displacement, just set to zero for the test
225  dS.resize(1);
226 
227  //now create second walker
228  ParticleSet elec_2(elec_);
229  elec_2.R[0] = {-0.4, 1.5, -0.2};
230  elec_2.spins[0] = -1.3;
231 
232  //create new reference values for new positions
233  ValueType val2(-0.00010787670610075059, -5.882498404872149e-05);
234  ValueType vdx2(-0.0002157534121903495, -0.00011764996809136147);
235  ValueType vdy2(0.0008090752956289096, 0.0004411873802963092);
236  ValueType vdz2(-0.00010787670612158852, -5.8824984060083926e-05);
237  ValueType vlp2(-0.004989237947754119, -0.0027206229528162103);
238  ValueType vds2(0.0001907917398151183, 0.005002478563410625);
239 
240  ResourceCollection pset_res("test_pset_res");
241  elec_.createResource(pset_res);
242  RefVectorWithLeader<ParticleSet> p_list(elec_);
243  p_list.push_back(elec_);
244  p_list.push_back(elec_2);
245 
246  ResourceCollectionTeamLock<ParticleSet> mw_pset_lock(pset_res, p_list);
247 
248  elec_.mw_update(p_list);
249  std::unique_ptr<SPOSet> spo_2(spo->makeClone());
250  RefVectorWithLeader<SPOSet> spo_list(*spo);
251  spo_list.push_back(*spo);
252  spo_list.push_back(*spo_2);
253 
254  //test resource APIs
255  //First resource is created, and then passed to the colleciton so it should be null
256  ResourceCollection spo_res("test_spo_res");
257  spo->createResource(spo_res);
258  SpinorSet& spinor = spo_list.getCastedLeader<SpinorSet>();
259  REQUIRE(!spinor.isResourceOwned());
260  ResourceCollectionTeamLock<SPOSet> mw_spo_lock(spo_res, spo_list);
261  REQUIRE(spinor.isResourceOwned());
262 
263  SPOSet::ValueMatrix psiM_2(elec_.R.size(), elec_.R.size());
264  SPOSet::GradMatrix dpsiM_2(elec_.R.size(), elec_.R.size());
265  SPOSet::ValueMatrix d2psiM_2(elec_.R.size(), elec_.R.size());
266 
267  RefVector<SPOSet::ValueMatrix> logdet_list;
268  RefVector<SPOSet::GradMatrix> dlogdet_list;
269  RefVector<SPOSet::ValueMatrix> d2logdet_list;
270 
271  logdet_list.push_back(psiM);
272  logdet_list.push_back(psiM_2);
273  dlogdet_list.push_back(dpsiM);
274  dlogdet_list.push_back(dpsiM_2);
275  d2logdet_list.push_back(d2psiM);
276  d2logdet_list.push_back(d2psiM_2);
277 
278  spo->mw_evaluate_notranspose(spo_list, p_list, 0, 1, logdet_list, dlogdet_list, d2logdet_list);
279  for (unsigned int iat = 0; iat < 1; iat++)
280  {
281  //walker 0
282  CHECK(logdet_list[0].get()[iat][0] == ComplexApprox(val).epsilon(eps));
283  CHECK(dlogdet_list[0].get()[iat][0][0] == ComplexApprox(vdx).epsilon(eps));
284  CHECK(dlogdet_list[0].get()[iat][0][1] == ComplexApprox(vdy).epsilon(eps));
285  CHECK(dlogdet_list[0].get()[iat][0][2] == ComplexApprox(vdz).epsilon(eps));
286  CHECK(d2logdet_list[0].get()[iat][0] == ComplexApprox(vlp).epsilon(eps));
287  //walker 1
288  CHECK(logdet_list[1].get()[iat][0] == ComplexApprox(val2).epsilon(eps));
289  CHECK(dlogdet_list[1].get()[iat][0][0] == ComplexApprox(vdx2).epsilon(eps));
290  CHECK(dlogdet_list[1].get()[iat][0][1] == ComplexApprox(vdy2).epsilon(eps));
291  CHECK(dlogdet_list[1].get()[iat][0][2] == ComplexApprox(vdz2).epsilon(eps));
292  CHECK(d2logdet_list[1].get()[iat][0] == ComplexApprox(vlp2).epsilon(eps));
293  }
294 
295  //first, lets displace all the elec in each walker
296  for (int iat = 0; iat < 1; iat++)
297  {
299  displs.positions = {dR[iat], dR[iat]};
300  displs.spins = {dS[iat], dS[iat]};
301  elec_.mw_makeMove(p_list, iat, displs);
302  std::vector<bool> accept = {true, true};
303  elec_.mw_accept_rejectMove<CoordsType::POS_SPIN>(p_list, iat, accept);
304  }
305  elec_.mw_update(p_list);
306 
307  SPOSet::ValueVector psi_work_2(elec_.R.size());
308  SPOSet::GradVector dpsi_work_2(elec_.R.size());
309  SPOSet::ValueVector d2psi_work_2(elec_.R.size());
310 
311  RefVector<SPOSet::ValueVector> psi_v_list = {psi_work, psi_work_2};
312  RefVector<SPOSet::GradVector> dpsi_v_list = {dpsi_work, dpsi_work_2};
313  RefVector<SPOSet::ValueVector> d2psi_v_list = {d2psi_work, d2psi_work_2};
315  mw_dspin.resize(2, elec_.R.size());
316  //check mw_evaluateVGLWithSpin
317  for (int iat = 0; iat < 1; iat++)
318  {
319  //reset values to zero, updates the ref vectors to zero as well
320  psi_work = 0.0;
321  dpsi_work = 0.0;
322  d2psi_work = 0.0;
323  dspsi_work = 0.0;
324  psi_work_2 = 0.0;
325  dpsi_work_2 = 0.0;
326  d2psi_work_2 = 0.0;
327 
329  displs.positions = {-dR[iat], -dR[iat]};
330  displs.spins = {-dS[iat], -dS[iat]};
331  elec_.mw_makeMove(p_list, iat, displs);
332  spo->mw_evaluateVGLWithSpin(spo_list, p_list, iat, psi_v_list, dpsi_v_list, d2psi_v_list, mw_dspin);
333  //walker 0
334  CHECK(psi_v_list[0].get()[0] == ComplexApprox(val).epsilon(eps));
335  CHECK(dpsi_v_list[0].get()[0][0] == ComplexApprox(vdx).epsilon(eps));
336  CHECK(dpsi_v_list[0].get()[0][1] == ComplexApprox(vdy).epsilon(eps));
337  CHECK(dpsi_v_list[0].get()[0][2] == ComplexApprox(vdz).epsilon(eps));
338  CHECK(d2psi_v_list[0].get()[0] == ComplexApprox(vlp).epsilon(eps));
339  CHECK(mw_dspin(0, 0) == ComplexApprox(vds).epsilon(eps));
340  //walker 1
341  CHECK(psi_v_list[1].get()[0] == ComplexApprox(val2).epsilon(eps));
342  CHECK(dpsi_v_list[1].get()[0][0] == ComplexApprox(vdx2).epsilon(eps));
343  CHECK(dpsi_v_list[1].get()[0][1] == ComplexApprox(vdy2).epsilon(eps));
344  CHECK(dpsi_v_list[1].get()[0][2] == ComplexApprox(vdz2).epsilon(eps));
345  CHECK(d2psi_v_list[1].get()[0] == ComplexApprox(vlp2).epsilon(eps));
346  CHECK(mw_dspin(1, 0) == ComplexApprox(vds2).epsilon(eps));
347 
348  std::vector<bool> accept = {false, false};
349  elec_.mw_accept_rejectMove<CoordsType::POS_SPIN>(p_list, iat, accept);
350  }
351 }
352 
354 {
355  app_log() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
356  app_log() << "!! LCAO SpinorSet from HDF with excited !!\n";
357  app_log() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
358 
360  using RealType = SPOSet::RealType;
362 
364  auto ions_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
365  auto elec_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
366  ParticleSet& ions_(*ions_uptr);
367  ParticleSet& elec_(*elec_uptr);
368 
369  ions_.setName("ion");
370  ptcl.addParticleSet(std::move(ions_uptr));
371  ions_.create({1});
372 
373  ions_.R[0] = {0.00000000, 0.00000000, 0.00000000};
374  SpeciesSet& ispecies = ions_.getSpeciesSet();
375  int hIdx = ispecies.addSpecies("H");
376  ions_.update();
377 
378  elec_.setName("elec");
379  ptcl.addParticleSet(std::move(elec_uptr));
380  elec_.create({1});
381  elec_.R[0] = {0.1, -0.3, 1.7};
382  elec_.spins[0] = 0.6;
383  elec_.setSpinor(true);
384 
385  SpeciesSet& tspecies = elec_.getSpeciesSet();
386  int upIdx = tspecies.addSpecies("u");
387  int chargeIdx = tspecies.addAttribute("charge");
388  tspecies(chargeIdx, upIdx) = -1;
389 
390 
391  elec_.addTable(ions_);
392  elec_.update();
393 
394  const char* particles = R"XML(<tmp>
395  <sposet_builder name="spinorbuilder" type="molecularorbital" href="lcao_spinor.h5" source="ion" precision="float">
396  <basisset name="myset" transform="yes"/>
397  <sposet name="myspo" basisset="myset" size="1">
398  <occupation mode="excited">
399  -1 2
400  </occupation>
401  </sposet>
402  </sposet_builder>
403  </tmp>)XML";
404 
406  bool okay = doc.parseFromString(particles);
407  REQUIRE(okay);
408 
409  xmlNodePtr root = doc.getRoot();
410 
411  xmlNodePtr bnode = xmlFirstElementChild(root);
412  SPOSetBuilderFactory fac(c, elec_, ptcl.getPool());
413  const auto sposet_builder_ptr = fac.createSPOSetBuilder(bnode);
414  auto& bb = *sposet_builder_ptr;
415 
416  // only pick up the last sposet
417  std::unique_ptr<SPOSet> spo;
418  processChildren(bnode, [&](const std::string& cname, const xmlNodePtr element) {
419  if (cname == "sposet")
420  spo = bb.createSPOSet(element);
421  });
422  REQUIRE(spo);
423 
424  const int OrbitalSetSize = spo->getOrbitalSetSize();
425  CHECK(OrbitalSetSize == 1);
426 
427  SPOSet::ValueMatrix psiM(elec_.R.size(), spo->getOrbitalSetSize());
428  SPOSet::GradMatrix dpsiM(elec_.R.size(), spo->getOrbitalSetSize());
429  SPOSet::ValueMatrix dspsiM(elec_.R.size(), spo->getOrbitalSetSize()); //spin gradient
430  SPOSet::ValueMatrix d2psiM(elec_.R.size(), spo->getOrbitalSetSize());
431 
432  spo->evaluate_notranspose(elec_, 0, elec_.R.size(), psiM, dpsiM, d2psiM);
433 
434  ValueType val(0.0008237860500019983, 1.0474021389417806e-05);
435  ValueType vdx(-0.00041189302538224967, -5.237010699556317e-06);
436  ValueType vdy(0.0012356790748129446, 1.5711032081710294e-05);
437  ValueType vdz(-0.007002181424606922, -8.90291818048377e-05);
438  ValueType vlp(0.04922415803252472, 0.0006258601782677606);
439  ValueType vds(-0.0010017050778321178, -5.584596565578559e-05);
440  const RealType eps = 1e-4;
441 
442  for (unsigned int iat = 0; iat < 1; iat++)
443  {
444  CHECK(psiM[iat][0] == ComplexApprox(val).epsilon(eps));
445  CHECK(dpsiM[iat][0][0] == ComplexApprox(vdx).epsilon(eps));
446  CHECK(dpsiM[iat][0][1] == ComplexApprox(vdy).epsilon(eps));
447  CHECK(dpsiM[iat][0][2] == ComplexApprox(vdz).epsilon(eps));
448  CHECK(d2psiM[iat][0] == ComplexApprox(vlp).epsilon(eps));
449  }
450 
451  /** this is a somewhat simple example. We have an ion at the origin
452  * and a gaussian basis function centered on the ion as a orbital.
453  * In this case, the ion derivative is actually just the negative of
454  * the electron gradient.
455  */
456  SPOSet::GradMatrix gradIon(elec_.R.size(), spo->getOrbitalSetSize());
457  spo->evaluateGradSource(elec_, 0, elec_.R.size(), ions_, 0, gradIon);
458  for (int iat = 0; iat < 1; iat++)
459  {
460  CHECK(gradIon[iat][0][0] == ComplexApprox(-vdx).epsilon(eps));
461  CHECK(gradIon[iat][0][1] == ComplexApprox(-vdy).epsilon(eps));
462  CHECK(gradIon[iat][0][2] == ComplexApprox(-vdz).epsilon(eps));
463  }
464 
465  //temporary arrays for holding the values of the up and down channels respectively.
466  SPOSet::ValueVector psi_work;
467 
468  //temporary arrays for holding the gradients of the up and down channels respectively.
469  SPOSet::GradVector dpsi_work;
470 
471  //temporary arrays for holding the laplacians of the up and down channels respectively.
472  SPOSet::ValueVector d2psi_work;
473 
474  //temporary arrays for holding spin gradient
475  SPOSet::ValueVector dspsi_work;
476 
477  psi_work.resize(OrbitalSetSize);
478  dpsi_work.resize(OrbitalSetSize);
479  d2psi_work.resize(OrbitalSetSize);
480  dspsi_work.resize(OrbitalSetSize);
481 
482  //We worked hard to generate nice reference data above. Let's generate a test for evaluateV
483  //and evaluateVGL by perturbing the electronic configuration by dR, and then make
484  //single particle moves that bring it back to our original R reference values.
485 
486  //Our perturbation vector.
488  dR.resize(1);
489  dR[0][0] = 0.1;
490  dR[0][1] = 0.2;
491  dR[0][2] = 0.1;
492 
493  //The new R of our perturbed particle set. Ma
495  Rnew.resize(1);
496  Rnew = elec_.R + dR;
497  elec_.R = Rnew;
498  elec_.update();
499 
500  //Now we test evaluateValue()
501  for (unsigned int iat = 0; iat < 1; iat++)
502  {
503  psi_work = 0.0;
504  elec_.makeMove(iat, -dR[iat], false);
505  spo->evaluateValue(elec_, iat, psi_work);
506 
507  CHECK(psi_work[0] == ComplexApprox(val));
508  elec_.rejectMove(iat);
509  }
510 
511  //Now we test evaluateVGL()
512  for (unsigned int iat = 0; iat < 1; iat++)
513  {
514  psi_work = 0.0;
515  dpsi_work = 0.0;
516  d2psi_work = 0.0;
517  dspsi_work = 0.0;
518 
519  elec_.makeMove(iat, -dR[iat], false);
520  spo->evaluateVGL_spin(elec_, iat, psi_work, dpsi_work, d2psi_work, dspsi_work);
521 
522  CHECK(psi_work[0] == ComplexApprox(val).epsilon(eps));
523  CHECK(dpsi_work[0][0] == ComplexApprox(vdx).epsilon(eps));
524  CHECK(dpsi_work[0][1] == ComplexApprox(vdy).epsilon(eps));
525  CHECK(dpsi_work[0][2] == ComplexApprox(vdz).epsilon(eps));
526  CHECK(d2psi_work[0] == ComplexApprox(vlp).epsilon(eps));
527  CHECK(dspsi_work[0] == ComplexApprox(vds).epsilon(eps));
528  elec_.rejectMove(iat);
529  }
530 
531  //Now we test evaluateSpin:
532  for (unsigned int iat = 0; iat < 1; iat++)
533  {
534  psi_work = 0.0;
535  dspsi_work = 0.0;
536 
537  elec_.makeMove(iat, -dR[iat], false);
538  spo->evaluate_spin(elec_, iat, psi_work, dspsi_work);
539 
540  CHECK(psi_work[0] == ComplexApprox(val).epsilon(eps));
541  CHECK(dspsi_work[0] == ComplexApprox(vds).epsilon(eps));
542 
543  elec_.rejectMove(iat);
544  }
545 
546  //test batched interface
547  // first move elec_ back to orginal positions for reference
548  Rnew = elec_.R - dR;
549  elec_.R = Rnew;
550  elec_.update();
551 
552  //add spin displacement, just set to zero for sake of test
554  dS.resize(1);
555 
556  //now create second walker
557  ParticleSet elec_2(elec_);
558  elec_2.R[0] = {-0.4, 1.5, -0.2};
559  elec_2.spins[0] = -1.3;
560 
561  //create new reference values for new positions
562  ValueType val2(0.0026291910291941015, 0.00019079173981511807);
563  ValueType vdx2(0.005258382058116388, 0.00038158347961051147);
564  ValueType vdy2(-0.019718932715867252, -0.0014309380483892627);
565  ValueType vdz2(0.002629191029701947, 0.00019079173985197097);
566  ValueType vlp2(0.1215986298515522, 0.008824012363842379);
567  ValueType vds2(0.004256243259981321, 0.00010787670610075102);
568 
569  ResourceCollection pset_res("test_pset_res");
570  elec_.createResource(pset_res);
571  RefVectorWithLeader<ParticleSet> p_list(elec_);
572  p_list.push_back(elec_);
573  p_list.push_back(elec_2);
574 
575 
576  ResourceCollection spo_res("test_spo_res");
577  spo->createResource(spo_res);
578  std::unique_ptr<SPOSet> spo_2(spo->makeClone());
579  RefVectorWithLeader<SPOSet> spo_list(*spo);
580  spo_list.push_back(*spo);
581  spo_list.push_back(*spo_2);
582 
583  SPOSet::ValueMatrix psiM_2(elec_.R.size(), spo->getOrbitalSetSize());
584  SPOSet::GradMatrix dpsiM_2(elec_.R.size(), spo->getOrbitalSetSize());
585  SPOSet::ValueMatrix d2psiM_2(elec_.R.size(), spo->getOrbitalSetSize());
586 
587  RefVector<SPOSet::ValueMatrix> logdet_list;
588  RefVector<SPOSet::GradMatrix> dlogdet_list;
589  RefVector<SPOSet::ValueMatrix> d2logdet_list;
590 
591  logdet_list.push_back(psiM);
592  logdet_list.push_back(psiM_2);
593  dlogdet_list.push_back(dpsiM);
594  dlogdet_list.push_back(dpsiM_2);
595  d2logdet_list.push_back(d2psiM);
596  d2logdet_list.push_back(d2psiM_2);
597 
598  ResourceCollectionTeamLock<ParticleSet> mw_pset_lock(pset_res, p_list);
599  ResourceCollectionTeamLock<SPOSet> mw_spo_lock(spo_res, spo_list);
600 
601  elec_.mw_update(p_list);
602  spo->mw_evaluate_notranspose(spo_list, p_list, 0, 1, logdet_list, dlogdet_list, d2logdet_list);
603  for (unsigned int iat = 0; iat < 1; iat++)
604  {
605  //walker 0
606  CHECK(logdet_list[0].get()[iat][0] == ComplexApprox(val).epsilon(eps));
607  CHECK(dlogdet_list[0].get()[iat][0][0] == ComplexApprox(vdx).epsilon(eps));
608  CHECK(dlogdet_list[0].get()[iat][0][1] == ComplexApprox(vdy).epsilon(eps));
609  CHECK(dlogdet_list[0].get()[iat][0][2] == ComplexApprox(vdz).epsilon(eps));
610  CHECK(d2logdet_list[0].get()[iat][0] == ComplexApprox(vlp).epsilon(eps));
611  //walker 1
612  CHECK(logdet_list[1].get()[iat][0] == ComplexApprox(val2).epsilon(eps));
613  CHECK(dlogdet_list[1].get()[iat][0][0] == ComplexApprox(vdx2).epsilon(eps));
614  CHECK(dlogdet_list[1].get()[iat][0][1] == ComplexApprox(vdy2).epsilon(eps));
615  CHECK(dlogdet_list[1].get()[iat][0][2] == ComplexApprox(vdz2).epsilon(eps));
616  CHECK(d2logdet_list[1].get()[iat][0] == ComplexApprox(vlp2).epsilon(eps));
617  }
618 
619  //first, lets displace all the elec in each walker
620  for (int iat = 0; iat < 1; iat++)
621  {
623  displs.positions = {dR[iat], dR[iat]};
624  displs.spins = {dS[iat], dS[iat]};
625  elec_.mw_makeMove(p_list, iat, displs);
626  std::vector<bool> accept = {true, true};
627  elec_.mw_accept_rejectMove<CoordsType::POS_SPIN>(p_list, iat, accept);
628  }
629  elec_.mw_update(p_list);
630 
631  SPOSet::ValueVector psi_work_2(OrbitalSetSize);
632  SPOSet::GradVector dpsi_work_2(OrbitalSetSize);
633  SPOSet::ValueVector d2psi_work_2(OrbitalSetSize);
634 
635  RefVector<SPOSet::ValueVector> psi_v_list = {psi_work, psi_work_2};
636  RefVector<SPOSet::GradVector> dpsi_v_list = {dpsi_work, dpsi_work_2};
637  RefVector<SPOSet::ValueVector> d2psi_v_list = {d2psi_work, d2psi_work_2};
639  mw_dspin.resize(2, OrbitalSetSize); //two walkers
640  //check mw_evaluateVGLWithSpin
641  for (int iat = 0; iat < 1; iat++)
642  {
643  //reset values to zero, updates the ref vectors to zero as well
644  psi_work = 0.0;
645  dpsi_work = 0.0;
646  d2psi_work = 0.0;
647  dspsi_work = 0.0;
648  psi_work_2 = 0.0;
649  dpsi_work_2 = 0.0;
650  d2psi_work_2 = 0.0;
651 
653  displs.positions = {-dR[iat], -dR[iat]};
654  displs.spins = {-dS[iat], -dS[iat]};
655  elec_.mw_makeMove(p_list, iat, displs);
656  spo->mw_evaluateVGLWithSpin(spo_list, p_list, iat, psi_v_list, dpsi_v_list, d2psi_v_list, mw_dspin);
657  //walker 0
658  CHECK(psi_v_list[0].get()[0] == ComplexApprox(val).epsilon(eps));
659  CHECK(dpsi_v_list[0].get()[0][0] == ComplexApprox(vdx).epsilon(eps));
660  CHECK(dpsi_v_list[0].get()[0][1] == ComplexApprox(vdy).epsilon(eps));
661  CHECK(dpsi_v_list[0].get()[0][2] == ComplexApprox(vdz).epsilon(eps));
662  CHECK(d2psi_v_list[0].get()[0] == ComplexApprox(vlp).epsilon(eps));
663  CHECK(mw_dspin(0, 0) == ComplexApprox(vds).epsilon(eps));
664  //walker 1
665  CHECK(psi_v_list[1].get()[0] == ComplexApprox(val2).epsilon(eps));
666  CHECK(dpsi_v_list[1].get()[0][0] == ComplexApprox(vdx2).epsilon(eps));
667  CHECK(dpsi_v_list[1].get()[0][1] == ComplexApprox(vdy2).epsilon(eps));
668  CHECK(dpsi_v_list[1].get()[0][2] == ComplexApprox(vdz2).epsilon(eps));
669  CHECK(d2psi_v_list[1].get()[0] == ComplexApprox(vlp2).epsilon(eps));
670  CHECK(mw_dspin(1, 0) == ComplexApprox(vds2).epsilon(eps));
671  std::vector<bool> accept = {false, false};
672  elec_.mw_accept_rejectMove<CoordsType::POS_SPIN>(p_list, iat, accept);
673  }
674 }
675 
677 {
678  app_log() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
679  app_log() << "!!!! LCAO SpinorSet from HDF (ion derivatives) !!!!\n";
680  app_log() << "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n";
681 
683  using RealType = SPOSet::RealType;
685 
687  auto ions_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
688  auto elec_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
689  ParticleSet& ions_(*ions_uptr);
690  ParticleSet& elec_(*elec_uptr);
691 
692  ions_.setName("ion");
693  ptcl.addParticleSet(std::move(ions_uptr));
694  ions_.create({2});
695 
696  ions_.R[0] = {0.10000000, 0.20000000, 0.30000000};
697  ions_.R[1] = {-0.30000000, -0.20000000, -0.10000000};
698  SpeciesSet& ispecies = ions_.getSpeciesSet();
699  int hIdx = ispecies.addSpecies("H");
700  ions_.update();
701 
702  elec_.setName("elec");
703  ptcl.addParticleSet(std::move(elec_uptr));
704  elec_.create({1});
705  elec_.R[0] = {0.01, -0.02, 0.03};
706  elec_.spins[0] = 0.6;
707  elec_.setSpinor(true);
708 
709  SpeciesSet& tspecies = elec_.getSpeciesSet();
710  int upIdx = tspecies.addSpecies("u");
711  int chargeIdx = tspecies.addAttribute("charge");
712  tspecies(chargeIdx, upIdx) = -1;
713 
714 
715  elec_.addTable(ions_);
716  elec_.update();
717 
718  const char* particles = R"XML(<tmp>
719  <sposet_builder name="spinorbuilder" type="molecularorbital" href="lcao_spinor_molecule.h5" source="ion" precision="float">
720  <basisset transform="yes"/>
721  <sposet name="myspo" size="1"/>
722  </sposet_builder>
723  </tmp>)XML";
724 
726  bool okay = doc.parseFromString(particles);
727  REQUIRE(okay);
728 
729  xmlNodePtr root = doc.getRoot();
730 
731  xmlNodePtr bnode = xmlFirstElementChild(root);
732  SPOSetBuilderFactory fac(c, elec_, ptcl.getPool());
733  const auto spo_builder_ptr = fac.createSPOSetBuilder(bnode);
734  auto& bb = *spo_builder_ptr;
735 
736  // only pick up the last sposet
737  std::unique_ptr<SPOSet> spo;
738  processChildren(bnode, [&](const std::string& cname, const xmlNodePtr element) {
739  if (cname == "sposet")
740  spo = bb.createSPOSet(element);
741  });
742  REQUIRE(spo);
743 
744  //reference values from finite difference in lcao_spinor_molecule_test.py
745  ValueType dx0(-0.0492983, -0.3192778);
746  ValueType dy0(-0.1205071, -0.7804567);
747  ValueType dz0(-0.1478950, -0.9578333);
748  ValueType dx1(-0.0676367, 1.0506422);
749  ValueType dy1(-0.0392729, 0.6100503);
750  ValueType dz1(-0.0283638, 0.4405919);
751 
752  const RealType eps = 1e-4;
753  SPOSet::GradMatrix gradIon(elec_.R.size(), spo->getOrbitalSetSize());
754  spo->evaluateGradSource(elec_, 0, elec_.R.size(), ions_, 0, gradIon);
755  CHECK(gradIon[0][0][0] == ComplexApprox(dx0).epsilon(eps));
756  CHECK(gradIon[0][0][1] == ComplexApprox(dy0).epsilon(eps));
757  CHECK(gradIon[0][0][2] == ComplexApprox(dz0).epsilon(eps));
758  spo->evaluateGradSource(elec_, 0, elec_.R.size(), ions_, 1, gradIon);
759  CHECK(gradIon[0][0][0] == ComplexApprox(dx1).epsilon(eps));
760  CHECK(gradIon[0][0][1] == ComplexApprox(dy1).epsilon(eps));
761  CHECK(gradIon[0][0][2] == ComplexApprox(dz1).epsilon(eps));
762 }
763 
764 TEST_CASE("ReadMolecularOrbital GTO spinor", "[wavefunction]") { test_lcao_spinor(); }
765 TEST_CASE("ReadMolecularOrbital GTO spinor with excited", "[wavefunction]") { test_lcao_spinor_excited(); }
766 TEST_CASE("spinor ion derivatives for molecule", "[wavefunction]") { test_lcao_spinor_ion_derivs(); }
767 
768 } // namespace qmcplusplus
void resize(size_type n, Type_t val=Type_t())
Resize the container.
Definition: OhmmsVector.h:166
Class for Melton & Mitas style Spinors.
Definition: SpinorSet.h:24
void setName(const std::string &aname)
Definition: ParticleSet.h:237
class that handles xmlDoc
Definition: Libxml2Doc.h:76
static void mw_makeMove(const RefVectorWithLeader< ParticleSet > &p_list, int iat, const MCCoords< CT > &displs)
batched version of makeMove
int addSpecies(const std::string &aname)
When a name species does not exist, add a new species.
Definition: SpeciesSet.cpp:33
std::vector< QMCTraits::PosType > positions
Definition: MCCoords.hpp:60
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
ParticleScalar spins
internal spin variables for dynamical spin calculations
Definition: ParticleSet.h:81
QTBase::RealType RealType
Definition: Configuration.h:58
std::ostream & app_log()
Definition: OutputManager.h:65
TEST_CASE("complex_helper", "[type_traits]")
void addParticleSet(std::unique_ptr< ParticleSet > &&p)
add a ParticleSet* to the pool with its ownership transferred ParticleSet built outside the ParticleS...
xmlNodePtr getRoot()
Definition: Libxml2Doc.h:88
OrbitalSetTraits< ValueType >::ValueMatrix ValueMatrix
Definition: SPOSet.h:50
void createResource(ResourceCollection &collection) const
initialize a shared resource and hand it to a collection
void resize(size_type n, size_type m)
Resize the container.
Definition: OhmmsMatrix.h:99
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
static void mw_accept_rejectMove(const RefVectorWithLeader< ParticleSet > &p_list, Index_t iat, const std::vector< bool > &isAccepted, bool forward_mode=true)
batched version of acceptMove and rejectMove fused, templated on CoordsType
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
std::vector< QMCTraits::FullPrecRealType > spins
Definition: MCCoords.hpp:61
OrbitalSetTraits< ValueType >::GradMatrix GradMatrix
Definition: SPOSet.h:52
Wrapping information on parallelism.
Definition: Communicate.h:68
int addTable(const ParticleSet &psrc, DTModes modes=DTModes::ALL_OFF)
add a distance table
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
void test_lcao_spinor()
QTBase::ValueType ValueType
Definition: Configuration.h:60
REQUIRE(std::filesystem::exists(filename))
void rejectMove(Index_t iat)
reject a proposed move in regular mode
void test_lcao_spinor_excited()
Manage a collection of ParticleSet objects.
OrbitalSetTraits< ValueType >::ValueVector ValueVector
Definition: SPOSet.h:49
ParticlePos R
Position.
Definition: ParticleSet.h:79
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
void create(const std::vector< int > &agroup)
create grouped particles
std::vector< std::reference_wrapper< T > > RefVector
void processChildren(const xmlNodePtr cur, const F &functor)
process through all the children of an XML element F is a lambda or functor void F/[](const std::stri...
Definition: libxmldefs.h:175
OrbitalSetTraits< ValueType >::GradVector GradVector
Definition: SPOSet.h:51
void makeMove(Index_t iat, const SingleParticlePos &displ, bool maybe_accept=true)
move the iat-th particle to active_pos_
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 }))
handles acquire/release resource by the consumer (RefVectorWithLeader type).
LatticeGaussianProduct::ValueType ValueType
std::unique_ptr< SPOSetBuilder > createSPOSetBuilder(xmlNodePtr rootNode)
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
void setSpinor(bool is_spinor)
Definition: ParticleSet.h:257
const PoolType & getPool() const
get the Pool object
void test_lcao_spinor_ion_derivs()
const auto & getSimulationCell() const
get simulation cell
bool isResourceOwned() const
check if the multi walker resource is owned. For testing only.
Definition: SpinorSet.h:190
Declaration of ParticleSetPool.