QMCPACK
SphericalTensor.h
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) 2016 Jeongnim Kim and QMCPACK developers.
6 //
7 // File developed by: Jordan E. Vincent, University of Illinois at Urbana-Champaign
8 // Miguel Morales, moralessilva2@llnl.gov, Lawrence Livermore National Laboratory
9 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
10 // Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
11 // Mark A. Berrill, berrillma@ornl.gov, Oak Ridge National Laboratory
12 //
13 // File created by: Jordan E. Vincent, University of Illinois at Urbana-Champaign
14 //////////////////////////////////////////////////////////////////////////////////////
15 
16 
17 #ifndef QMCPLUSPLUS_SPHERICAL_CARTESIAN_TENSOR_H
18 #define QMCPLUSPLUS_SPHERICAL_CARTESIAN_TENSOR_H
19 
20 #include "OhmmsPETE/Tensor.h"
21 
22 /** SphericalTensor that evaluates the Real Spherical Harmonics
23  *
24  * The template parameters
25  * - T, the value_type, e.g. double
26  * - Point_t, a vector type to provide xyz coordinate.
27  * Point_t must have the operator[] defined, e.g., TinyVector<double,3>.
28  *
29  * Real Spherical Harmonics Ylm\f$=r^l S_l^m(x,y,z) \f$ is stored
30  * in an array ordered as [0,-1 0 1,-2 -1 0 1 2, -Lmax,-Lmax+1,..., Lmax-1,Lmax]
31  * where Lmax is the maximum angular momentum of a center.
32  * All the data members, e.g, Ylm and pre-calculated factors,
33  * can be accessed by index(l,m) which returns the
34  * locator of the combination for l and m.
35  */
36 template<class T,
37  class Point_t,
38  class Tensor_t = qmcplusplus::Tensor<T, 3>,
41 {
42 public:
43  using value_type = T;
44  using pos_type = Point_t;
45  using hess_type = Tensor_t;
46  using ggg_type = GGG_t;
48 
49  /** constructor
50  * @param l_max maximum angular momentum
51  * @param addsign flag to determine what convention to use
52  *
53  * Evaluate all the constants and prefactors.
54  * The spherical harmonics is defined as
55  * \f[ Y_l^m (\theta,\phi) = \sqrt{\frac{(2l+1)(l-m)!}{4\pi(l+m)!}} P_l^m(\cos\theta)e^{im\phi}\f]
56  * Note that the data member Ylm is a misnomer and should not be confused with "spherical harmonics"
57  * \f$Y_l^m\f$.
58  - When addsign == true, e.g., Gaussian packages
59  \f{eqnarray*}
60  S_l^m &=& (-1)^m \sqrt{2}\Re(Y_l^{|m|}), \;\;\;m > 0 \\
61  &=& Y_l^0, \;\;\;m = 0 \\
62  &=& (-1)^m \sqrt{2}\Im(Y_l^{|m|}),\;\;\;m < 0
63  \f}
64  - When addsign == false, e.g., SIESTA package,
65  \f{eqnarray*}
66  S_l^m &=& \sqrt{2}\Re(Y_l^{|m|}), \;\;\;m > 0 \\
67  &=& Y_l^0, \;\;\;m = 0 \\
68  &=&\sqrt{2}\Im(Y_l^{|m|}),\;\;\;m < 0
69  \f}
70  */
71  explicit SphericalTensor(const int l_max, bool addsign = false);
72 
73  ///makes a table of \f$ r^l S_l^m \f$ and their gradients up to Lmax.
74  void evaluate(const Point_t& p);
75 
76  ///makes a table of \f$ r^l S_l^m \f$ and their gradients up to Lmax.
77  void evaluateAll(const Point_t& p);
78 
79  ///makes a table of \f$ r^l S_l^m \f$ and their gradients up to Lmax.
80  void evaluateTest(const Point_t& p);
81 
82  ///makes a table of \f$ r^l S_l^m \f$ and their gradients and hessians up to Lmax.
83  void evaluateWithHessian(const Point_t& p);
84 
85  ///makes a table of \f$ r^l S_l^m \f$ and their gradients and hessians and third derivatives up to Lmax.
86  void evaluateThirdDerivOnly(const Point_t& p);
87 
88  ///returns the index/locator for (\f$l,m\f$) combo, \f$ l(l+1)+m \f$
89  inline int index(int l, int m) const { return (l * (l + 1)) + m; }
90 
91  ///returns the value of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
92  inline value_type getYlm(int l, int m) const { return Ylm[index(l, m)]; }
93 
94  ///returns the gradient of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
95  inline Point_t getGradYlm(int l, int m) const { return gradYlm[index(l, m)]; }
96 
97  ///returns the hessian of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
98  inline Tensor_t getHessYlm(int l, int m) const { return hessYlm[index(l, m)]; }
99 
100  ///returns the matrix of third derivatives of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
101  inline GGG_t getGGGYlm(int lm) const { return gggYlm[lm]; }
102 
103  ///returns the value of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
104  inline value_type getYlm(int lm) const { return Ylm[lm]; }
105 
106  ///returns the gradient of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
107  inline Point_t getGradYlm(int lm) const { return gradYlm[lm]; }
108 
109  ///returns the hessian of \f$ r^l S_l^m \f$ given \f$ (l,m) \f$
110  inline Tensor_t getHessYlm(int lm) const { return hessYlm[lm]; }
111 
112  inline int size() const { return Ylm.size(); }
113 
114  inline int lmax() const { return Lmax; }
115 
116  ///maximum angular momentum for the center
117  int Lmax;
118 
119  ///values Ylm\f$=r^l S_l^m(x,y,z)\f$
120  std::vector<value_type> Ylm;
121  /// Normalization factors
122  std::vector<value_type> NormFactor;
123  ///pre-evaluated factor \f$1/\sqrt{(l+m)\times(l+1-m)}\f$
124  std::vector<value_type> FactorLM;
125  ///pre-evaluated factor \f$\sqrt{(2l+1)/(4\pi)}\f$
126  std::vector<value_type> FactorL;
127  ///pre-evaluated factor \f$(2l+1)/(2l-1)\f$
128  std::vector<value_type> Factor2L;
129  ///gradients gradYlm\f$=\nabla r^l S_l^m(x,y,z)\f$
130  std::vector<Point_t> gradYlm;
131  ///hessian hessYlm\f$=(\nabla X \nabla) r^l S_l^m(x,y,z)\f$
132  std::vector<hess_type> hessYlm;
133  /// mmorales: HACK HACK HACK, to avoid having to rewrite
134  /// QMCWaveFunctions/SphericalBasisSet.h
135  std::vector<value_type> laplYlm; //(always zero)
136 
137  std::vector<ggg_type> gggYlm;
138 };
139 
140 template<class T, class Point_t, class Tensor_t, class GGG_t>
141 SphericalTensor<T, Point_t, Tensor_t, GGG_t>::SphericalTensor(const int l_max, bool addsign) : Lmax(l_max)
142 {
143  int ntot = (Lmax + 1) * (Lmax + 1);
144  const value_type pi = 4.0 * atan(1.0);
145  Ylm.resize(ntot);
146  gradYlm.resize(ntot);
147  gradYlm[0] = 0.0;
148  laplYlm.resize(ntot);
149  for (int i = 0; i < ntot; i++)
150  laplYlm[i] = 0.0;
151  hessYlm.resize(ntot);
152  gggYlm.resize(ntot);
153  hessYlm[0] = 0.0;
154  if (ntot >= 4)
155  {
156  hessYlm[1] = 0.0;
157  hessYlm[2] = 0.0;
158  hessYlm[3] = 0.0;
159  }
160  if (ntot >= 9)
161  {
162  // m=-2
163  hessYlm[4] = 0.0;
164  hessYlm[4](1, 0) = std::sqrt(15.0 / 4.0 / pi);
165  hessYlm[4](0, 1) = hessYlm[4](1, 0);
166  // m=-1
167  hessYlm[5] = 0.0;
168  hessYlm[5](1, 2) = std::sqrt(15.0 / 4.0 / pi);
169  hessYlm[5](2, 1) = hessYlm[5](1, 2);
170  // m=0
171  hessYlm[6] = 0.0;
172  hessYlm[6](0, 0) = -std::sqrt(5.0 / 4.0 / pi);
173  hessYlm[6](1, 1) = hessYlm[6](0, 0);
174  hessYlm[6](2, 2) = -2.0 * hessYlm[6](0, 0);
175  // m=1
176  hessYlm[7] = 0.0;
177  hessYlm[7](0, 2) = std::sqrt(15.0 / 4.0 / pi);
178  hessYlm[7](2, 0) = hessYlm[7](0, 2);
179  // m=2
180  hessYlm[8] = 0.0;
181  hessYlm[8](0, 0) = std::sqrt(15.0 / 4.0 / pi);
182  hessYlm[8](1, 1) = -hessYlm[8](0, 0);
183  }
184  for (int i = 0; i < ntot; i++)
185  {
186  gggYlm[i][0] = 0.0;
187  gggYlm[i][1] = 0.0;
188  gggYlm[i][2] = 0.0;
189  }
190  NormFactor.resize(ntot, 1);
191  const value_type sqrt2 = sqrt(2.0);
192  if (addsign)
193  {
194  for (int l = 0; l <= Lmax; l++)
195  {
196  NormFactor[index(l, 0)] = 1.0;
197  for (int m = 1; m <= l; m++)
198  {
199  NormFactor[index(l, m)] = std::pow(-1.0e0, m) * sqrt2;
200  NormFactor[index(l, -m)] = std::pow(-1.0e0, -m) * sqrt2;
201  }
202  }
203  }
204  else
205  {
206  for (int l = 0; l <= Lmax; l++)
207  {
208  for (int m = 1; m <= l; m++)
209  {
210  NormFactor[index(l, m)] = sqrt2;
211  NormFactor[index(l, -m)] = sqrt2;
212  }
213  }
214  }
215  FactorL.resize(Lmax + 1);
216  const value_type omega = 1.0 / sqrt(16.0 * atan(1.0));
217  for (int l = 1; l <= Lmax; l++)
218  FactorL[l] = sqrt(static_cast<T>(2 * l + 1)) * omega;
219  Factor2L.resize(Lmax + 1);
220  for (int l = 1; l <= Lmax; l++)
221  Factor2L[l] = static_cast<T>(2 * l + 1) / static_cast<T>(2 * l - 1);
222  FactorLM.resize(ntot);
223  for (int l = 1; l <= Lmax; l++)
224  for (int m = 1; m <= l; m++)
225  {
226  T fac2 = 1.0 / sqrt(static_cast<T>((l + m) * (l + 1 - m)));
227  FactorLM[index(l, m)] = fac2;
228  FactorLM[index(l, -m)] = fac2;
229  }
230 }
231 
232 template<class T, class Point_t, class Tensor_t, class GGG_t>
234 {
235  value_type x = p[0], y = p[1], z = p[2];
236  const value_type pi = 4.0 * atan(1.0);
237  const value_type pi4 = 4.0 * pi;
238  const value_type omega = 1.0 / sqrt(pi4);
239  const value_type sqrt2 = sqrt(2.0);
240  /* Calculate r, cos(theta), sin(theta), cos(phi), sin(phi) from input
241  coordinates. Check here the coordinate singularity at cos(theta) = +-1.
242  This also takes care of r=0 case. */
243  value_type cphi, sphi, ctheta;
244  value_type r2xy = x * x + y * y;
245  value_type r = sqrt(r2xy + z * z);
246  if (r2xy < std::numeric_limits<T>::epsilon())
247  {
248  cphi = 0.0;
249  sphi = 1.0;
250  ctheta = (z < 0) ? -1.0 : 1.0;
251  }
252  else
253  {
254  ctheta = z / r;
255  value_type rxyi = 1.0 / sqrt(r2xy);
256  cphi = x * rxyi;
257  sphi = y * rxyi;
258  }
259  value_type stheta = sqrt(1.0 - ctheta * ctheta);
260  /* Now to calculate the associated legendre functions P_lm from the
261  recursion relation from l=0 to Lmax. Conventions of J.D. Jackson,
262  Classical Electrodynamics are used. */
263  Ylm[0] = 1.0;
264  // calculate P_ll and P_l,l-1
265  value_type fac = 1.0;
266  int j = -1;
267  for (int l = 1; l <= Lmax; l++)
268  {
269  j += 2;
270  fac *= -j * stheta;
271  int ll = index(l, l);
272  int l1 = index(l, l - 1);
273  int l2 = index(l - 1, l - 1);
274  Ylm[ll] = fac;
275  Ylm[l1] = j * ctheta * Ylm[l2];
276  }
277  // Use recurence to get other plm's //
278  for (int m = 0; m < Lmax - 1; m++)
279  {
280  int j = 2 * m + 1;
281  for (int l = m + 2; l <= Lmax; l++)
282  {
283  j += 2;
284  int lm = index(l, m);
285  int l1 = index(l - 1, m);
286  int l2 = index(l - 2, m);
287  Ylm[lm] = (ctheta * j * Ylm[l1] - (l + m - 1) * Ylm[l2]) / (l - m);
288  }
289  }
290  // Now to calculate r^l Y_lm. //
291  value_type sphim, cphim, temp;
292  Ylm[0] = omega; //1.0/sqrt(pi4);
293  value_type rpow = 1.0;
294  for (int l = 1; l <= Lmax; l++)
295  {
296  rpow *= r;
297  //fac = rpow*sqrt(static_cast<T>(2*l+1))*omega;//rpow*sqrt((2*l+1)/pi4);
298  //FactorL[l] = sqrt(2*l+1)/sqrt(4*pi)
299  fac = rpow * FactorL[l];
300  int l0 = index(l, 0);
301  Ylm[l0] *= fac;
302  cphim = 1.0;
303  sphim = 0.0;
304  for (int m = 1; m <= l; m++)
305  {
306  temp = cphim * cphi - sphim * sphi;
307  sphim = sphim * cphi + cphim * sphi;
308  cphim = temp;
309  int lm = index(l, m);
310  fac *= FactorLM[lm];
311  temp = fac * Ylm[lm];
312  Ylm[lm] = temp * cphim;
313  lm = index(l, -m);
314  Ylm[lm] = temp * sphim;
315  }
316  }
317  for (int i = 0; i < Ylm.size(); i++)
318  Ylm[i] *= NormFactor[i];
319 }
320 
321 template<class T, class Point_t, class Tensor_t, class GGG_t>
323 {
324  value_type x = p[0], y = p[1], z = p[2];
325  const value_type pi = 4.0 * atan(1.0);
326  const value_type pi4 = 4.0 * pi;
327  const value_type omega = 1.0 / sqrt(pi4);
328  const value_type sqrt2 = sqrt(2.0);
329  /* Calculate r, cos(theta), sin(theta), cos(phi), sin(phi) from input
330  coordinates. Check here the coordinate singularity at cos(theta) = +-1.
331  This also takes care of r=0 case. */
332  value_type cphi, sphi, ctheta;
333  value_type r2xy = x * x + y * y;
334  value_type r = sqrt(r2xy + z * z);
335  if (r2xy < std::numeric_limits<T>::epsilon())
336  {
337  cphi = 0.0;
338  sphi = 1.0;
339  ctheta = (z < 0) ? -1.0 : 1.0;
340  }
341  else
342  {
343  ctheta = z / r;
344  value_type rxyi = 1.0 / sqrt(r2xy);
345  cphi = x * rxyi;
346  sphi = y * rxyi;
347  }
348  value_type stheta = sqrt(1.0 - ctheta * ctheta);
349  /* Now to calculate the associated legendre functions P_lm from the
350  recursion relation from l=0 to Lmax. Conventions of J.D. Jackson,
351  Classical Electrodynamics are used. */
352  Ylm[0] = 1.0;
353  // calculate P_ll and P_l,l-1
354  value_type fac = 1.0;
355  int j = -1;
356  for (int l = 1; l <= Lmax; l++)
357  {
358  j += 2;
359  fac *= -j * stheta;
360  int ll = index(l, l);
361  int l1 = index(l, l - 1);
362  int l2 = index(l - 1, l - 1);
363  Ylm[ll] = fac;
364  Ylm[l1] = j * ctheta * Ylm[l2];
365  }
366  // Use recurence to get other plm's //
367  for (int m = 0; m < Lmax - 1; m++)
368  {
369  int j = 2 * m + 1;
370  for (int l = m + 2; l <= Lmax; l++)
371  {
372  j += 2;
373  int lm = index(l, m);
374  int l1 = index(l - 1, m);
375  int l2 = index(l - 2, m);
376  Ylm[lm] = (ctheta * j * Ylm[l1] - (l + m - 1) * Ylm[l2]) / (l - m);
377  }
378  }
379  // Now to calculate r^l Y_lm. //
380  value_type sphim, cphim, temp;
381  Ylm[0] = omega; //1.0/sqrt(pi4);
382  value_type rpow = 1.0;
383  for (int l = 1; l <= Lmax; l++)
384  {
385  rpow *= r;
386  //fac = rpow*sqrt(static_cast<T>(2*l+1))*omega;//rpow*sqrt((2*l+1)/pi4);
387  //FactorL[l] = sqrt(2*l+1)/sqrt(4*pi)
388  fac = rpow * FactorL[l];
389  int l0 = index(l, 0);
390  Ylm[l0] *= fac;
391  cphim = 1.0;
392  sphim = 0.0;
393  for (int m = 1; m <= l; m++)
394  {
395  //fac2 = (l+m)*(l+1-m);
396  //fac = fac/sqrt(fac2);
397  temp = cphim * cphi - sphim * sphi;
398  sphim = sphim * cphi + cphim * sphi;
399  cphim = temp;
400  int lm = index(l, m);
401  //fac2,fac use precalculated FactorLM
402  fac *= FactorLM[lm];
403  temp = fac * Ylm[lm];
404  Ylm[lm] = temp * cphim;
405  lm = index(l, -m);
406  Ylm[lm] = temp * sphim;
407  }
408  }
409  // Calculating Gradient now//
410  for (int l = 1; l <= Lmax; l++)
411  {
412  //value_type fac = ((value_type) (2*l+1))/(2*l-1);
413  value_type fac = Factor2L[l];
414  for (int m = -l; m <= l; m++)
415  {
416  int lm = index(l - 1, 0);
417  value_type gx, gy, gz, dpr, dpi, dmr, dmi;
418  int ma = std::abs(m);
419  value_type cp = sqrt(fac * (l - ma - 1) * (l - ma));
420  value_type cm = sqrt(fac * (l + ma - 1) * (l + ma));
421  value_type c0 = sqrt(fac * (l - ma) * (l + ma));
422  gz = (l > ma) ? c0 * Ylm[lm + m] : 0.0;
423  if (l > ma + 1)
424  {
425  dpr = cp * Ylm[lm + ma + 1];
426  dpi = cp * Ylm[lm - ma - 1];
427  }
428  else
429  {
430  dpr = 0.0;
431  dpi = 0.0;
432  }
433  if (l > 1)
434  {
435  switch (ma)
436  {
437  case 0:
438  dmr = -cm * Ylm[lm + 1];
439  dmi = cm * Ylm[lm - 1];
440  break;
441  case 1:
442  dmr = cm * Ylm[lm];
443  dmi = 0.0;
444  break;
445  default:
446  dmr = cm * Ylm[lm + ma - 1];
447  dmi = cm * Ylm[lm - ma + 1];
448  }
449  }
450  else
451  {
452  dmr = cm * Ylm[lm];
453  dmi = 0.0;
454  //dmr = (l==1) ? cm*Ylm[lm]:0.0;
455  //dmi = 0.0;
456  }
457  if (m < 0)
458  {
459  gx = 0.5 * (dpi - dmi);
460  gy = -0.5 * (dpr + dmr);
461  }
462  else
463  {
464  gx = 0.5 * (dpr - dmr);
465  gy = 0.5 * (dpi + dmi);
466  }
467  lm = index(l, m);
468  if (ma)
469  gradYlm[lm] = NormFactor[lm] * Point_t(gx, gy, gz);
470  else
471  gradYlm[lm] = Point_t(gx, gy, gz);
472  }
473  }
474  for (int i = 0; i < Ylm.size(); i++)
475  Ylm[i] *= NormFactor[i];
476  //for (int i=0; i<Ylm.size(); i++) gradYlm[i]*= NormFactor[i];
477 }
478 
479 
480 template<class T, class Point_t, class Tensor_t, class GGG_t>
482 {
483  value_type x = p[0], y = p[1], z = p[2];
484  const value_type pi = 4.0 * atan(1.0);
485  const value_type pi4 = 4.0 * pi;
486  const value_type omega = 1.0 / sqrt(pi4);
487  const value_type sqrt2 = sqrt(2.0);
488  /* Calculate r, cos(theta), sin(theta), cos(phi), sin(phi) from input
489  coordinates. Check here the coordinate singularity at cos(theta) = +-1.
490  This also takes care of r=0 case. */
491  value_type cphi, sphi, ctheta;
492  value_type r2xy = x * x + y * y;
493  value_type r = sqrt(r2xy + z * z);
494  if (r2xy < std::numeric_limits<T>::epsilon())
495  {
496  cphi = 0.0;
497  sphi = 1.0;
498  ctheta = (z < 0) ? -1.0 : 1.0;
499  }
500  else
501  {
502  ctheta = z / r;
503  value_type rxyi = 1.0 / sqrt(r2xy);
504  cphi = x * rxyi;
505  sphi = y * rxyi;
506  }
507  value_type stheta = sqrt(1.0 - ctheta * ctheta);
508  /* Now to calculate the associated legendre functions P_lm from the
509  recursion relation from l=0 to Lmax. Conventions of J.D. Jackson,
510  Classical Electrodynamics are used. */
511  Ylm[0] = 1.0;
512  // calculate P_ll and P_l,l-1
513  value_type fac = 1.0;
514  int j = -1;
515  for (int l = 1; l <= Lmax; l++)
516  {
517  j += 2;
518  fac *= -j * stheta;
519  int ll = index(l, l);
520  int l1 = index(l, l - 1);
521  int l2 = index(l - 1, l - 1);
522  Ylm[ll] = fac;
523  Ylm[l1] = j * ctheta * Ylm[l2];
524  }
525  // Use recurence to get other plm's //
526  for (int m = 0; m < Lmax - 1; m++)
527  {
528  int j = 2 * m + 1;
529  for (int l = m + 2; l <= Lmax; l++)
530  {
531  j += 2;
532  int lm = index(l, m);
533  int l1 = index(l - 1, m);
534  int l2 = index(l - 2, m);
535  Ylm[lm] = (ctheta * j * Ylm[l1] - (l + m - 1) * Ylm[l2]) / (l - m);
536  }
537  }
538  // Now to calculate r^l Y_lm. //
539  value_type sphim, cphim, temp;
540  Ylm[0] = omega; //1.0/sqrt(pi4);
541  value_type rpow = 1.0;
542  for (int l = 1; l <= Lmax; l++)
543  {
544  rpow *= r;
545  //fac = rpow*sqrt(static_cast<T>(2*l+1))*omega;//rpow*sqrt((2*l+1)/pi4);
546  //FactorL[l] = sqrt(2*l+1)/sqrt(4*pi)
547  fac = rpow * FactorL[l];
548  int l0 = index(l, 0);
549  Ylm[l0] *= fac;
550  cphim = 1.0;
551  sphim = 0.0;
552  for (int m = 1; m <= l; m++)
553  {
554  //fac2 = (l+m)*(l+1-m);
555  //fac = fac/sqrt(fac2);
556  temp = cphim * cphi - sphim * sphi;
557  sphim = sphim * cphi + cphim * sphi;
558  cphim = temp;
559  int lm = index(l, m);
560  //fac2,fac use precalculated FactorLM
561  fac *= FactorLM[lm];
562  temp = fac * Ylm[lm];
563  Ylm[lm] = temp * cphim;
564  lm = index(l, -m);
565  Ylm[lm] = temp * sphim;
566  }
567  }
568  // Calculating Gradient now//
569  for (int l = 1; l <= Lmax; l++)
570  {
571  //value_type fac = ((value_type) (2*l+1))/(2*l-1);
572  value_type fac = Factor2L[l];
573  for (int m = -l; m <= l; m++)
574  {
575  int lm = index(l - 1, 0);
576  value_type gx, gy, gz, dpr, dpi, dmr, dmi;
577  int ma = std::abs(m);
578  value_type cp = sqrt(fac * (l - ma - 1) * (l - ma));
579  value_type cm = sqrt(fac * (l + ma - 1) * (l + ma));
580  value_type c0 = sqrt(fac * (l - ma) * (l + ma));
581  gz = (l > ma) ? c0 * Ylm[lm + m] : 0.0;
582  if (l > ma + 1)
583  {
584  dpr = cp * Ylm[lm + ma + 1];
585  dpi = cp * Ylm[lm - ma - 1];
586  }
587  else
588  {
589  dpr = 0.0;
590  dpi = 0.0;
591  }
592  if (l > 1)
593  {
594  switch (ma)
595  {
596  case 0:
597  dmr = -cm * Ylm[lm + 1];
598  dmi = cm * Ylm[lm - 1];
599  break;
600  case 1:
601  dmr = cm * Ylm[lm];
602  dmi = 0.0;
603  break;
604  default:
605  dmr = cm * Ylm[lm + ma - 1];
606  dmi = cm * Ylm[lm - ma + 1];
607  }
608  }
609  else
610  {
611  dmr = cm * Ylm[lm];
612  dmi = 0.0;
613  //dmr = (l==1) ? cm*Ylm[lm]:0.0;
614  //dmi = 0.0;
615  }
616  if (m < 0)
617  {
618  gx = 0.5 * (dpi - dmi);
619  gy = -0.5 * (dpr + dmr);
620  }
621  else
622  {
623  gx = 0.5 * (dpr - dmr);
624  gy = 0.5 * (dpi + dmi);
625  }
626  lm = index(l, m);
627  if (ma)
628  gradYlm[lm] = NormFactor[lm] * Point_t(gx, gy, gz);
629  else
630  gradYlm[lm] = Point_t(gx, gy, gz);
631  }
632  }
633  for (int i = 0; i < Ylm.size(); i++)
634  Ylm[i] *= NormFactor[i];
635  //for (int i=0; i<Ylm.size(); i++) gradYlm[i]*= NormFactor[i];
636 }
637 
638 // Not implemented yet, but third derivatives are zero for l<=2
639 // so ok for lmax<=2
640 template<class T, class Point_t, class Tensor_t, class GGG_t>
642 {}
643 
644 //These template functions are slower than the recursive one above
645 template<class SCT, unsigned L>
647 {
648  using value_type = typename SCT::value_type;
649  using pos_type = typename SCT::pos_type;
650  static inline void apply(std::vector<value_type>& Ylm, std::vector<pos_type>& gYlm, const pos_type& p)
651  {
653  }
654 };
655 
656 template<class SCT>
657 struct SCTFunctor<SCT, 1>
658 {
659  using value_type = typename SCT::value_type;
660  using pos_type = typename SCT::pos_type;
661  static inline void apply(std::vector<value_type>& Ylm, std::vector<pos_type>& gYlm, const pos_type& p)
662  {
663  const value_type L1 = sqrt(3.0);
664  Ylm[1] = L1 * p[1];
665  Ylm[2] = L1 * p[2];
666  Ylm[3] = L1 * p[0];
667  gYlm[1] = pos_type(0.0, L1, 0.0);
668  gYlm[2] = pos_type(0.0, 0.0, L1);
669  gYlm[3] = pos_type(L1, 0.0, 0.0);
670  }
671 };
672 
673 template<class SCT>
674 struct SCTFunctor<SCT, 2>
675 {
676  using value_type = typename SCT::value_type;
677  using pos_type = typename SCT::pos_type;
678  static inline void apply(std::vector<value_type>& Ylm, std::vector<pos_type>& gYlm, const pos_type& p)
679  {
680  SCTFunctor<SCT, 1>::apply(Ylm, gYlm, p);
681  value_type x = p[0], y = p[1], z = p[2];
682  value_type x2 = x * x, y2 = y * y, z2 = z * z;
683  value_type xy = x * y, xz = x * z, yz = y * z;
684  const value_type L0 = sqrt(1.25);
685  const value_type L1 = sqrt(15.0);
686  const value_type L2 = sqrt(3.75);
687  Ylm[4] = L1 * xy;
688  Ylm[5] = L1 * yz;
689  Ylm[6] = L0 * (2.0 * z2 - x2 - y2);
690  Ylm[7] = L1 * xz;
691  Ylm[8] = L2 * (x2 - y2);
692  gYlm[4] = pos_type(L1 * y, L1 * x, 0.0);
693  gYlm[5] = pos_type(0.0, L1 * z, L1 * y);
694  gYlm[6] = pos_type(-2.0 * L0 * x, -2.0 * L0 * y, 4.0 * L0 * z);
695  gYlm[7] = pos_type(L1 * z, 0.0, L1 * x);
696  gYlm[8] = pos_type(2.0 * L2 * x, -2.0 * L2 * y, 0.0);
697  }
698 };
699 
700 template<class SCT>
701 struct SCTFunctor<SCT, 3>
702 {
703  using value_type = typename SCT::value_type;
704  using pos_type = typename SCT::pos_type;
705  static inline void apply(std::vector<value_type>& Ylm, std::vector<pos_type>& gYlm, const pos_type& p)
706  {
707  SCTFunctor<SCT, 2>::apply(Ylm, gYlm, p);
708  }
709 };
710 
711 
712 template<class T, class Point_t, class Tensor_t, class GGG_t>
714 {
715  const value_type pi = 4.0 * atan(1.0);
716  const value_type norm = 1.0 / sqrt(4.0 * pi);
717  Ylm[0] = 1.0;
718  gradYlm[0] = 0.0;
719  switch (Lmax)
720  {
721  case (0):
722  break;
723  case (1):
724  SCTFunctor<This_t, 1>::apply(Ylm, gradYlm, p);
725  break;
726  case (2):
727  SCTFunctor<This_t, 2>::apply(Ylm, gradYlm, p);
728  break;
729  //case(3): SCTFunctor<This_t,3>::apply(Ylm,gradYlm,p); break;
730  //case(4): SCTFunctor<This_t,4>::apply(Ylm,gradYlm,p); break;
731  //case(5): SCTFunctor<This_t,5>::apply(Ylm,gradYlm,p); break;
732  defaults:
733  std::cerr << "Lmax>2 is not valid." << std::endl;
734  break;
735  }
736  for (int i = 0; i < Ylm.size(); i++)
737  Ylm[i] *= norm;
738  for (int i = 0; i < Ylm.size(); i++)
739  gradYlm[i] *= norm;
740 }
741 
742 #endif
Point_t getGradYlm(int l, int m) const
returns the gradient of given
std::vector< value_type > Ylm
values Ylm
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
void evaluateThirdDerivOnly(const Point_t &p)
makes a table of and their gradients and hessians and third derivatives up to Lmax.
Tensor_t getHessYlm(int l, int m) const
returns the hessian of given
value_type getYlm(int lm) const
returns the value of given
std::vector< ggg_type > gggYlm
static void apply(std::vector< value_type > &Ylm, std::vector< pos_type > &gYlm, const pos_type &p)
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
GGG_t getGGGYlm(int lm) const
returns the matrix of third derivatives of given
std::vector< value_type > FactorLM
pre-evaluated factor
const double pi
Definition: Standard.h:56
std::vector< Point_t > gradYlm
gradients gradYlm
static void apply(std::vector< value_type > &Ylm, std::vector< pos_type > &gYlm, const pos_type &p)
typename SCT::pos_type pos_type
static void apply(std::vector< value_type > &Ylm, std::vector< pos_type > &gYlm, const pos_type &p)
typename SCT::value_type value_type
int Lmax
maximum angular momentum for the center
typename SCT::pos_type pos_type
int index(int l, int m) const
returns the index/locator for ( ) combo,
std::vector< value_type > FactorL
pre-evaluated factor
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)
value_type getYlm(int l, int m) const
returns the value of given
Tensor_t getHessYlm(int lm) const
returns the hessian of given
typename SCT::pos_type pos_type
double norm(const zVec &c)
Definition: VectorOps.h:118
Tensor<T,D> class for D by D tensor.
Definition: OhmmsTinyMeta.h:32
static void apply(std::vector< value_type > &Ylm, std::vector< pos_type > &gYlm, const pos_type &p)
typename SCT::value_type value_type
void evaluate(const Point_t &p)
makes a table of and their gradients up to Lmax.
MakeReturn< UnaryNode< FnArcTan, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t atan(const Vector< T1, C1 > &l)
typename SCT::pos_type pos_type
std::vector< hess_type > hessYlm
hessian hessYlm
std::complex< double > Ylm(int l, int m, const std::vector< double > &sph)
void evaluateTest(const Point_t &p)
makes a table of and their gradients up to Lmax.
SphericalTensor(const int l_max, bool addsign=false)
constructor
int size() const
typename SCT::value_type value_type
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
void evaluateWithHessian(const Point_t &p)
makes a table of and their gradients and hessians up to Lmax.
Point_t getGradYlm(int lm) const
returns the gradient of given
std::vector< value_type > Factor2L
pre-evaluated factor
std::vector< value_type > laplYlm
mmorales: HACK HACK HACK, to avoid having to rewrite QMCWaveFunctions/SphericalBasisSet.h
void evaluateAll(const Point_t &p)
makes a table of and their gradients up to Lmax.
QMCTraits::FullPrecRealType value_type
std::vector< value_type > NormFactor
Normalization factors.
typename SCT::value_type value_type
int lmax() const
SphericalTensor that evaluates the Real Spherical Harmonics.