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#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 @brief Maximum kappa index for a given orbital angular momentum l.
122
123 @param l Orbital angular momentum quantum number
124 @return Kappa index of the state with maximum (larger) j
125
126 @see Angular::kappa_to_kindex()
127*/
128constexpr std::uint64_t l_to_max_kindex(int l) {
129 return (l == 0) ? 0 : std::uint64_t(2 * l);
130}
131
132//==============================================================================
133/*!
134 @brief Returns number of possible states _below_ given n (i.e., n' < n)
135 @details
136
137 This could be made more "compact" with a maximum l.
138 In practice, we go to large n, but never very large l.
139
140 @warning
141 - n must be >1 (no non-standard states)
142
143 Cannot overflow; converts to std::uint64_t.
144*/
145constexpr std::uint64_t states_below_n(int n) {
146 const std::uint64_t nn = static_cast<std::uint64_t>(n);
147 return nn * nn - 2 * nn + 1;
148}
149
150//! @brief Returns nk_index, given {n, kappa}
151/*! @details
152 For convenient array access we define a one-to-one mapping between the pair
153 \f$(n,\kappa)\f$ and a non-negative index:
154
155 \f[
156 i_{nk}(n,\kappa) = (n-1)^2 + i_k(\kappa),
157 \f]
158
159 where \f$i_k(\kappa)\f$ is the kappa index defined by \ref Angular::kappa_to_kindex()
160
161 Equivalently,
162
163 \f[
164 i_{nk}(n,\kappa) = n^2 - 2n + 1 + i_k(\kappa).
165 \f]
166
167 Since
168
169 \f[
170 n^2 - 2n + 1 = (n-1)^2 = \texttt{states\_below\_n}(n),
171 \f]
172
173 this counts the number of states with principal quantum number \f$n' < n\f$,
174 plus the index within the \f$n\f$ shell.
175
176 @note This indexing is only valid for physical bound-state quantum numbers, n >= 1,
177 and cannot in general be used for arbitrary basis states.
178
179 @warning To safely convert the returned index (`uint64_t`) to `int`, one must
180 have `n <= 46340`.
181
182 @warning To safely convert the returned index to \ref Coulomb::nkIndex
183 (`uint16_t`), one must have `n <= 256`.
184*/
185constexpr std::uint64_t nk_to_index(int n, int k) {
187}
188
189//! Returns {n, kappa} given nk_index
190//! @details Inverse of \ref Angular::nk_to_index().
191inline std::pair<int, int> index_to_nk(std::uint64_t nk_index) {
192 // Better way? isqrt?
193 const auto n = 1 + int(std::sqrt(nk_index));
194 const auto kappa_index = nk_index - states_below_n(n);
195 return {n, Angular::kindex_to_kappa(kappa_index)};
196}
197
198//! Returns {n, kappa_index} given nk_index
199//! @details Inverse of \ref Angular::nk_to_index().
200inline std::pair<int, std::uint64_t>
201nkindex_to_n_kindex(std::uint64_t nk_index) {
202 const auto n = 1 + int(std::sqrt(nk_index));
203 const auto kappa_index = nk_index - states_below_n(n);
204 return {n, kappa_index};
205}
206
207//! Returns kappa, given nk_index
208//! @details See \ref Angular::nk_to_index().
209inline int nkindex_to_kappa(std::uint64_t nk_index) {
210 const auto n = 1 + int(std::sqrt(nk_index));
211 const auto kappa_index = nk_index - states_below_n(n);
212 return kindex_to_kappa(kappa_index);
213}
214
215//! Returns 2*j, given nk_index
216//! @details See \ref Angular::nk_to_index().
217inline int nkindex_to_twoj(std::uint64_t nk_index) {
218 const auto n = 1 + int(std::sqrt(nk_index));
219 const auto kappa_index = nk_index - states_below_n(n);
220 return kindex_to_twoj(kappa_index);
221}
222
223//! Returns l, given nk_index
224//! @details See \ref Angular::nk_to_index().
225inline int nkindex_to_l(std::uint64_t nk_index) {
226 const auto n = 1 + int(std::sqrt(double(nk_index) + 0.01));
227 const auto kappa_index = nk_index - states_below_n(n);
228 return l_k(kindex_to_kappa(kappa_index));
229}
230
231//==============================================================================
232//! Returns true if a is even - for integer values
233constexpr bool evenQ(int a) { return (a % 2 == 0); }
234//! Returns true if a (an int) is even, given 2*a (true if two_a/2 is even)
235constexpr bool evenQ_2(int two_a) { return (two_a % 4 == 0); }
236//! Evaluates (-1)^{a} (for integer a)
237constexpr int neg1pow(int a) { return evenQ(a) ? 1 : -1; }
238//! Evaluates (-1)^{two_a/2} (for integer a; two_a is even)
239constexpr int neg1pow_2(int two_a) { return evenQ_2(two_a) ? 1 : -1; }
240
241//==============================================================================
242//! Parity rule. Returns 1 only if la+lb+k is even
243constexpr int parity(int la, int lb, int k) {
244 return evenQ(la + lb + k) ? 1 : 0;
245}
246
247//==============================================================================
248//! Returns 1 if triangle rule is satisfied. nb: works with j OR twoj!
249constexpr int triangle(int j1, int j2, int J) {
250 // nb: can be called with wither j or twoj!
251 return ((j1 + j2 < J) || (std::abs(j1 - j2) > J)) ? 0 : 1;
252}
253//! Checks if three ints sum to zero, returns 1 if they do
254constexpr int sumsToZero(int m1, int m2, int m3) {
255 return (m1 + m2 + m3 != 0) ? 0 : 1;
256}
257
258//==============================================================================
259/*!
260 @brief Wigner 3j symbol. Inputs are 2*j (or 2*l) as integers.
261 @details
262 Computes the Wigner 3j symbol:
263 \f[
264 \begin{pmatrix} j_1 & j_2 & j_3 \\ m_1 & m_2 & m_3 \end{pmatrix}
265 \f]
266 Returns zero if the triangle rule or \f$ m_1+m_2+m_3=0 \f$ is not satisfied.
267 Wraps \c gsl_sf_coupling_3j.
268
269 @param two_j1 2*j1
270 @param two_j2 2*j2
271 @param two_j3 2*j3
272 @param two_m1 2*m1
273 @param two_m2 2*m2
274 @param two_m3 2*m3
275 @return Value of the 3j symbol; 0 if selection rules are not met.
276*/
277inline double threej_2(int two_j1, int two_j2, int two_j3, int two_m1,
278 int two_m2, int two_m3) {
279 if (triangle(two_j1, two_j2, two_j3) * sumsToZero(two_m1, two_m2, two_m3) ==
280 0)
281 return 0;
282 return gsl_sf_coupling_3j(two_j1, two_j2, two_j3, two_m1, two_m2, two_m3);
283}
284
285//==============================================================================
286/*!
287 @brief Special 3j symbol: (j1 j2 k; -1/2 1/2 0). Inputs are 2*j as integers.
288 @details
289 Evaluates the commonly occurring 3j symbol:
290 \f[
291 \begin{pmatrix} j_1 & j_2 & k \\ -\tfrac{1}{2} & \tfrac{1}{2} & 0 \end{pmatrix}
292 \f]
293 Handles the \f$ k=0 \f$ case analytically; otherwise wraps \c gsl_sf_coupling_3j.
294 Returns zero if the triangle rule is not satisfied.
295
296 @param two_j1 2*j1
297 @param two_j2 2*j2
298 @param two_k 2*k
299 @return Value of the 3j symbol; 0 if selection rules are not met.
300*/
301inline double special_threej_2(int two_j1, int two_j2, int two_k) {
302 if (triangle(two_j1, two_j2, two_k) == 0)
303 return 0.0;
304 if (two_k == 0) {
305 auto s = evenQ_2(two_j1 + 1) ? 1.0 : -1.0;
306 return s / std::sqrt(two_j1 + 1);
307 }
308 return gsl_sf_coupling_3j(two_j1, two_j2, two_k, -1, 1, 0);
309}
310
311//==============================================================================
312/*!
313 @brief Clebsch-Gordon coefficient <j1 m1, j2 m2 | J M>. Takes 2*j as integers.
314 @details
315 Computes the Clebsch-Gordon coefficient:
316 \f[
317 \langle j_1 m_1,\, j_2 m_2 \,|\, J M \rangle
318 = (-1)^{j_1-j_2+M}\sqrt{2J+1}
319 \begin{pmatrix} j_1 & j_2 & J \\ m_1 & m_2 & -M \end{pmatrix}
320 \f]
321 Returns zero if the triangle rule or \f$ m_1+m_2=M \f$ is not satisfied.
322
323 @param two_j1 2*j1
324 @param two_m1 2*m1
325 @param two_j2 2*j2
326 @param two_m2 2*m2
327 @param two_J 2*J
328 @param two_M 2*M
329 @return Value of the CG coefficient; 0 if selection rules are not met.
330*/
331inline double cg_2(int two_j1, int two_m1, int two_j2, int two_m2, int two_J,
332 int two_M) {
333 if (triangle(two_j1, two_j2, two_J) * sumsToZero(two_m1, two_m2, -two_M) == 0)
334 return 0;
335 int sign = -1;
336 if ((two_j1 - two_j2 + two_M) % 4 == 0)
337 sign = 1; // mod 4 (instead 2), since x2
338 return sign * std::sqrt(two_J + 1.) *
339 gsl_sf_coupling_3j(two_j1, two_j2, two_J, two_m1, two_m2, -two_M);
340}
341
342//==============================================================================
343/*!
344 @brief Returns true if the 6j symbol is zero by triangle/parity rules. Inputs are 2*j.
345 @details
346 Checks all four triangle triads and integer-sum (parity) conditions for:
347 \f[
348 \sixj{a}{b}{c}{d}{e}{f}
349 \f]
350 The triads (abc), (cde), (bdf), (efa) must each satisfy the triangle rule
351 and sum to an even integer (inputs are 2*j).
352
353 @note Some symbols that pass these checks are still numerically zero.
354 GSL may return a very small non-zero value in such cases.
355 @warning Only valid for inputs that are 2*(integer or half-integer).
356*/
357inline bool sixj_zeroQ(int a, int b, int c, int d, int e, int f) {
358 if (triangle(a, b, c) == 0)
359 return true;
360 if (triangle(c, d, e) == 0)
361 return true;
362 if (triangle(b, d, f) == 0)
363 return true;
364 if (triangle(e, f, a) == 0)
365 return true;
366 if (!evenQ(a + b + c))
367 return true;
368 if (!evenQ(c + d + e))
369 return true;
370 if (!evenQ(b + d + f))
371 return true;
372 if (!evenQ(e + f + a))
373 return true;
374 return false;
375}
376
377/*!
378 @brief Checks 6j triangle conditions with optional arguments (wildcards). Inputs are 2*j.
379 @details
380 Checks only the triads formed by the provided (non-null) arguments.
381 Missing (empty) optionals act as wildcards.
382 For example, \c sixjTriads(a,b,c,{},{},{}) checks whether any 6j symbol
383 \f$ \{ a\, b\, c \;|\; *\, *\, * \} \f$ could be non-zero.
384
385 The four triads of \f$ \{a\,b\,c\;|\;d\,e\,f\} \f$ are: (abc), (cde), (aef), (bdf).
386
387 @param a 2*j1 (optional)
388 @param b 2*j2 (optional)
389 @param c 2*j3 (optional)
390 @param d 2*j4 (optional)
391 @param e 2*j5 (optional)
392 @param f 2*j6 (optional)
393 @return false if any complete triad fails the triangle rule; true otherwise.
394*/
395inline bool sixjTriads(std::optional<int> a, std::optional<int> b,
396 std::optional<int> c, std::optional<int> d,
397 std::optional<int> e, std::optional<int> f) {
398 // nb: works for 2*integers ONLY
399 // checks triangle consitions, with optional parameters
400 if (a && b && c && triangle(*a, *b, *c) == 0)
401 return false;
402 if (c && d && e && triangle(*c, *d, *e) == 0)
403 return false;
404 if (a && e && f && triangle(*a, *e, *f) == 0)
405 return false;
406 if (b && d && f && triangle(*b, *d, *f) == 0)
407 return false;
408
409 return true;
410}
411
412//==============================================================================
413/*!
414 @brief Wigner 6j symbol {j1 j2 j3 | j4 j5 j6}. Inputs are 2*j as integers.
415 @details
416 Computes the Wigner 6j symbol:
417 \f[
418 \sixj{j_1}{j_2}{j_3}{j_4}{j_5}{j_6}
419 \f]
420 Returns zero if any triangle or parity condition is violated (via \ref sixj_zeroQ).
421 Wraps \c gsl_sf_coupling_6j.
422
423 @param two_j1 2*j1
424 @param two_j2 2*j2
425 @param two_j3 2*j3
426 @param two_j4 2*j4
427 @param two_j5 2*j5
428 @param two_j6 2*j6
429 @return Value of the 6j symbol; 0 if selection rules are not met.
430*/
431inline double sixj_2(int two_j1, int two_j2, int two_j3, int two_j4, int two_j5,
432 int two_j6) {
433 if (sixj_zeroQ(two_j1, two_j2, two_j3, two_j4, two_j5, two_j6))
434 return 0.0;
435 return gsl_sf_coupling_6j(two_j1, two_j2, two_j3, two_j4, two_j5, two_j6);
436}
437
438//------------------------------------------------------------------------------
439/*!
440 @brief Wigner 9j symbol. Inputs are 2*j as integers.
441 @details
442 Computes the Wigner 9j symbol:
443 \f[
444 \begin{Bmatrix} j_1 & j_2 & j_3 \\ j_4 & j_5 & j_6 \\ j_7 & j_8 & j_9 \end{Bmatrix}
445 \f]
446 Wraps \c gsl_sf_coupling_9j.
447
448 @param two_j1 2*j1
449 @param two_j2 2*j2
450 @param two_j3 2*j3
451 @param two_j4 2*j4
452 @param two_j5 2*j5
453 @param two_j6 2*j6
454 @param two_j7 2*j7
455 @param two_j8 2*j8
456 @param two_j9 2*j9
457 @return Value of the 9j symbol.
458*/
459inline double ninej_2(int two_j1, int two_j2, int two_j3, int two_j4,
460 int two_j5, int two_j6, int two_j7, int two_j8,
461 int two_j9) {
462 return gsl_sf_coupling_9j(two_j1, two_j2, two_j3, two_j4, two_j5, two_j6,
463 two_j7, two_j8, two_j9);
464}
465
466//==============================================================================
467/*!
468 @brief Reduced relativistic angular ME: <ka||C^k||kb>. Takes kappa values.
469 @details
470 Computes the reduced matrix element of the spherical tensor \f$ C^k \f$
471 between relativistic states labelled by Dirac quantum numbers:
472 \f[
473 \langle \kappa_a \| C^k \| \kappa_b \rangle
474 = (-1)^{j_a+\tfrac{1}{2}} \sqrt{[j_a][j_b]}
475 \begin{pmatrix} j_a & j_b & k \\ -\tfrac{1}{2} & \tfrac{1}{2} & 0 \end{pmatrix}
476 \pi(l_a+l_b+k),
477 \f]
478 where \f$ [j] \equiv 2j+1 \f$ and \f$ \pi(l_a+l_b+k) \f$ is 1 if \f$ l_a+l_b+k \f$
479 is even, 0 otherwise.
480
481 @param k Multipole rank.
482 @param ka Dirac quantum number \f$ \kappa_a \f$ (bra).
483 @param kb Dirac quantum number \f$ \kappa_b \f$ (ket).
484 @return \f$ \langle \kappa_a \| C^k \| \kappa_b \rangle \f$; 0 if selection rules are not met.
485*/
486inline double Ck_kk(int k, int ka, int kb) {
487 if (parity(l_k(ka), l_k(kb), k) == 0) {
488 return 0.0;
489 }
490 auto two_ja = twoj_k(ka);
491 auto two_jb = twoj_k(kb);
492 // auto sign = ((two_ja + 1) / 2 % 2 == 0) ? 1 : -1;
493 auto sign = evenQ_2(two_ja + 1) ? 1 : -1;
494 auto f = std::sqrt((two_ja + 1) * (two_jb + 1));
495 auto g = special_threej_2(two_ja, two_jb, 2 * k);
496 return sign * f * g;
497}
498
499/*!
500 @brief Full (non-reduced) C^k_q matrix element. Takes kappa and 2*m values.
501 @details
502 Computes the full matrix element including magnetic quantum numbers via
503 the Wigner-Eckart theorem:
504 \f[
505 \langle \kappa_a m_a | C^k_q | \kappa_b m_b \rangle
506 = (-1)^{j_a-m_a}
507 \begin{pmatrix} j_a & k & j_b \\ -m_a & q & m_b \end{pmatrix}
508 \langle \kappa_a \| C^k \| \kappa_b \rangle
509 \f]
510
511 @param k Multipole rank.
512 @param ka Dirac quantum number \f$ \kappa_a \f$ (bra).
513 @param kb Dirac quantum number \f$ \kappa_b \f$ (ket).
514 @param twoma 2*m_a
515 @param twomb 2*m_b
516 @param twoq 2*q
517 @return \f$ \langle \kappa_a m_a | C^k_q | \kappa_b m_b \rangle \f$
518*/
519inline double Ck_kk_mmq(int k, int ka, int kb, int twoma, int twomb, int twoq) {
520 const auto tja = twoj_k(ka);
521 const auto tjb = twoj_k(kb);
522 return neg1pow_2(tja - twoma) *
523 threej_2(tja, 2 * k, tjb, -twoma, twoq, twomb) * Ck_kk(k, ka, kb);
524}
525
526/*!
527 @brief Selection rule check for C^k: returns true if <ka||C^k||kb> may be non-zero.
528 @details
529 Checks parity and triangle conditions only; does not compute the value.
530 Equivalent to \c Ck_kk(k,ka,kb)!=0 but avoids the full computation.
531
532 @param k Multipole rank.
533 @param ka Dirac quantum number \f$ \kappa_a \f$.
534 @param kb Dirac quantum number \f$ \kappa_b \f$.
535 @return false if \f$ \langle \kappa_a \| C^k \| \kappa_b \rangle = 0 \f$ by selection rules; true otherwise.
536*/
537inline bool Ck_kk_SR(int k, int ka, int kb) {
538 if (parity(l_k(ka), l_k(kb), k) == 0)
539 return false;
540 if (triangle(twoj_k(ka), twoj_k(kb), 2 * k) == 0)
541 return false;
542 return true;
543}
544
545/*!
546 @brief Tilde variant of the C^k reduced ME: (-1)^{ja+1/2} * <ka||C^k||kb>
547 @details
548 Computes \f$ \widetilde{C}^k_{ab} \equiv (-1)^{j_a+1/2} \langle \kappa_a \| C^k \| \kappa_b \rangle \f$.
549 This removes the \f$ (-1)^{j_a+1/2} \f$ phase from \ref Ck_kk, leaving
550 the purely geometric 3j piece times \f$ \sqrt{[j_a][j_b]} \f$.
551
552 @param k Multipole rank.
553 @param ka Dirac quantum number \f$ \kappa_a \f$.
554 @param kb Dirac quantum number \f$ \kappa_b \f$.
555 @return \f$ \widetilde{C}^k_{ab} \f$
556*/
557inline double tildeCk_kk(int k, int ka, int kb) {
558 auto m1tjph = evenQ_2(twoj_k(ka) + 1) ? 1 : -1;
559 return m1tjph * Ck_kk(k, ka, kb);
560}
561
562/*!
563 @brief Min and max non-zero multipole rank k for C^k, given kappa_a and kappa_b.
564 @details
565 Returns \f$ (k_\text{min}, k_\text{max}) \f$ such that
566 \f$ \langle \kappa_a \| C^k \| \kappa_b \rangle \neq 0 \f$ only for
567 \f$ k_\text{min} \leq k \leq k_\text{max} \f$.
568 Steps are in increments of 2, enforced by parity.
569
570 Derived from:
571 \f[
572 k_\text{min} = |j_a - j_b|, \quad k_\text{max} = j_a + j_b,
573 \f]
574 then adjusted so that \f$ l_a + l_b + k \f$ is even.
575
576 @param ka Dirac quantum number \f$ \kappa_a \f$.
577 @param kb Dirac quantum number \f$ \kappa_b \f$.
578 @return \f$ \{k_\text{min},\, k_\text{max}\} \f$
579*/
580inline std::pair<int, int> kminmax_Ck(int ka, int kb) {
581 // j = |k|-0.5
582 // kmin = |ja-jb| = | |ka| - |kb| |
583 // kmax = ja+jb = |ka| + |kb| - 1
584 const auto aka = std::abs(ka);
585 const auto akb = std::abs(kb);
586
587 auto kmin = std::abs(aka - akb);
588 auto kmax = aka + akb - 1;
589 // account for parity
590 if (parity(l_k(ka), l_k(kb), kmin) == 0)
591 ++kmin;
592 if (parity(l_k(ka), l_k(kb), kmax) == 0)
593 --kmax;
594
595 return {kmin, kmax};
596}
597
598//==============================================================================
599/*!
600 @brief Reduced spin-1/2 angular ME: <ka||S||kb>. Takes kappa values.
601 @details
602 Computes the reduced matrix element of the spin operator \f$ \mathbf{S} \f$
603 (for spin-1/2) between relativistic states:
604 \f[
605 \langle \kappa_a \| S \| \kappa_b \rangle
606 = \delta_{l_a l_b} \, (-1)^{j_a+l_a+3/2} \sqrt{[j_a][j_b]\tfrac{3}{2}}
607 \sixj{j_a}{1}{j_b}{\tfrac{1}{2}}{l_a}{\tfrac{1}{2}}
608 \f]
609 The 6j symbol is evaluated analytically:
610 \f[
611 \sixj{j_a}{1}{j_b}{\tfrac{1}{2}}{l_a}{\tfrac{1}{2}}
612 = \frac{(-1)^{\kappa_a+\kappa_b}}{2}
613 \sqrt{\left|\frac{(\kappa_a-1)^2 - \kappa_b^2}{3\kappa_a(1+2\kappa_a)}\right|}
614 \f]
615 This special-case formula is ~20% faster than the general 6j routine.
616 Returns 0 if \f$ l_a \neq l_b \f$ or the triangle rule is violated.
617
618 @param ka Dirac quantum number \f$ \kappa_a \f$.
619 @param kb Dirac quantum number \f$ \kappa_b \f$.
620 @return \f$ \langle \kappa_a \| S \| \kappa_b \rangle \f$; 0 if selection rules are not met.
621*/
622inline double S_kk(int ka, int kb) {
623 auto la = l_k(ka);
624 if (la != l_k(kb))
625 return 0.0;
626 auto tja = twoj_k(ka);
627 auto tjb = twoj_k(kb);
628 if (triangle(tja, 2, tjb) == 0)
629 return 0;
630 auto sign = (((tja + 2 * la + 3) / 2) % 2 == 0) ? 1 : -1;
631 auto f = std::sqrt((tja + 1) * (tjb + 1) * 1.5);
632 // auto sixj = gsl_sf_coupling_6j(tja, 2, tjb, 1, 2 * la, 1);
633 auto sixj_sign = ((ka + kb) % 2 == 0) ? 1.0 : -1.0;
634 auto sixj = 0.5 * sixj_sign *
635 std::sqrt(std::fabs(((ka - 1) * (ka - 1) - kb * kb) /
636 (3.0 * ka * (1.0 + 2.0 * ka))));
637 return sign * f * sixj;
638}
639
640} // 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:185
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:191
std::pair< int, int > kminmax_Ck(int ka, int kb)
Min and max non-zero multipole rank k for C^k, given kappa_a and kappa_b.
Definition Wigner369j.hpp:580
constexpr std::uint64_t l_to_max_kindex(int l)
Maximum kappa index for a given orbital angular momentum l.
Definition Wigner369j.hpp:128
double Ck_kk_mmq(int k, int ka, int kb, int twoma, int twomb, int twoq)
Full (non-reduced) C^k_q matrix element. Takes kappa and 2*m values.
Definition Wigner369j.hpp:519
double threej_2(int two_j1, int two_j2, int two_j3, int two_m1, int two_m2, int two_m3)
Wigner 3j symbol. Inputs are 2*j (or 2*l) as integers.
Definition Wigner369j.hpp:277
double cg_2(int two_j1, int two_m1, int two_j2, int two_m2, int two_J, int two_M)
Clebsch-Gordon coefficient <j1 m1, j2 m2 | J M>. Takes 2*j as integers.
Definition Wigner369j.hpp:331
double sixj_2(int two_j1, int two_j2, int two_j3, int two_j4, int two_j5, int two_j6)
Wigner 6j symbol {j1 j2 j3 | j4 j5 j6}. Inputs are 2*j as integers.
Definition Wigner369j.hpp:431
int nkindex_to_kappa(std::uint64_t nk_index)
Returns kappa, given nk_index.
Definition Wigner369j.hpp:209
constexpr int neg1pow(int a)
Evaluates (-1)^{a} (for integer a)
Definition Wigner369j.hpp:237
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:201
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:217
double tildeCk_kk(int k, int ka, int kb)
Tilde variant of the C^k reduced ME: (-1)^{ja+1/2} * <ka||C^k||kb>
Definition Wigner369j.hpp:557
double S_kk(int ka, int kb)
Reduced spin-1/2 angular ME: <ka||S||kb>. Takes kappa values.
Definition Wigner369j.hpp:622
constexpr int sumsToZero(int m1, int m2, int m3)
Checks if three ints sum to zero, returns 1 if they do.
Definition Wigner369j.hpp:254
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:145
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:235
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 3j symbol: (j1 j2 k; -1/2 1/2 0). Inputs are 2*j as integers.
Definition Wigner369j.hpp:301
bool Ck_kk_SR(int k, int ka, int kb)
Selection rule check for C^k: returns true if <ka||C^k||kb> may be non-zero.
Definition Wigner369j.hpp:537
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:239
constexpr int parity(int la, int lb, int k)
Parity rule. Returns 1 only if la+lb+k is even.
Definition Wigner369j.hpp:243
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)
Returns true if the 6j symbol is zero by triangle/parity rules. Inputs are 2*j.
Definition Wigner369j.hpp:357
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:249
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)
Wigner 9j symbol. Inputs are 2*j as integers.
Definition Wigner369j.hpp:459
int nkindex_to_l(std::uint64_t nk_index)
Returns l, given nk_index.
Definition Wigner369j.hpp:225
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 6j triangle conditions with optional arguments (wildcards). Inputs are 2*j.
Definition Wigner369j.hpp:395
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:233
double Ck_kk(int k, int ka, int kb)
Reduced relativistic angular ME: <ka||C^k||kb>. Takes kappa values.
Definition Wigner369j.hpp:486