2#include "Angular/Wigner369j.hpp"
3#include "Wavefunction/DiracSpinor.hpp"
11#ifdef SIXJ_USE_STD_MAP
12#include <unordered_map>
14#include "ankerl/unordered_dense.h"
25#ifdef SIXJ_USE_STD_MAP
26using SixJMap = std::unordered_map<uint64_t, double>;
28using SixJMap = ankerl::unordered_dense::map<uint64_t, double>;
35 if constexpr (std::is_same_v<A, DiracSpinor>) {
37 }
else if constexpr (std::is_same_v<A, int>) {
40 static_assert(std::is_same_v<A, std::size_t>);
41 return 2 *
static_cast<int>(a);
53template <
class A,
class B,
class C,
class D,
class E,
class F>
54double SixJ(
const A &a,
const B &b,
const C &c,
const D &d,
const E &e,
86 static auto s(
int i) {
return static_cast<uint8_t
>(i); };
105 std::size_t
size()
const {
return m_data.size(); }
114 inline double get_2(
int a,
int b,
int c,
int d,
int e,
int f)
const {
117 const auto it = m_data.find(normal_order(a, b, c, d, e, f));
118 return (it == m_data.cend()) ? 0.0 : it->second;
129 template <
class A,
class B,
class C,
class D,
class E,
class F>
130 double get(
const A &a,
const B &b,
const C &c,
const D &d,
const E &e,
137 bool contains(
int a,
int b,
int c,
int d,
int e,
int f)
const {
138 const auto it = m_data.find(normal_order(a, b, c, d, e, f));
139 return (it != m_data.cend());
152 if (max_2j_k <= m_max_2j_k)
159 const auto max_2k = 2 * max_2j_k;
160 for (
int a = 0; a <= max_2k; ++a) {
162 for (
int b = a0; b <= max_2k; ++b) {
163 for (
int c = b; c <= max_2k; ++c) {
164 for (
int d = a0; d <= max_2k; ++d) {
165 for (
int e = b; e <= max_2k; ++e) {
166 for (
int f = b; f <= max_2k; ++f) {
172 if (std::abs(sj) > 1.0e-16) {
173 m_data[normal_order(a, b, c, d, e, f)] = sj;
183 m_max_2j_k = max_2j_k;
188 inline static auto make_key(uint8_t a, uint8_t b, uint8_t c, uint8_t d,
189 uint8_t e, uint8_t f) {
190 static_assert(
sizeof(uint64_t) >= 6 *
sizeof(uint8_t));
192 const auto pk =
reinterpret_cast<uint8_t *
>(&key);
193 std::memcpy(pk, &a,
sizeof(uint8_t));
194 std::memcpy(pk + 1, &b,
sizeof(uint8_t));
195 std::memcpy(pk + 2, &c,
sizeof(uint8_t));
196 std::memcpy(pk + 3, &d,
sizeof(uint8_t));
197 std::memcpy(pk + 4, &e,
sizeof(uint8_t));
198 std::memcpy(pk + 5, &f,
sizeof(uint8_t));
201 inline static auto make_key(
int a,
int b,
int c,
int d,
int e,
int f) {
202 return make_key(s(a), s(b), s(c), s(d), s(e), s(f));
206 inline static auto normal_order_level2(
int a,
int b,
int c,
int d,
int e,
211 const auto min_bcef = std::min({b,
c, e,
f});
214 return make_key(s(a), s(b), s(c), s(d), s(e), s(f));
215 }
else if (min_bcef == c) {
216 return make_key(s(a), s(c), s(b), s(d), s(f), s(e));
217 }
else if (min_bcef == e) {
218 return make_key(s(a), s(e), s(f), s(d), s(b), s(c));
219 }
else if (min_bcef == f) {
220 return make_key(s(a), s(f), s(e), s(d), s(c), s(b));
222 assert(
false &&
"Fatal error 170: unreachable");
226 static uint64_t normal_order(
int a,
int b,
int c,
int d,
int e,
int f) {
264 const auto min = std::min({a, b,
c, d, e,
f});
270 return normal_order_level2(a, b, c, d, e, f);
271 }
else if (min == b) {
272 return normal_order_level2(b, a, c, e, d, f);
273 }
else if (min == c) {
274 return normal_order_level2(c, a, b, f, d, e);
275 }
else if (min == d) {
276 return normal_order_level2(d, e, c, a, b, f);
277 }
else if (min == e) {
278 return normal_order_level2(e, d, c, b, a, f);
279 }
else if (min == f) {
280 return normal_order_level2(f, a, e, c, d, b);
282 assert(
false &&
"Fatal error 193: unreachable");
Lookup table for Wigner 6j symbols.
Definition SixJTable.hpp:82
int max_2jk() const
Returns the maximum 2j (or k) currently stored; max(k) = 2*max(j).
Definition SixJTable.hpp:102
bool contains(int a, int b, int c, int d, int e, int f) const
Returns true if the symbol is present in the table (absent symbols may be zero or simply out of range...
Definition SixJTable.hpp:137
void fill(int max_2j_k)
Extends the table to cover all symbols up to max_2j_k.
Definition SixJTable.hpp:150
SixJTable()=default
Constructs an empty table; extend later with fill() or get().
std::size_t size() const
Returns the number of non-zero symbols stored in the table.
Definition SixJTable.hpp:105
double get_2(int a, int b, int c, int d, int e, int f) const
Returns 6j symbol {a/2, b/2, c/2; d/2, e/2, f/2}.
Definition SixJTable.hpp:114
double get(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f) const
"Magic" table lookup: pass integers (for k) or DiracSpinors (for j).
Definition SixJTable.hpp:130
SixJTable(int max_2j_k)
Constructs the table, pre-filling all symbols up to max_2j_k.
Definition SixJTable.hpp:99
Angular provides functions and classes for calculating and storing angular factors (3,...
Definition CkTable.cpp:7
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
ankerl::unordered_dense::map< uint64_t, double > SixJMap
Hashmap type used to store 6j symbols.
Definition SixJTable.hpp:28
int twojk(const A &a)
Returns 2*k if a is an integer, or 2*j if a is a DiracSpinor.
Definition SixJTable.hpp:34
double SixJ(const A &a, const B &b, const C &c, const D &d, const E &e, const F &f)
"Magic" 6j symbol accepting integers or DiracSpinors.
Definition SixJTable.hpp:54
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
double f(double r, double en, int kappa, double zeff, double alpha, double m)
Upper (large) radial component.
Definition DiracContinuum.cpp:147
constexpr double c
speed of light in a.u. (=1/alpha)
Definition PhysConst_constants.hpp:63
T min(T first, Args... rest)
Returns the minimum of any number of parameters (variadic).
Definition Maths.hpp:41