QMCPACK
Ylm.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: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
8 // Jeremy McMinnis, jmcminis@gmail.com, University of Illinois at Urbana-Champaign
9 //
10 // File created by: Jeongnim Kim, jeongnim.kim@gmail.com, University of Illinois at Urbana-Champaign
11 //////////////////////////////////////////////////////////////////////////////////////
12 
13 
14 #ifndef QMCPLUSPLUS_YLM_H
15 #define QMCPLUSPLUS_YLM_H
16 
17 #include <cmath>
18 #include <complex>
19 #include "OhmmsPETE/TinyVector.h"
20 #include "config/stdlib/Constants.h"
21 
22 namespace qmcplusplus
23 {
24 template<typename T>
25 inline T LegendrePll(int l, T x)
26 {
27  if (l == 0)
28  return 1.0;
29  else
30  {
31  T sqt = std::sqrt(1.0 - x) * std::sqrt(1.0 + x);
32  T val = 1.0;
33  T dblfact = 1.0;
34  for (int i = 1; i <= l; i++)
35  {
36  val *= -sqt;
37  val *= dblfact;
38  dblfact += 2.0;
39  }
40  return val;
41  }
42 }
43 
44 template<typename T>
45 inline T LegendrePlm(int l, int m, T x)
46 {
47  if (m < 0)
48  {
49  m = std::abs(m);
50  T posval = LegendrePlm(l, m, x);
51  T sign = (m % 2 == 0) ? 1.0 : -1.0;
52  T mfact = 1.0;
53  for (int i = 2; i <= (l - m); i++)
54  mfact *= static_cast<T>(i);
55  T pfact = 1.0;
56  for (int i = 2; i <= (l + m); i++)
57  pfact *= static_cast<T>(i);
58  return posval * sign * mfact / pfact;
59  }
60  // Now we can assume that m is not negative
61  T pmm = LegendrePll(m, x);
62  T pmp1m = x * (2 * m + 1) * pmm;
63  if (m == l)
64  return pmm;
65  else if (l == (m + 1))
66  return pmp1m;
67  else
68  // Use recursive formula
69  {
70  T Plm2m = pmm;
71  T Plm1m = pmp1m;
72  T Pl = 0;
73  for (int i = m + 2; i <= l; i++)
74  {
75  Pl = (1.0 / static_cast<T>(i - m)) * (x * (2 * i - 1) * Plm1m - (i + m - 1) * Plm2m);
76  Plm2m = Plm1m;
77  Plm1m = Pl;
78  }
79  return Pl;
80  }
81 }
82 
83 /** calculates Ylm
84  * param[in] l angular momentum
85  * param[in] m magnetic quantum number
86  * param[in] r position vector. Note: This must be a unit vector and in the order [z,x,y] to be correct
87  */
88 template<typename T>
89 inline std::complex<T> Ylm(int l, int m, const TinyVector<T, 3>& r)
90 {
91  T costheta = r[0];
92  T phi = std::atan2(r[2], r[1]);
93  int lmm = l - m;
94  int lpm = l + m;
95  T mfact = 1.0;
96  T pfact = 1.0;
97  for (int i = lmm; i > 0; i--)
98  mfact *= static_cast<T>(i);
99  for (int i = lpm; i > 0; i--)
100  pfact *= static_cast<T>(i);
101  T prefactor = std::sqrt(static_cast<T>(2 * l + 1) * mfact / (4.0 * M_PI * pfact));
102  prefactor *= LegendrePlm(l, m, costheta);
103  return std::complex<T>(prefactor * std::cos(m * phi), prefactor * std::sin(m * phi));
104 }
105 
106 /** calculate the derivative of a Ylm with respect to theta and phi
107  * param[in] l: angular momentum
108  * param[in] m: magnetic quantum number
109  * param[in] r: cartesian position align with [z,x,y]. note: MUST BE UNIT VECTOR to be consistent with Ylm above
110  * param[out] theta_deriv: derivative of Ylm with respect to theta
111  * param[out] phi_deriv: derivative of Ylm with respect to phi
112  * param[in] conj: true if we are taking derivatives of conj(Ylm)
113  */
114 template<typename T>
115 inline void derivYlmSpherical(const int l,
116  const int m,
117  const TinyVector<T, 3>& r,
118  std::complex<T>& theta_deriv,
119  std::complex<T>& phi_deriv,
120  const bool conj)
121 {
122  T theta = std::acos(r[0]);
123  T phi = std::atan2(r[2], r[1]);
124  std::complex<T> emiphi = std::complex<T>(std::cos(phi), -std::sin(phi));
125  theta_deriv = static_cast<T>(m) / std::tan(theta) * Ylm(l, m, r);
126  theta_deriv += std::sqrt(static_cast<T>((l - m) * (l + m + 1))) * emiphi * Ylm(l, m + 1, r);
127  phi_deriv = std::complex<T>(0.0, static_cast<T>(m)) * Ylm(l, m, r);
128  if (conj)
129  {
130  theta_deriv = std::conj(theta_deriv);
131  phi_deriv = std::conj(phi_deriv);
132  }
133 }
134 
135 /** wrapper for Ylm, which can take any normal position vector as an argument
136  * param[in] l angular momentum
137  * param[in] m magnetic quantum number
138  * param[in] r is a position vector. This does not have to be normalized and is in the standard ordering [x,y,z]
139  */
140 template<typename T>
141 inline std::complex<T> sphericalHarmonic(const int l, const int m, const TinyVector<T, 3>& r)
142 {
143  TinyVector<T, 3> unit;
144  T norm = std::sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
145  unit[0] = r[2] / norm;
146  unit[1] = r[0] / norm;
147  unit[2] = r[1] / norm;
148  return Ylm(l, m, unit);
149 }
150 
151 /** get cartesian derivatives of spherical Harmonics. This takes a arbitrary position vector (x,y,z) and returns (d/dx, d/dy, d/dz)Ylm
152  * param[in] l angular momentum
153  * param[in] m magnetic quantum number
154  * param[in] r position vector. This does not have to be normalized and is in the standard ordering [x,y,z]
155  * param[out] grad (d/dx, d/dy, d/dz) of Ylm
156  */
157 template<typename T>
158 inline void sphericalHarmonicGrad(const int l,
159  const int m,
160  const TinyVector<T, 3>& r,
161  TinyVector<std::complex<T>, 3>& grad)
162 {
163  TinyVector<T, 3> unit;
164  T norm = std::sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]);
165  unit[0] = r[2] / norm;
166  unit[1] = r[0] / norm;
167  unit[2] = r[1] / norm;
168  std::complex<T> dth, dph;
169  derivYlmSpherical(l, m, unit, dth, dph, false);
170 
171  T dth_dx = r[0] * r[2] / (norm * norm * std::sqrt(r[0] * r[0] + r[1] * r[1]));
172  T dph_dx = -r[1] / (r[0] * r[0] + r[1] * r[1]);
173  T dth_dy = r[1] * r[2] / (norm * norm * std::sqrt(r[0] * r[0] + r[1] * r[1]));
174  T dph_dy = r[0] / (r[0] * r[0] + r[1] * r[1]);
175  T dth_dz = -std::sqrt(r[0] * r[0] + r[1] * r[1]) / (norm * norm);
176  T dph_dz = 0;
177 
178  grad[0] = dth * dth_dx + dph * dph_dx;
179  grad[1] = dth * dth_dy + dph * dph_dy;
180  grad[2] = dth * dth_dz + dph * dph_dz;
181 }
182 
183 } // namespace qmcplusplus
184 #endif
Fixed-size array.
Definition: OhmmsTinyMeta.h:30
T LegendrePlm(int l, int m, T x)
Definition: Ylm.h:45
helper functions for EinsplineSetBuilder
Definition: Configuration.h:43
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)
MakeReturn< UnaryNode< FnSin, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sin(const Vector< T1, C1 > &l)
void sphericalHarmonicGrad(const int l, const int m, const TinyVector< T, 3 > &r, TinyVector< std::complex< T >, 3 > &grad)
get cartesian derivatives of spherical Harmonics.
Definition: Ylm.h:158
MakeReturn< UnaryNode< FnCos, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t cos(const Vector< T1, C1 > &l)
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)
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)
MakeReturn< UnaryNode< FnTan, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t tan(const Vector< T1, C1 > &l)
double sign(double x)
Definition: Standard.h:73
float conj(const float &c)
Workaround to allow conj on scalar to return real instead of complex.
MakeReturn< UnaryNode< FnSqrt, typename CreateLeaf< Vector< T1, C1 > >::Leaf_t > >::Expression_t sqrt(const Vector< T1, C1 > &l)
void derivYlmSpherical(const int l, const int m, const TinyVector< T, 3 > &r, std::complex< T > &theta_deriv, std::complex< T > &phi_deriv, const bool conj)
calculate the derivative of a Ylm with respect to theta and phi param[in] l: angular momentum param[i...
Definition: Ylm.h:115
T LegendrePll(int l, T x)
Definition: Ylm.h:25
std::complex< T > sphericalHarmonic(const int l, const int m, const TinyVector< T, 3 > &r)
wrapper for Ylm, which can take any normal position vector as an argument param[in] l angular momentu...
Definition: Ylm.h:141