QMCPACK
test_RotatedSPOs.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: Joshua Townsend, jptowns@sandia.gov, Sandia National Laboratories
8 //
9 // File created by: Joshua Townsend, jptowns@sandia.gov, Sandia National Laboratories
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 #include "catch.hpp"
13 
17 #include "OhmmsData/Libxml2Doc.h"
18 #include "OhmmsPETE/OhmmsMatrix.h"
19 #include "Particle/ParticleSet.h"
24 #include "checkMatrix.hpp"
25 #include "FakeSPO.h"
26 #include <ResourceCollection.h>
27 
28 #include <stdio.h>
29 #include <string>
30 #include <limits>
31 
32 using std::string;
33 
34 namespace qmcplusplus
35 {
36 /*
37  JPT 04.01.2022: Adapted from test_einset.cpp
38  Test the spline rotated machinery for SplineR2R (extend to others later).
39 */
40 TEST_CASE("RotatedSPOs via SplineR2R", "[wavefunction]")
41 {
43 
44  /*
45  BEGIN Boilerplate stuff to make a simple SPOSet. Copied from test_einset.cpp
46  */
47 
49 
50  // We get a "Mismatched supercell lattices" error due to default ctor?
52 
53  // diamondC_1x1x1
54  lattice.R = {3.37316115, 3.37316115, 0.0, 0.0, 3.37316115, 3.37316115, 3.37316115, 0.0, 3.37316115};
55 
58  // LAttice seems fine after this point...
59 
60  auto ions_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
61  auto elec_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
62  ParticleSet& ions_(*ions_uptr);
63  ParticleSet& elec_(*elec_uptr);
64 
65  ions_.setName("ion");
66  ptcl.addParticleSet(std::move(ions_uptr));
67  ions_.create({2});
68  ions_.R[0] = {0.0, 0.0, 0.0};
69  ions_.R[1] = {1.68658058, 1.68658058, 1.68658058};
70  elec_.setName("elec");
71  ptcl.addParticleSet(std::move(elec_uptr));
72  elec_.create({2});
73  elec_.R[0] = {0.0, 0.0, 0.0};
74  elec_.R[1] = {0.0, 1.0, 0.0};
75  SpeciesSet& tspecies = elec_.getSpeciesSet();
76  int upIdx = tspecies.addSpecies("u");
77  int chargeIdx = tspecies.addAttribute("charge");
78  tspecies(chargeIdx, upIdx) = -1;
79 
80  //diamondC_1x1x1 - 8 bands available
81  const char* particles = R"(<tmp>
82 <determinantset type="einspline" href="diamondC_1x1x1.pwscf.h5" tilematrix="1 0 0 0 1 0 0 0 1" twistnum="0" source="ion" meshfactor="1.0" precision="float" size="8"/>
83 </tmp>
84 )";
85 
87  bool okay = doc.parseFromString(particles);
88  REQUIRE(okay);
89 
90  xmlNodePtr root = doc.getRoot();
91 
92  xmlNodePtr ein1 = xmlFirstElementChild(root);
93 
94  EinsplineSetBuilder einSet(elec_, ptcl.getPool(), c, ein1);
95  auto spo = einSet.createSPOSetFromXML(ein1);
96  REQUIRE(spo);
97 
98  /*
99  END Boilerplate stuff. Now we have a SplineR2R wavefunction
100  ready for rotation. What follows is the actual test.
101  */
102 
103  // SplineR2R only for the moment, so skip if QMC_COMPLEX is set
104 #if !defined(QMC_COMPLEX)
105 
106  spo->storeParamsBeforeRotation();
107  // 1.) Make a RotatedSPOs object so that we can use the rotation routines
108  auto rot_spo = std::make_unique<RotatedSPOs>("one_rotated_set", std::move(spo));
109 
110  // Sanity check for orbs. Expect 2 electrons, 8 orbitals, & 79507 coefs/orb.
111  const auto orbitalsetsize = rot_spo->getOrbitalSetSize();
112  REQUIRE(orbitalsetsize == 8);
113 
114  // 2.) Get data for unrotated orbitals. Check that there's no rotation
115  rot_spo->buildOptVariables(elec_.R.size());
116  SPOSet::ValueMatrix psiM_bare(elec_.R.size(), orbitalsetsize);
117  SPOSet::GradMatrix dpsiM_bare(elec_.R.size(), orbitalsetsize);
118  SPOSet::ValueMatrix d2psiM_bare(elec_.R.size(), orbitalsetsize);
119  rot_spo->evaluate_notranspose(elec_, 0, elec_.R.size(), psiM_bare, dpsiM_bare, d2psiM_bare);
120 
121  // This stuff checks that no rotation was applied. Copied from test_einset.cpp.
122  // value
123  CHECK(std::real(psiM_bare[1][0]) == Approx(-0.8886948824));
124  CHECK(std::real(psiM_bare[1][1]) == Approx(1.4194120169));
125  // grad
126  CHECK(std::real(dpsiM_bare[1][0][0]) == Approx(-0.0000183403));
127  CHECK(std::real(dpsiM_bare[1][0][1]) == Approx(0.1655139178));
128  CHECK(std::real(dpsiM_bare[1][0][2]) == Approx(-0.0000193077));
129  CHECK(std::real(dpsiM_bare[1][1][0]) == Approx(-1.3131694794));
130  CHECK(std::real(dpsiM_bare[1][1][1]) == Approx(-1.1174004078));
131  CHECK(std::real(dpsiM_bare[1][1][2]) == Approx(-0.8462534547));
132  // lapl
133  CHECK(std::real(d2psiM_bare[1][0]) == Approx(1.3313053846));
134  CHECK(std::real(d2psiM_bare[1][1]) == Approx(-4.712583065));
135 
136  /*
137  3.) Apply a rotation to the orbitals
138  To do this, construct a params vector and call the
139  RotatedSPOs::apply_rotation(params) method. That should do the
140  right thing for this particular spline class.
141 
142  For 2 electrons in 8 orbs, we expect 2*(8-2) = 12 params.
143  */
144  const auto rot_size = rot_spo->m_act_rot_inds_.size();
145  REQUIRE(rot_size == 12); // = Nelec*(Norbs - Nelec) = 2*(8-2) = 12
146  std::vector<RealType> param(rot_size);
147  for (auto i = 0; i < rot_size; i++)
148  {
149  param[i] = 0.01 * static_cast<RealType>(i);
150  }
151  rot_spo->apply_rotation(param, false); // Expect this to call SplineR2R::applyRotation()
152 
153  // 4.) Get data for rotated orbitals.
154  SPOSet::ValueMatrix psiM_rot(elec_.R.size(), orbitalsetsize);
155  SPOSet::GradMatrix dpsiM_rot(elec_.R.size(), orbitalsetsize);
156  SPOSet::ValueMatrix d2psiM_rot(elec_.R.size(), orbitalsetsize);
157  rot_spo->evaluate_notranspose(elec_, 0, elec_.R.size(), psiM_rot, dpsiM_rot, d2psiM_rot);
158 
159  /*
160  Manually encode the unitary transformation. Ugly, but it works.
161  @TODO: Use the total rotation machinery when it's implemented
162 
163  NB: This is truncated to 5 sig-figs, so there is some slop here as
164  compared to what is done in the splines via apply_rotation().
165  So below we reduce the threshold for comparison. This can
166  probably be ditched once we have a way to grab the actual
167  rotation matrix...
168  */
169  SPOSet::ValueMatrix rot_mat(orbitalsetsize, orbitalsetsize);
170  rot_mat[0][0] = 0.99726;
171  rot_mat[0][1] = -0.00722;
172  rot_mat[0][2] = 0.00014;
173  rot_mat[0][3] = -0.00982;
174  rot_mat[0][4] = -0.01979;
175  rot_mat[0][5] = -0.02976;
176  rot_mat[0][6] = -0.03972;
177  rot_mat[0][7] = -0.04969;
178  rot_mat[1][0] = -0.00722;
179  rot_mat[1][1] = 0.97754;
180  rot_mat[1][2] = -0.05955;
181  rot_mat[1][3] = -0.06945;
182  rot_mat[1][4] = -0.07935;
183  rot_mat[1][5] = -0.08925;
184  rot_mat[1][6] = -0.09915;
185  rot_mat[1][7] = -0.10905;
186  rot_mat[2][0] = -0.00014;
187  rot_mat[2][1] = 0.05955;
188  rot_mat[2][2] = 0.99821;
189  rot_mat[2][3] = -0.00209;
190  rot_mat[2][4] = -0.00239;
191  rot_mat[2][5] = -0.00269;
192  rot_mat[2][6] = -0.00299;
193  rot_mat[2][7] = -0.00329;
194  rot_mat[3][0] = 0.00982;
195  rot_mat[3][1] = 0.06945;
196  rot_mat[3][2] = -0.00209;
197  rot_mat[3][3] = 0.99751;
198  rot_mat[3][4] = -0.00289;
199  rot_mat[3][5] = -0.00329;
200  rot_mat[3][6] = -0.00368;
201  rot_mat[3][7] = -0.00408;
202  rot_mat[4][0] = 0.01979;
203  rot_mat[4][1] = 0.07935;
204  rot_mat[4][2] = -0.00239;
205  rot_mat[4][3] = -0.00289;
206  rot_mat[4][4] = 0.99661;
207  rot_mat[4][5] = -0.00388;
208  rot_mat[4][6] = -0.00438;
209  rot_mat[4][7] = -0.00488;
210  rot_mat[5][0] = 0.02976;
211  rot_mat[5][1] = 0.08925;
212  rot_mat[5][2] = -0.00269;
213  rot_mat[5][3] = -0.00329;
214  rot_mat[5][4] = -0.00388;
215  rot_mat[5][5] = 0.99552;
216  rot_mat[5][6] = -0.00508;
217  rot_mat[5][7] = -0.00568;
218  rot_mat[6][0] = 0.03972;
219  rot_mat[6][1] = 0.09915;
220  rot_mat[6][2] = -0.00299;
221  rot_mat[6][3] = -0.00368;
222  rot_mat[6][4] = -0.00438;
223  rot_mat[6][5] = -0.00508;
224  rot_mat[6][6] = 0.99422;
225  rot_mat[6][7] = -0.00647;
226  rot_mat[7][0] = 0.04969;
227  rot_mat[7][1] = 0.10905;
228  rot_mat[7][2] = -0.00329;
229  rot_mat[7][3] = -0.00408;
230  rot_mat[7][4] = -0.00488;
231  rot_mat[7][5] = -0.00568;
232  rot_mat[7][6] = -0.00647;
233  rot_mat[7][7] = 0.99273;
234 
235  // Now compute the expected values by hand using the transformation above
236  double val1 = 0.;
237  double val2 = 0.;
238  for (auto i = 0; i < rot_mat.size1(); i++)
239  {
240  val1 += psiM_bare[0][i] * rot_mat[i][0];
241  val2 += psiM_bare[1][i] * rot_mat[i][0];
242  }
243 
244  // value
245  CHECK(std::real(psiM_rot[0][0]) == Approx(val1));
246  CHECK(std::real(psiM_rot[1][0]) == Approx(val2));
247 
248  std::vector<double> grad1(3);
249  std::vector<double> grad2(3);
250  for (auto j = 0; j < grad1.size(); j++)
251  {
252  for (auto i = 0; i < rot_mat.size1(); i++)
253  {
254  grad1[j] += dpsiM_bare[0][i][j] * rot_mat[i][0];
255  grad2[j] += dpsiM_bare[1][i][j] * rot_mat[i][0];
256  }
257  }
258 
259  // grad
260  CHECK(dpsiM_rot[0][0][0] == Approx(grad1[0]).epsilon(0.0001));
261  CHECK(dpsiM_rot[0][0][1] == Approx(grad1[1]).epsilon(0.0001));
262  CHECK(dpsiM_rot[0][0][2] == Approx(grad1[2]).epsilon(0.0001));
263  CHECK(dpsiM_rot[1][0][0] == Approx(grad2[0]).epsilon(0.0001));
264  CHECK(dpsiM_rot[1][0][1] == Approx(grad2[1]).epsilon(0.0001));
265  CHECK(dpsiM_rot[1][0][2] == Approx(grad2[2]).epsilon(0.0001));
266 
267  double lap1 = 0.;
268  double lap2 = 0.;
269  for (auto i = 0; i < rot_mat.size1(); i++)
270  {
271  lap1 += d2psiM_bare[0][i] * rot_mat[i][0];
272  lap2 += d2psiM_bare[1][i] * rot_mat[i][0];
273  }
274 
275  // Lapl
276  CHECK(std::real(d2psiM_rot[0][0]) == Approx(lap1).epsilon(0.0001));
277  CHECK(std::real(d2psiM_rot[1][0]) == Approx(lap2).epsilon(0.0001));
278 
279 #endif
280 }
281 
282 TEST_CASE("RotatedSPOs createRotationIndices", "[wavefunction]")
283 {
284  // No active-active or virtual-virtual rotations
285  // Only active-virtual
287  int nel = 1;
288  int nmo = 3;
289  RotatedSPOs::createRotationIndices(nel, nmo, rot_ind);
290  CHECK(rot_ind.size() == 2);
291 
292  // Full rotation contains all rotations
293  // Size should be number of pairs of orbitals: nmo*(nmo-1)/2
294  RotatedSPOs::RotationIndices full_rot_ind;
295  RotatedSPOs::createRotationIndicesFull(nel, nmo, full_rot_ind);
296  CHECK(full_rot_ind.size() == 3);
297 
298  nel = 2;
300  RotatedSPOs::createRotationIndices(nel, nmo, rot_ind2);
301  CHECK(rot_ind2.size() == 2);
302 
303  RotatedSPOs::RotationIndices full_rot_ind2;
304  RotatedSPOs::createRotationIndicesFull(nel, nmo, full_rot_ind2);
305  CHECK(full_rot_ind2.size() == 3);
306 
307  nmo = 4;
309  RotatedSPOs::createRotationIndices(nel, nmo, rot_ind3);
310  CHECK(rot_ind3.size() == 4);
311 
312  RotatedSPOs::RotationIndices full_rot_ind3;
313  RotatedSPOs::createRotationIndicesFull(nel, nmo, full_rot_ind3);
314  CHECK(full_rot_ind3.size() == 6);
315 }
316 
317 TEST_CASE("RotatedSPOs constructAntiSymmetricMatrix", "[wavefunction]")
318 {
320  using ValueMatrix = SPOSet::ValueMatrix;
321 
323  int nel = 1;
324  int nmo = 3;
325  RotatedSPOs::createRotationIndices(nel, nmo, rot_ind);
326 
327  ValueMatrix m3(nmo, nmo);
328  m3 = ValueType(0);
329  std::vector<ValueType> params = {0.1, 0.2};
330 
331  RotatedSPOs::constructAntiSymmetricMatrix(rot_ind, params, m3);
332 
333  // clang-format off
334  std::vector<ValueType> expected_data = { 0.0, -0.1, -0.2,
335  0.1, 0.0, 0.0,
336  0.2, 0.0, 0.0 };
337  // clang-format on
338 
339  ValueMatrix expected_m3(expected_data.data(), 3, 3);
340 
341  CheckMatrixResult check_matrix_result = checkMatrix(m3, expected_m3, true);
342  CHECKED_ELSE(check_matrix_result.result) { FAIL(check_matrix_result.result_message); }
343 
344  std::vector<ValueType> params_out(2);
345  RotatedSPOs::extractParamsFromAntiSymmetricMatrix(rot_ind, m3, params_out);
346  //Using ComplexApprox handles real or complex builds. In any case, no imaginary component expected.
347  CHECK(std::real(params_out[0]) == Approx(0.1));
348  CHECK(std::real(params_out[1]) == Approx(0.2));
349 }
350 
351 // Expected values of the matrix exponential come from gen_matrix_ops.py
352 TEST_CASE("RotatedSPOs exponentiate matrix", "[wavefunction]")
353 {
355  using RealType = SPOSet::RealType;
356  using ValueMatrix = SPOSet::ValueMatrix;
357 
358  std::vector<SPOSet::ValueType> mat1_data = {0.0};
359  SPOSet::ValueMatrix m1(mat1_data.data(), 1, 1);
361  // Always return 1.0 (the only possible anti-symmetric 1x1 matrix is 0)
362  CHECK(m1(0, 0) == ValueApprox(1.0));
363 
364  // clang-format off
365  std::vector<SPOSet::ValueType> mat2_data = { 0.0, -0.1,
366  0.1, 0.0 };
367  // clang-format on
368 
369  SPOSet::ValueMatrix m2(mat2_data.data(), 2, 2);
371 
372  // clang-format off
373  std::vector<ValueType> expected_rot2 = { 0.995004165278026, -0.0998334166468282,
374  0.0998334166468282, 0.995004165278026 };
375  // clang-format on
376 
377  ValueMatrix expected_m2(expected_rot2.data(), 2, 2);
378  CheckMatrixResult check_matrix_result2 = checkMatrix(m2, expected_m2, true);
379  CHECKED_ELSE(check_matrix_result2.result) { FAIL(check_matrix_result2.result_message); }
380 
381 
382  // clang-format off
383  std::vector<ValueType> m3_input_data = { 0.0, -0.3, -0.1,
384  0.3, 0.0, -0.2,
385  0.1, 0.2, 0.0 };
386 
387 
388  std::vector<ValueType> expected_rot3 = { 0.950580617906092, -0.302932713402637, -0.0680313164049401,
389  0.283164960565074, 0.935754803277919, -0.210191705950743,
390  0.127334574917630, 0.180540076694398, 0.975290308953046 };
391 
392  // clang-format on
393 
394  ValueMatrix m3(m3_input_data.data(), 3, 3);
395  ValueMatrix expected_m3(expected_rot3.data(), 3, 3);
396 
398 
399  CheckMatrixResult check_matrix_result3 = checkMatrix(m3, expected_m3, true);
400  CHECKED_ELSE(check_matrix_result3.result) { FAIL(check_matrix_result3.result_message); }
401 #ifdef QMC_COMPLEX
402  //Going to test exponentiating a complex antihermitian matrix.
403  using cmplx_t = std::complex<RealType>;
404  std::vector<cmplx_t> m3_input_data_cplx = {cmplx_t(0, 0), cmplx_t(0.3, 0.1), cmplx_t(0.1, -0.3),
405  cmplx_t(-0.3, 0.1), cmplx_t(0, 0), cmplx_t(0.2, 0.01),
406  cmplx_t(-0.1, -0.3), cmplx_t(-0.2, 0.01), cmplx_t(0, 0)};
407 
408  std::vector<cmplx_t> expected_rot_cmplx = {cmplx_t(0.90198269, -0.00652118), cmplx_t(0.27999104, 0.12545423),
409  cmplx_t(0.12447606, -0.27704993), cmplx_t(-0.29632557, 0.06664911),
410  cmplx_t(0.93133822, -0.00654092), cmplx_t(0.19214149, 0.05828413),
411  cmplx_t(-0.06763124, -0.29926537), cmplx_t(-0.19210869, -0.03907491),
412  cmplx_t(0.93133822, -0.00654092)};
413 
414  Matrix<std::complex<RealType>> m3_cmplx(m3_input_data_cplx.data(), 3, 3);
415  Matrix<std::complex<RealType>> m3_cmplx_expected(expected_rot_cmplx.data(), 3, 3);
416 
418 
419  CheckMatrixResult check_matrix_result4 = checkMatrix(m3_cmplx, m3_cmplx_expected, true);
420  CHECKED_ELSE(check_matrix_result4.result) { FAIL(check_matrix_result4.result_message); }
421 #endif
422 }
423 
424 TEST_CASE("RotatedSPOs log matrix", "[wavefunction]")
425 {
427  using ValueMatrix = SPOSet::ValueMatrix;
428  using RealType = SPOSet::RealType;
429 
430  std::vector<SPOSet::ValueType> mat1_data = {1.0};
431  SPOSet::ValueMatrix m1(mat1_data.data(), 1, 1);
432  SPOSet::ValueMatrix out_m1(1, 1);
434  // Should always be 1.0 (the only possible anti-symmetric 1x1 matrix is 0)
435  CHECK(out_m1(0, 0) == ValueApprox(0.0));
436 
437  // clang-format off
438  std::vector<ValueType> start_rot2 = { 0.995004165278026, -0.0998334166468282,
439  0.0998334166468282, 0.995004165278026 };
440 
441  std::vector<SPOSet::ValueType> mat2_data = { 0.0, -0.1,
442  0.1, 0.0 };
443  // clang-format on
444 
445  ValueMatrix rot_m2(start_rot2.data(), 2, 2);
446  ValueMatrix out_m2(2, 2);
447  RotatedSPOs::log_antisym_matrix(rot_m2, out_m2);
448 
449  SPOSet::ValueMatrix m2(mat2_data.data(), 2, 2);
450  CheckMatrixResult check_matrix_result2 = checkMatrix(m2, out_m2, true);
451  CHECKED_ELSE(check_matrix_result2.result) { FAIL(check_matrix_result2.result_message); }
452 
453  // clang-format off
454  std::vector<ValueType> start_rot3 = { 0.950580617906092, -0.302932713402637, -0.0680313164049401,
455  0.283164960565074, 0.935754803277919, -0.210191705950743,
456  0.127334574917630, 0.180540076694398, 0.975290308953046 };
457 
458  std::vector<ValueType> m3_input_data = { 0.0, -0.3, -0.1,
459  0.3, 0.0, -0.2,
460  0.1, 0.2, 0.0 };
461  // clang-format on
462  ValueMatrix rot_m3(start_rot3.data(), 3, 3);
463  ValueMatrix out_m3(3, 3);
464  RotatedSPOs::log_antisym_matrix(rot_m3, out_m3);
465 
466  SPOSet::ValueMatrix m3(m3_input_data.data(), 3, 3);
467  CheckMatrixResult check_matrix_result3 = checkMatrix(m3, out_m3, true);
468  CHECKED_ELSE(check_matrix_result3.result) { FAIL(check_matrix_result3.result_message); }
469 
470 #ifdef QMC_COMPLEX
471  using cmplx_t = std::complex<RealType>;
472  std::vector<cmplx_t> m3_input_data_cplx = {cmplx_t(0, 0), cmplx_t(0.3, 0.1), cmplx_t(0.1, -0.3),
473  cmplx_t(-0.3, 0.1), cmplx_t(0, 0), cmplx_t(0.2, 0.01),
474  cmplx_t(-0.1, -0.3), cmplx_t(-0.2, 0.01), cmplx_t(0, 0)};
475 
476  std::vector<cmplx_t> start_rot_cmplx = {cmplx_t(0.90198269, -0.00652118), cmplx_t(0.27999104, 0.12545423),
477  cmplx_t(0.12447606, -0.27704993), cmplx_t(-0.29632557, 0.06664911),
478  cmplx_t(0.93133822, -0.00654092), cmplx_t(0.19214149, 0.05828413),
479  cmplx_t(-0.06763124, -0.29926537), cmplx_t(-0.19210869, -0.03907491),
480  cmplx_t(0.93133822, -0.00654092)};
481 
482  //packing vector data into matrix form.
483  Matrix<std::complex<RealType>> m3_cmplx_rot(start_rot_cmplx.data(), 3, 3);
484  Matrix<std::complex<RealType>> m3_cmplx_ref_data(m3_input_data_cplx.data(), 3, 3);
485  Matrix<std::complex<RealType>> result_matrix(3, 3);
486  RotatedSPOs::log_antisym_matrix(m3_cmplx_rot, result_matrix);
487 
488  CheckMatrixResult check_matrix_result4 = checkMatrix(result_matrix, m3_cmplx_ref_data, true);
489  CHECKED_ELSE(check_matrix_result4.result) { FAIL(check_matrix_result4.result_message); }
490 #endif
491 }
492 
493 // Test round trip A -> exp(A) -> log(exp(A))
494 // The log is multi-valued so this test may fail if the rotation parameters are too large.
495 // The exponentials will be the same, though
496 // exp(log(exp(A))) == exp(A)
497 TEST_CASE("RotatedSPOs exp-log matrix", "[wavefunction]")
498 {
500  using ValueMatrix = SPOSet::ValueMatrix;
501 
503  int nel = 2;
504  int nmo = 4;
505  RotatedSPOs::createRotationIndices(nel, nmo, rot_ind);
506 
507  ValueMatrix rot_m4(nmo, nmo);
508  rot_m4 = ValueType(0);
509 
510  std::vector<ValueType> params4 = {-1.1, 1.5, 0.2, -0.15};
511 
512  RotatedSPOs::constructAntiSymmetricMatrix(rot_ind, params4, rot_m4);
513  ValueMatrix orig_rot_m4 = rot_m4;
514  ValueMatrix out_m4(nmo, nmo);
515 
517 
518  RotatedSPOs::log_antisym_matrix(rot_m4, out_m4);
519 
520  CheckMatrixResult check_matrix_result4 = checkMatrix(out_m4, orig_rot_m4, true);
521  CHECKED_ELSE(check_matrix_result4.result) { FAIL(check_matrix_result4.result_message); }
522 
523  std::vector<ValueType> params4out(4);
524  RotatedSPOs::extractParamsFromAntiSymmetricMatrix(rot_ind, out_m4, params4out);
525  for (int i = 0; i < params4.size(); i++)
526  {
527  CHECK(std::real(params4[i]) == Approx(std::real(params4out[i])));
528  }
529 
530 #ifdef QMC_COMPLEX
531  ValueMatrix rot_m4_cmplx(nmo, nmo);
532  rot_m4_cmplx = ValueType(0);
533 
534  //We have to be careful with the size of the components here. Exponentiate has
535  //a nice modulo 2pi property in it, and so log(A) is not uniquely defined without
536  //specifying a branch in the complex plane. Verified that the exp() and log() are one-to-one
537  //in this little regime.
538  std::vector<ValueType> params4_cmplx = {ValueType(-1.1, 0.3), ValueType(0.5, -0.2), ValueType(0.2, 1.1),
539  ValueType(-0.15, -.3)};
540 
541  RotatedSPOs::constructAntiSymmetricMatrix(rot_ind, params4_cmplx, rot_m4_cmplx);
542  ValueMatrix orig_rot_m4_cmplx = rot_m4_cmplx;
543  ValueMatrix out_m4_cmplx(nmo, nmo);
544 
546  RotatedSPOs::log_antisym_matrix(rot_m4_cmplx, out_m4_cmplx);
547  CheckMatrixResult check_matrix_result5 = checkMatrix(out_m4_cmplx, orig_rot_m4_cmplx, true);
548  CHECKED_ELSE(check_matrix_result5.result) { FAIL(check_matrix_result5.result_message); }
549 
550  std::vector<ValueType> params4out_cmplx(4);
551  RotatedSPOs::extractParamsFromAntiSymmetricMatrix(rot_ind, out_m4_cmplx, params4out_cmplx);
552  for (int i = 0; i < params4_cmplx.size(); i++)
553  {
554  CHECK(params4_cmplx[i] == ValueApprox(params4out_cmplx[i]));
555  }
556 
557 
558 #endif
559 }
560 
561 TEST_CASE("RotatedSPOs hcpBe", "[wavefunction]")
562 {
563  //until the parameter passing issue gets worked out, we won't do this test, since ostensibly
564  //theres a rotation coming from somewhere.
567 
569  lattice.R = {4.32747284, 0.00000000, 0.00000000, -2.16373642, 3.74770142,
570  0.00000000, 0.00000000, 0.00000000, 6.78114995};
571 
574  auto ions_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
575  auto elec_uptr = std::make_unique<ParticleSet>(ptcl.getSimulationCell());
576  ParticleSet& ions(*ions_uptr);
577  ParticleSet& elec(*elec_uptr);
578 
579  ions.setName("ion");
580  ptcl.addParticleSet(std::move(ions_uptr));
581  ions.create({1});
582  ions.R[0] = {0.0, 0.0, 0.0};
583 
584  elec.setName("elec");
585  ptcl.addParticleSet(std::move(elec_uptr));
586  elec.create({1});
587  elec.R[0] = {0.0, 0.0, 0.0};
588 
589  SpeciesSet& tspecies = elec.getSpeciesSet();
590  int upIdx = tspecies.addSpecies("u");
591  int chargeIdx = tspecies.addAttribute("charge");
592  tspecies(chargeIdx, upIdx) = -1;
593 
594  // Add the attribute save_coefs="yes" to the sposet_builder tag to generate the
595  // spline file for use in eval_bspline_spo.py
596 
597  const char* particles = R"(<tmp>
598 <sposet_builder type="bspline" href="hcpBe.pwscf.h5" tilematrix="1 0 0 0 1 0 0 0 1" twistnum="0" source="ion" meshfactor="1.0" precision="double" gpu="no">
599  <sposet type="bspline" name="spo_ud" spindataset="0" size="2"/>
600 </sposet_builder>
601 </tmp>)";
602 
604  bool okay = doc.parseFromString(particles);
605  REQUIRE(okay);
606 
607  xmlNodePtr root = doc.getRoot();
608 
609  xmlNodePtr sposet_builder = xmlFirstElementChild(root);
610  xmlNodePtr sposet_ptr = xmlFirstElementChild(sposet_builder);
611 
612  EinsplineSetBuilder einSet(elec, ptcl.getPool(), c, sposet_builder);
613  auto spo = einSet.createSPOSetFromXML(sposet_ptr);
614  REQUIRE(spo);
615 
616  spo->storeParamsBeforeRotation();
617  auto rot_spo = std::make_unique<RotatedSPOs>("one_rotated_set", std::move(spo));
618 
619  // Sanity check for orbs. Expect 1 electron, 2 orbitals
620  const auto orbitalsetsize = rot_spo->getOrbitalSetSize();
621  REQUIRE(orbitalsetsize == 2);
622 
623  rot_spo->buildOptVariables(elec.R.size());
624 
625  SPOSet::ValueMatrix psiM_bare(elec.R.size(), orbitalsetsize);
626  SPOSet::GradMatrix dpsiM_bare(elec.R.size(), orbitalsetsize);
627  SPOSet::ValueMatrix d2psiM_bare(elec.R.size(), orbitalsetsize);
628  rot_spo->evaluate_notranspose(elec, 0, elec.R.size(), psiM_bare, dpsiM_bare, d2psiM_bare);
629 
630  // Values generated from eval_bspline_spo.py, the generate_point_values_hcpBe function
631  CHECK(std::real(psiM_bare[0][0]) == Approx(0.210221765375514));
632  CHECK(std::real(psiM_bare[0][1]) == Approx(-2.984345024542937e-06));
633 
634  CHECK(std::real(d2psiM_bare[0][0]) == Approx(5.303848362116568));
635 
636  opt_variables_type opt_vars;
637  rot_spo->checkInVariablesExclusive(opt_vars);
638  opt_vars.resetIndex();
639  rot_spo->checkOutVariables(opt_vars);
640  rot_spo->resetParametersExclusive(opt_vars);
641 
643  size_t dim = IsComplex_t<ValueType>::value ? 2 : 1;
644  Vector<ValueType> dlogpsi(dim);
645  Vector<ValueType> dhpsioverpsi(dim);
646  rot_spo->evaluateDerivatives(elec, opt_vars, dlogpsi, dhpsioverpsi, 0, 1);
647 
648  CHECK(std::real(dlogpsi[0]) == Approx(-1.41961753e-05));
649 #ifndef QMC_COMPLEX
650  //This one value is off by 8e-5 (real part) with a 1e-5 imaginary component. Not sure what's going on.
651  //Maybe stretched the "take the real part" assumption past its limit. Some testing is better than no
652  //testing.
653  CHECK(std::real(dhpsioverpsi[0]) == Approx(-0.00060853));
654 #endif
655 
656  std::vector<ValueType> params = {0.1};
657  rot_spo->apply_rotation(params, false);
658 
659  rot_spo->evaluate_notranspose(elec, 0, elec.R.size(), psiM_bare, dpsiM_bare, d2psiM_bare);
660  CHECK(std::real(psiM_bare[0][0]) == Approx(0.20917123424337608));
661  CHECK(std::real(psiM_bare[0][1]) == Approx(-0.02099012652669549));
662 
663  CHECK(std::real(d2psiM_bare[0][0]) == Approx(5.277362065087747));
664 
665  dlogpsi[0] = 0.0;
666  dhpsioverpsi[0] = 0.0;
667 
668  rot_spo->evaluateDerivatives(elec, opt_vars, dlogpsi, dhpsioverpsi, 0, 1);
669  CHECK(std::real(dlogpsi[0]) == Approx(-0.10034901119468914));
670  CHECK(std::real(dhpsioverpsi[0]) == Approx(32.96939041498753));
671 }
672 
673 // Test construction of delta rotation
674 TEST_CASE("RotatedSPOs construct delta matrix", "[wavefunction]")
675 {
677  using ValueMatrix = SPOSet::ValueMatrix;
678 
679  int nel = 2;
680  int nmo = 4;
682  RotatedSPOs::createRotationIndices(nel, nmo, rot_ind);
683  RotatedSPOs::RotationIndices full_rot_ind;
684  RotatedSPOs::createRotationIndicesFull(nel, nmo, full_rot_ind);
685  // rot_ind size is 4 and full rot_ind size is 6
686 
687  ValueMatrix rot_m4(nmo, nmo);
688  rot_m4 = ValueType(0);
689 
690  // When comparing with gen_matrix_ops.py, be aware of the order of indices
691  // in full_rot
692  // rot_ind is (0,2) (0,3) (1,2) (1,3)
693  // full_rot_ind is (0,2) (0,3) (1,2) (1,3) (0,1) (2,3)
694  // The extra indices go at the back
695  std::vector<ValueType> old_params = {1.5, 0.2, -0.15, 0.03, -1.1, 0.05};
696  std::vector<ValueType> delta_params = {0.1, 0.3, 0.2, -0.1};
697  std::vector<ValueType> new_params(6);
698 
699  RotatedSPOs::constructDeltaRotation(delta_params, old_params, rot_ind, full_rot_ind, new_params, rot_m4);
700 
701  // clang-format off
702  std::vector<ValueType> rot_data4 =
703  { -0.371126931484737, 0.491586564957393, -0.784780958819798, 0.0687480658200083,
704  -0.373372784561548, 0.66111547793048, 0.610450337985578, 0.225542620014052,
705  0.751270334458895, 0.566737323353515, -0.0297901110611425, -0.336918744155143,
706  0.398058348785074, 0.00881931472604944, -0.102867783149713, 0.911531672428406 };
707  // clang-format on
708 
709  ValueMatrix new_rot_m4(rot_data4.data(), 4, 4);
710 
711  CheckMatrixResult check_matrix_result4 = checkMatrix(rot_m4, new_rot_m4, true);
712  CHECKED_ELSE(check_matrix_result4.result) { FAIL(check_matrix_result4.result_message); }
713 
714  // Reminder: Ordering!
715  std::vector<ValueType> expected_new_param = {1.6813965019790489, 0.3623564254653294, -0.05486544454559908,
716  -0.20574472941408453, -0.9542513302873077, 0.27497788909911774};
717  for (int i = 0; i < new_params.size(); i++)
718  CHECK(new_params[i] == ValueApprox(expected_new_param[i]));
719 
720 
721  // Rotated back to original position
722 
723  std::vector<ValueType> new_params2(6);
724  std::vector<ValueType> reverse_delta_params = {-0.1, -0.3, -0.2, 0.1};
725  RotatedSPOs::constructDeltaRotation(reverse_delta_params, new_params, rot_ind, full_rot_ind, new_params2, rot_m4);
726  for (int i = 0; i < new_params2.size(); i++)
727  CHECK(new_params2[i] == ValueApprox(old_params[i]));
728 }
729 
730 namespace testing
731 {
733 std::vector<QMCTraits::ValueType>& getMyVarsFull(RotatedSPOs& rot) { return rot.myVarsFull_; }
734 std::vector<std::vector<QMCTraits::ValueType>>& getHistoryParams(RotatedSPOs& rot) { return rot.history_params_; }
735 } // namespace testing
736 
737 // Test using global rotation
738 TEST_CASE("RotatedSPOs read and write parameters", "[wavefunction]")
739 {
740  //There is an issue with the real<->complex parameter parsing to h5 in QMC_COMPLEX.
741  //This needs to be fixed in a future PR.
742  auto fake_spo = std::make_unique<FakeSPO>();
743  fake_spo->setOrbitalSetSize(4);
744  RotatedSPOs rot("fake_rot", std::move(fake_spo));
745  int nel = 2;
746  rot.buildOptVariables(nel);
747 
748  std::vector<SPOSet::ValueType> vs_values{0.1, 0.15, 0.2, 0.25};
749 
752  auto* vs_values_data_real = (SPOSet::RealType*)vs_values.data();
753  for (size_t i = 0; i < vs.size(); i++)
754  vs[i] = vs_values_data_real[i];
755  rot.resetParametersExclusive(vs);
756 
757  {
758  hdf_archive hout;
759  vs.writeToHDF("rot_vp.h5", hout);
760 
761  rot.writeVariationalParameters(hout);
762  }
763 
764  auto fake_spo2 = std::make_unique<FakeSPO>();
765  fake_spo2->setOrbitalSetSize(4);
766 
767  RotatedSPOs rot2("fake_rot", std::move(fake_spo2));
768  rot2.buildOptVariables(nel);
769 
771  rot2.checkInVariablesExclusive(vs2);
772 
773  hdf_archive hin;
774  vs2.readFromHDF("rot_vp.h5", hin);
775  rot2.readVariationalParameters(hin);
776 
778  for (size_t i = 0; i < vs.size(); i++)
779  CHECK(var[i] == Approx(vs[i]));
780 
781  //add extra parameters for full set
782  vs_values.push_back(0.0);
783  vs_values.push_back(0.0);
784  std::vector<SPOSet::ValueType>& full_var = testing::getMyVarsFull(rot2);
785  for (size_t i = 0; i < full_var.size(); i++)
786  CHECK(full_var[i] == ValueApprox(vs_values[i]));
787 }
788 
789 // Test using history list.
790 TEST_CASE("RotatedSPOs read and write parameters history", "[wavefunction]")
791 {
792  //Problem with h5 parameter parsing for complex build. To be fixed in future PR.
793  auto fake_spo = std::make_unique<FakeSPO>();
794  fake_spo->setOrbitalSetSize(4);
795  RotatedSPOs rot("fake_rot", std::move(fake_spo));
796  rot.set_use_global_rotation(false);
797  int nel = 2;
798  rot.buildOptVariables(nel);
799 
800  std::vector<SPOSet::ValueType> vs_values{0.1, 0.15, 0.2, 0.25};
801 
804  auto* vs_values_data_real = (SPOSet::RealType*)vs_values.data();
805  for (size_t i = 0; i < vs.size(); i++)
806  vs[i] = vs_values_data_real[i];
807  rot.resetParametersExclusive(vs);
808 
809  {
810  hdf_archive hout;
811  vs.writeToHDF("rot_vp_hist.h5", hout);
812 
813  rot.writeVariationalParameters(hout);
814  }
815 
816  auto fake_spo2 = std::make_unique<FakeSPO>();
817  fake_spo2->setOrbitalSetSize(4);
818 
819  RotatedSPOs rot2("fake_rot", std::move(fake_spo2));
820  rot2.buildOptVariables(nel);
821 
823  rot2.checkInVariablesExclusive(vs2);
824 
825  hdf_archive hin;
826  vs2.readFromHDF("rot_vp_hist.h5", hin);
827  rot2.readVariationalParameters(hin);
828 
830  for (size_t i = 0; i < var.size(); i++)
831  CHECK(var[i] == Approx(vs[i]));
832 
833  auto hist = testing::getHistoryParams(rot2);
834  REQUIRE(hist.size() == 1);
835  REQUIRE(hist[0].size() == 4);
836 }
837 
839 {
840 public:
841  DummySPOSetWithoutMW(const std::string& my_name) : SPOSet(my_name) {}
842  void setOrbitalSetSize(int norbs) override {}
843  void evaluateValue(const ParticleSet& P, int iat, SPOSet::ValueVector& psi) override
844  {
845  assert(psi.size() == 3);
846  psi[0] = 123;
847  psi[1] = 456;
848  psi[2] = 789;
849  }
850  void evaluateVGL(const ParticleSet& P, int iat, ValueVector& psi, GradVector& dpsi, ValueVector& d2psi) override {}
851 #ifdef QMC_COMPLEX
852  void evaluate_spin(const ParticleSet& P, int iat, ValueVector& psi, ValueVector& dspin_psi) override
853  {
854  for (auto& sg : dspin_psi)
855  sg = ComplexType(0.9, 0.8);
856  }
857  void evaluateVGL_spin(const ParticleSet& P,
858  int iat,
859  ValueVector& psi,
860  GradVector& dpsi,
861  ValueVector& d2psi,
862  ValueVector& dspin_psi) override
863  {
864  for (auto& g : dpsi)
865  {
866  g[0] = 0.123;
867  g[1] = 0.456;
868  g[2] = 0.789;
869  }
870  for (auto& sg : dspin_psi)
871  sg = ComplexType(0.1, 0.2);
872  }
873 
874  void mw_evaluateVGLWithSpin(const RefVectorWithLeader<SPOSet>& spo_list,
875  const RefVectorWithLeader<ParticleSet>& P_list,
876  int iat,
877  const RefVector<ValueVector>& psi_v_list,
878  const RefVector<GradVector>& dpsi_v_list,
879  const RefVector<ValueVector>& d2psi_v_list,
880  OffloadMatrix<ComplexType>& mw_dspin) const override
881  {
882  assert(this == &spo_list.getLeader());
883  for (int iw = 0; iw < spo_list.size(); iw++)
884  {
885  auto* sg_row = mw_dspin[iw];
886  ValueVector sg(sg_row, mw_dspin.cols());
887  spo_list[iw].evaluateVGL_spin(P_list[iw], iat, psi_v_list[iw], dpsi_v_list[iw], d2psi_v_list[iw], sg);
888  }
889  }
890 #endif
892  int first,
893  int last,
894  ValueMatrix& logdet,
895  GradMatrix& dlogdet,
896  ValueMatrix& d2logdet) override
897  {}
898  std::string getClassName() const override { return my_name_; }
899 };
900 
902 {
903 public:
904  DummySPOSetWithMW(const std::string& my_name) : DummySPOSetWithoutMW(my_name) {}
906  const RefVectorWithLeader<ParticleSet>& P_list,
907  int iat,
908  const RefVector<ValueVector>& psi_v_list) const override
909  {
910  for (auto& psi : psi_v_list)
911  {
912  assert(psi.get().size() == 3);
913  psi.get()[0] = 321;
914  psi.get()[1] = 654;
915  psi.get()[2] = 987;
916  }
917  }
918 
919 #ifdef QMC_COMPLEX
921  const RefVectorWithLeader<ParticleSet>& P_list,
922  int iat,
923  const RefVector<ValueVector>& psi_v_list,
924  const RefVector<GradVector>& dpsi_v_list,
925  const RefVector<ValueVector>& d2psi_v_list,
926  OffloadMatrix<ComplexType>& mw_dspin) const override
927  {
928  for (auto& dpsi : dpsi_v_list)
929  {
930  assert(dpsi.get().size() == 3);
931  dpsi.get()[0][0] = 0.321;
932  dpsi.get()[0][1] = 0.654;
933  dpsi.get()[0][2] = 0.987;
934  }
935  for (auto& m : mw_dspin)
936  m = ComplexType(0.2, 0.1);
937  }
938 #endif
939 };
940 
941 TEST_CASE("RotatedSPOs mw_ APIs", "[wavefunction]")
942 {
943  {
944  //First check calling the mw_ APIs for RotatedSPOs, for which the
945  //underlying implementation just calls the underlying SPOSet mw_ API
946  //In the case that the underlying SPOSet doesn't specialize the mw_ API,
947  //the underlying SPOSet will fall back to the default SPOSet mw_, which is
948  //just a loop over the single walker API.
949  RotatedSPOs rot_spo0("rotated0", std::make_unique<DummySPOSetWithoutMW>("no mw 0"));
950  RotatedSPOs rot_spo1("rotated1", std::make_unique<DummySPOSetWithoutMW>("no mw 1"));
951  RefVectorWithLeader<SPOSet> spo_list(rot_spo0, {rot_spo0, rot_spo1});
952 
953  ResourceCollection spo_res("test_rot_res");
954  rot_spo0.createResource(spo_res);
955  ResourceCollectionTeamLock<SPOSet> mw_sposet_lock(spo_res, spo_list);
956 
957  const SimulationCell simulation_cell;
958  ParticleSet elec0(simulation_cell);
959  ParticleSet elec1(simulation_cell);
960  RefVectorWithLeader<ParticleSet> p_list(elec0, {elec0, elec1});
961 
962  SPOSet::ValueVector psi0(3);
963  SPOSet::ValueVector psi1(3);
964  RefVector<SPOSet::ValueVector> psi_v_list{psi0, psi1};
965 
966  rot_spo0.mw_evaluateValue(spo_list, p_list, 0, psi_v_list);
967  for (int iw = 0; iw < spo_list.size(); iw++)
968  {
969  CHECK(psi_v_list[iw].get()[0] == ValueApprox(123.));
970  CHECK(psi_v_list[iw].get()[1] == ValueApprox(456.));
971  CHECK(psi_v_list[iw].get()[2] == ValueApprox(789.));
972  }
973 #ifdef QMC_COMPLEX
974  SPOSet::GradVector dpsi0(3);
975  SPOSet::GradVector dpsi1(3);
976  RefVector<SPOSet::GradVector> dpsi_v_list{dpsi0, dpsi1};
977  SPOSet::ValueVector d2psi0(3);
978  SPOSet::ValueVector d2psi1(3);
979  SPOSet::ValueVector dspin(3);
980  RefVector<SPOSet::ValueVector> d2psi_v_list{d2psi0, d2psi1};
982  // check evaluate_spin, gets used by SlaterDet in evaluateVGL_spin. So checking to make sure RotatedSPO has it
983  rot_spo0.evaluate_spin(elec0, 0, psi0, dspin);
984  for (auto& m : dspin)
985  CHECK(m == ComplexApprox(SPOSet::ComplexType(0.9, 0.8)));
986  rot_spo0.mw_evaluateVGLWithSpin(spo_list, p_list, 0, psi_v_list, dpsi_v_list, d2psi_v_list, mw_dspin);
987  for (int iw = 0; iw < spo_list.size(); iw++)
988  {
989  CHECK(dpsi_v_list[iw].get()[0][0] == ValueApprox(0.123));
990  CHECK(dpsi_v_list[iw].get()[0][1] == ValueApprox(0.456));
991  CHECK(dpsi_v_list[iw].get()[0][2] == ValueApprox(0.789));
992  }
993  for (auto& m : mw_dspin)
994  CHECK(m == ComplexApprox(SPOSet::ComplexType(0.1, 0.2)));
995 #endif
996  }
997  {
998  //In the case that the underlying SPOSet DOES have mw_ specializations,
999  //we want to make sure that RotatedSPOs are triggering that appropriately
1000  //This will mean that the underlying SPOSets will do the appropriate offloading
1001  //To check this, DummySPOSetWithMW has an explicit mw_evaluateValue which sets
1002  //different values than what gets set in evaluateValue. By doing this,
1003  //we are ensuring that RotatedSPOs->mw_evaluaeValue is calling the specialization
1004  //in the underlying SPO and not using the default SPOSet implementation which
1005  //loops over single walker APIs (which have different values enforced in
1006  // DummySPOSetWithoutMW
1007 
1008  RotatedSPOs rot_spo0("rotated0", std::make_unique<DummySPOSetWithMW>("mw 0"));
1009  RotatedSPOs rot_spo1("rotated1", std::make_unique<DummySPOSetWithMW>("mw 1"));
1010  RefVectorWithLeader<SPOSet> spo_list(rot_spo0, {rot_spo0, rot_spo1});
1011 
1012  ResourceCollection spo_res("test_rot_res");
1013  rot_spo0.createResource(spo_res);
1014  ResourceCollectionTeamLock<SPOSet> mw_sposet_lock(spo_res, spo_list);
1015 
1016  const SimulationCell simulation_cell;
1017  ParticleSet elec0(simulation_cell);
1018  ParticleSet elec1(simulation_cell);
1019  RefVectorWithLeader<ParticleSet> p_list(elec0, {elec0, elec1});
1020 
1021  SPOSet::ValueVector psi0(3);
1022  SPOSet::ValueVector psi1(3);
1023  RefVector<SPOSet::ValueVector> psi_v_list{psi0, psi1};
1024 
1025  rot_spo0.mw_evaluateValue(spo_list, p_list, 0, psi_v_list);
1026  for (int iw = 0; iw < spo_list.size(); iw++)
1027  {
1028  CHECK(psi_v_list[iw].get()[0] == ValueApprox(321.));
1029  CHECK(psi_v_list[iw].get()[1] == ValueApprox(654.));
1030  CHECK(psi_v_list[iw].get()[2] == ValueApprox(987.));
1031  }
1032 #ifdef QMC_COMPLEX
1033  SPOSet::GradVector dpsi0(3);
1034  SPOSet::GradVector dpsi1(3);
1035  RefVector<SPOSet::GradVector> dpsi_v_list{dpsi0, dpsi1};
1036  SPOSet::ValueVector d2psi0(3);
1037  SPOSet::ValueVector d2psi1(3);
1038  RefVector<SPOSet::ValueVector> d2psi_v_list{d2psi0, d2psi1};
1040  rot_spo0.mw_evaluateVGLWithSpin(spo_list, p_list, 0, psi_v_list, dpsi_v_list, d2psi_v_list, mw_dspin);
1041  for (int iw = 0; iw < spo_list.size(); iw++)
1042  {
1043  CHECK(dpsi_v_list[iw].get()[0][0] == ValueApprox(0.321));
1044  CHECK(dpsi_v_list[iw].get()[0][1] == ValueApprox(0.654));
1045  CHECK(dpsi_v_list[iw].get()[0][2] == ValueApprox(0.987));
1046  }
1047  for (auto& m : mw_dspin)
1048  CHECK(m == ComplexApprox(SPOSet::ComplexType(0.2, 0.1)));
1049 #endif
1050  }
1051 }
1052 
1053 } // namespace qmcplusplus
void resetParametersExclusive(const opt_variables_type &active) override
reset
base class for Single-particle orbital sets
Definition: SPOSet.h:46
void writeVariationalParameters(hdf_archive &hout) override
Write the variational parameters for this object to the VP HDF file.
a class that defines a supercell in D-dimensional Euclean space.
void set_use_global_rotation(bool use_global_rotation)
Use history list (false) or global rotation (true)
Definition: RotatedSPOs.h:403
void setName(const std::string &aname)
Definition: ParticleSet.h:237
static void log_antisym_matrix(const ValueMatrix &mat, ValueMatrix &output)
static void constructAntiSymmetricMatrix(const RotationIndices &rot_indices, const std::vector< ValueType > &param, ValueMatrix &rot_mat)
Definition: RotatedSPOs.cpp:76
void setSimulationCell(const SimulationCell &simulation_cell)
set simulation cell
class that handles xmlDoc
Definition: Libxml2Doc.h:76
std::vector< ValueType > myVarsFull_
Full set of rotation matrix parameters for use in global rotation method.
Definition: RotatedSPOs.h:469
void writeToHDF(const std::string &filename, qmcplusplus::hdf_archive &hout) const
int addSpecies(const std::string &aname)
When a name species does not exist, add a new species.
Definition: SpeciesSet.cpp:33
QMCTraits::RealType real
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
std::string getClassName() const override
return class name
const std::string my_name_
name of the object, unique identifier
Definition: SPOSet.h:564
QTBase::RealType RealType
Definition: Configuration.h:58
void evaluate_spin(const ParticleSet &P, int iat, ValueVector &psi, ValueVector &dspin_psi) override
evaluate the values of this single-particle orbital set
Definition: RotatedSPOs.h:351
void checkInVariablesExclusive(opt_variables_type &active) override
check in variational parameters to the global list of parameters used by the optimizer.
Definition: RotatedSPOs.h:257
void setOrbitalSetSize(int norbs) override
set the OrbitalSetSize
std::vector< std::vector< ValueType > > history_params_
List of previously applied parameters.
Definition: RotatedSPOs.h:475
TEST_CASE("complex_helper", "[type_traits]")
void readFromHDF(const std::string &filename, qmcplusplus::hdf_archive &hin)
Read variational parameters from an HDF file.
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
Builder class for einspline-based SPOSet objects.
opt_variables_type myVars
Optimizable variables.
Definition: SPOSet.h:568
OrbitalSetTraits< ValueType >::ValueMatrix ValueMatrix
Definition: SPOSet.h:50
CHECKED_ELSE(check_matrix_result.result)
class to handle hdf file
Definition: hdf_archive.h:51
QTBase::ComplexType ComplexType
Definition: Configuration.h:59
static void createRotationIndices(int nel, int nmo, RotationIndices &rot_indices)
Definition: RotatedSPOs.cpp:48
auto check_matrix_result
void resetIndex()
reset Index
void mw_evaluateVGLWithSpin(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list, const RefVector< GradVector > &dpsi_v_list, const RefVector< ValueVector > &d2psi_v_list, OffloadMatrix< ComplexType > &mw_dspin) const override
evaluate the values, gradients and laplacians and spin gradient of this single-particle orbital sets ...
Communicate * Controller
Global Communicator for a process.
Definition: Communicate.cpp:35
int addAttribute(const std::string &aname)
for a new attribute, allocate the data, !More often used to get the index of a species ...
Definition: SpeciesSet.cpp:45
OrbitalSetTraits< ValueType >::ValueVector ValueVector
DummySPOSetWithMW(const std::string &my_name)
OrbitalSetTraits< ValueType >::GradMatrix GradMatrix
Definition: SPOSet.h:52
Wrapping information on parallelism.
Definition: Communicate.h:68
void buildOptVariables(size_t nel)
CrystalLattice< OHMMS_PRECISION, OHMMS_DIM > lattice
void evaluateValue(const ParticleSet &P, int iat, SPOSet::ValueVector &psi) override
evaluate the values of this single-particle orbital set
Specialized paritlce class for atomistic simulations.
Definition: ParticleSet.h:55
size_type size() const
return the current size
Definition: OhmmsVector.h:162
static void extractParamsFromAntiSymmetricMatrix(const RotationIndices &rot_indices, const ValueMatrix &rot_mat, std::vector< ValueType > &param)
Definition: RotatedSPOs.cpp:97
QTBase::ValueType ValueType
Definition: Configuration.h:60
REQUIRE(std::filesystem::exists(filename))
Manage a collection of ParticleSet objects.
std::vector< QMCTraits::ValueType > & getMyVarsFull(RotatedSPOs &rot)
OrbitalSetTraits< ValueType >::ValueVector ValueVector
Definition: SPOSet.h:49
virtual void evaluateVGL_spin(const ParticleSet &P, int iat, ValueVector &psi, GradVector &dpsi, ValueVector &d2psi, ValueVector &dspin)
evaluate the values, gradients and laplacians and spin gradient of this single-particle orbital set ...
Definition: SPOSet.cpp:83
class to handle a set of variables that can be modified during optimizations
Definition: VariableSet.h:49
ParticlePos R
Position.
Definition: ParticleSet.h:79
void mw_evaluateValue(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list) const override
evaluate the values this single-particle orbital sets of multiple walkers
std::vector< std::pair< int, int > > RotationIndices
Definition: RotatedSPOs.h:42
void evaluateVGL(const ParticleSet &P, int iat, ValueVector &psi, GradVector &dpsi, ValueVector &d2psi) override
evaluate the values, gradients and laplacians of this single-particle orbital set ...
static void createRotationIndicesFull(int nel, int nmo, RotationIndices &rot_indices)
Definition: RotatedSPOs.cpp:55
opt_variables_type & getMyVars(SPOSet &spo)
size_type size() const
return the size
Definition: VariableSet.h:88
void evaluate_notranspose(const ParticleSet &P, int first, int last, ValueMatrix &logdet, GradMatrix &dlogdet, ValueMatrix &d2logdet) override
evaluate the values, gradients and laplacians of this single-particle orbital for [first...
SpeciesSet & getSpeciesSet()
retrun the SpeciesSet of this particle set
Definition: ParticleSet.h:231
void create(const std::vector< int > &agroup)
create grouped particles
static void exponentiate_antisym_matrix(ValueMatrix &mat)
DummySPOSetWithoutMW(const std::string &my_name)
std::vector< std::reference_wrapper< T > > RefVector
std::vector< std::vector< QMCTraits::ValueType > > & getHistoryParams(RotatedSPOs &rot)
static void constructDeltaRotation(const std::vector< ValueType > &delta_param, const std::vector< ValueType > &old_param, const RotationIndices &act_rot_inds, const RotationIndices &full_rot_inds, std::vector< ValueType > &new_param, ValueMatrix &new_rot_mat)
OrbitalSetTraits< ValueType >::GradVector GradVector
Definition: SPOSet.h:51
virtual void mw_evaluateVGLWithSpin(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list, const RefVector< GradVector > &dpsi_v_list, const RefVector< ValueVector > &d2psi_v_list, OffloadMatrix< ComplexType > &mw_dspin) const
evaluate the values, gradients and laplacians and spin gradient of this single-particle orbital sets ...
Definition: SPOSet.cpp:115
bool parseFromString(const std::string_view data)
Definition: Libxml2Doc.cpp:204
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
CHECK(log_values[0]==ComplexApprox(std::complex< double >{ 5.603777579195571, -6.1586603331188225 }))
void mw_evaluateValue(const RefVectorWithLeader< SPOSet > &spo_list, const RefVectorWithLeader< ParticleSet > &P_list, int iat, const RefVector< ValueVector > &psi_v_list) const override
evaluate the values this single-particle orbital sets of multiple walkers
handles acquire/release resource by the consumer (RefVectorWithLeader type).
LatticeGaussianProduct::ValueType ValueType
Declaration of WaveFunctionComponent.
Custom container for set of attributes for a set of species.
Definition: SpeciesSet.h:33
const PoolType & getPool() const
get the Pool object
std::unique_ptr< SPOSet > createSPOSetFromXML(xmlNodePtr cur) override
initialize the Antisymmetric wave function for electrons
void readVariationalParameters(hdf_archive &hin) override
Read the variational parameters for this object from the VP HDF file.
const auto & getSimulationCell() const
get simulation cell
Declaration of ParticleSetPool.
void createResource(ResourceCollection &collection) const override
initialize a shared resource and hand it to collection
virtual void evaluate_spin(const ParticleSet &P, int iat, ValueVector &psi, ValueVector &dpsi)
evaluate the values of this single-particle orbital set
Definition: SPOSet.cpp:409