QMCPACK
SoaSphericalTensor.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:
8 //
9 // File created by: Jeongnim Kim, jeongnim.kim@intel.com, Intel Corp.
10 //////////////////////////////////////////////////////////////////////////////////////
11 
12 
13 #ifndef QMCPLUSPLUS_SOA_SPHERICAL_CARTESIAN_TENSOR_H
14 #define QMCPLUSPLUS_SOA_SPHERICAL_CARTESIAN_TENSOR_H
15 
16 #include <stdexcept>
17 #include <limits>
19 #include "OhmmsPETE/Tensor.h"
20 #include "OhmmsPETE/OhmmsArray.h"
22 
23 namespace qmcplusplus
24 {
25 /** SoaSphericalTensor that evaluates the Real Spherical Harmonics
26  *
27  * The template parameters
28  * - T, the value_type, e.g. double
29  * - Point_t, a vector type to provide xyz coordinate.
30  * Point_t must have the operator[] defined, e.g., TinyVector<double,3>.
31  *
32  * Real Spherical Harmonics Ylm\f$=r^l S_l^m(x,y,z) \f$ is stored
33  * in an array ordered as [0,-1 0 1,-2 -1 0 1 2, -Lmax,-Lmax+1,..., Lmax-1,Lmax]
34  * where Lmax is the maximum angular momentum of a center.
35  * All the data members, e.g, Ylm and pre-calculated factors,
36  * can be accessed by index(l,m) which returns the
37  * locator of the combination for l and m.
38  */
39 template<typename T>
41 {
42 private:
47  ///maximum angular momentum for the center
48  int Lmax;
49  /// Normalization factors
50  const std::shared_ptr<OffloadVector> norm_factor_ptr_;
51  ///pre-evaluated factor \f$1/\sqrt{(l+m)\times(l+1-m)}\f$
52  const std::shared_ptr<OffloadVector> factorLM_ptr_;
53  ///pre-evaluated factor \f$\sqrt{(2l+1)/(4\pi)}\f$
54  const std::shared_ptr<OffloadVector> factorL_ptr_;
55  ///pre-evaluated factor \f$(2l+1)/(2l-1)\f$
56  const std::shared_ptr<OffloadVector> factor2L_ptr_;
57  /// norm_factor reference
59  /// factorLM reference
61  /// factorL reference
63  /// factor2L reference
65  ///composite
67 
68 public:
69  explicit SoaSphericalTensor(const int l_max, bool addsign = false);
70 
71  SoaSphericalTensor(const SoaSphericalTensor& rhs) = default;
72 
73  ///compute Ylm for single position
74  static void evaluate_bare(T x, T y, T z, T* Ylm, int lmax, const T* factorL, const T* factorLM);
75  ///compute Ylm_vgl for single position
76  static void evaluateVGL_impl(const T x,
77  const T y,
78  const T z,
79  T* restrict Ylm_vgl,
80  int lmax,
81  const T* factorL,
82  const T* factorLM,
83  const T* factor2L,
84  const T* normfactor,
85  size_t offset);
86 
87  ///compute Ylm
88  inline void evaluateV(T x, T y, T z, T* Ylm) const
89  {
90  evaluate_bare(x, y, z, Ylm, Lmax, factorL_.data(), factorLM_.data());
91  for (int i = 0, nl = cYlm.size(); i < nl; i++)
92  Ylm[i] *= norm_factor_[i];
93  }
94 
95  /**
96  * @brief evaluate V for multiple electrons and multiple pbc images
97  *
98  * @param [in] xyz electron positions [Nelec, Npbc, 3(x,y,z)]
99  * @param [out] Ylm Spherical tensor elements [Nelec, Npbc, Nlm]
100  */
101  inline void batched_evaluateV(const OffloadArray3D& xyz, OffloadArray3D& Ylm) const
102  {
103  const size_t nElec = xyz.size(0);
104  const size_t Npbc = xyz.size(1); // number of PBC images
105  assert(xyz.size(2) == 3);
106 
107  assert(Ylm.size(0) == nElec);
108  assert(Ylm.size(1) == Npbc);
109  const size_t Nlm = Ylm.size(2);
110 
111  size_t nR = nElec * Npbc; // total number of positions to evaluate
112 
113  auto* xyz_ptr = xyz.data();
114  auto* Ylm_ptr = Ylm.data();
115  auto* factorLM__ptr = factorLM_.data();
116  auto* factorL__ptr = factorL_.data();
117  auto* norm_factor__ptr = norm_factor_.data();
118 
119  PRAGMA_OFFLOAD("omp target teams distribute parallel for \
120  map(to:factorLM__ptr[:Nlm], factorL__ptr[:Lmax+1], norm_factor__ptr[:Nlm]) \
121  map(to: xyz_ptr[:3*nR], Ylm_ptr[:Nlm*nR])")
122  for (uint32_t ir = 0; ir < nR; ir++)
123  {
124  evaluate_bare(xyz_ptr[0 + 3 * ir], xyz_ptr[1 + 3 * ir], xyz_ptr[2 + 3 * ir], Ylm_ptr + (ir * Nlm), Lmax,
125  factorL__ptr, factorLM__ptr);
126  for (int i = 0; i < Nlm; i++)
127  Ylm_ptr[ir * Nlm + i] *= norm_factor__ptr[i];
128  }
129  }
130 
131  /**
132  * @brief evaluate VGL for multiple electrons and multiple pbc images
133  *
134  * when offload is enabled, xyz is assumed to be up to date on the device before entering the function
135  * Ylm_vgl will be up to date on the device (but not host) when this function exits
136  *
137  * @param [in] xyz electron positions [Nelec, Npbc, 3(x,y,z)]
138  * @param [out] Ylm_vgl Spherical tensor elements [5(v, gx, gy, gz, lapl), Nelec, Npbc, Nlm]
139  */
140  inline void batched_evaluateVGL(const OffloadArray3D& xyz, OffloadArray4D& Ylm_vgl) const
141  {
142  const size_t nElec = xyz.size(0);
143  const size_t Npbc = xyz.size(1); // number of PBC images
144  assert(xyz.size(2) == 3);
145 
146  assert(Ylm_vgl.size(0) == 5);
147  assert(Ylm_vgl.size(1) == nElec);
148  assert(Ylm_vgl.size(2) == Npbc);
149  const size_t Nlm = Ylm_vgl.size(3);
150  assert(norm_factor_.size() == Nlm);
151 
152  const size_t nR = nElec * Npbc; // total number of positions to evaluate
153  const size_t offset = Nlm * nR; // stride for v/gx/gy/gz/l
154 
155  auto* xyz_ptr = xyz.data();
156  auto* Ylm_vgl_ptr = Ylm_vgl.data();
157  auto* factorLM__ptr = factorLM_.data();
158  auto* factorL__ptr = factorL_.data();
159  auto* factor2L__ptr = factor2L_.data();
160  auto* norm_factor__ptr = norm_factor_.data();
161 
162  PRAGMA_OFFLOAD("omp target teams distribute parallel for \
163  map(to:factorLM__ptr[:Nlm], factorL__ptr[:Lmax+1], norm_factor__ptr[:Nlm], factor2L__ptr[:Lmax+1]) \
164  map(to: xyz_ptr[:nR*3], Ylm_vgl_ptr[:5*nR*Nlm])")
165  for (uint32_t ir = 0; ir < nR; ir++)
166  evaluateVGL_impl(xyz_ptr[0 + 3 * ir], xyz_ptr[1 + 3 * ir], xyz_ptr[2 + 3 * ir], Ylm_vgl_ptr + (ir * Nlm), Lmax,
167  factorL__ptr, factorLM__ptr, factor2L__ptr, norm_factor__ptr, offset);
168  }
169 
170  ///compute Ylm
171  inline void evaluateV(T x, T y, T z)
172  {
173  T* restrict Ylm = cYlm.data(0);
174  evaluate_bare(x, y, z, Ylm, Lmax, factorL_.data(), factorLM_.data());
175  for (int i = 0, nl = cYlm.size(); i < nl; i++)
176  Ylm[i] *= norm_factor_[i];
177  }
178 
179  ///makes a table of \f$ r^l S_l^m \f$ and their gradients up to Lmax.
180  void evaluateVGL(T x, T y, T z);
181 
182  ///makes a table of \f$ r^l S_l^m \f$ and their gradients up to Lmax.
183  void evaluateVGH(T x, T y, T z);
184 
185  ///makes a table of \f$ r^l S_l^m \f$ and their gradients up to Lmax.
186  void evaluateVGHGH(T x, T y, T z);
187 
188  ///returns the index/locator for (\f$l,m\f$) combo, \f$ l(l+1)+m \f$
189  static inline int index(int l, int m) { return (l * (l + 1)) + m; }
190 
191  /** return the starting address of the component
192  *
193  * component=0(V), 1(dx), 2(dy), 3(dz), 4(Lap)
194  */
195  inline const T* operator[](size_t component) const { return cYlm.data(component); }
196 
197  inline size_t size() const { return cYlm.size(); }
198 
199  inline int lmax() const { return Lmax; }
200 };
201 
202 /** constructor
203  * @param l_max maximum angular momentum
204  * @param addsign flag to determine what convention to use
205  *
206  * Evaluate all the constants and prefactors.
207  * The spherical harmonics is defined as
208  * \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]
209  * Note that the data member Ylm is a misnomer and should not be confused with "spherical harmonics"
210  * \f$Y_l^m\f$.
211  - When addsign == true, e.g., Gaussian packages
212  \f{eqnarray*}
213  S_l^m &=& (-1)^m \sqrt{2}\Re(Y_l^{|m|}), \;\;\;m > 0 \\
214  &=& Y_l^0, \;\;\;m = 0 \\
215  &=& (-1)^m \sqrt{2}\Im(Y_l^{|m|}),\;\;\;m < 0
216  \f}
217  - When addsign == false, e.g., SIESTA package,
218  \f{eqnarray*}
219  S_l^m &=& \sqrt{2}\Re(Y_l^{|m|}), \;\;\;m > 0 \\
220  &=& Y_l^0, \;\;\;m = 0 \\
221  &=&\sqrt{2}\Im(Y_l^{|m|}),\;\;\;m < 0
222  \f}
223  */
224 template<typename T>
225 inline SoaSphericalTensor<T>::SoaSphericalTensor(const int l_max, bool addsign)
226  : Lmax(l_max),
227  norm_factor_ptr_(std::make_shared<OffloadVector>()),
228  factorLM_ptr_(std::make_shared<OffloadVector>()),
229  factorL_ptr_(std::make_shared<OffloadVector>()),
230  factor2L_ptr_(std::make_shared<OffloadVector>()),
231  norm_factor_(*norm_factor_ptr_),
232  factorLM_(*factorLM_ptr_),
233  factorL_(*factorL_ptr_),
234  factor2L_(*factor2L_ptr_)
235 {
236  constexpr T czero(0);
237  constexpr T cone(1);
238  const int ntot = (Lmax + 1) * (Lmax + 1);
239  cYlm.resize(ntot);
240  norm_factor_.resize(ntot, cone);
241  const T sqrt2 = std::sqrt(2.0);
242  if (addsign)
243  {
244  for (int l = 0; l <= Lmax; l++)
245  {
246  norm_factor_[index(l, 0)] = cone;
247  for (int m = 1; m <= l; m++)
248  {
249  norm_factor_[index(l, m)] = std::pow(-cone, m) * sqrt2;
250  norm_factor_[index(l, -m)] = std::pow(-cone, -m) * sqrt2;
251  }
252  }
253  }
254  else
255  {
256  for (int l = 0; l <= Lmax; l++)
257  {
258  for (int m = 1; m <= l; m++)
259  {
260  norm_factor_[index(l, m)] = sqrt2;
261  norm_factor_[index(l, -m)] = sqrt2;
262  }
263  }
264  }
265  factorL_.resize(Lmax + 1);
266  const T omega = 1.0 / std::sqrt(16.0 * std::atan(1.0));
267  for (int l = 1; l <= Lmax; l++)
268  factorL_[l] = std::sqrt(static_cast<T>(2 * l + 1)) * omega;
269  factor2L_.resize(Lmax + 1);
270  for (int l = 1; l <= Lmax; l++)
271  factor2L_[l] = static_cast<T>(2 * l + 1) / static_cast<T>(2 * l - 1);
272  factorLM_.resize(ntot);
273  for (int l = 1; l <= Lmax; l++)
274  for (int m = 1; m <= l; m++)
275  {
276  T fac2 = 1.0 / std::sqrt(static_cast<T>((l + m) * (l + 1 - m)));
277  factorLM_[index(l, m)] = fac2;
278  factorLM_[index(l, -m)] = fac2;
279  }
280  norm_factor_.updateTo();
281  factorLM_.updateTo();
282  factorL_.updateTo();
283  factor2L_.updateTo();
284 }
285 
286 PRAGMA_OFFLOAD("omp declare target")
287 template<typename T>
288 inline void SoaSphericalTensor<T>::evaluate_bare(T x,
289  T y,
290  T z,
291  T* restrict Ylm,
292  int lmax,
293  const T* factorL,
294  const T* factorLM)
295 {
296  constexpr T czero(0);
297  constexpr T cone(1);
298  const T pi = 4.0 * std::atan(1.0);
299  const T omega = 1.0 / std::sqrt(4.0 * pi);
300  constexpr T eps2 = std::numeric_limits<T>::epsilon() * std::numeric_limits<T>::epsilon();
301 
302  /* Calculate r, cos(theta), sin(theta), cos(phi), sin(phi) from input
303  coordinates. Check here the coordinate singularity at cos(theta) = +-1.
304  This also takes care of r=0 case. */
305  T cphi, sphi, ctheta;
306  T r2xy = x * x + y * y;
307  T r = std::sqrt(r2xy + z * z);
308  if (r2xy < eps2)
309  {
310  cphi = czero;
311  sphi = cone;
312  ctheta = (z < czero) ? -cone : cone;
313  }
314  else
315  {
316  ctheta = z / r;
317  //protect ctheta, when ctheta is slightly >1 or <-1
318  if (ctheta > cone)
319  ctheta = cone;
320  if (ctheta < -cone)
321  ctheta = -cone;
322  T rxyi = cone / std::sqrt(r2xy);
323  cphi = x * rxyi;
324  sphi = y * rxyi;
325  }
326  T stheta = std::sqrt(cone - ctheta * ctheta);
327  /* Now to calculate the associated legendre functions P_lm from the
328  recursion relation from l=0 to Lmax. Conventions of J.D. Jackson,
329  Classical Electrodynamics are used. */
330  Ylm[0] = cone;
331  // calculate P_ll and P_l,l-1
332  T fac = cone;
333  int j = -1;
334  for (int l = 1; l <= lmax; l++)
335  {
336  j += 2;
337  fac *= -j * stheta;
338  int ll = index(l, l);
339  int l1 = index(l, l - 1);
340  int l2 = index(l - 1, l - 1);
341  Ylm[ll] = fac;
342  Ylm[l1] = j * ctheta * Ylm[l2];
343  }
344  // Use recurence to get other plm's //
345  for (int m = 0; m < lmax - 1; m++)
346  {
347  int j = 2 * m + 1;
348  for (int l = m + 2; l <= lmax; l++)
349  {
350  j += 2;
351  int lm = index(l, m);
352  int l1 = index(l - 1, m);
353  int l2 = index(l - 2, m);
354  Ylm[lm] = (ctheta * j * Ylm[l1] - (l + m - 1) * Ylm[l2]) / (l - m);
355  }
356  }
357  // Now to calculate r^l Y_lm. //
358  T sphim, cphim, temp;
359  Ylm[0] = omega; //1.0/sqrt(pi4);
360  T rpow = 1.0;
361  for (int l = 1; l <= lmax; l++)
362  {
363  rpow *= r;
364  //fac = rpow*sqrt(static_cast<T>(2*l+1))*omega;//rpow*sqrt((2*l+1)/pi4);
365  //factorL[l] = sqrt(2*l+1)/sqrt(4*pi)
366  fac = rpow * factorL[l];
367  int l0 = index(l, 0);
368  Ylm[l0] *= fac;
369  cphim = cone;
370  sphim = czero;
371  for (int m = 1; m <= l; m++)
372  {
373  temp = cphim * cphi - sphim * sphi;
374  sphim = sphim * cphi + cphim * sphi;
375  cphim = temp;
376  int lm = index(l, m);
377  fac *= factorLM[lm];
378  temp = fac * Ylm[lm];
379  Ylm[lm] = temp * cphim;
380  lm = index(l, -m);
381  Ylm[lm] = temp * sphim;
382  }
383  }
384  //for (int i=0; i<Ylm.size(); i++)
385  // Ylm[i]*= norm_factor_[i];
386 }
387 PRAGMA_OFFLOAD("omp end declare target")
388 
389 
390 PRAGMA_OFFLOAD("omp declare target")
391 template<typename T>
392 inline void SoaSphericalTensor<T>::evaluateVGL_impl(const T x,
393  const T y,
394  const T z,
395  T* restrict Ylm_vgl,
396  int lmax,
397  const T* factorL,
398  const T* factorLM,
399  const T* factor2L,
400  const T* normfactor,
401  size_t offset)
402 {
403  T* restrict Ylm = Ylm_vgl;
404  // T* restrict Ylm = cYlm.data(0);
405  evaluate_bare(x, y, z, Ylm, lmax, factorL, factorLM);
406  const size_t Nlm = (lmax + 1) * (lmax + 1);
407 
408  constexpr T czero(0);
409  constexpr T ahalf(0.5);
410  T* restrict gYlmX = Ylm_vgl + offset * 1;
411  T* restrict gYlmY = Ylm_vgl + offset * 2;
412  T* restrict gYlmZ = Ylm_vgl + offset * 3;
413  T* restrict lYlm = Ylm_vgl + offset * 4; // just need to set to zero
414 
415  gYlmX[0] = czero;
416  gYlmY[0] = czero;
417  gYlmZ[0] = czero;
418  lYlm[0] = czero;
419 
420  // Calculating Gradient now//
421  for (int l = 1; l <= lmax; l++)
422  {
423  //T fac = ((T) (2*l+1))/(2*l-1);
424  T fac = factor2L[l];
425  for (int m = -l; m <= l; m++)
426  {
427  int lm = index(l - 1, 0);
428  T gx, gy, gz, dpr, dpi, dmr, dmi;
429  const int ma = std::abs(m);
430  const T cp = std::sqrt(fac * (l - ma - 1) * (l - ma));
431  const T cm = std::sqrt(fac * (l + ma - 1) * (l + ma));
432  const T c0 = std::sqrt(fac * (l - ma) * (l + ma));
433  gz = (l > ma) ? c0 * Ylm[lm + m] : czero;
434  if (l > ma + 1)
435  {
436  dpr = cp * Ylm[lm + ma + 1];
437  dpi = cp * Ylm[lm - ma - 1];
438  }
439  else
440  {
441  dpr = czero;
442  dpi = czero;
443  }
444  if (l > 1)
445  {
446  switch (ma)
447  {
448  case 0:
449  dmr = -cm * Ylm[lm + 1];
450  dmi = cm * Ylm[lm - 1];
451  break;
452  case 1:
453  dmr = cm * Ylm[lm];
454  dmi = czero;
455  break;
456  default:
457  dmr = cm * Ylm[lm + ma - 1];
458  dmi = cm * Ylm[lm - ma + 1];
459  }
460  }
461  else
462  {
463  dmr = cm * Ylm[lm];
464  dmi = czero;
465  //dmr = (l==1) ? cm*Ylm[lm]:0.0;
466  //dmi = 0.0;
467  }
468  if (m < 0)
469  {
470  gx = ahalf * (dpi - dmi);
471  gy = -ahalf * (dpr + dmr);
472  }
473  else
474  {
475  gx = ahalf * (dpr - dmr);
476  gy = ahalf * (dpi + dmi);
477  }
478  lm = index(l, m);
479  if (ma)
480  {
481  gYlmX[lm] = normfactor[lm] * gx;
482  gYlmY[lm] = normfactor[lm] * gy;
483  gYlmZ[lm] = normfactor[lm] * gz;
484  }
485  else
486  {
487  gYlmX[lm] = gx;
488  gYlmY[lm] = gy;
489  gYlmZ[lm] = gz;
490  }
491  }
492  }
493  for (int i = 0; i < Nlm; i++)
494  {
495  Ylm[i] *= normfactor[i];
496  lYlm[i] = 0;
497  }
498  //for (int i=0; i<Ylm.size(); i++) gradYlm[i]*= norm_factor_[i];
499 }
500 PRAGMA_OFFLOAD("omp end declare target")
501 
502 template<typename T>
503 inline void SoaSphericalTensor<T>::evaluateVGL(T x, T y, T z)
504 {
505  evaluateVGL_impl(x, y, z, cYlm.data(), Lmax, factorL_.data(), factorLM_.data(), factor2L_.data(), norm_factor_.data(),
506  cYlm.capacity());
507 }
508 
509 template<typename T>
510 inline void SoaSphericalTensor<T>::evaluateVGH(T x, T y, T z)
511 {
512  throw std::runtime_error("SoaSphericalTensor<T>::evaluateVGH(x,y,z): Not implemented\n");
513 }
514 
515 template<typename T>
516 inline void SoaSphericalTensor<T>::evaluateVGHGH(T x, T y, T z)
517 {
518  throw std::runtime_error("SoaSphericalTensor<T>::evaluateVGHGH(x,y,z): Not implemented\n");
519 }
520 
521 extern template class SoaSphericalTensor<float>;
522 extern template class SoaSphericalTensor<double>;
523 } // namespace qmcplusplus
524 #endif
OffloadVector & norm_factor_
norm_factor reference
const std::shared_ptr< OffloadVector > norm_factor_ptr_
Normalization factors.
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
SoaSphericalTensor(const int l_max, bool addsign=false)
constructor
void batched_evaluateVGL(const OffloadArray3D &xyz, OffloadArray4D &Ylm_vgl) const
evaluate VGL for multiple electrons and multiple pbc images
const std::shared_ptr< OffloadVector > factor2L_ptr_
pre-evaluated factor
void evaluateV(T x, T y, T z)
compute Ylm
std::complex< T > Ylm(int l, int m, const TinyVector< T, 3 > &r)
calculates Ylm param[in] l angular momentum param[in] m magnetic quantum number param[in] r position ...
Definition: Ylm.h:89
MakeReturn< UnaryNode< FnFabs, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t abs(const Vector< T1, C1 > &l)
OffloadVector & factorL_
factorL reference
constexpr std::complex< float > czero
Definition: BLAS.hpp:51
const double pi
Definition: Standard.h:56
Type_t * data()
Definition: OhmmsArray.h:87
constexpr std::complex< float > cone
Definition: BLAS.hpp:50
Soa Container for D-dim vectors.
const T * operator[](size_t component) const
return the starting address of the component
VectorSoaContainer< T, 5 > cYlm
composite
SoaSphericalTensor that evaluates the Real Spherical Harmonics.
void evaluateVGL(T x, T y, T z)
makes a table of and their gradients up to Lmax.
static void evaluate_bare(T x, T y, T z, T *Ylm, int lmax, const T *factorL, const T *factorLM)
compute Ylm for single position
void evaluateVGHGH(T x, T y, T z)
makes a table of and their gradients up to Lmax.
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)
size_type size() const
return the current size
Definition: OhmmsVector.h:162
MakeReturn< UnaryNode< FnArcTan, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t atan(const Vector< T1, C1 > &l)
size_t size() const
Definition: OhmmsArray.h:57
std::complex< double > Ylm(int l, int m, const std::vector< double > &sph)
void batched_evaluateV(const OffloadArray3D &xyz, OffloadArray3D &Ylm) const
evaluate V for multiple electrons and multiple pbc images
void evaluateV(T x, T y, T z, T *Ylm) const
compute Ylm
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
const std::shared_ptr< OffloadVector > factorL_ptr_
pre-evaluated factor
void evaluateVGH(T x, T y, T z)
makes a table of and their gradients up to Lmax.
int Lmax
maximum angular momentum for the center
static int index(int l, int m)
returns the index/locator for ( ) combo,
A D-dimensional Array class based on PETE.
Definition: OhmmsArray.h:25
size_type size() const
return the physical size
static void evaluateVGL_impl(const T x, const T y, const T z, T *restrict Ylm_vgl, int lmax, const T *factorL, const T *factorLM, const T *factor2L, const T *normfactor, size_t offset)
compute Ylm_vgl for single position
OffloadVector & factor2L_
factor2L reference
const std::shared_ptr< OffloadVector > factorLM_ptr_
pre-evaluated factor
OffloadVector & factorLM_
factorLM reference