2#include "CoulombIntegrals.hpp"
3#include "IO/ChronoTimer.hpp"
4#include "IO/FRW_fileReadWrite.hpp"
5#include "Physics/AtomData.hpp"
7#include "fmt/format.hpp"
8#include "qip/Widgets.hpp"
21 std::cout <<
"Stored non-zero two-body integrals (" <<
to_string(S)
25 for (
auto &qk : m_data) {
26 fmt::print(
"k = {:2}: {}\n", k, qk.size());
31 std::cout <<
"Total: " << total <<
"\n";
37 for (
auto &qk : m_data) {
47 add(k, NormalOrder(a, b, c, d), value);
59 const auto sk = std::size_t(k);
60 if (sk >= m_data.size()) {
61 m_data.resize(sk + 1);
63 m_data.at(sk).insert({index, value});
71 update(k, NormalOrder(a, b, c, d), value);
86 const auto sk = std::size_t(k);
87 if (sk >= m_data.size()) {
88 m_data.resize(sk + 1);
90 m_data.at(sk).insert_or_assign(index, value);
96 const auto sk = std::size_t(k);
97 if (sk >= m_data.size())
99 return m_data.at(sk).find(NormalOrder(a, b, c, d)) != m_data.at(sk).cend();
111 const auto sk = std::size_t(k);
112 if (sk >= m_data.size())
114 return m_data.at(sk).find(index) != m_data.at(sk).cend();
122 const auto sk = std::size_t(k);
123 if (sk >= m_data.size())
126 const auto map_it = m_data.at(sk).find(index);
127 if (map_it == m_data.at(sk).cend())
129 return &(map_it->second);
136 const auto sk = std::size_t(k);
137 if (sk >= m_data.size())
140 const auto map_it = m_data.at(sk).find(NormalOrder(a, b, c, d));
141 if (map_it == m_data.at(sk).cend())
143 return map_it->second;
154 const auto sk = std::size_t(k);
155 if (sk >= m_data.size())
158 const auto map_it = m_data.at(sk).find(index);
159 if (map_it == m_data.at(sk).cend())
161 return map_it->second;
168 const auto tQk = Q(k, a, b, c, d);
180 return tQk / (s * tCkac * tCkbd);
213 const auto [lmin, lmax] = [&]() -> std::pair<int, int> {
214 if constexpr (S == Symmetry::Qk)
219 const int dl = (S == Symmetry::Qk) ? 2 : 1;
221 for (
int l = lmin; l <= lmax; l += dl) {
222 const auto ql = this->Q(l, a, b, d, c);
225 const auto sixj = sj ? sj->
get_2(tja, tjc, 2 * k, tjb, tjd, 2 * l) :
248 const std::vector<double> &fk)
const {
252 if (Coulomb::triangle(a, c, k) == 0 || Coulomb::triangle(k, b, d) == 0)
258 const auto [lmin, lmax] = [&]() -> std::pair<int, int> {
259 if constexpr (S == Symmetry::Qk)
264 const int dl = (S == Symmetry::Qk) ? 2 : 1;
266 for (
int l = lmin; l <= lmax; l += dl) {
267 const auto ql = this->Q(l, a, b, d, c);
270 const auto sixj = sj.
get(a, c, k, b, d, l);
273 const auto f_scr_l = (l < (int)fk.size()) ? fk[std::size_t(l)] : 1.0;
275 Pk_abcd += f_scr_l * sixj * ql;
292 return Q(k, a, b, c, d) + P(k, a, b, c, d, sj);
299 int tmb,
int tmc,
int tmd)
const {
301 if (tmc - tma != tmb - tmd)
303 const int twoq = tmc - tma;
307 const auto [k0, ki] = [&]() -> std::pair<int, int> {
308 if constexpr (S == Symmetry::Qk)
313 const int dk = (S == Symmetry::Qk) ? 2 : 1;
315 for (
int k = k0; k <= ki; k += dk) {
316 if (std::abs(twoq) > 2 * k)
332 g += s * tjs1 * tjs2 * Q(k, a, b, c, d);
364 nk4Index out = FormIndex(a, b, c, d);
365 const auto min = std::min({a, b, c, d});
367 const auto tmp = FormIndex(a, d, c, b);
372 const auto tmp = std::min(FormIndex(b, a, d, c), FormIndex(b, c, d, a));
377 const auto tmp = std::min(FormIndex(c, b, a, d), FormIndex(c, d, a, b));
382 const auto tmp = std::min(FormIndex(d, a, b, c), FormIndex(d, c, b, a));
393 const auto tmp1 = FormIndex(a, b, c, d);
394 const auto tmp2 = FormIndex(b, a, d, c);
395 const auto tmp3 = FormIndex(c, d, a, b);
396 const auto tmp4 = FormIndex(d, c, b, a);
397 return std::min({tmp1, tmp2, tmp3, tmp4});
405 const auto tmp1 = FormIndex(a, b, c, d);
406 const auto tmp2 = FormIndex(b, a, d, c);
407 return std::min({tmp1, tmp2});
415 return FormIndex(a, b, c, d);
422 return NormalOrder_impl(a, b, c, d);
436 return FormIndex(a, b, c, d);
464 static_assert(
sizeof(
nkIndex) * 8 == 16);
471std::array<nkIndex, 4>
473 static_assert(
sizeof(
nk4Index) ==
sizeof(std::array<nkIndex, 4>));
474 std::array<nkIndex, 4> set;
475 std::memcpy(&set, &index,
sizeof(
nk4Index));
480 std::swap(set[0], set[3]);
481 std::swap(set[1], set[2]);
487std::array<std::size_t, 4>
489 std::size_t k_cutoff,
491 static_assert(S == Symmetry::Qk);
495 const auto tmp_max_k =
498 (k_cutoff <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cutoff));
500 std::vector<std::size_t> count_non_zero_k_tot(max_k + 1);
501 std::vector<std::size_t> count_non_zero_k_Excited(max_k + 1);
502 std::vector<std::size_t> count_non_zero_k_MBPT(max_k + 1);
504 const auto select_Q_Excited = [eF](int,
const DiracSpinor &s,
511 const auto select_Q_MBPT = [eF](int,
const DiracSpinor &s,
515 return num == 1 || num == 2;
518#pragma omp parallel for schedule(dynamic, 1)
519 for (
auto k = 0ul; k <= max_k; ++k) {
520 const auto ik =
static_cast<int>(k);
521 for (
const auto &a : basis) {
522 for (
const auto &b : basis) {
523 for (
const auto &c : basis) {
526 for (
const auto &d : basis) {
528 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
530 ++count_non_zero_k_tot[k];
532 if (select_Q_Excited(0, a, b, c, d)) {
533 ++count_non_zero_k_Excited[k];
535 if (select_Q_MBPT(0, a, b, c, d)) {
536 ++count_non_zero_k_MBPT[k];
548 const auto count_non_zero_tot = std::accumulate(
549 count_non_zero_k_tot.begin(), count_non_zero_k_tot.end(), 0ul);
551 const auto count_non_zero_Excited = std::accumulate(
552 count_non_zero_k_Excited.begin(), count_non_zero_k_Excited.end(), 0ul);
554 const auto count_non_zero_MBPT = std::accumulate(
555 count_non_zero_k_MBPT.begin(), count_non_zero_k_MBPT.end(), 0ul);
557 return {count_non_zero_tot, count_non_zero_Excited, count_non_zero_MBPT,
565 const YkTable &yk,
int k_cut,
bool print) {
566 static_assert(S == Symmetry::Qk);
587 const auto tmp_max_k =
591 (k_cut <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cut));
593 if (m_data.size() < max_k + 1)
594 m_data.resize(max_k + 1);
597 std::vector<std::size_t> count_non_zero_k(max_k + 1);
598#pragma omp parallel for
599 for (
auto k = 0ul; k <= max_k; ++k) {
600 const auto ik =
static_cast<int>(k);
601 for (
const auto &a : basis) {
602 for (
const auto &b : basis) {
603 for (
const auto &c : basis) {
606 for (
const auto &d : basis) {
608 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
610 ++count_non_zero_k[k];
620#pragma omp parallel for
621 for (
auto ik = 0ul; ik <= max_k; ++ik) {
622 m_data[ik].reserve(count_non_zero_k[ik]);
626#pragma omp parallel for schedule(dynamic, 1)
627 for (
auto k = 0ul; k <= max_k; ++k) {
628 for (
const auto &a : basis) {
629 for (
const auto &c : basis) {
632 for (
const auto &b : basis) {
633 for (
const auto &d : basis) {
636 const auto normal_index = NormalOrder(a, b, c, d);
637 if (normal_index == CurrentOrder(a, b, c, d)) {
638 add(
int(k), normal_index, 0.0);
646 std::cout <<
"Construct empty table: " << t.
lap_reading_str() << std::endl;
652 std::cout <<
"Fill w/ values:\n" << std::flush;
655#pragma omp parallel for schedule(dynamic, 1)
656 for (
auto ia = 0ul; ia < basis.size(); ++ia) {
657 const auto &a = basis[ia];
658 for (
const auto &b : basis) {
659 for (
const auto &c : basis) {
660 for (
const auto &d : basis) {
662 const auto normal_index = NormalOrder(a, b, c, d);
663 if (normal_index != CurrentOrder(a, b, c, d))
666 const auto [kmin, kmax] =
k_minmax_Q(a, b, c, d);
667 for (
int k = kmin; k <= kmax && k <= int(max_k); k += 2) {
668 double *ptr = get(k, normal_index);
669 assert(ptr !=
nullptr);
673 *ptr = yk.
Q(k, a, b, c, d);
694 int k_cut,
bool print) {
695 static_assert(S == Symmetry::Qk);
702 const auto tmp_max_k =
706 (k_cut <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cut));
708 if (m_data.size() < max_k + 1)
709 m_data.resize(max_k + 1);
712 std::vector<std::size_t> count_non_zero_k(max_k + 1);
713#pragma omp parallel for
714 for (
auto k = 0ul; k <= max_k; ++k) {
715 const auto ik =
static_cast<int>(k);
716 for (
const auto &a : basis) {
717 for (
const auto &b : basis) {
718 for (
const auto &c : basis) {
721 for (
const auto &d : basis) {
723 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
725 SelectionFunction(ik, a, b, c, d)) {
726 ++count_non_zero_k[k];
736#pragma omp parallel for
737 for (
auto ik = 0ul; ik <= max_k; ++ik) {
738 m_data[ik].reserve(count_non_zero_k[ik]);
742#pragma omp parallel for
743 for (
auto k = 0ul; k <= max_k; ++k) {
744 for (
const auto &a : basis) {
745 for (
const auto &c : basis) {
748 for (
const auto &b : basis) {
749 for (
const auto &d : basis) {
752 if (!SelectionFunction(
int(k), a, b, c, d))
754 const auto normal_index = NormalOrder(a, b, c, d);
755 if (normal_index == CurrentOrder(a, b, c, d)) {
756 add(
int(k), normal_index, 0.0);
764 std::cout <<
"Construct empty table: " << t.
lap_reading_str() << std::endl;
770 std::cout <<
"Fill w/ values:\n" << std::flush;
773#pragma omp parallel for schedule(dynamic, 1)
774 for (
auto ia = 0ul; ia < basis.size(); ++ia) {
775 const auto &a = basis[ia];
776 for (
const auto &b : basis) {
777 for (
const auto &c : basis) {
778 for (
const auto &d : basis) {
780 const auto normal_index = NormalOrder(a, b, c, d);
781 if (normal_index != CurrentOrder(a, b, c, d))
784 const auto [kmin, kmax] =
k_minmax_Q(a, b, c, d);
785 for (
int k = kmin; k <= kmax && k <= int(max_k); k += 2) {
786 if (!SelectionFunction(k, a, b, c, d))
788 double *ptr = get(k, normal_index);
789 assert(ptr !=
nullptr);
793 *ptr = yk.
Q(k, a, b, c, d);
836 (k_cut <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cut));
838 if (m_data.size() < max_k + 1)
839 m_data.resize(max_k + 1);
842 std::vector<std::size_t> count_non_zero_k(max_k + 1);
843#pragma omp parallel for
844 for (
auto k = 0ul; k <= max_k; ++k) {
845 const auto ik =
static_cast<int>(k);
846 for (
const auto &a : basis) {
847 for (
const auto &b : basis) {
848 for (
const auto &c : basis) {
849 for (
const auto &d : basis) {
851 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
852 if (Fk_SR(ik, a, b, c, d)) {
853 ++count_non_zero_k[k];
863#pragma omp parallel for
864 for (
auto ik = 0ul; ik <= max_k; ++ik) {
865 m_data[ik].reserve(count_non_zero_k[ik]);
869#pragma omp parallel for
870 for (
auto k = 0ul; k <= max_k; ++k) {
871 for (
const auto &a : basis) {
872 for (
const auto &b : basis) {
873 for (
const auto &c : basis) {
874 for (
const auto &d : basis) {
875 if (Fk_SR(
int(k), a, b, c, d)) {
876 const auto normal_index = NormalOrder(a, b, c, d);
877 if (normal_index == CurrentOrder(a, b, c, d)) {
878 add(
int(k), normal_index, 0.0);
887 std::cout <<
"Construct empty table: " << t.
lap_reading_str() << std::endl;
893 std::cout <<
"Fill w/ values:\n" << std::flush;
897#pragma omp parallel for schedule(dynamic, 1)
898 for (std::size_t ia = 0; ia < basis.size(); ++ia) {
900 const auto &a = basis[ia];
901 for (
const auto &b : basis) {
902 for (
const auto &c : basis) {
903 for (
const auto &d : basis) {
905 const auto normal_index = NormalOrder(a, b, c, d);
906 if (normal_index != CurrentOrder(a, b, c, d))
909 for (
int k = 0; k <= int(max_k); ++k) {
911 if (!Fk_SR(k, a, b, c, d))
913 double *ptr = get(k, normal_index);
914 assert(ptr !=
nullptr);
917 *ptr = Fk(k, a, b, c, d);
940 const auto max_k = m_data.size() - 1;
945 const auto x = std::clamp(damp, 0.0, 1.0);
946 const auto y = 1.0 - damp;
953#pragma omp parallel for schedule(dynamic, 1)
954 for (std::size_t ia = 0; ia < basis.size(); ++ia) {
956 const auto &a = basis[ia];
957 for (
const auto &b : basis) {
958 for (
const auto &c : basis) {
959 for (
const auto &d : basis) {
963 const auto c_index = CurrentOrder(a, b, c, d);
964 const auto n_index = NormalOrder(a, b, c, d);
965 if (c_index != n_index)
968 for (
int k = 0; k <= int(max_k); ++k) {
969 double *ptr = get(k, n_index);
971 if (ptr !=
nullptr) {
972 *ptr = (*ptr == 0.0 || x == 0.0) ?
974 y * Fk(k, a, b, c, d) + x * *ptr;
988 if (fname ==
"false" || fname ==
"")
991 std::cout <<
"Writing " << count() <<
" integrals to file: " << fname
992 <<
".." << std::flush;
994 const auto rw = IO::FRW::write;
997 auto size = m_data.size();
998 rw_binary(f, rw, size);
999 for (
const auto &Q_k : m_data) {
1000 auto size_k = Q_k.size();
1001 rw_binary(f, rw, size_k);
1002 for (
auto [key, value] : Q_k) {
1003 auto key_copy = key;
1004 rw_binary(f, rw, key_copy, value);
1008 std::cout <<
"\n" << std::flush;
1012template <Symmetry S>
1014 if (fname ==
"false" || fname.empty())
1018 const auto rw = IO::FRW::read;
1023 std::vector<int> max_n_l;
1024 constexpr bool count_orbs =
true;
1030 std::cout <<
"Reading: " << fname <<
"\n" << std::flush;
1032 std::size_t size{0};
1033 rw_binary(f, rw, size);
1034 m_data.resize(size);
1035 if (m_data.size() == 0)
1037 for (std::size_t i = 0; i < m_data.size(); ++i) {
1038 auto &Q_k = m_data[i];
1039 std::size_t size_k{0};
1040 rw_binary(f, rw, size_k);
1041 Q_k.reserve(size_k);
1042 for (std::size_t ik = 0; ik < size_k; ++ik) {
1045 rw_binary(f, rw, key, value);
1049 if constexpr (count_orbs) {
1050 const auto indexes = UnFormIndex(key);
1051 for (
const auto index : indexes) {
1054 if (max_n_l.size() < l + 1)
1055 max_n_l.resize(l + 1);
1056 if (n > max_n_l.at(l))
1067 std::string basis_str;
1068 for (
const auto &n : max_n_l) {
1070 basis_str += std::to_string(n);
1075 if (!basis_str.empty())
1076 basis_str =
"[" + basis_str +
"] ";
1078 std::cout <<
"Read " << count() <<
" integrals " << basis_str
1079 <<
"from file: " << fname <<
"\n"
Lookup table for Wigner 6j symbols.
Definition SixJTable.hpp:68
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:100
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:116
Base class template to store Coulomb integrals, and similar. 3 specific cases (by template instantiat...
Definition QkTable.hpp:102
Real P2(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, const Angular::SixJTable &sj, const std::vector< double > &fk) const
Exchange integral P^k_abcd with effective Coulomb screening.
Definition QkTable.ipp:245
double * get(int k, nk4Index index)
Directly gets one of the stored elements, given normal-ordered nk4Index.
Definition QkTable.ipp:121
void fill_if(const std::vector< DiracSpinor > &basis, const YkTable &yk, const SelectionRules &SelectionFunction, int k_cut=-1, bool print=true)
Fill table with Coulomb Q integrals satisfying a selection rule.
Definition QkTable.ipp:691
Real P(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, const Angular::SixJTable *const sj=nullptr) const
Exchange integral P^k_abcd = (2k+1) sum_l {6j} Q^l_abdc.
Definition QkTable.ipp:236
void update(const std::vector< DiracSpinor > &basis, const CoulombFunction &Fk, double damp, bool print=true)
Re-calculate all existing table entries using a CoulombFunction.
Definition QkTable.ipp:935
bool read(const std::string &fname, bool verbose=true)
Reads coulomb integrals to disk. Returns false if none read in.
Definition QkTable.ipp:1013
std::array< std::size_t, 4 > count_non_zero_integrals(const std::vector< DiracSpinor > &basis, std::size_t max_k=99, double eF=0.0) const
Definition QkTable.ipp:488
void write(const std::string &fname, bool verbose=true) const
Writes coulomb integrals to disk.
Definition QkTable.ipp:987
bool contains(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d) const
Checks if given {k,a,b,c,d} is in the table.
Definition QkTable.ipp:103
nk4Index NormalOrder(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d) const
Creates single 'nk4Index' corresponding to 'NormalOrder' symmetry of {a,b,c,d}.
Definition QkTable.ipp:427
nk4Index CurrentOrder(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d) const
Creates single 'nk4Index', WITHOUT accounting for 'NormalOrder'. Can be used to check if {a,...
Definition QkTable.ipp:440
static nk4Index FormIndex(nkIndex a, nkIndex b, nkIndex c, nkIndex d)
Converts given set of nkIndex's (in any order) to nk4Index.
Definition QkTable.ipp:449
Real R(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d) const
Returns 'R', defined via: R := Q / (angular_coef)
Definition QkTable.ipp:184
std::array< nkIndex, 4 > UnFormIndex(const nk4Index &index) const
Breaks nk4Index back into {ia,ib,ic,id}. Not often used.
Definition QkTable.ipp:472
void fill(const std::vector< DiracSpinor > &basis, const YkTable &yk, int k_cut=-1, bool print=true)
Fill table with all non-zero Coulomb Q integrals from a YkTable.
Definition QkTable.ipp:564
void summary() const
For testing: prints details of coulomb integrals stored.
Definition QkTable.ipp:19
Real g(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, int tma, int tmb, int tmc, int tmd) const
Full matrix element g_abcd with explicit magnetic quantum numbers.
Definition QkTable.ipp:297
void add(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, Real value)
adds a new value. Note: does nothing if {k,a,b,c,d} already exists
Definition QkTable.ipp:51
Real Q(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d) const
Retrieve a stored Q. If not present, returns 0. (Returns exactly as stored in table....
Definition QkTable.ipp:147
Real W(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, const Angular::SixJTable *const sj=nullptr) const
Antisymmetrised integral W^k_abcd = Q^k_abcd + P^k_abcd.
Definition QkTable.ipp:283
std::size_t count() const
Returns number of stored integrals.
Definition QkTable.ipp:35
Calculates + stores Hartree Y functions + Angular (w/ look-up), taking advantage of symmetry.
Definition YkTable.hpp:31
double Q(const int k, const DiracSpinor &Fa, const DiracSpinor &Fb, const DiracSpinor &Fc, const DiracSpinor &Fd) const
Calculates Qk using the existing yk integrals. Note: Ck tables must include all required values,...
Definition YkTable.cpp:129
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:42
static int max_tj(const std::vector< DiracSpinor > &orbs)
Returns maximum (2j) found in {orbs}.
Definition DiracSpinor.cpp:266
Index nk_index() const
(n,kappa) index (see AtomData)
Definition DiracSpinor.hpp:101
Class that uses std::chrono to easily time code.
Definition ChronoTimer.hpp:35
std::string lap_reading_str() const
Current lap elapsed time as a human-readable string.
Definition ChronoTimer.hpp:157
void start()
Starts (or resumes) timing.
Definition ChronoTimer.hpp:93
Thread-safe progress bar for OpenMP parallel loops.
Definition Widgets.hpp:85
void update()
Atomically increment progress counter and print updated bar.
Definition Widgets.hpp:108
std::pair< int, int > index_to_nk(std::uint64_t nk_index)
Returns {n, kappa} given nk_index.
Definition Wigner369j.hpp:191
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 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
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
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 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 triangle(int j1, int j2, int J)
Returns 1 if triangle rule is satisfied. nb: works with j OR twoj!
Definition Wigner369j.hpp:249
constexpr int twoj_k(int ka)
returns 2j given kappa
Definition Wigner369j.hpp:46
std::string l_symbol(int l)
l (int) to symbol (e.g., 0->'s', 1->'p')
Definition AtomData.cpp:110
Functions (+classes) for computing Coulomb integrals.
Definition CoulombBreit.cpp:13
double Real
Data type used to store integrals.
Definition QkTable.hpp:32
std::function< bool(int, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)> SelectionRules
Function type for determining Coulomb(-like) integral selection rules. Takes k and 4 DiracSpinors,...
Definition QkTable.hpp:54
std::string_view to_string(Symmetry s)
Convert Symmetry to string.
Definition QkTable.hpp:17
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:443
uint64_t nk4Index
index type for set of 4 orbitals {nk,nk,nk,nk} -> nk4Index [max n: 256]
Definition QkTable.hpp:36
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:352
uint16_t nkIndex
index type for each {nk} (orbital) [max n: 256]
Definition QkTable.hpp:40
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.cpp:496
std::function< double(int, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)> CoulombFunction
Function type for calculating Coulomb(-like) integrals. Takes k and 4 DiracSpinors,...
Definition QkTable.hpp:48
void open_binary(std::fstream &stream, const std::string &fname, RoW row)
Opens a binary fstream for reading or writing according to row.
Definition FRW_fileReadWrite.hpp:108