High-precision calculations for one- and two-valence atomic systems
CoulombIntegrals.hpp
1#pragma once
2#include "Angular/include.hpp"
3#include "Wavefunction/DiracSpinor.hpp"
4#include <algorithm>
5#include <cstdlib>
6#include <optional>
7#include <utility>
8#include <vector>
9
10//! Functions (+classes) for computing Coulomb integrals
11namespace Coulomb {
12
13//! Calculates Hartree Screening functions \f$y^k_{ab}(r)\f$
14//! @details maxi is max point to calculate; blank or zero means all the way
15std::vector<double> yk_ab(const int k, const DiracSpinor &Fa,
16 const DiracSpinor &Fb, const std::size_t maxi = 0);
17
18//! Overload: does not allocate ykab
19void yk_ab(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
20 std::vector<double> &ykab, const std::size_t maxi = 0);
21
22//==============================================================================
23
24//! Calculates R^k_abcd for given k. From scratch (calculates y)
25double Rk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
26 const DiracSpinor &Fc, const DiracSpinor &Fd);
27
28//! Overload for when y^k_bd already exists [much faster]
29double Rk_abcd(const DiracSpinor &Fa, const DiracSpinor &Fc,
30 const std::vector<double> &ykbd);
31
32//! "Right-hand-side" R^k{v}_bcd [i.e., without Fv integral]
33DiracSpinor Rkv_bcd(const int k, const int kappa_v, const DiracSpinor &Fb,
34 const DiracSpinor &Fc, const DiracSpinor &Fd);
35
36//! Overload for when y^k_bd already exists [much faster]
37DiracSpinor Rkv_bcd(const int kappa_v, const DiracSpinor &Fc,
38 const std::vector<double> &ykbd);
39
40//! Overload for when spinor exists. Rkv is overwritten
41void Rkv_bcd(DiracSpinor *const Rkv, const DiracSpinor &Fc,
42 const std::vector<double> &ykbd);
43
44//==============================================================================
45
46//! Calculates Q^k_abcd for given k. From scratch (calculates y) [see YkTable
47//! version if already have YkTable]
48double Qk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
49 const DiracSpinor &Fc, const DiracSpinor &Fd);
50
51//! Calculates Q^k(v)_bcd for given k,kappa_v. From scratch (calculates y) [see
52//! YkTable version if already have YkTable]
53DiracSpinor Qkv_bcd(const int k, int kappa_v, const DiracSpinor &Fb,
54 const DiracSpinor &Fc, const DiracSpinor &Fd);
55
56//==============================================================================
57//! Calculates g from scratch - not used often
58double g_abcd(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c,
59 const DiracSpinor &d, int tma, int tmb, int tmc, int tmd);
60
61//==============================================================================
62//! Just selection rule for Qk_abcd
63bool Qk_abcd_SR(int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
64 const DiracSpinor &Fc, const DiracSpinor &Fd);
65//! Just selection rule for Qk_abcd
66bool Qk_abcd_SR(int k, int ka, int kb, int kc, int kd);
67
68//! Just selection rule for Pk_abcd
69bool Pk_abcd_SR(int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
70 const DiracSpinor &Fc, const DiracSpinor &Fd);
71
72//! Just selection rule for Pk_abcd
73bool Pk_abcd_SR(int k, int ka, int kb, int kc, int kd);
74
75//==============================================================================
76
77//! Exchange only version of W (W-Q): W = Q + P [see Qk above]
78double Pk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
79 const DiracSpinor &Fc, const DiracSpinor &Fd);
80
81//! Exchange only version of W (W-Q): W = Q + P [see Qk above]
82DiracSpinor Pkv_bcd(const int k, int kappa_v, const DiracSpinor &Fb,
83 const DiracSpinor &Fc, const DiracSpinor &Fd);
84
85//==============================================================================
86
87//! Calculates W^k_abcd for given k. From scratch (calculates y)
88/*! @details
89 \f[ W^k_{abcd} = Q^k_{abcd} + \sum_l [k]
90 \begin{Bmatrix}a&c&k\\b&d&l\end{Bmatrix} * Q^l_{abdc} \f]
91 \f[ W^k_{abcd} = Q^k_{abcd} + P^k_{abcd} \f]
92 */
93double Wk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb,
94 const DiracSpinor &Fc, const DiracSpinor &Fd);
95
96DiracSpinor Wkv_bcd(const int k, int kappa_v, const DiracSpinor &Fb,
97 const DiracSpinor &Fc, const DiracSpinor &Fd);
98
99//==============================================================================
100
101//! Returns min and max k (multipolarity) allowed for Triangle(k,a,b),
102//! NOT accounting for parity (2j only, not kappa/l) (used by k_minmax_P,W)
103//! @details made inline - called very often
104inline std::pair<int, int> k_minmax_tj(int tja, int tjb) {
105 return std::make_pair(std::abs(tja - tjb) / 2, (tja + tjb) / 2);
106}
107
108//! Returns min and max k (multipolarity) allowed for C^k_ab, accounting for
109//! parity (used by k_minmax_Q)
110//! @details made inline - called very often
111inline std::pair<int, int> k_minmax_Ck(const DiracSpinor &a,
112 const DiracSpinor &b) {
113 auto minmax = k_minmax_tj(a.twoj(), b.twoj());
114 auto &min_k = minmax.first;
115 auto &max_k = minmax.second;
116 if ((a.l() + b.l() + min_k) % 2 != 0) {
117 ++min_k;
118 }
119 if ((a.l() + b.l() + max_k) % 2 != 0) {
120 --max_k;
121 }
122 return minmax;
123}
124//! Returns min and max k (multipolarity) allowed for C^k_ab, accounting for
125//! parity (used by k_minmax_Q)
126//! @details inline (header) - hot inner-loop helper.
127inline std::pair<int, int> k_minmax_Ck(int kappa_a, int kappa_b) {
128 auto minmax = k_minmax_tj(Angular::twoj_k(kappa_a), Angular::twoj_k(kappa_b));
129 auto &min_k = minmax.first;
130 auto &max_k = minmax.second;
131 const auto la = Angular::l_k(kappa_a);
132 const auto lb = Angular::l_k(kappa_b);
133 if ((la + lb + min_k) % 2 != 0) {
134 ++min_k;
135 }
136 if ((la + lb + max_k) % 2 != 0) {
137 --max_k;
138 }
139 return minmax;
140}
141
142//! Returns min and max k (multipolarity) allowed for Q^k_abcd.
143//! Parity rule is included, so you may safely call k+=2.
144//! Guaranteed to be non-zero *at* min and max, and every 2nd inbetween.
145//! @details made inline - called very often
146inline std::pair<int, int> k_minmax_Q(const DiracSpinor &a,
147 const DiracSpinor &b,
148 const DiracSpinor &c,
149 const DiracSpinor &d) {
150 // Determine if K needs to be even/odd (parity selection rule)
151 const auto k_even_ac = (a.l() + c.l()) % 2 == 0;
152 const auto k_even_bd = (b.l() + d.l()) % 2 == 0;
153 if (k_even_ac != k_even_bd) {
154 // no K satisfies selection rule!
155 return {1, 0};
156 }
157
158 // Find min/max k from triangle rule:
159 const auto [l1, u1] = k_minmax_Ck(a, c);
160 const auto [l2, u2] = k_minmax_Ck(b, d);
161 return {std::max(l1, l2), std::min(u1, u2)};
162}
163
164//! Returns min and max k (multipolarity) allowed for Q^k_abcd.
165//! Parity rule is included, so you may safely call k+=2.
166//! Guaranteed to be non-zero *at* min and max, and every 2nd inbetween.
167//! @details made inline - called very often
168inline std::pair<int, int> k_minmax_Q(int kap_a, int kap_b, int kap_c,
169 int kap_d) {
170 // Determine if K needs to be even/odd (parity selection rule)
171 const auto k_even_ac = (Angular::l_k(kap_a) + Angular::l_k(kap_c)) % 2 == 0;
172 const auto k_even_bd = (Angular::l_k(kap_b) + Angular::l_k(kap_d)) % 2 == 0;
173 if (k_even_ac != k_even_bd) {
174 // no K satisfies selection rule!
175 return {1, 0};
176 }
177
178 // Find min/max k from triangle rule:
179 const auto [l1, u1] = k_minmax_Ck(kap_a, kap_c);
180 const auto [l2, u2] = k_minmax_Ck(kap_b, kap_d);
181 return {std::max(l1, l2), std::min(u1, u2)};
182}
183
184//! Returns min and max k (multipolarity) allowed for P^k_abcd.
185//! DOES NOT contain parity rules (6j only) - so NOT safe to call k+=2.
186//! Guaranteed to be non-zero *at* min and max.
187std::pair<int, int> k_minmax_P(const DiracSpinor &a, const DiracSpinor &b,
188 const DiracSpinor &c, const DiracSpinor &d);
189
190//! Returns min and max k (multipolarity) allowed for W^k_abcd.
191//! DOES NOT contain parity rules (6j only) - so NOT safe to call k+=2.
192//! Cannot guarantee non-zero, since when a=b or c=d, sometimes have P=-Q.
193//! But when a!=b and c!=d, guaranteed to be non-zero *at* min and max.
194std::pair<int, int> k_minmax_W(const DiracSpinor &a, const DiracSpinor &b,
195 const DiracSpinor &c, const DiracSpinor &d);
196
197//==============================================================================
198
199//! Returns number of orbitals that are below Fermi level. Used for Qk selection
200int number_below_Fermi(const DiracSpinor &i, const DiracSpinor &j,
201 const DiracSpinor &k, const DiracSpinor &l,
202 double eFermi);
203
204//==============================================================================
205
206template <class A>
207static int twojk(const A &a) {
208 if constexpr (std::is_same_v<A, DiracSpinor>) {
209 return a.twoj();
210 } else {
211 static_assert(std::is_same_v<A, int>);
212 return 2 * a;
213 }
214}
215
216template <class A>
217static std::optional<int> twojknull(const A &a) {
218 if constexpr (std::is_same_v<A, DiracSpinor>) {
219 return a.twoj();
220 } else if constexpr (std::is_same_v<A, int>) {
221 static_assert(std::is_same_v<A, int>);
222 return 2 * a;
223 } else {
224 return std::nullopt;
225 }
226}
227
228template <class A, class B, class C, class D, class E, class F>
229static double sixj(const A &a, const B &b, const C &c, const D &d, const E &e,
230 const F &f) {
231 return Angular::sixj_2(twojk(a), twojk(b), twojk(c), twojk(d), twojk(e),
232 twojk(f));
233}
234
235template <class A = std::optional<int>, class B = std::optional<int>,
236 class C = std::optional<int>, class D = std::optional<int>,
237 class E = std::optional<int>, class F = std::optional<int>>
238static bool sixjTriads(const A &a, const B &b, const C &c, const D &d,
239 const E &e, const F &f) {
240 return Angular::sixjTriads(twojknull(a), twojknull(b), twojknull(c),
241 twojknull(d), twojknull(e), twojknull(f));
242}
243
244template <class A, class B, class C>
245static bool triangle(const A &a, const B &b, const C &c) {
246 return Angular::triangle(twojk(a), twojk(b), twojk(c));
247}
248
249} // namespace Coulomb
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:44
int twoj() const
2j (twice the total angular momentum)
Definition DiracSpinor.hpp:97
int l() const
Orbital angular momentum Q number.
Definition DiracSpinor.hpp:93
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
constexpr int l_k(int ka)
returns l given kappa
Definition Wigner369j.hpp:44
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
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
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
Functions (+classes) for computing Coulomb integrals.
Definition CoulombBreit.cpp:13
std::pair< int, int > k_minmax_tj(int tja, int tjb)
Returns min and max k (multipolarity) allowed for Triangle(k,a,b), NOT accounting for parity (2j only...
Definition CoulombIntegrals.hpp:104
DiracSpinor Qkv_bcd(const int k, const int kappa_a, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
Calculates Q^k(v)_bcd for given k,kappa_v. From scratch (calculates y) [see YkTable version if alread...
Definition CoulombIntegrals.cpp:331
bool Pk_abcd_SR(int k, int ka, int kb, int kc, int kd)
Just selection rule for Pk_abcd.
Definition CoulombIntegrals.cpp:321
std::pair< int, int > k_minmax_Ck(const DiracSpinor &a, const DiracSpinor &b)
Returns min and max k (multipolarity) allowed for C^k_ab, accounting for parity (used by k_minmax_Q)
Definition CoulombIntegrals.hpp:111
double g_abcd(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, int tma, int tmb, int tmc, int tmd)
Calculates g from scratch - not used often.
Definition CoulombIntegrals.cpp:424
double Rk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
Calculates R^k_abcd for given k. From scratch (calculates y)
Definition CoulombIntegrals.cpp:233
double Qk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
Calculates Q^k_abcd for given k. From scratch (calculates y) [see YkTable version if already have YkT...
Definition CoulombIntegrals.cpp:290
DiracSpinor Rkv_bcd(const int k, const int kappa_a, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
"Right-hand-side" R^k{v}_bcd [i.e., without Fv integral]
Definition CoulombIntegrals.cpp:253
int number_below_Fermi(const DiracSpinor &i, const DiracSpinor &j, const DiracSpinor &k, const DiracSpinor &l, double eFermi)
Returns number of orbitals that are below Fermi level. Used for Qk selection.
Definition CoulombIntegrals.cpp:452
bool Qk_abcd_SR(int k, int ka, int kb, int kc, int kd)
Just selection rule for Qk_abcd.
Definition CoulombIntegrals.cpp:312
double Pk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
Exchange only version of W (W-Q): W = Q + P [see Qk above].
Definition CoulombIntegrals.cpp:361
std::pair< int, int > k_minmax_P(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)
Returns min and max k (multipolarity) allowed for P^k_abcd. DOES NOT contain parity rules (6j only) -...
Definition CoulombIntegrals.cpp:472
DiracSpinor Pkv_bcd(const int k, int kappa_a, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
Exchange only version of W (W-Q): W = Q + P [see Qk above].
Definition CoulombIntegrals.cpp:382
double Wk_abcd(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd)
Calculates W^k_abcd for given k. From scratch (calculates y)
Definition CoulombIntegrals.cpp:417
std::pair< int, int > k_minmax_W(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)
Returns min and max k (multipolarity) allowed for W^k_abcd. DOES NOT contain parity rules (6j only) -...
Definition CoulombIntegrals.cpp:492
std::pair< int, int > k_minmax_Q(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)
Returns min and max k (multipolarity) allowed for Q^k_abcd. Parity rule is included,...
Definition CoulombIntegrals.hpp:146
std::vector< double > yk_ab(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb, const std::size_t maxi)
Calculates Hartree Screening functions .
Definition CoulombIntegrals.cpp:191