ampsci
High-precision calculations for one- and two-valence atomic systems
Wigner369j.hpp
1#pragma once
2#include <algorithm> //std::min!
3#include <cmath>
4#include <cstdint>
5#include <gsl/gsl_sf_coupling.h>
6#include <optional>
7#include <utility>
8
9/*!
10 @brief
11 Angular provides functions and classes for calculating and storing angular
12 factors (3,6,9-J symbols etc.)
13
14 @details
15 Provides functions to:
16 - Calculate wigner 3,6,9-J symbols + Clebsh-Gordon coefs etc..
17 - Also provied look-up tables, which are faster than calculating symbols
18 on-the-fly
19 - Wrapper functions to calculate wigner 3,6,9-J symbols.
20 - Uses GSL:
21 https://www.gnu.org/software/gsl/doc/html/specfunc.html?highlight=3j#coupling-coefficients
22
23 The general equations are defined:
24 \f{align}{
25 \frac{1}{r_{12}} &= \sum_{kq} \frac{r_<^k}{r_>^{k+1}}(-1)^q
26 C^k_{-q}(\hat{n}_1)C^k_{q}(\hat{n}_2)\\
27 C^k_{q} &\equiv \sqrt{\frac{4\pi}{2k+1}} Y_{kq}(\hat{n}),
28 \f}
29 and
30 \f{align}{
31 C^k_{ab} &\equiv \langle{\kappa_a}||C^k||{\kappa_b}\rangle
32 \equiv (-1)^{j_a+1/2} \widetilde C^k_{ab} ,\\
33 &= (-1)^{j_a+1/2}\sqrt{[j_a][j_b]}
34 \begin{pmatrix}
35 {j_a} & {j_b} & {k} \\ {-1/2} & {1/2} &{0}
36 \end{pmatrix}
37 \pi(l_a+l_b+k).
38 \f}
39*/
40namespace Angular {
41
42//==============================================================================
43//! returns l given kappa
44constexpr int l_k(int ka) { return (ka > 0) ? ka : -ka - 1; }
45//! returns 2j given kappa
46constexpr int twoj_k(int ka) { return (ka > 0) ? 2 * ka - 1 : -2 * ka - 1; }
47//! returns parity [(-1)^l] given kappa
48constexpr int parity_k(int ka) {
49 return (ka % 2 == 0) ? ((ka > 0) ? 1 : -1) : ((ka < 0) ? 1 : -1);
50}
51//! returns parity [(-1)^l] given l
52constexpr int parity_l(int l) { return (l % 2 == 0) ? 1 : -1; }
53//! "Complimentary" l := (2j-l) = l+/-1, for j=l+/-1/2
54constexpr int l_tilde_k(int ka) { return (ka > 0) ? ka - 1 : -ka; }
55//! returns kappa, given 2j and l
56constexpr int kappa_twojl(int twoj, int l) {
57 return ((2 * l - twoj) * (twoj + 1)) / 2;
58}
59//! returns kappa, given 2*j and parity (+/-1),
60constexpr int kappa_twojpi(const int twoj, const int pi) {
61 const auto l_minus = (twoj - 1) / 2;
62 const auto l_minus_pi = (l_minus % 2 == 0) ? 1 : -1;
63 const auto l = l_minus_pi == pi ? l_minus : l_minus + 1;
64 return kappa_twojl(twoj, l); // must be simpler way?
65}
66//! Checks if a double is within eps of 0.0 [eps=1.0e-10 by default]
67inline constexpr bool zeroQ(double x, double eps = 1.0e-10) {
68 return x >= 0 ? x < eps : x > -eps;
69}
70
71//==============================================================================
72
73//! @brief returns kappa_index, given kappa
74/*! @details
75 Kappa Index:
76 For easy array access, define 1-to-1 index for each kappa:
77
78 | kappa | -1 | 1 | -2 | 2 | -3 | 3 | -4 | 4 | ... |
79 |-------|----|---|----|---|----|---|----|---|-----|
80 | index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ... |
81
82 \f[
83 i_k(\kappa)=
84 \begin{cases}
85 -2\kappa-2, & \kappa<0, \\
86 2\kappa-1, & \kappa>0 .
87 \end{cases}
88 \f]
89
90 \f[
91 \kappa(i_k)=
92 \begin{cases}
93 -\left(\frac{i_k}{2}+1\right), & i_k\ \text{even},\\
94 \frac{i_k+1}{2}, & i_k\ \text{odd}.
95 \end{cases}
96 \f]
97*/
98constexpr std::uint64_t kappa_to_kindex(int ka) {
99 return (ka < 0) ? std::uint64_t(-2 * ka - 2) : std::uint64_t(2 * ka - 1);
100}
101
102//! Returns kappa, given kappa_index
103//! @details see \ref Angular::kappa_to_kindex()
104constexpr int kindex_to_kappa(std::uint64_t i) {
105 return (i % 2 == 0) ? int(-(i + 2) / 2) : int((i + 1) / 2);
106}
107
108//! returns 2j, given kappa_index
109//! @details see \ref Angular::kappa_to_kindex()
110constexpr int kindex_to_twoj(std::uint64_t i) {
111 return (i % 2 == 0) ? int(i + 1) : int(i);
112}
113
114//! returns l, given kappa_index
115//! @details see \ref Angular::kappa_to_kindex()
116constexpr int kindex_to_l(std::uint64_t i) {
117 return (i % 2 == 0) ? int(i / 2) : int((i + 1) / 2);
118}
119
120//==============================================================================
121//! Returns number of possible states _below_ given n (i.e., n' < n)
122/*! @details
123
124 This could be made more "compact" with a maximum l.
125 In practice, we go to large n, but never very large l.
126
127 @warning
128 - n must be >1 (no non-standard states)
129
130 Cannot overflow; converts to std::uint64_t.
131*/
132constexpr std::uint64_t states_below_n(int n) {
133 const std::uint64_t nn = static_cast<std::uint64_t>(n);
134 return nn * nn - 2 * nn + 1;
135}
136
137//! @brief Returns nk_index, given {n, kappa}
138/*! @details
139 For convenient array access we define a one-to-one mapping between the pair
140 \f$(n,\kappa)\f$ and a non-negative index:
141
142 \f[
143 i_{nk}(n,\kappa) = (n-1)^2 + i_k(\kappa),
144 \f]
145
146 where \f$i_k(\kappa)\f$ is the kappa index defined by \ref Angular::kappa_to_kindex()
147
148 Equivalently,
149
150 \f[
151 i_{nk}(n,\kappa) = n^2 - 2n + 1 + i_k(\kappa).
152 \f]
153
154 Since
155
156 \f[
157 n^2 - 2n + 1 = (n-1)^2 = \texttt{states\_below\_n}(n),
158 \f]
159
160 this counts the number of states with principal quantum number \f$n' < n\f$,
161 plus the index within the \f$n\f$ shell.
162
163 @note This indexing is only valid for physical bound-state quantum numbers, n >= 1,
164 and cannot in general be used for arbitrary basis states.
165
166 @warning To safely convert the returned index (`uint64_t`) to `int`, one must
167 have `n <= 46340`.
168
169 @warning To safely convert the returned index to \ref Coulomb::nkIndex
170 (`uint16_t`), one must have `n <= 256`.
171*/
172constexpr std::uint64_t nk_to_index(int n, int k) {
174}
175
176//! Returns {n, kappa} given nk_index
177//! @details Inverse of \ref Angular::nk_to_index().
178inline std::pair<int, int> index_to_nk(std::uint64_t nk_index) {
179 // Better way? isqrt?
180 const auto n = 1 + int(std::sqrt(nk_index));
181 const auto kappa_index = nk_index - states_below_n(n);
182 return {n, Angular::kindex_to_kappa(kappa_index)};
183}
184
185//! Returns {n, kappa_index} given nk_index
186//! @details Inverse of \ref Angular::nk_to_index().
187inline std::pair<int, std::uint64_t>
188nkindex_to_n_kindex(std::uint64_t nk_index) {
189 const auto n = 1 + int(std::sqrt(nk_index));
190 const auto kappa_index = nk_index - states_below_n(n);
191 return {n, kappa_index};
192}
193
194//! Returns kappa, given nk_index
195//! @details See \ref Angular::nk_to_index().
196inline int nkindex_to_kappa(std::uint64_t nk_index) {
197 const auto n = 1 + int(std::sqrt(nk_index));
198 const auto kappa_index = nk_index - states_below_n(n);
199 return kindex_to_kappa(kappa_index);
200}
201
202//! Returns 2*j, given nk_index
203//! @details See \ref Angular::nk_to_index().
204inline int nkindex_to_twoj(std::uint64_t nk_index) {
205 const auto n = 1 + int(std::sqrt(nk_index));
206 const auto kappa_index = nk_index - states_below_n(n);
207 return kindex_to_twoj(kappa_index);
208}
209
210//! Returns l, given nk_index
211//! @details See \ref Angular::nk_to_index().
212inline int nkindex_to_l(std::uint64_t nk_index) {
213 const auto n = 1 + int(std::sqrt(double(nk_index) + 0.01));
214 const auto kappa_index = nk_index - states_below_n(n);
215 return l_k(kindex_to_kappa(kappa_index));
216}
217
218//==============================================================================
219//! Returns true if a is even - for integer values
220constexpr bool evenQ(int a) { return (a % 2 == 0); }
221//! Returns true if a (an int) is even, given 2*a (true if two_a/2 is even)
222constexpr bool evenQ_2(int two_a) { return (two_a % 4 == 0); }
223//! Evaluates (-1)^{a} (for integer a)
224constexpr int neg1pow(int a) { return evenQ(a) ? 1 : -1; }
225//! Evaluates (-1)^{two_a/2} (for integer a; two_a is even)
226constexpr int neg1pow_2(int two_a) { return evenQ_2(two_a) ? 1 : -1; }
227
228//==============================================================================
229//! Parity rule. Returns 1 only if la+lb+k is even
230constexpr int parity(int la, int lb, int k) {
231 return evenQ(la + lb + k) ? 1 : 0;
232}
233
234//==============================================================================
235//! Returns 1 if triangle rule is satisfied. nb: works with j OR twoj!
236constexpr int triangle(int j1, int j2, int J) {
237 // nb: can be called with wither j or twoj!
238 return ((j1 + j2 < J) || (std::abs(j1 - j2) > J)) ? 0 : 1;
239}
240//! Checks if three ints sum to zero, returns 1 if they do
241constexpr int sumsToZero(int m1, int m2, int m3) {
242 return (m1 + m2 + m3 != 0) ? 0 : 1;
243}
244
245//==============================================================================
246//! @brief Calculates wigner 3j symbol. Takes in 2*j (or 2*l) - intput is
247//! integer
248/*! @details
249 \f[ \begin{pmatrix}j1&j2&j3\\m1&m2&m3\end{pmatrix} \f]
250*/
251inline double threej_2(int two_j1, int two_j2, int two_j3, int two_m1,
252 int two_m2, int two_m3) {
253 if (triangle(two_j1, two_j2, two_j3) * sumsToZero(two_m1, two_m2, two_m3) ==
254 0)
255 return 0;
256 return gsl_sf_coupling_3j(two_j1, two_j2, two_j3, two_m1, two_m2, two_m3);
257}
258
259//==============================================================================
260//!@brief Special (common) 3js case: (j1 j2 k, -0.5, 0.5, 0)
261/*! @details
262 \f[ \begin{pmatrix}j1&j2&k\\-1/2&1/2&0\end{pmatrix} \f]
263*/
264inline double special_threej_2(int two_j1, int two_j2, int two_k) {
265 if (triangle(two_j1, two_j2, two_k) == 0)
266 return 0.0;
267 if (two_k == 0) {
268 auto s = evenQ_2(two_j1 + 1) ? 1.0 : -1.0;
269 return s / std::sqrt(two_j1 + 1);
270 }
271 return gsl_sf_coupling_3j(two_j1, two_j2, two_k, -1, 1, 0);
272}
273
274//==============================================================================
275//! Clebsh-Gordon coeficient <j1 m1, j2 m2 | J M> [takes 2*j, as int]
276inline double cg_2(int two_j1, int two_m1, int two_j2, int two_m2, int two_J,
277 int two_M)
278// <j1 m1, j2 m2 | J M> = (-1)^(j1-j2+M) * std::sqrt(2J+1) * (j1 j2 J)
279// . (m1 m2 -M)
280// (Last term is 3j symbol)
281// Note: this function takes INTEGER values, that have already multiplied by 2!
282// Works for l and j (integer and half-integer)
283{
284 if (triangle(two_j1, two_j2, two_J) * sumsToZero(two_m1, two_m2, -two_M) == 0)
285 return 0;
286 int sign = -1;
287 if ((two_j1 - two_j2 + two_M) % 4 == 0)
288 sign = 1; // mod 4 (instead 2), since x2
289 return sign * std::sqrt(two_J + 1.) *
290 gsl_sf_coupling_3j(two_j1, two_j2, two_J, two_m1, two_m2, -two_M);
291}
292
293//==============================================================================
294//! Checks triangle conditions for 6j symbols (for 2*j)
295inline bool sixj_zeroQ(int a, int b, int c, int d, int e, int f) {
296 // nb: works for 2*integers ONLY
297 // check triangle consitions
298 // Note: there are some 6j symbols that pass this test, though are still zero
299 // GSL calculates these to have extremely small (but non-zero) value
300 if (triangle(a, b, c) == 0)
301 return true;
302 if (triangle(c, d, e) == 0)
303 return true;
304 if (triangle(b, d, f) == 0)
305 return true;
306 if (triangle(e, f, a) == 0)
307 return true;
308 if (!evenQ(a + b + c))
309 return true;
310 if (!evenQ(c + d + e))
311 return true;
312 if (!evenQ(b + d + f))
313 return true;
314 if (!evenQ(e + f + a))
315 return true;
316 return false;
317}
318
319//! Checks if a 6j symbol is valid - each input is optional
320//! @details i.e., sixjTriads(a,b,c,{},{},{}) will check if _any_ 6J symbol of
321//! form {a b c \ * * *} is valid (* can be any value)
322inline bool sixjTriads(std::optional<int> a, std::optional<int> b,
323 std::optional<int> c, std::optional<int> d,
324 std::optional<int> e, std::optional<int> f) {
325 // nb: works for 2*integers ONLY
326 // checks triangle consitions, with optional parameters
327 if (a && b && c && triangle(*a, *b, *c) == 0)
328 return false;
329 if (c && d && e && triangle(*c, *d, *e) == 0)
330 return false;
331 if (a && e && f && triangle(*a, *e, *f) == 0)
332 return false;
333 if (b && d && f && triangle(*b, *d, *f) == 0)
334 return false;
335
336 return true;
337}
338
339//==============================================================================
340//! 6j symbol {j1 j2 j3 \\ j4 j5 j6} - [takes 2*j as int]
341inline double sixj_2(int two_j1, int two_j2, int two_j3, int two_j4, int two_j5,
342 int two_j6)
343// Calculates wigner 6j symbol:
344// {j1 j2 j3}
345// {j4 j5 j6}
346// Note: this function takes INTEGER values, that have already multiplied by 2!
347// Works for l and j (integer and half-integer)
348{
349 if (sixj_zeroQ(two_j1, two_j2, two_j3, two_j4, two_j5, two_j6))
350 return 0.0;
351 return gsl_sf_coupling_6j(two_j1, two_j2, two_j3, two_j4, two_j5, two_j6);
352}
353
354//------------------------------------------------------------------------------
355//! 9j symbol {j1 j2 j3 \\ j4 j5 j6 \\ j7 j8 j9} [takes 2*j as int]
356inline double ninej_2(int two_j1, int two_j2, int two_j3, int two_j4,
357 int two_j5, int two_j6, int two_j7, int two_j8,
358 int two_j9)
359// Calculates wigner 9j symbol:
360// {j1 j2 j3}
361// {j4 j5 j6}
362// {j7 j8 j9}
363// Note: this function takes INTEGER values, that have already multiplied by 2!
364// Works for l and j (integer and half-integer)
365{
366 return gsl_sf_coupling_9j(two_j1, two_j2, two_j3, two_j4, two_j5, two_j6,
367 two_j7, two_j8, two_j9);
368}
369
370//==============================================================================
371//! Reduced (relativistic) angular ME: <ka||C^k||kb> [takes k and kappa]
372inline double Ck_kk(int k, int ka, int kb)
373// Reduced (relativistic) angular ME:
374// <ka||C^k||kb> = (-1)^(ja+1/2) * srt([ja][jb]) * 3js(ja jb k, -1/2 1/2 0) * Pi
375// Note: takes in kappa! (not j!)
376{
377 if (parity(l_k(ka), l_k(kb), k) == 0) {
378 return 0.0;
379 }
380 auto two_ja = twoj_k(ka);
381 auto two_jb = twoj_k(kb);
382 // auto sign = ((two_ja + 1) / 2 % 2 == 0) ? 1 : -1;
383 auto sign = evenQ_2(two_ja + 1) ? 1 : -1;
384 auto f = std::sqrt((two_ja + 1) * (two_jb + 1));
385 auto g = special_threej_2(two_ja, two_jb, 2 * k);
386 return sign * f * g;
387}
388
389//! Full C^k_q matrix element - rarely used
390inline double Ck_kk_mmq(int k, int ka, int kb, int twoma, int twomb, int twoq) {
391 const auto tja = twoj_k(ka);
392 const auto tjb = twoj_k(kb);
393 return neg1pow_2(tja - twoma) *
394 threej_2(tja, 2 * k, tjb, -twoma, twoq, twomb) * Ck_kk(k, ka, kb);
395}
396
397//! Ck selection rule only. Returns false if C^k=0, true if non-zero.
398inline bool Ck_kk_SR(int k, int ka, int kb) {
399 if (parity(l_k(ka), l_k(kb), k) == 0)
400 return false;
401 if (triangle(twoj_k(ka), twoj_k(kb), 2 * k) == 0)
402 return false;
403 return true;
404}
405
406//! tildeCk_kk = (-1)^{ja+1/2}*Ck_kk
407inline double tildeCk_kk(int k, int ka, int kb) {
408 // tildeCk_kk = (-1)^{ja+1/2}*Ck_kk
409 auto m1tjph = evenQ_2(twoj_k(ka) + 1) ? 1 : -1;
410 return m1tjph * Ck_kk(k, ka, kb);
411}
412
413//! Returns [k_min, k_kmax] for C^k (min/max non-zero k, given kappa_a, kappa_b)
414//! Accounts for parity
415inline std::pair<int, int> kminmax_Ck(int ka, int kb) {
416 // j = |k|-0.5
417 // kmin = |ja-jb| = | |ka| - |kb| |
418 // kmax = ja+jb = |ka| + |kb| - 1
419 const auto aka = std::abs(ka);
420 const auto akb = std::abs(kb);
421
422 auto kmin = std::abs(aka - akb);
423 auto kmax = aka + akb - 1;
424 // account for parity
425 if (parity(l_k(ka), l_k(kb), kmin) == 0)
426 ++kmin;
427 if (parity(l_k(ka), l_k(kb), kmax) == 0)
428 --kmax;
429
430 return {kmin, kmax};
431}
432
433//==============================================================================
434//! @brief Reduced spin angular ME: (for spin 1/2): <ka||S||kb>
435/*! @details
436 Reduced spin angular ME: (for spin 1/2!)
437 <ka||S||kb> = d(la,lb) * (-1)^{ja+la+3/2} * Sqrt([ja][jb](3/2)) *
438 * sjs{ja, 1, jb, 1/2, la, 1/2}
439 Special 6j case:
440 sjs{ja, 1, jb, 1/2, la, 1/2}
441 = 0.5 (-1)^{ka+kb} * Sqrt(abs[{(ka-1)^2 - kb^2}/{3ka(1+2ka)}])
442 * triangle rule for j!
443 At least ~least 20% faster
444*/
445inline double S_kk(int ka, int kb) {
446 auto la = l_k(ka);
447 if (la != l_k(kb))
448 return 0.0;
449 auto tja = twoj_k(ka);
450 auto tjb = twoj_k(kb);
451 if (triangle(tja, 2, tjb) == 0)
452 return 0;
453 auto sign = (((tja + 2 * la + 3) / 2) % 2 == 0) ? 1 : -1;
454 auto f = std::sqrt((tja + 1) * (tjb + 1) * 1.5);
455 // auto sixj = gsl_sf_coupling_6j(tja, 2, tjb, 1, 2 * la, 1);
456 auto sixj_sign = ((ka + kb) % 2 == 0) ? 1.0 : -1.0;
457 auto sixj = 0.5 * sixj_sign *
458 std::sqrt(std::fabs(((ka - 1) * (ka - 1) - kb * kb) /
459 (3.0 * ka * (1.0 + 2.0 * ka))));
460 return sign * f * sixj;
461}
462
463} // namespace Angular
Angular provides functions and classes for calculating and storing angular factors (3,...
Definition CkTable.cpp:7
constexpr std::uint64_t kappa_to_kindex(int ka)
returns kappa_index, given kappa
Definition Wigner369j.hpp:98
constexpr bool zeroQ(double x, double eps=1.0e-10)
Checks if a double is within eps of 0.0 [eps=1.0e-10 by default].
Definition Wigner369j.hpp:67
constexpr std::uint64_t nk_to_index(int n, int k)
Returns nk_index, given {n, kappa}.
Definition Wigner369j.hpp:172
constexpr int kindex_to_kappa(std::uint64_t i)
Returns kappa, given kappa_index.
Definition Wigner369j.hpp:104
std::pair< int, int > index_to_nk(std::uint64_t nk_index)
Returns {n, kappa} given nk_index.
Definition Wigner369j.hpp:178
std::pair< int, int > kminmax_Ck(int ka, int kb)
Returns [k_min, k_kmax] for C^k (min/max non-zero k, given kappa_a, kappa_b) Accounts for parity.
Definition Wigner369j.hpp:415
double Ck_kk_mmq(int k, int ka, int kb, int twoma, int twomb, int twoq)
Full C^k_q matrix element - rarely used.
Definition Wigner369j.hpp:390
double threej_2(int two_j1, int two_j2, int two_j3, int two_m1, int two_m2, int two_m3)
Calculates wigner 3j symbol. Takes in 2*j (or 2*l) - intput is integer.
Definition Wigner369j.hpp:251
double cg_2(int two_j1, int two_m1, int two_j2, int two_m2, int two_J, int two_M)
Clebsh-Gordon coeficient <j1 m1, j2 m2 | J M> [takes 2*j, as int].
Definition Wigner369j.hpp:276
double sixj_2(int two_j1, int two_j2, int two_j3, int two_j4, int two_j5, int two_j6)
6j symbol {j1 j2 j3 \ j4 j5 j6} - [takes 2*j as int]
Definition Wigner369j.hpp:341
int nkindex_to_kappa(std::uint64_t nk_index)
Returns kappa, given nk_index.
Definition Wigner369j.hpp:196
constexpr int neg1pow(int a)
Evaluates (-1)^{a} (for integer a)
Definition Wigner369j.hpp:224
std::pair< int, std::uint64_t > nkindex_to_n_kindex(std::uint64_t nk_index)
Returns {n, kappa_index} given nk_index.
Definition Wigner369j.hpp:188
constexpr int kappa_twojl(int twoj, int l)
returns kappa, given 2j and l
Definition Wigner369j.hpp:56
int nkindex_to_twoj(std::uint64_t nk_index)
Returns 2*j, given nk_index.
Definition Wigner369j.hpp:204
double tildeCk_kk(int k, int ka, int kb)
tildeCk_kk = (-1)^{ja+1/2}*Ck_kk
Definition Wigner369j.hpp:407
double S_kk(int ka, int kb)
Reduced spin angular ME: (for spin 1/2): <ka||S||kb>
Definition Wigner369j.hpp:445
constexpr int sumsToZero(int m1, int m2, int m3)
Checks if three ints sum to zero, returns 1 if they do.
Definition Wigner369j.hpp:241
constexpr int l_k(int ka)
returns l given kappa
Definition Wigner369j.hpp:44
constexpr std::uint64_t states_below_n(int n)
Returns number of possible states below given n (i.e., n' < n)
Definition Wigner369j.hpp:132
constexpr int parity_l(int l)
returns parity [(-1)^l] given l
Definition Wigner369j.hpp:52
constexpr bool evenQ_2(int two_a)
Returns true if a (an int) is even, given 2*a (true if two_a/2 is even)
Definition Wigner369j.hpp:222
constexpr int kappa_twojpi(const int twoj, const int pi)
returns kappa, given 2*j and parity (+/-1),
Definition Wigner369j.hpp:60
double special_threej_2(int two_j1, int two_j2, int two_k)
Special (common) 3js case: (j1 j2 k, -0.5, 0.5, 0)
Definition Wigner369j.hpp:264
bool Ck_kk_SR(int k, int ka, int kb)
Ck selection rule only. Returns false if C^k=0, true if non-zero.
Definition Wigner369j.hpp:398
constexpr int l_tilde_k(int ka)
"Complimentary" l := (2j-l) = l+/-1, for j=l+/-1/2
Definition Wigner369j.hpp:54
constexpr int kindex_to_twoj(std::uint64_t i)
returns 2j, given kappa_index
Definition Wigner369j.hpp:110
constexpr int kindex_to_l(std::uint64_t i)
returns l, given kappa_index
Definition Wigner369j.hpp:116
constexpr int neg1pow_2(int two_a)
Evaluates (-1)^{two_a/2} (for integer a; two_a is even)
Definition Wigner369j.hpp:226
constexpr int parity(int la, int lb, int k)
Parity rule. Returns 1 only if la+lb+k is even.
Definition Wigner369j.hpp:230
constexpr int parity_k(int ka)
returns parity [(-1)^l] given kappa
Definition Wigner369j.hpp:48
bool sixj_zeroQ(int a, int b, int c, int d, int e, int f)
Checks triangle conditions for 6j symbols (for 2*j)
Definition Wigner369j.hpp:295
constexpr int triangle(int j1, int j2, int J)
Returns 1 if triangle rule is satisfied. nb: works with j OR twoj!
Definition Wigner369j.hpp:236
double ninej_2(int two_j1, int two_j2, int two_j3, int two_j4, int two_j5, int two_j6, int two_j7, int two_j8, int two_j9)
9j symbol {j1 j2 j3 \ j4 j5 j6 \ j7 j8 j9} [takes 2*j as int]
Definition Wigner369j.hpp:356
int nkindex_to_l(std::uint64_t nk_index)
Returns l, given nk_index.
Definition Wigner369j.hpp:212
bool sixjTriads(std::optional< int > a, std::optional< int > b, std::optional< int > c, std::optional< int > d, std::optional< int > e, std::optional< int > f)
Checks if a 6j symbol is valid - each input is optional.
Definition Wigner369j.hpp:322
constexpr int twoj_k(int ka)
returns 2j given kappa
Definition Wigner369j.hpp:46
constexpr bool evenQ(int a)
Returns true if a is even - for integer values.
Definition Wigner369j.hpp:220
double Ck_kk(int k, int ka, int kb)
Reduced (relativistic) angular ME: <ka||C^k||kb> [takes k and kappa].
Definition Wigner369j.hpp:372