QMCPACK
test_DiracDeterminantBatched.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) 2020 QMCPACK developers.
6 //
7 // File developed by: Mark Dewing, mdewing@anl.gov, Argonne National Laboratory
8 // Ye Luo, yeluo@anl.gov, Argonne National Laboratory
9 //
10 // File created by: Ye Luo, yeluo@anl.gov, Argonne National Laboratory
11 //////////////////////////////////////////////////////////////////////////////////////
12 
13 
14 #include "catch.hpp"
15 
16 #include "OhmmsData/Libxml2Doc.h"
17 #include "OhmmsPETE/OhmmsMatrix.h"
23 #include "checkMatrix.hpp"
24 #include <ResourceCollection.h>
25 
26 namespace qmcplusplus
27 {
33 using LogValue = std::complex<QMCTraits::QTFull::RealType>;
35 
36 template<PlatformKind PL>
38 {
40  auto spo_init = std::make_unique<FakeSPO>();
41  const int norb = 3;
42  spo_init->setOrbitalSetSize(norb);
43  DetType ddb(std::move(spo_init), 0, norb);
44  auto spo = dynamic_cast<FakeSPO*>(ddb.getPhi());
45 
46  const SimulationCell simulation_cell;
47  ParticleSet elec(simulation_cell);
48 
49  elec.create({3});
50  ddb.recompute(elec);
51 
53  b.resize(3, 3);
54 
55  b(0, 0) = 0.6159749342;
56  b(0, 1) = -0.2408954682;
57  b(0, 2) = -0.1646081192;
58  b(1, 0) = 0.07923894288;
59  b(1, 1) = 0.1496231042;
60  b(1, 2) = -0.1428117337;
61  b(2, 0) = -0.2974298429;
62  b(2, 1) = -0.04586322768;
63  b(2, 2) = 0.3927890292;
64 
65  auto check = checkMatrix(b, ddb.get_psiMinv());
66  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
67 
69  PsiValue det_ratio = ddb.ratioGrad(elec, 0, grad);
70  PsiValue det_ratio1 = 0.178276269185;
71  CHECK(det_ratio1 == ValueApprox(det_ratio));
72 
73  ddb.acceptMove(elec, 0);
74 
75  b(0, 0) = 3.455170657;
76  b(0, 1) = -1.35124809;
77  b(0, 2) = -0.9233316353;
78  b(1, 0) = 0.05476311768;
79  b(1, 1) = 0.1591951095;
80  b(1, 2) = -0.1362710138;
81  b(2, 0) = -2.235099338;
82  b(2, 1) = 0.7119205298;
83  b(2, 2) = 0.9105960265;
84 
85  check = checkMatrix(b, ddb.get_psiMinv());
86  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
87 
88  // set virtutal particle position
89  PosType newpos(0.3, 0.2, 0.5);
90 
91  elec.makeVirtualMoves(newpos);
92  std::vector<ValueType> ratios(elec.getTotalNum());
93  ddb.evaluateRatiosAlltoOne(elec, ratios);
94 
95  CHECK(std::real(ratios[0]) == Approx(1.2070809985));
96  CHECK(std::real(ratios[1]) == Approx(0.2498726439));
97  CHECK(std::real(ratios[2]) == Approx(-1.3145695364));
98 
99  elec.makeMove(0, newpos - elec.R[0]);
100  PsiValue ratio_0 = ddb.ratio(elec, 0);
101  elec.rejectMove(0);
102 
103  CHECK(std::real(ratio_0) == Approx(-0.5343861437));
104 
105  VirtualParticleSet VP(elec, 2);
106  std::vector<PosType> newpos2(2);
107  std::vector<ValueType> ratios2(2);
108  newpos2[0] = newpos - elec.R[1];
109  newpos2[1] = PosType(0.2, 0.5, 0.3) - elec.R[1];
110  VP.makeMoves(elec, 1, newpos2);
111  ddb.evaluateRatios(VP, ratios2);
112 
113  CHECK(std::real(ratios2[0]) == Approx(0.4880285278));
114  CHECK(std::real(ratios2[1]) == Approx(0.9308456444));
115 
116  //test acceptMove
117  elec.makeMove(1, newpos - elec.R[1]);
118  PsiValue ratio_1 = ddb.ratio(elec, 1);
119  ddb.acceptMove(elec, 1);
120  elec.acceptMove(1);
121 
122  CHECK(std::real(ratio_1) == Approx(0.9308456444));
123  CHECK(std::real(ddb.get_log_value()) == Approx(1.9891064655));
124 }
125 
126 TEST_CASE("DiracDeterminantBatched_first", "[wavefunction][fermion]")
127 {
128 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_CUDA)
129  test_DiracDeterminantBatched_first<PlatformKind::CUDA>();
130 #endif
131 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_SYCL)
132  test_DiracDeterminantBatched_first<PlatformKind::SYCL>();
133 #endif
134  test_DiracDeterminantBatched_first<PlatformKind::OMPTARGET>();
135 }
136 
137 //#define DUMP_INFO
138 
139 template<PlatformKind PL>
141 {
143  auto spo_init = std::make_unique<FakeSPO>();
144  const int norb = 4;
145  spo_init->setOrbitalSetSize(norb);
146  DetType ddb(std::move(spo_init), 0, norb);
147  auto spo = dynamic_cast<FakeSPO*>(ddb.getPhi());
148 
149  const SimulationCell simulation_cell;
150  ParticleSet elec(simulation_cell);
151 
152  elec.create({4});
153  ddb.recompute(elec);
154 
155  Matrix<ValueType> orig_a;
156  orig_a.resize(4, 4);
157  orig_a = spo->a2;
158 
159  for (int i = 0; i < 3; i++)
160  {
161  for (int j = 0; j < norb; j++)
162  {
163  orig_a(j, i) = spo->v2(i, j);
164  }
165  }
166 
167  //check_matrix(ddb.getPsiMinv(), b);
169 
170  Matrix<ValueType> a_update1, scratchT;
171  a_update1.resize(4, 4);
172  scratchT.resize(4, 4);
173  a_update1 = spo->a2;
174  for (int j = 0; j < norb; j++)
175  {
176  a_update1(j, 0) = spo->v2(0, j);
177  }
178 
179  Matrix<ValueType> a_update2;
180  a_update2.resize(4, 4);
181  a_update2 = spo->a2;
182  for (int j = 0; j < norb; j++)
183  {
184  a_update2(j, 0) = spo->v2(0, j);
185  a_update2(j, 1) = spo->v2(1, j);
186  }
187 
188  Matrix<ValueType> a_update3;
189  a_update3.resize(4, 4);
190  a_update3 = spo->a2;
191  for (int j = 0; j < norb; j++)
192  {
193  a_update3(j, 0) = spo->v2(0, j);
194  a_update3(j, 1) = spo->v2(1, j);
195  a_update3(j, 2) = spo->v2(2, j);
196  }
197 
199  PsiValue det_ratio = ddb.ratioGrad(elec, 0, grad);
200 
201  simd::transpose(a_update1.data(), a_update1.rows(), a_update1.cols(), scratchT.data(), scratchT.rows(),
202  scratchT.cols());
203  LogValue det_update1;
204  dm.invert_transpose(scratchT, a_update1, det_update1);
205  PsiValue det_ratio1 = LogToValue<ValueType>::convert(det_update1 - ddb.get_log_value());
206 #ifdef DUMP_INFO
207  app_log() << "det 0 = " << std::exp(ddb.get_log_value()) << std::endl;
208  app_log() << "det 1 = " << std::exp(det_update1) << std::endl;
209  app_log() << "det ratio 1 = " << det_ratio1 << std::endl;
210 #endif
211  //double det_ratio1 = 0.178276269185;
212 
213  CHECK(det_ratio1 == ValueApprox(det_ratio));
214 
215  ddb.acceptMove(elec, 0);
216 
217  PsiValue det_ratio2 = ddb.ratioGrad(elec, 1, grad);
218  LogValue det_update2;
219  simd::transpose(a_update2.data(), a_update2.rows(), a_update2.cols(), scratchT.data(), scratchT.rows(),
220  scratchT.cols());
221  dm.invert_transpose(scratchT, a_update2, det_update2);
222  PsiValue det_ratio2_val = LogToValue<ValueType>::convert(det_update2 - det_update1);
223 #ifdef DUMP_INFO
224  app_log() << "det 1 = " << std::exp(ddb.get_log_value()) << std::endl;
225  app_log() << "det 2 = " << std::exp(det_update2) << std::endl;
226  app_log() << "det ratio 2 = " << det_ratio2 << std::endl;
227 #endif
228  //double det_ratio2_val = 0.178276269185;
229  CHECK(det_ratio2 == ValueApprox(det_ratio2_val));
230 
231  ddb.acceptMove(elec, 1);
232 
233  PsiValue det_ratio3 = ddb.ratioGrad(elec, 2, grad);
234  LogValue det_update3;
235  simd::transpose(a_update3.data(), a_update3.rows(), a_update3.cols(), scratchT.data(), scratchT.rows(),
236  scratchT.cols());
237  dm.invert_transpose(scratchT, a_update3, det_update3);
238  PsiValue det_ratio3_val = LogToValue<ValueType>::convert(det_update3 - det_update2);
239 #ifdef DUMP_INFO
240  app_log() << "det 2 = " << std::exp(ddb.get_log_value()) << std::endl;
241  app_log() << "det 3 = " << std::exp(det_update3) << std::endl;
242  app_log() << "det ratio 3 = " << det_ratio3 << std::endl;
243 #endif
244  CHECK(det_ratio3 == ValueApprox(det_ratio3_val));
245  //check_value(det_ratio3, det_ratio3_val);
246 
247  ddb.acceptMove(elec, 2);
248 
249  simd::transpose(orig_a.data(), orig_a.rows(), orig_a.cols(), scratchT.data(), scratchT.rows(), scratchT.cols());
250  dm.invert_transpose(scratchT, orig_a, det_update3);
251 
252 #ifdef DUMP_INFO
253  app_log() << "original " << std::endl;
254  app_log() << orig_a << std::endl;
255  app_log() << "block update " << std::endl;
256  app_log() << ddb.getPsiMinv() << std::endl;
257 #endif
258 
259  auto check = checkMatrix(orig_a, ddb.get_psiMinv());
260  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
261 }
262 
263 TEST_CASE("DiracDeterminantBatched_second", "[wavefunction][fermion]")
264 {
265 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_CUDA)
266  test_DiracDeterminantBatched_second<PlatformKind::CUDA>();
267 #endif
268 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_SYCL)
269  test_DiracDeterminantBatched_second<PlatformKind::SYCL>();
270 #endif
271  test_DiracDeterminantBatched_second<PlatformKind::OMPTARGET>();
272 }
273 
274 template<PlatformKind PL>
275 void test_DiracDeterminantBatched_delayed_update(int delay_rank, DetMatInvertor matrix_inverter_kind)
276 {
278  auto spo_init = std::make_unique<FakeSPO>();
279  const int norb = 4;
280  spo_init->setOrbitalSetSize(norb);
281  DetType ddc(std::move(spo_init), 0, norb, delay_rank, matrix_inverter_kind);
282  auto spo = dynamic_cast<FakeSPO*>(ddc.getPhi());
283 
284  const SimulationCell simulation_cell;
285  ParticleSet elec(simulation_cell);
286 
287  elec.create({4});
288  ddc.recompute(elec);
289 
290  Matrix<ValueType> orig_a;
291  orig_a.resize(4, 4);
292  orig_a = spo->a2;
293 
294  for (int i = 0; i < 3; i++)
295  {
296  for (int j = 0; j < norb; j++)
297  {
298  orig_a(j, i) = spo->v2(i, j);
299  }
300  }
301 
302  //check_matrix(ddc.getPsiMinv(), b);
304 
305  Matrix<ValueType> a_update1, scratchT;
306  scratchT.resize(4, 4);
307  a_update1.resize(4, 4);
308  a_update1 = spo->a2;
309  for (int j = 0; j < norb; j++)
310  {
311  a_update1(j, 0) = spo->v2(0, j);
312  }
313 
314  Matrix<ValueType> a_update2;
315  a_update2.resize(4, 4);
316  a_update2 = spo->a2;
317  for (int j = 0; j < norb; j++)
318  {
319  a_update2(j, 0) = spo->v2(0, j);
320  a_update2(j, 1) = spo->v2(1, j);
321  }
322 
323  Matrix<ValueType> a_update3;
324  a_update3.resize(4, 4);
325  a_update3 = spo->a2;
326  for (int j = 0; j < norb; j++)
327  {
328  a_update3(j, 0) = spo->v2(0, j);
329  a_update3(j, 1) = spo->v2(1, j);
330  a_update3(j, 2) = spo->v2(2, j);
331  }
332 
333 
335  PsiValue det_ratio = ddc.ratioGrad(elec, 0, grad);
336 
337  simd::transpose(a_update1.data(), a_update1.rows(), a_update1.cols(), scratchT.data(), scratchT.rows(),
338  scratchT.cols());
339  LogValue det_update1;
340  dm.invert_transpose(scratchT, a_update1, det_update1);
341  PsiValue det_ratio1 = LogToValue<ValueType>::convert(det_update1 - ddc.get_log_value());
342 #ifdef DUMP_INFO
343  app_log() << "det 0 = " << std::exp(ddc.get_log_value()) << std::endl;
344  app_log() << "det 1 = " << std::exp(det_update1) << std::endl;
345  app_log() << "det ratio 1 = " << det_ratio1 << std::endl;
346 #endif
347  //double det_ratio1 = 0.178276269185;
348 
349  CHECK(det_ratio1 == ValueApprox(det_ratio));
350 
351  // update of Ainv in ddc is delayed
352  ddc.acceptMove(elec, 0, true);
353  // force update Ainv in ddc using SM-1 code path
354  ddc.completeUpdates();
355 
356  auto check = checkMatrix(a_update1, ddc.get_psiMinv());
357  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
358 
359  grad = ddc.evalGrad(elec, 1);
360 
361  PsiValue det_ratio2 = ddc.ratioGrad(elec, 1, grad);
362  simd::transpose(a_update2.data(), a_update2.rows(), a_update2.cols(), scratchT.data(), scratchT.rows(),
363  scratchT.cols());
364  LogValue det_update2;
365  dm.invert_transpose(scratchT, a_update2, det_update2);
366  PsiValue det_ratio2_val = LogToValue<ValueType>::convert(det_update2 - det_update1);
367 #ifdef DUMP_INFO
368  app_log() << "det 1 = " << std::exp(ddc.get_log_value()) << std::endl;
369  app_log() << "det 2 = " << std::exp(det_update2) << std::endl;
370  app_log() << "det ratio 2 = " << det_ratio2 << std::endl;
371 #endif
372  // check ratio computed directly and the one computed by ddc with no delay
373  //double det_ratio2_val = 0.178276269185;
374  CHECK(det_ratio2 == ValueApprox(det_ratio2_val));
375 
376  // update of Ainv in ddc is delayed
377  ddc.acceptMove(elec, 1, true);
378 
379  grad = ddc.evalGrad(elec, 2);
380 
381  PsiValue det_ratio3 = ddc.ratioGrad(elec, 2, grad);
382  simd::transpose(a_update3.data(), a_update3.rows(), a_update3.cols(), scratchT.data(), scratchT.rows(),
383  scratchT.cols());
384  LogValue det_update3;
385  dm.invert_transpose(scratchT, a_update3, det_update3);
386  PsiValue det_ratio3_val = LogToValue<ValueType>::convert(det_update3 - det_update2);
387 #ifdef DUMP_INFO
388  app_log() << "det 2 = " << std::exp(ddc.get_log_value()) << std::endl;
389  app_log() << "det 3 = " << std::exp(det_update3) << std::endl;
390  app_log() << "det ratio 3 = " << det_ratio3 << std::endl;
391 #endif
392  // check ratio computed directly and the one computed by ddc with 1 delay
393  CHECK(det_ratio3 == ValueApprox(det_ratio3_val));
394  //check_value(det_ratio3, det_ratio3_val);
395 
396  // maximal delay reached and Ainv is updated fully
397  ddc.acceptMove(elec, 2, true);
398  ddc.completeUpdates();
399 
400  // fresh invert orig_a
401  simd::transpose(orig_a.data(), orig_a.rows(), orig_a.cols(), scratchT.data(), scratchT.rows(), scratchT.cols());
402  dm.invert_transpose(scratchT, orig_a, det_update3);
403 
404 #ifdef DUMP_INFO
405  app_log() << "original " << std::endl;
406  app_log() << orig_a << std::endl;
407  app_log() << "delayed update " << std::endl;
408  app_log() << ddc.getPsiMinv() << std::endl;
409 #endif
410 
411  // compare all the elements of get_ref_psiMinv() in ddc and orig_a
412  check = checkMatrix(orig_a, ddc.get_psiMinv());
413  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
414 
415  // testing batched interfaces
416  ResourceCollection pset_res("test_pset_res");
417  ResourceCollection wfc_res("test_wfc_res");
418 
419  elec.createResource(pset_res);
420  ddc.createResource(wfc_res);
421 
422  // make a clones
423  ParticleSet elec_clone(elec);
424  std::unique_ptr<WaveFunctionComponent> ddc_clone(ddc.makeCopy(ddc.getPhi()->makeClone()));
425  auto& ddc_clone_ref = dynamic_cast<DetType&>(*ddc_clone);
426 
427  // testing batched interfaces
428  RefVectorWithLeader<ParticleSet> p_ref_list(elec, {elec, elec_clone});
429  RefVectorWithLeader<WaveFunctionComponent> ddc_ref_list(ddc, {ddc, *ddc_clone});
430 
431  ResourceCollectionTeamLock<ParticleSet> mw_pset_lock(pset_res, p_ref_list);
432  ResourceCollectionTeamLock<WaveFunctionComponent> mw_wfc_lock(wfc_res, ddc_ref_list);
433 
434  std::vector<bool> isAccepted(2, true);
435  ParticleSet::mw_update(p_ref_list);
436  ddc.mw_recompute(ddc_ref_list, p_ref_list, isAccepted);
437 
438  std::vector<PsiValue> ratios(2);
439  std::vector<GradType> grad_new(2);
440  ddc.mw_ratioGrad(ddc_ref_list, p_ref_list, 0, ratios, grad_new);
441 
442  CHECK(det_ratio1 == ValueApprox(ratios[0]));
443  CHECK(det_ratio1 == ValueApprox(ratios[1]));
444 
445  ddc.mw_accept_rejectMove(ddc_ref_list, p_ref_list, 0, isAccepted, true);
446  ddc.mw_completeUpdates(ddc_ref_list);
447 
448  check = checkMatrix(a_update1, ddc.get_psiMinv());
449  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
450 
451  check = checkMatrix(a_update1, ddc_clone_ref.get_psiMinv());
452  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
453 
454  ddc.mw_evalGrad(ddc_ref_list, p_ref_list, 1, grad_new);
455  ddc.mw_ratioGrad(ddc_ref_list, p_ref_list, 1, ratios, grad_new);
456 
457  CHECK(det_ratio2 == ValueApprox(ratios[0]));
458  CHECK(det_ratio2 == ValueApprox(ratios[1]));
459 
460  ddc.mw_accept_rejectMove(ddc_ref_list, p_ref_list, 1, isAccepted, true);
461  ddc.mw_evalGrad(ddc_ref_list, p_ref_list, 2, grad_new);
462  ddc.mw_ratioGrad(ddc_ref_list, p_ref_list, 2, ratios, grad_new);
463 
464  CHECK(det_ratio3 == ValueApprox(ratios[0]));
465  CHECK(det_ratio3 == ValueApprox(ratios[1]));
466 
467  ddc.mw_accept_rejectMove(ddc_ref_list, p_ref_list, 2, isAccepted, true);
468  ddc.mw_completeUpdates(ddc_ref_list);
469 
470  check = checkMatrix(orig_a, ddc.get_psiMinv());
471  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
472 
473  check = checkMatrix(orig_a, ddc_clone_ref.get_psiMinv());
474  CHECKED_ELSE(check.result) { FAIL(check.result_message); }
475 }
476 
477 TEST_CASE("DiracDeterminantBatched_delayed_update", "[wavefunction][fermion]")
478 {
479  // maximum delay 2
480 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_CUDA)
481  test_DiracDeterminantBatched_delayed_update<PlatformKind::CUDA>(2, DetMatInvertor::ACCEL);
482  test_DiracDeterminantBatched_delayed_update<PlatformKind::CUDA>(2, DetMatInvertor::HOST);
483 #endif
484 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_SYCL)
485  //test_DiracDeterminantBatched_delayed_update<PlatformKind::SYCL>(2, DetMatInvertor::ACCEL);
486  test_DiracDeterminantBatched_delayed_update<PlatformKind::SYCL>(2, DetMatInvertor::HOST);
487 #endif
488  test_DiracDeterminantBatched_delayed_update<PlatformKind::OMPTARGET>(2, DetMatInvertor::ACCEL);
489  test_DiracDeterminantBatched_delayed_update<PlatformKind::OMPTARGET>(2, DetMatInvertor::HOST);
490 }
491 
492 
493 #ifdef QMC_COMPLEX
494 template<PlatformKind PL>
495 void test_DiracDeterminantBatched_spinor_update(const int delay_rank, DetMatInvertor matrix_inverter_kind)
496 {
497  using ParticlePos = ParticleSet::ParticlePos;
498  using ParticleGradient = ParticleSet::ParticleGradient;
499  using ParticleLaplacian = ParticleSet::ParticleLaplacian;
500 
501  // O2 test example from pwscf non-collinear calculation.
503  lattice.R = {5.10509515, -3.23993545, 0.00000000, 5.10509515, 3.23993545,
504  0.00000000, -6.49690625, 0.00000000, 7.08268015};
505 
506  //Shamelessly stealing this from test_einset.cpp. 3 particles though.
507  const SimulationCell simulation_cell(lattice);
508  ParticleSet ions_(simulation_cell);
509  ParticleSet elec_(simulation_cell);
510  ions_.setName("ion");
511  ions_.create({2});
512 
513  ions_.R[0] = {0.00000000, 0.00000000, 1.08659253};
514  ions_.R[1] = {0.00000000, 0.00000000, -1.08659253};
515 
516  elec_.setName("elec");
517  elec_.create({3});
518  elec_.R[0] = {0.1, -0.3, 1.0};
519  elec_.R[1] = {-0.1, 0.3, 1.0};
520  elec_.R[2] = {0.1, 0.2, 0.3};
521 
522  elec_.spins[0] = 0.0;
523  elec_.spins[1] = 0.2;
524  elec_.spins[2] = 0.4;
525  elec_.setSpinor(true);
526 
527  SpeciesSet& tspecies = elec_.getSpeciesSet();
528  int upIdx = tspecies.addSpecies("u");
529  int chargeIdx = tspecies.addAttribute("charge");
530  tspecies(chargeIdx, upIdx) = -1;
531 
532  elec_.addTable(ions_);
533  elec_.resetGroups();
534  elec_.update();
535  // </steal>
536 
537 
538  const auto nelec = elec_.R.size();
539  //Our test case is going to be three electron gas orbitals distinguished by 3 different kpoints.
540  //Independent SPO's for the up and down channels.
541  //
542  std::vector<PosType> kup, kdn;
543  std::vector<RealType> k2up, k2dn;
544 
545 
546  kup.resize(nelec);
547  kup[0] = PosType(0, 0, 0);
548  kup[1] = PosType(0.1, 0.2, 0.3);
549  kup[2] = PosType(0.4, 0.5, 0.6);
550 
551  kdn.resize(nelec);
552  kdn[0] = PosType(0, 0, 0);
553  kdn[1] = PosType(-0.1, 0.2, -0.3);
554  kdn[2] = PosType(0.4, -0.5, 0.6);
555 
556  auto spo_up = std::make_unique<FreeOrbital>("free_orb_up", kup);
557  auto spo_dn = std::make_unique<FreeOrbital>("free_orb_up", kdn);
558 
559  auto spinor_set = std::make_unique<SpinorSet>("free_orb_spinor");
560  spinor_set->set_spos(std::move(spo_up), std::move(spo_dn));
561 
562  using DetType = DiracDeterminantBatched<PL, ValueType, QMCTraits::QTFull::ValueType>;
563  DetType dd(std::move(spinor_set), 0, nelec, delay_rank, matrix_inverter_kind);
564  app_log() << " nelec=" << nelec << std::endl;
565 
566  ParticleGradient G;
567  ParticleLaplacian L;
568  ParticleAttrib<ComplexType> SG;
569 
570  G.resize(nelec);
571  L.resize(nelec);
572  SG.resize(nelec);
573 
574  G = 0.0;
575  L = 0.0;
576  SG = 0.0;
577 
578  PosType dr(0.1, -0.05, 0.2);
579  RealType ds = 0.3;
580 
581  app_log() << " BEFORE\n";
582  app_log() << " R = " << elec_.R << std::endl;
583  app_log() << " s = " << elec_.spins << std::endl;
584 
585  //In this section, we're going to test that values and various derivatives come out
586  //correctly at the reference configuration.
587 
588  LogValue logref = dd.evaluateLog(elec_, G, L);
589 
590  CHECK(logref == ComplexApprox(ValueType(-1.1619939279564413, 0.8794794652468605)));
591  CHECK(G[0][0] == ComplexApprox(ValueType(0.13416635, 0.2468612)));
592  CHECK(G[0][1] == ComplexApprox(ValueType(-1.1165475, 0.71497753)));
593  CHECK(G[0][2] == ComplexApprox(ValueType(0.0178403, 0.08212244)));
594  CHECK(G[1][0] == ComplexApprox(ValueType(1.00240841, 0.12371593)));
595  CHECK(G[1][1] == ComplexApprox(ValueType(1.62679698, -0.41080777)));
596  CHECK(G[1][2] == ComplexApprox(ValueType(1.81324632, 0.78589013)));
597  CHECK(G[2][0] == ComplexApprox(ValueType(-1.10994555, 0.15525902)));
598  CHECK(G[2][1] == ComplexApprox(ValueType(-0.46335602, -0.50809713)));
599  CHECK(G[2][2] == ComplexApprox(ValueType(-1.751199, 0.10949589)));
600  CHECK(L[0] == ComplexApprox(ValueType(-2.06554158, 1.18145239)));
601  CHECK(L[1] == ComplexApprox(ValueType(-5.06340536, 0.82126749)));
602  CHECK(L[2] == ComplexApprox(ValueType(-4.82375261, -1.97943258)));
603 
604  //This is a workaround for the fact that I haven't implemented
605  // evaluateLogWithSpin(). Shouldn't be needed unless we do drifted all-electron moves...
606  for (int iat = 0; iat < nelec; iat++)
607  dd.evalGradWithSpin(elec_, iat, SG[iat]);
608 
609  CHECK(SG[0] == ComplexApprox(ValueType(-1.05686704, -2.01802154)));
610  CHECK(SG[1] == ComplexApprox(ValueType(1.18922259, 2.80414598)));
611  CHECK(SG[2] == ComplexApprox(ValueType(-0.62617675, -0.51093984)));
612 
613  GradType g_singleeval(0.0);
614  g_singleeval = dd.evalGrad(elec_, 1);
615 
616  CHECK(g_singleeval[0] == ComplexApprox(G[1][0]));
617  CHECK(g_singleeval[1] == ComplexApprox(G[1][1]));
618  CHECK(g_singleeval[2] == ComplexApprox(G[1][2]));
619 
620 
621  //And now we're going to propose a trial spin+particle move and check the ratio and gradients at the
622  //new location.
623  //
624  elec_.makeMoveAndCheckWithSpin(1, dr, ds);
625 
626  ValueType ratio_new;
627  ValueType spingrad_new;
628  GradType grad_new;
629 
630  //This tests ratio only evaluation. Indirectly a call to evaluate(P,iat)
631  ratio_new = dd.ratio(elec_, 1);
632  CHECK(ratio_new == ComplexApprox(ValueType(1.7472917722050971, 1.1900872950904169)));
633 
634  ratio_new = dd.ratioGrad(elec_, 1, grad_new);
635  CHECK(ratio_new == ComplexApprox(ValueType(1.7472917722050971, 1.1900872950904169)));
636  CHECK(grad_new[0] == ComplexApprox(ValueType(0.5496675534224996, -0.07968022499097227)));
637  CHECK(grad_new[1] == ComplexApprox(ValueType(0.4927399293808675, -0.29971549854643653)));
638  CHECK(grad_new[2] == ComplexApprox(ValueType(1.2792642963632226, 0.12110307514989149)));
639 
640  grad_new = 0;
641  spingrad_new = 0;
642  ratio_new = dd.ratioGradWithSpin(elec_, 1, grad_new, spingrad_new);
643  CHECK(ratio_new == ComplexApprox(ValueType(1.7472917722050971, 1.1900872950904169)));
644  CHECK(grad_new[0] == ComplexApprox(ValueType(0.5496675534224996, -0.07968022499097227)));
645  CHECK(grad_new[1] == ComplexApprox(ValueType(0.4927399293808675, -0.29971549854643653)));
646  CHECK(grad_new[2] == ComplexApprox(ValueType(1.2792642963632226, 0.12110307514989149)));
647  CHECK(spingrad_new == ComplexApprox(ValueType(1.164708841479661, 0.9576425115390172)));
648 
649 
650  //Cool. Now we test the transition between rejecting a move and accepting a move.
651  //Reject the move first. We want to see if everything stays the same. evalGrad and evalSpinGrad for ease of use.
652 
653  elec_.rejectMove(1);
654  //Going to check evalGrad and evalGradWithSpin for simplicity.
655  g_singleeval = dd.evalGrad(elec_, 1);
656  CHECK(g_singleeval[0] == ComplexApprox(G[1][0]));
657  CHECK(g_singleeval[1] == ComplexApprox(G[1][1]));
658  CHECK(g_singleeval[2] == ComplexApprox(G[1][2]));
659 
660  ValueType spingrad_old_test;
661  g_singleeval = dd.evalGradWithSpin(elec_, 1, spingrad_old_test);
662 
663  CHECK(spingrad_old_test == ComplexApprox(SG[1]));
664  CHECK(g_singleeval[0] == ComplexApprox(G[1][0]));
665  CHECK(g_singleeval[1] == ComplexApprox(G[1][1]));
666  CHECK(g_singleeval[2] == ComplexApprox(G[1][2]));
667 
668  //Now we test what happens if we accept a move...
669  elec_.makeMoveAndCheckWithSpin(1, dr, ds);
670  elec_.acceptMove(1);
671 
672  LogValue lognew(0.0);
673  G = 0.0; //evalauteLog += onto the G and L arguments. So we zero them out.
674  L = 0.0;
675  SG = 0.0;
676  lognew = dd.evaluateLog(elec_, G, L);
677 
678  for (int iat = 0; iat < nelec; iat++)
679  dd.evalGradWithSpin(elec_, iat, SG[iat]);
680  //logval for the new configuration has been computed with python.
681  //The others reference values are computed earlier in this section. New values equal the previous
682  // "new values" associated with the previous trial moves.
683  CHECK(lognew == ComplexApprox(ValueType(-0.41337396772929913, 1.4774106123071726)));
684  CHECK(G[1][0] == ComplexApprox(grad_new[0]));
685  CHECK(G[1][1] == ComplexApprox(grad_new[1]));
686  CHECK(G[1][2] == ComplexApprox(grad_new[2]));
687  CHECK(SG[1] == ComplexApprox(spingrad_new));
688 
689  //move back to original config
690  elec_.makeMoveAndCheckWithSpin(1, -dr, -ds);
691  elec_.acceptMove(1);
692  dd.acceptMove(elec_, 1, true);
693 
694  //test batched APIs
695  ResourceCollection pset_res("test_pset_res");
696  ResourceCollection wfc_res("test_wfc_res");
697 
698  elec_.createResource(pset_res);
699  dd.createResource(wfc_res);
700 
701  ParticleSet elec_clone(elec_);
702  std::unique_ptr<WaveFunctionComponent> dd_clone(dd.makeCopy(dd.getPhi()->makeClone()));
703  auto& dd_clone_ref = dynamic_cast<DetType&>(*dd_clone);
704 
705  RefVectorWithLeader<ParticleSet> p_ref_list(elec_, {elec_, elec_clone});
706  RefVectorWithLeader<WaveFunctionComponent> dd_ref_list(dd, {dd, *dd_clone});
707 
708  ResourceCollectionTeamLock<ParticleSet> mw_pset_lock(pset_res, p_ref_list);
709  ResourceCollectionTeamLock<WaveFunctionComponent> mw_wfc_lock(wfc_res, dd_ref_list);
710 
711  G = 0;
712  L = 0;
713  ParticleGradient G2;
714  ParticleLaplacian L2;
715  G2.resize(nelec);
716  L2.resize(nelec);
717 
718  //Check initial values for both walkers
719  RefVector<ParticleGradient> G_list = {G, G2};
720  RefVector<ParticleLaplacian> L_list = {L, L2};
721  dd.mw_evaluateLog(dd_ref_list, p_ref_list, G_list, L_list);
722  for (int iw = 0; iw < dd_ref_list.size(); iw++)
723  {
724  PsiValue ref = dd_ref_list[iw].getValue();
725  CHECK(std::log(ref) == ComplexApprox(ValueType(-1.1619939279564413, 0.8794794652468605)));
726  CHECK(G_list[iw].get()[0][0] == ComplexApprox(ValueType(0.13416635, 0.2468612)));
727  CHECK(G_list[iw].get()[0][1] == ComplexApprox(ValueType(-1.1165475, 0.71497753)));
728  CHECK(G_list[iw].get()[0][2] == ComplexApprox(ValueType(0.0178403, 0.08212244)));
729  CHECK(G_list[iw].get()[1][0] == ComplexApprox(ValueType(1.00240841, 0.12371593)));
730  CHECK(G_list[iw].get()[1][1] == ComplexApprox(ValueType(1.62679698, -0.41080777)));
731  CHECK(G_list[iw].get()[1][2] == ComplexApprox(ValueType(1.81324632, 0.78589013)));
732  CHECK(G_list[iw].get()[2][0] == ComplexApprox(ValueType(-1.10994555, 0.15525902)));
733  CHECK(G_list[iw].get()[2][1] == ComplexApprox(ValueType(-0.46335602, -0.50809713)));
734  CHECK(G_list[iw].get()[2][2] == ComplexApprox(ValueType(-1.751199, 0.10949589)));
735  CHECK(L_list[iw].get()[0] == ComplexApprox(ValueType(-2.06554158, 1.18145239)));
736  CHECK(L_list[iw].get()[1] == ComplexApprox(ValueType(-5.06340536, 0.82126749)));
737  CHECK(L_list[iw].get()[2] == ComplexApprox(ValueType(-4.82375261, -1.97943258)));
738  }
739 
740  //Move particle 1 in each walker
741  MCCoords<CoordsType::POS_SPIN> displs(2);
742  displs.positions = {dr, dr};
743  displs.spins = {ds, ds};
744  elec_.mw_makeMove(p_ref_list, 1, displs);
745 
746  //Check ratios and grads for both walkers for proposed move
747  std::vector<PsiValue> ratios(2);
748  std::vector<GradType> grads(2);
749  std::vector<ComplexType> spingrads(2);
750  dd.mw_ratioGrad(dd_ref_list, p_ref_list, 1, ratios, grads);
751  for (int iw = 0; iw < grads.size(); iw++)
752  {
753  CHECK(ratios[iw] == ComplexApprox(ValueType(1.7472917722050971, 1.1900872950904169)));
754  CHECK(grads[iw][0] == ComplexApprox(ValueType(0.5496675534224996, -0.07968022499097227)));
755  CHECK(grads[iw][1] == ComplexApprox(ValueType(0.4927399293808675, -0.29971549854643653)));
756  CHECK(grads[iw][2] == ComplexApprox(ValueType(1.2792642963632226, 0.12110307514989149)));
757  }
758 
759  std::fill(ratios.begin(), ratios.end(), 0);
760  std::fill(grads.begin(), grads.end(), 0);
761  dd.mw_ratioGradWithSpin(dd_ref_list, p_ref_list, 1, ratios, grads, spingrads);
762  for (int iw = 0; iw < grads.size(); iw++)
763  {
764  CHECK(ratios[iw] == ComplexApprox(ValueType(1.7472917722050971, 1.1900872950904169)));
765  CHECK(grads[iw][0] == ComplexApprox(ValueType(0.5496675534224996, -0.07968022499097227)));
766  CHECK(grads[iw][1] == ComplexApprox(ValueType(0.4927399293808675, -0.29971549854643653)));
767  CHECK(grads[iw][2] == ComplexApprox(ValueType(1.2792642963632226, 0.12110307514989149)));
768  CHECK(spingrads[iw] == ComplexApprox(ValueType(1.164708841479661, 0.9576425115390172)));
769  }
770 
771  //reject move and check for initial values for mw_evalGrad
772  std::fill(grads.begin(), grads.end(), 0);
773  elec_.mw_accept_rejectMove<CoordsType::POS_SPIN>(p_ref_list, 1, {false, false});
774  dd.mw_evalGrad(dd_ref_list, p_ref_list, 1, grads);
775  for (int iw = 0; iw < grads.size(); iw++)
776  {
777  CHECK(grads[iw][0] == ComplexApprox(G_list[iw].get()[1][0]));
778  CHECK(grads[iw][1] == ComplexApprox(G_list[iw].get()[1][1]));
779  CHECK(grads[iw][2] == ComplexApprox(G_list[iw].get()[1][2]));
780  }
781 
782  std::fill(grads.begin(), grads.end(), 0);
783  std::fill(spingrads.begin(), spingrads.end(), 0);
784  dd.mw_evalGradWithSpin(dd_ref_list, p_ref_list, 1, grads, spingrads);
785  for (int iw = 0; iw < grads.size(); iw++)
786  {
787  CHECK(grads[iw][0] == ComplexApprox(G_list[iw].get()[1][0]));
788  CHECK(grads[iw][1] == ComplexApprox(G_list[iw].get()[1][1]));
789  CHECK(grads[iw][2] == ComplexApprox(G_list[iw].get()[1][2]));
790  CHECK(spingrads[iw] == ComplexApprox(ValueType(1.18922259, 2.80414598)));
791  }
792 
793  //now make and accept move, checking new values
794  elec_.mw_makeMove(p_ref_list, 1, displs);
795  elec_.mw_accept_rejectMove<CoordsType::POS_SPIN>(p_ref_list, 1, {true, true});
796 
797  G = 0;
798  L = 0;
799  G2 = 0;
800  L2 = 0;
801  dd.mw_evaluateLog(dd_ref_list, p_ref_list, G_list, L_list);
802  for (int iw = 0; iw < dd_ref_list.size(); iw++)
803  {
804  PsiValue ref = dd_ref_list[iw].getValue();
805  CHECK(std::log(ref) == ComplexApprox(ValueType(-0.41337396772929913, 1.4774106123071726)));
806  CHECK(G_list[iw].get()[1][0] == ComplexApprox(ValueType(0.5496675534224996, -0.07968022499097227)));
807  CHECK(G_list[iw].get()[1][1] == ComplexApprox(ValueType(0.4927399293808675, -0.29971549854643653)));
808  CHECK(G_list[iw].get()[1][2] == ComplexApprox(ValueType(1.2792642963632226, 0.12110307514989149)));
809  }
810 
811  dd.mw_evalGradWithSpin(dd_ref_list, p_ref_list, 1, grads, spingrads);
812  for (int iw = 0; iw < grads.size(); iw++)
813  CHECK(spingrads[iw] == ComplexApprox(ValueType(1.164708841479661, 0.9576425115390172)));
814 }
815 
816 TEST_CASE("DiracDeterminantBatched_spinor_update", "[wavefunction][fermion]")
817 {
818  /* Uncomment when DelayedUpdateBatched::mw_evalGradWithSpin is implemented
819 #if defined(ENABLE_OFFLOAD) && defined(ENABLE_CUDA)
820  test_DiracDeterminantBatched_spinor_update<
821  PlatformKind::CUDA>(1, DetMatInvertor::ACCEL);
822  test_DiracDeterminantBatched_spinor_update<
823  PlatformKind::CUDA>(1, DetMatInvertor::HOST);
824 #endif
825 */
826  test_DiracDeterminantBatched_spinor_update<PlatformKind::OMPTARGET>(1, DetMatInvertor::ACCEL);
827  test_DiracDeterminantBatched_spinor_update<PlatformKind::OMPTARGET>(1, DetMatInvertor::HOST);
828 }
829 #endif
830 } // namespace qmcplusplus
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
WaveFunctionComponent::PsiValue PsiValue
Definition: SlaterDet.cpp:25
static T convert(const std::complex< T1 > &logpsi)
QMCTraits::RealType real
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
QTBase::GradType GradType
Definition: Configuration.h:62
QTBase::RealType RealType
Definition: Configuration.h:58
size_t getTotalNum() const
Definition: ParticleSet.h:493
std::ostream & app_log()
Definition: OutputManager.h:65
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > ParticleLayout
Definition: Configuration.h:79
TEST_CASE("complex_helper", "[type_traits]")
RealType ValueType
Definition: QMCTypes.h:42
DetMatInvertor
determinant matrix inverter select
A ParticleSet that handles virtual moves of a selected particle of a given physical ParticleSet Virtu...
void makeMoves(const ParticleSet &refp, int jel, const std::vector< PosType > &deltaV, bool sphere=false, int iat=-1)
move virtual particles to new postions and update distance tables
CHECKED_ELSE(check_matrix_result.result)
ParticleAttrib< QTFull::ValueType > ParticleLaplacian
Definition: Configuration.h:96
LatticeGaussianProduct::GradType GradType
void createResource(ResourceCollection &collection) const
initialize a shared resource and hand it to a collection
void transpose(const T *restrict A, size_t m, size_t lda, TO *restrict B, size_t n, size_t ldb)
transpose of A(m,n) to B(n,m)
Definition: algorithm.hpp:97
QTBase::ComplexType ComplexType
Definition: Configuration.h:59
void resize(size_type n, size_type m)
Resize the container.
Definition: OhmmsMatrix.h:99
size_type cols() const
Definition: OhmmsMatrix.h:78
QMCTraits::PosType PosType
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
QTBase::ValueType ValueType
Definition: Configuration.h:60
void rejectMove(Index_t iat)
reject a proposed move in regular mode
helper class to compute matrix inversion and the log value of determinant
Definition: DiracMatrix.h:111
ParticlePos R
Position.
Definition: ParticleSet.h:79
QTBase::PosType PosType
Definition: Configuration.h:61
MakeReturn< UnaryNode< FnExp, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t exp(const Vector< T1, C1 > &l)
size_type rows() const
Definition: OhmmsMatrix.h:77
void create(const std::vector< int > &agroup)
create grouped particles
MakeReturn< UnaryNode< FnLog, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t log(const Vector< T1, C1 > &l)
QMCTraits::RealType RealType
Declaration of DiracDeterminantBatched with a S(ingle)P(article)O(rbital)Set.
void makeMove(Index_t iat, const SingleParticlePos &displ, bool maybe_accept=true)
move the iat-th particle to active_pos_
CheckMatrixResult checkMatrix(M1 &a_mat, M2 &b_mat, const bool check_all=false, std::optional< const double > eps=std::nullopt)
This function checks equality a_mat and b_mat elements M1, M2 need to have their element type declare...
Definition: checkMatrix.hpp:63
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 }))
ParticleAttrib< SingleParticlePos > ParticlePos
Definition: Configuration.h:92
TinyVector< double, 3 > PosType
QMCTraits::ComplexType ComplexType
handles acquire/release resource by the consumer (RefVectorWithLeader type).
LatticeGaussianProduct::ValueType ValueType
ParticleAttrib< QTFull::GradType > ParticleGradient
Definition: Configuration.h:95
Declaration of WaveFunctionComponent.
std::complex< double > LogValue
void acceptMove(Index_t iat)
accept the move and update the particle attribute by the proposed move in regular mode ...
std::enable_if_t< std::is_same< T_FP, TMAT >::value > invert_transpose(const Matrix< TMAT, ALLOC1 > &amat, Matrix< TMAT, ALLOC2 > &invMat, std::complex< TREAL > &LogDet)
compute the inverse of the transpose of matrix A and its determinant value in log when T_FP and TMAT ...
Definition: DiracMatrix.h:188
void test_DiracDeterminantBatched_delayed_update(int delay_rank, DetMatInvertor matrix_inverter_kind)
void makeVirtualMoves(const SingleParticlePos &newpos)
Handles virtual moves for all the particles to a single newpos.