QMCPACK
soecp_eval_reference.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <iomanip>
3 #include <cmath>
4 #include <vector>
5 #include <complex>
6 #include <cassert>
7 
8 double PI = 4. * std::atan(1);
9 
10 //Same quadrature grid as in QMCPACK
11 std::vector<std::vector<double>> quad = {{1, 0, 0},
12  {-1, 1.224646853e-16, 0},
13  {0.4472135901, 0.8944271803, 0},
14  {-0.4472135901, 0.7236068249, 0.5257310867},
15  {0.4472135901, 0.2763932049, 0.8506507874},
16  {-0.4472135901, -0.2763932049, 0.8506507874},
17  {0.4472135901, -0.7236068249, 0.5257310867},
18  {-0.4472135901, -0.8944271803, 1.095357398e-16},
19  {0.4472135901, -0.7236068249, -0.5257310867},
20  {-0.4472135901, -0.2763932049, -0.8506507874},
21  {0.4472135901, 0.2763932049, -0.8506507874},
22  {-0.4472135901, 0.7236068249, -0.5257310867}};
23 std::vector<double> wt = {0.08333333582, 0.08333333582, 0.08333333582, 0.08333333582, 0.08333333582, 0.08333333582,
24  0.08333333582, 0.08333333582, 0.08333333582, 0.08333333582, 0.08333333582, 0.08333333582};
25 
26 //add simple Bspline Jastrow to compare against
27 double B(double x, int k, int i, const std::vector<double>& t)
28 {
29  double c1, c2;
30  if (k == 0)
31  return (x >= t[i] && x < t[i + 1]) ? 1.0 : 0.0;
32  if (t[i + k] == t[i])
33  c1 = 0.0;
34  else
35  c1 = (x - t[i]) / (t[i + k] - t[i]) * B(x, k - 1, i, t);
36  if (t[i + k + 1] == t[i + 1])
37  c2 = 0.0;
38  else
39  c2 = (t[i + k + 1] - x) / (t[i + k + 1] - t[i + 1]) * B(x, k - 1, i + 1, t);
40  return c1 + c2;
41 }
42 
43 double bspline(double x, const std::vector<double>& t, const std::vector<double>& c, int k)
44 {
45  int n = t.size() - k - 1;
46  assert(n >= k + 1);
47  assert(n <= c.size());
48  double val = 0.0;
49  for (int i = 0; i < n; i++)
50  val += c[i] * B(x, k, i, t);
51  return val;
52 }
53 
55 {
56 public:
57  cubicBSpline(double rcut, double cusp_val, const std::vector<double>& coeffs)
58  {
59  int numknots = coeffs.size();
60  coeffs_.resize(numknots + 6);
61  knots_.resize(numknots + 6);
62  cusp_val_ = cusp_val;
63 
64  delta_ = rcut / (numknots + 1);
65  coeffs_[0] = -2 * cusp_val_ * delta_ + coeffs[1];
66  coeffs_[1] = coeffs[0];
67  coeffs_[2] = coeffs[1];
68  std::copy(coeffs.begin() + 2, coeffs.end(), coeffs_.begin() + 3);
69  for (int i = 0; i < knots_.size(); i++)
70  knots_[i] = (i - 3) * delta_;
71  }
72 
73  double getVal(double x) const { return bspline(x, knots_, coeffs_, degree_); }
74 
75  double parmDeriv(const int ip, double x)
76  {
77  //changing parameter 0 means changing coefficient 1, and so on
78  const int ic = ip + 1;
79  double dp = 0.0001;
80  std::vector<double> finite_diff_coeffs = {-1. / 60, 3. / 20, -3. / 4, 0, 3. / 4, -3. / 20, 1. / 60};
81  std::vector<double> values(finite_diff_coeffs.size());
82  double inital_value = getCoeff(ic);
83  int offset = (finite_diff_coeffs.size() - 1) / 2;
84  for (int id = 0; id < finite_diff_coeffs.size(); id++)
85  {
86  double newval = inital_value + (id - offset) * dp;
87  setCoeff(ic, newval);
88  values[id] = getVal(x);
89  }
90  setCoeff(ic, inital_value);
91 
92  double deriv = 0.0;
93  for (int id = 0; id < finite_diff_coeffs.size(); id++)
94  deriv += finite_diff_coeffs[id] * values[id] / dp;
95  return deriv;
96  }
97  void setCoeff(int i, double newcoeff)
98  {
99  coeffs_[i] = newcoeff;
100  if (i == 2)
101  coeffs_[0] = -2 * cusp_val_ * delta_ + newcoeff;
102  }
103  double getCoeff(int i) const { return coeffs_[i]; }
104 
105 private:
106  std::vector<double> coeffs_;
107  std::vector<double> knots_;
108  const int degree_ = 3;
109  double delta_;
110  double cusp_val_;
111 };
112 
114 {
115  //testing 1b cusp from gen_bspline_jastrow.py
116  {
117  const double rcut = 10;
118  const double cusp = 2.0;
119 
120  std::vector<double> coeffs = {-0.2032153051, -0.1625595974, -0.143124599, -0.1216434956,
121  -0.09919771951, -0.07111729038, -0.04445345869, -0.02135082917};
122 
123  cubicBSpline spl(rcut, cusp, coeffs);
124 
125  //from gen_bspline_jastrow.py
126  std::vector<double> refVals = {-0.9304041433, -0.252599792, -0.1637586749, -0.1506226948, -0.1394848415,
127  -0.128023472, -0.1161729491, -0.1036884223, -0.08992443283, -0.07519614609,
128  -0.06054074137, -0.04654631918, -0.03347994129, -0.0211986378, -0.01004416026,
129  -0.002594125744, -0.000166024047};
130 
131  std::vector<double> rvals(refVals.size());
132  for (int i = 0; i < refVals.size(); i++)
133  rvals[i] = i * 0.60;
134 
135  bool good = true;
136  for (int i = 0; i < refVals.size(); i++)
137  if (std::abs(refVals[i] - spl.getVal(rvals[i])) > 1E-6)
138  {
139  std::cout << "error: " << rvals[i] << " " << refVals[i] << " != " << spl.getVal(rvals[i]) << std::endl;
140  good = false;
141  }
142  std::cout << "1b jastrow w/ cusp correct: " << good << std::endl;
143  }
144 
145  //test J2 from gen_bspline_jastrow.py
146  {
147  const double rcut = 10;
148  const double cusp = -0.5;
149 
150  std::vector<double> coeffs = {0.02904699284, -0.1004179, -0.1752703883, -0.2232576505, -0.2728029201,
151  -0.3253286875, -0.3624525145, -0.3958223107, -0.4268582166, -0.4394531176};
152 
153  cubicBSpline spl(rcut, cusp, coeffs);
154 
155  //from gen_bspline_jastrow.py
156  std::vector<double> refVals = {0.1374071801, -0.04952403966, -0.121361995, -0.1695590431, -0.2058414025,
157  -0.2382237097, -0.2712606182, -0.3047843679, -0.3347515004, -0.3597048574,
158  -0.3823503292, -0.4036800017, -0.4219818468, -0.4192355508, -0.3019238309,
159  -0.09726352421, -0.006239062395};
160 
161 
162  double r = 0.6935647049;
163  double val = spl.getVal(r);
164  std::cout << r << " " << val << std::endl;
165  std::vector<double> rvals(refVals.size());
166  for (int i = 0; i < refVals.size(); i++)
167  rvals[i] = i * 0.60;
168 
169  bool good = true;
170  for (int i = 0; i < refVals.size(); i++)
171  if (std::abs(refVals[i] - spl.getVal(rvals[i])) > 1E-6)
172  {
173  std::cout << "error: " << rvals[i] << " " << refVals[i] << " != " << spl.getVal(rvals[i]) << std::endl;
174  good = false;
175  }
176  std::cout << "2b jastrow correct: " << good << std::endl;
177  }
178 }
179 
180 std::complex<double> I = std::complex<double>(0, 1);
181 
182 std::complex<double> Ylm(int l, int m, const std::vector<double>& sph)
183 {
184  //From wiki
185  double pref;
186  switch (l)
187  {
188  case 0:
189  return std::complex<double>(0.5 * std::sqrt(1. / PI), 0.0);
190  break;
191  case 1:
192  switch (m)
193  {
194  case -1:
195  pref = 0.5 * std::sqrt(3. / (2 * PI));
196  return pref * std::exp(-I * sph[2]) * std::sin(sph[1]);
197  break;
198  case 0:
199  pref = 0.5 * std::sqrt(3. / (PI));
200  return pref * std::cos(sph[1]);
201  break;
202  case 1:
203  pref = -0.5 * std::sqrt(3. / (2 * PI));
204  return pref * std::exp(I * sph[2]) * std::sin(sph[1]);
205  break;
206  default:
207  exit(1);
208  break;
209  }
210  break;
211  case 2:
212  switch (m)
213  {
214  case -2:
215  pref = 0.25 * std::sqrt(15. / (2 * PI));
216  return pref * std::exp(-2.0 * I * sph[2]) * std::sin(sph[1]) * std::sin(sph[1]);
217  break;
218  case -1:
219  pref = 0.5 * std::sqrt(15. / (2 * PI));
220  return pref * std::exp(-I * sph[2]) * std::sin(sph[1]) * std::cos(sph[1]);
221  break;
222  case 0:
223  pref = 0.25 * std::sqrt(5. / (PI));
224  return pref * (3. * std::cos(sph[1]) * std::cos(sph[1]) - 1.);
225  break;
226 
227  case 1:
228  pref = -0.5 * std::sqrt(15. / (2 * PI));
229  return pref * std::exp(I * sph[2]) * std::sin(sph[1]) * std::cos(sph[1]);
230  break;
231  case 2:
232  pref = 0.25 * std::sqrt(15. / (2 * PI));
233  return pref * std::exp(2.0 * I * sph[2]) * std::sin(sph[1]) * std::sin(sph[1]);
234  break;
235  }
236  case 3:
237  switch (m)
238  {
239  case -3:
240  pref = 0.125 * std::sqrt(35. / PI);
241  return pref * std::exp(-3. * I * sph[2]) * std::pow(std::sin(sph[1]), 3);
242  break;
243  case -2:
244  pref = 0.25 * std::sqrt(105. / (2 * PI));
245  return pref * std::exp(-2. * I * sph[2]) * std::pow(std::sin(sph[1]), 2) * std::cos(sph[1]);
246  break;
247  case -1:
248  pref = 0.125 * std::sqrt(21. / PI);
249  return pref * std::exp(-I * sph[2]) * std::sin(sph[1]) * (5 * std::pow(std::cos(sph[1]), 2) - 1);
250  break;
251  case 0:
252  pref = 0.25 * std::sqrt(7. / PI);
253  return pref * (5 * std::pow(std::cos(sph[1]), 3) - 3. * std::cos(sph[1]));
254  break;
255  case 1:
256  pref = -0.125 * std::sqrt(21. / PI);
257  return pref * std::exp(I * sph[2]) * std::sin(sph[1]) * (5 * std::pow(std::cos(sph[1]), 2) - 1);
258  break;
259  case 2:
260  pref = 0.25 * std::sqrt(105. / (2 * PI));
261  return pref * std::exp(2. * I * sph[2]) * std::pow(std::sin(sph[1]), 2) * std::cos(sph[1]);
262  break;
263  case 3:
264  pref = -0.125 * std::sqrt(35. / PI);
265  return pref * std::exp(3. * I * sph[2]) * std::pow(std::sin(sph[1]), 3);
266  break;
267  }
268  break;
269  default:
270  exit(1);
271  break;
272  }
273 }
274 
275 
276 std::vector<double> cart2sph(const std::vector<double>& cart)
277 {
278  //Physics convention
279  std::vector<double> sph(3);
280  sph[0] = std::sqrt(cart[0] * cart[0] + cart[1] * cart[1] + cart[2] * cart[2]);
281  sph[1] = std::acos(cart[2] / sph[0]);
282  sph[2] = std::atan2(cart[1], cart[0]);
283  return sph;
284 }
285 
286 std::vector<double> sph2cart(const std::vector<double>& sph)
287 {
288  //Physics convention
289  std::vector<double> cart(3);
290  cart[0] = sph[0] * std::sin(sph[1]) * std::cos(sph[2]);
291  cart[1] = sph[0] * std::sin(sph[1]) * std::sin(sph[2]);
292  cart[2] = sph[0] * std::cos(sph[1]);
293  return cart;
294 }
295 
296 //spin representation
297 std::complex<double> chiu(double s) { return std::exp(I * s); }
298 std::complex<double> chid(double s) { return std::exp(-I * s); }
299 
300 //simple plane-wave orbitals for spinor
301 std::complex<double> orbu(const std::vector<double>& sph)
302 {
303  std::vector<double> cart = sph2cart(sph);
304  return std::exp(I * (cart[0] + cart[1] + cart[2]));
305 }
306 std::complex<double> orbd(const std::vector<double>& sph)
307 {
308  std::vector<double> cart = sph2cart(sph);
309  return std::exp(2. * I * (cart[0] + cart[1] + cart[2]));
310 }
311 
312 //single particle spinors
313 std::complex<double> spinor0(const std::vector<double>& sph, double s)
314 {
315  return orbu(sph) * chiu(s) + orbd(sph) * chid(s);
316 }
317 std::complex<double> spinor1(const std::vector<double>& sph, double s)
318 {
319  return orbd(sph) * chiu(s) + orbu(sph) * chid(s);
320 }
321 
322 // <s1 | s_d | s2>, for L.S operator in SOECP
323 std::complex<double> sMatrixElement(double s1, double s2, int d)
324 {
325  switch (d)
326  {
327  case 0:
328  return std::complex<double>(std::cos(s1 + s2), 0.0);
329  break;
330  case 1:
331  return std::complex<double>(std::sin(s1 + s2), 0.0);
332  break;
333  case 2:
334  return std::complex<double>(0.0, std::sin(s1 - s2));
335  break;
336  default:
337  exit(1);
338  break;
339  }
340 }
341 
342 int kroneckerDelta(int x, int y) { return (x == y) ? 1 : 0; }
343 
344 //<l m1 | l_d | l m2>
345 std::complex<double> lMatrixElement(int l, int m1, int m2, int d)
346 {
347  double pref1, pref2, val;
348  switch (d)
349  {
350  case 0:
351  pref1 = std::sqrt(l * (l + 1) - m2 * (m2 + 1));
352  pref2 = std::sqrt(l * (l + 1) - m2 * (m2 - 1));
353  val = 0.5 * (pref1 * kroneckerDelta(m1, m2 + 1) + pref2 * kroneckerDelta(m1, m2 - 1));
354  return std::complex<double>(val, 0.0);
355  break;
356  case 1:
357  pref1 = std::sqrt(l * (l + 1) - m2 * (m2 - 1));
358  pref2 = std::sqrt(l * (l + 1) - m2 * (m2 + 1));
359  val = 0.5 * (pref1 * kroneckerDelta(m1, m2 - 1) - pref2 * kroneckerDelta(m1, m2 + 1));
360  return std::complex<double>(0.0, val);
361  break;
362  case 2:
363  return std::complex<double>(m2 * kroneckerDelta(m1, m2), 0.0);
364  break;
365  default:
366  exit(1);
367  break;
368  }
369 }
370 
371 //simple radial dependence. coded in so_ecp_test.xml
372 //used in so_ecp_test.xml for each spin channel
373 double Wso(int l, double r) { return exp(-l * r * r); }
374 
375 std::complex<double> TWF(std::vector<std::vector<double>>& positions,
376  std::vector<double>& spins,
377  const cubicBSpline& J2)
378 {
379  std::vector<double> cart0 = sph2cart(positions[0]);
380  std::vector<double> cart1 = sph2cart(positions[1]);
381  double dx = (cart1[0] - cart0[0]);
382  double dy = (cart1[1] - cart0[1]);
383  double dz = (cart1[2] - cart0[2]);
384  double r12 = std::sqrt(dx * dx + dy * dy + dz * dz);
385  std::complex<double> det = spinor0(positions[0], spins[0]) * spinor1(positions[1], spins[1]) -
386  spinor1(positions[0], spins[0]) * spinor0(positions[1], spins[1]);
387  return det * exp(-J2.getVal(r12));
388 }
389 
390 std::complex<double> dratioTWF(const int ip,
391  std::vector<std::vector<double>>& positions,
392  std::vector<double>& spins,
393  cubicBSpline& J2)
394 {
395  std::vector<double> cart0 = sph2cart(positions[0]);
396  std::vector<double> cart1 = sph2cart(positions[1]);
397  double dx = (cart1[0] - cart0[0]);
398  double dy = (cart1[1] - cart0[1]);
399  double dz = (cart1[2] - cart0[2]);
400  double r12 = std::sqrt(dx * dx + dy * dy + dz * dz);
401  //Since the det doesn't have any parameters to optimize, the dratioTWF is only -dJ
402  return -J2.parmDeriv(ip, r12);
403 }
404 
405 std::complex<double> calcAngInt(int iel,
406  double s2,
407  std::vector<std::vector<double>>& positions,
408  std::vector<double>& spins,
409  const cubicBSpline& J2)
410 {
411  std::complex<double> angint(0.0, 0.0);
412  for (int i = 0; i < quad.size(); i++)
413  {
414  std::vector<double> sph2 = cart2sph(quad[i]);
415  sph2[0] *= positions[iel][0]; //now scaled to appropriate distance
416 
417  std::vector<std::vector<double>> newpositions = positions;
418  std::vector<double> newspins = spins;
419  newpositions[iel] = sph2;
420  newspins[iel] = s2;
421 
422  std::complex<double> integrand(0.0, 0.0);
423  for (int l = 1; l <= 3; l++)
424  {
425  std::complex<double> msum(0.0, 0.0);
426  for (int m1 = -l; m1 <= l; m1++)
427  {
428  for (int m2 = -l; m2 <= l; m2++)
429  {
430  std::complex<double> ldots(0.0, 0.0);
431  for (int d = 0; d < 3; d++)
432  ldots += lMatrixElement(l, m1, m2, d) * sMatrixElement(spins[iel], newspins[iel], d);
433  msum += Ylm(l, m1, positions[iel]) * std::conj(Ylm(l, m2, newpositions[iel])) * ldots;
434  }
435  }
436  integrand += Wso(l, positions[iel][0]) * msum;
437  }
438 
439  std::complex<double> num = TWF(newpositions, newspins, J2);
440  std::complex<double> denom = TWF(positions, spins, J2);
441  integrand *= num / denom;
442  angint += integrand * wt[i] * 4.0 * PI;
443  }
444  return angint;
445 }
446 
447 std::complex<double> calcVal(int npts,
448  int iel,
449  std::vector<std::vector<double>>& positions,
450  std::vector<double>& spins,
451  const cubicBSpline& J2)
452 {
453  std::complex<double> sint(0.0, 0.0);
454  double smin = 0.0;
455  double smax = 2 * PI;
456  double h = (smax - smin) / npts;
457  for (int k = 1; k <= npts - 1; k += 2)
458  {
459  double s2 = smin + k * h;
460  std::complex<double> angint = calcAngInt(iel, s2, positions, spins, J2);
461  sint += 4 * h / 3. * angint;
462  }
463  for (int k = 2; k <= npts - 2; k += 2)
464  {
465  double s2 = smin + k * h;
466  std::complex<double> angint = calcAngInt(iel, s2, positions, spins, J2);
467  sint += 2 * h / 3. * angint;
468  }
469  sint += h / 3. * calcAngInt(iel, smin, positions, spins, J2);
470  sint += h / 3. * calcAngInt(iel, smax, positions, spins, J2);
471  sint /= (2.0 * PI);
472 
473  return sint;
474 }
475 
476 void calcSOECP(int npts)
477 {
478  //2el system, atom at origin, 2body jastrow only
479  std::vector<double> pos_e1 = {0.138, -0.24, 0.216};
480  std::vector<double> pos_e2 = {-0.216, 0.24, -0.138};
481  std::vector<std::vector<double>> positions = {cart2sph(pos_e1), cart2sph(pos_e2)};
482  double spin_e1 = 0.2;
483  double spin_e2 = 0.51;
484  std::vector<double> spins = {spin_e1, spin_e2};
485 
486  double rcut = 5.0;
487  double cusp = -0.25;
488  std::vector<double> coeffs = {0.02904699284, -0.1004179, -0.1752703883, -0.2232576505, -0.2728029201};
489  cubicBSpline J2(rcut, cusp, coeffs);
490 
491  std::complex<double> val;
492  for (int iel = 0; iel < 2; iel++)
493  val += calcVal(npts, iel, positions, spins, J2);
494  std::cout << npts << " " << std::setprecision(10) << std::real(val) << " " << std::imag(val) << std::endl;
495 }
496 
498 {
499  const int npts = 8; //number of spin integral pts
500  //2el system, atom at origin, 2body jastrow only
501  std::vector<double> pos_e1 = {0.138, -0.24, 0.216};
502  std::vector<double> pos_e2 = {-0.216, 0.24, -0.138};
503  std::vector<std::vector<double>> positions = {cart2sph(pos_e1), cart2sph(pos_e2)};
504  double spin_e1 = 0.2;
505  double spin_e2 = 0.51;
506  std::vector<double> spins = {spin_e1, spin_e2};
507 
508  double rcut = 5.0;
509  double cusp = -0.25;
510  std::vector<double> coeffs = {0.02904699284, -0.1004179, -0.1752703883, -0.2232576505, -0.2728029201};
511  cubicBSpline spl(rcut, cusp, coeffs);
512 
513  //these are the reference values from evaluateDerivatives, which gets dhpsioverpsi for the
514  //kinetic energy component only. Going to print the accumulated value for the SOECP component
515  //and the kinetic energy and print to add to unit test in test_ecp
516  std::vector<double> dhpsioverpsi = {-3.807451601, 0.1047251267, 3.702726474, 0, 0};
517 
518  std::complex<double> soecp_value;
519  //loop over each particle
520  for (int iel = 0; iel < 2; iel++)
521  {
522  //set positions, spins, and weights for all integral points for particle iel
523  std::vector<std::vector<std::vector<double>>> positions_vp;
524  std::vector<std::vector<double>> spins_vp;
525  std::vector<double> spin_quad_wts;
526 
527  auto add_quad_points = [&](const double spinval, const double spin_wt) {
528  for (int i = 0; i < quad.size(); i++)
529  {
530  std::vector<double> sph2 = cart2sph(quad[i]);
531  sph2[0] *= positions[iel][0]; //now scaled to appropriate distance
532  positions_vp.push_back(positions);
533  spins_vp.push_back(spins);
534  positions_vp.back()[iel] = sph2;
535  spins_vp.back()[iel] = spinval;
536  double spin_norm = 1.0 / (2.0 * PI);
537  double spatial_norm = 4.0 * PI;
538  double norm = spin_norm * spatial_norm;
539  spin_quad_wts.push_back(spin_wt * wt[i] * norm);
540  }
541  };
542  double smin = 0.0;
543  double smax = 2 * PI;
544  double h = (smax - smin) / npts;
545  for (int k = 1; k <= npts - 1; k += 2)
546  {
547  double newspin = smin + k * h;
548  double spinwt = 4. * h / 3.;
549  add_quad_points(newspin, spinwt);
550  }
551  for (int k = 2; k <= npts - 2; k += 2)
552  {
553  double newspin = smin + k * h;
554  double spinwt = 2. * h / 3.;
555  add_quad_points(newspin, spinwt);
556  }
557  add_quad_points(smin, h / 3.);
558  add_quad_points(smax, h / 3.);
559  assert(positions_vp.size() == spins_vp.size());
560  assert(spins_vp.size() == spin_quad_wts.size());
561  assert(spin_quad_wts.size() == (npts + 1) * quad.size());
562 
563  std::vector<std::complex<double>> dlogpsi(coeffs.size());
564  for (int ip = 0; ip < dlogpsi.size(); ip++)
565  dlogpsi[ip] = dratioTWF(ip, positions, spins, spl);
566  if (iel == 0) //only print for first electron
567  {
568  std::cout << "std::vector<RealType> dlogpsi_refs = { ";
569  for (int ip = 0; ip < dlogpsi.size(); ip++)
570  {
571  double real = std::real(dlogpsi[ip]);
572  (ip != dlogpsi.size() - 1) ? std::cout << std::setprecision(10) << real << ", "
573  : std::cout << std::setprecision(10) << real << "};" << std::endl;
574  }
575  }
576 
577  std::vector<std::vector<std::complex<double>>> dratio;
578  for (int iq = 0; iq < spin_quad_wts.size(); iq++)
579  {
580  std::vector<std::complex<double>> dratio_row(coeffs.size());
581  for (int ip = 0; ip < dratio_row.size(); ip++)
582  dratio_row[ip] = dratioTWF(ip, positions_vp[iq], spins_vp[iq], spl) - dlogpsi[ip];
583  dratio.push_back(dratio_row);
584  }
585 
586  //Now we can evaluate the contribution to the potential from each quadrature/spin point
587  auto SOECP_spin_quad = [&](std::vector<std::vector<double>>& newpos, std::vector<std::vector<double>>& oldpos,
588  std::vector<double>& newspin, std::vector<double>& oldspin, const cubicBSpline& J2) {
589  std::complex<double> integrand;
590  for (int l = 1; l <= 3; l++)
591  {
592  std::complex<double> msum;
593  for (int m1 = -l; m1 <= l; m1++)
594  {
595  for (int m2 = -l; m2 <= l; m2++)
596  {
597  std::complex<double> ldots;
598  for (int id = 0; id < 3; id++)
599  ldots += lMatrixElement(l, m1, m2, id) * sMatrixElement(oldspin[iel], newspin[iel], id);
600  msum += Ylm(l, m1, oldpos[iel]) * std::conj(Ylm(l, m2, newpos[iel])) * ldots;
601  }
602  }
603  integrand += Wso(l, oldpos[iel][0]) * msum;
604  }
605  std::complex<double> psinew = TWF(newpos, newspin, J2);
606  std::complex<double> psiold = TWF(oldpos, oldspin, J2);
607  integrand *= psinew / psiold;
608  return integrand;
609  };
610 
611  std::vector<std::complex<double>> wvec(spin_quad_wts.size());
612  for (int iq = 0; iq < spin_quad_wts.size(); iq++)
613  {
614  wvec[iq] = spin_quad_wts[iq] * SOECP_spin_quad(positions_vp[iq], positions, spins_vp[iq], spins, spl);
615  soecp_value += wvec[iq];
616  }
617 
618  //Now do final evaluation of dhpsioverpsi, using a gemv
619  for (int ip = 0; ip < dhpsioverpsi.size(); ip++)
620  {
621  std::complex<double> sum;
622  for (int iq = 0; iq < wvec.size(); iq++)
623  sum += wvec[iq] * dratio[iq][ip];
624  dhpsioverpsi[ip] += std::real(sum);
625  }
626  } // loop over each particle
627  std::cout << std::setprecision(10) << "SOECP Value: " << soecp_value << std::endl;
628  std::cout << "std::vector<RealType> dhpsioverpsi_refs = { ";
629  for (int ip = 0; ip < dhpsioverpsi.size(); ip++)
630  (ip != dhpsioverpsi.size() - 1) ? std::cout << std::setprecision(10) << dhpsioverpsi[ip] << ", "
631  : std::cout << std::setprecision(10) << dhpsioverpsi[ip] << "};" << std::endl;
632 }
633 
634 int main()
635 {
636  //used to validate bspline jastrow implementation
637  //testJastrow();
638  //for (int n = 2; n <= 100; n += 2)
639  // calcSOECP(n);
640  //looks converged by n=8 if you uncomment above,, used in evaluateValueAndDerivative
642 }
double bspline(double x, const std::vector< double > &t, const std::vector< double > &c, int k)
std::complex< double > spinor0(const std::vector< double > &sph, double s)
QMCTraits::RealType real
std::complex< double > dratioTWF(const int ip, std::vector< std::vector< double >> &positions, std::vector< double > &spins, cubicBSpline &J2)
std::vector< double > knots_
Tensor< T, D >::Type_t det(const Tensor< T, D > &a)
Definition: TensorOps.h:838
std::complex< double > calcVal(int npts, int iel, std::vector< std::vector< double >> &positions, std::vector< double > &spins, const cubicBSpline &J2)
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
MakeReturn< UnaryNode< FnSin, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sin(const Vector< T1, C1 > &l)
void calcSOECP(int npts)
std::complex< double > orbd(const std::vector< double > &sph)
std::complex< double > orbu(const std::vector< double > &sph)
int kroneckerDelta(int x, int y)
void setCoeff(int i, double newcoeff)
std::vector< double > wt
void copy(const Array< T1, 3 > &src, Array< T2, 3 > &dest)
Definition: Blitz.h:639
MakeReturn< BinaryNode< FnPow, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t, typename CreateLeaf< Vector< T2, C2 > >::Leaf_t > >::Expression_t pow(const Vector< T1, C1 > &l, const Vector< T2, C2 > &r)
void testJastrow()
float imag(const float &c)
imaginary part of a scalar. Cannot be replaced by std::imag due to AFQMC specific needs...
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
double parmDeriv(const int ip, double x)
double norm(const zVec &c)
Definition: VectorOps.h:118
MakeReturn< UnaryNode< FnArcCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t acos(const Vector< T1, C1 > &l)
double PI
MakeReturn< BinaryNode< FnArcTan2, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t, typename CreateLeaf< Vector< T2, C2 > >::Leaf_t > >::Expression_t atan2(const Vector< T1, C1 > &l, const Vector< T2, C2 > &r)
int main()
std::vector< double > coeffs_
MakeReturn< UnaryNode< FnArcTan, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t atan(const Vector< T1, C1 > &l)
std::vector< double > cart2sph(const std::vector< double > &cart)
std::complex< double > spinor1(const std::vector< double > &sph, double s)
void evaluateValueAndDerivative()
MakeReturn< UnaryNode< FnExp, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t exp(const Vector< T1, C1 > &l)
std::vector< std::vector< double > > quad
std::complex< double > Ylm(int l, int m, const std::vector< double > &sph)
std::vector< double > sph2cart(const std::vector< double > &sph)
std::complex< double > I
float conj(const float &c)
Workaround to allow conj on scalar to return real instead of complex.
cubicBSpline(double rcut, double cusp_val, const std::vector< double > &coeffs)
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
double getVal(double x) const
std::complex< double > calcAngInt(int iel, double s2, std::vector< std::vector< double >> &positions, std::vector< double > &spins, const cubicBSpline &J2)
std::complex< double > sMatrixElement(double s1, double s2, int d)
std::complex< double > TWF(std::vector< std::vector< double >> &positions, std::vector< double > &spins, const cubicBSpline &J2)
double B(double x, int k, int i, const std::vector< double > &t)
std::complex< double > chiu(double s)
double Wso(int l, double r)
std::complex< double > chid(double s)
std::complex< double > lMatrixElement(int l, int m1, int m2, int d)
double getCoeff(int i) const