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"
23 std::cout <<
"Stored non-zero two-body integrals (" <<
to_string(S)
27 for (
auto &qk : m_data) {
28 fmt::print(
"k = {:2}: {}\n", k, qk.size());
33 std::cout <<
"Total: " << total <<
"\n";
39 for (
auto &qk : m_data) {
49 add(k, NormalOrder(a, b, c, d), value);
61 const auto sk = std::size_t(k);
62 if (sk >= m_data.size()) {
63 m_data.resize(sk + 1);
65 m_data.at(sk).insert({index, value});
73 update(k, NormalOrder(a, b, c, d), value);
88 const auto sk = std::size_t(k);
89 if (sk >= m_data.size()) {
90 m_data.resize(sk + 1);
92 m_data.at(sk).insert_or_assign(index, value);
98 const auto sk = std::size_t(k);
99 if (sk >= m_data.size())
101 return m_data.at(sk).find(NormalOrder(a, b, c, d)) != m_data.at(sk).cend();
113 const auto sk = std::size_t(k);
114 if (sk >= m_data.size())
116 return m_data.at(sk).find(index) != m_data.at(sk).cend();
124 const auto sk = std::size_t(k);
125 if (sk >= m_data.size())
128 const auto map_it = m_data.at(sk).find(index);
129 if (map_it == m_data.at(sk).cend())
131 return &(map_it->second);
138 const auto sk = std::size_t(k);
139 if (sk >= m_data.size())
142 const auto map_it = m_data.at(sk).find(NormalOrder(a, b, c, d));
143 if (map_it == m_data.at(sk).cend())
145 return map_it->second;
156 const auto sk = std::size_t(k);
157 if (sk >= m_data.size())
160 const auto map_it = m_data.at(sk).find(index);
161 if (map_it == m_data.at(sk).cend())
163 return map_it->second;
170 const auto tQk = Q(k, a, b, c, d);
182 return tQk / (s * tCkac * tCkbd);
215 const auto [lmin, lmax] = [&]() -> std::pair<int, int> {
216 if constexpr (S == Symmetry::Qk)
221 const int dl = (S == Symmetry::Qk) ? 2 : 1;
223 for (
int l = lmin; l <= lmax; l += dl) {
224 const auto ql = this->Q(l, a, b, d, c);
227 const auto sixj = sj ? sj->
get_2(tja, tjc, 2 * k, tjb, tjd, 2 * l) :
250 const std::vector<double> &fk)
const {
254 if (Coulomb::triangle(a, c, k) == 0 || Coulomb::triangle(k, b, d) == 0)
260 const auto [lmin, lmax] = [&]() -> std::pair<int, int> {
261 if constexpr (S == Symmetry::Qk)
266 const int dl = (S == Symmetry::Qk) ? 2 : 1;
268 for (
int l = lmin; l <= lmax; l += dl) {
269 const auto ql = this->Q(l, a, b, d, c);
272 const auto sixj = sj.
get(a, c, k, b, d, l);
275 const auto f_scr_l = (l < (int)fk.size()) ? fk[std::size_t(l)] : 1.0;
277 Pk_abcd += f_scr_l * sixj * ql;
294 return Q(k, a, b, c, d) + P(k, a, b, c, d, sj);
301 int tmb,
int tmc,
int tmd)
const {
303 if (tmc - tma != tmb - tmd)
305 const int twoq = tmc - tma;
309 const auto [k0, ki] = [&]() -> std::pair<int, int> {
310 if constexpr (S == Symmetry::Qk)
315 const int dk = (S == Symmetry::Qk) ? 2 : 1;
317 for (
int k = k0; k <= ki; k += dk) {
318 if (std::abs(twoq) > 2 * k)
334 g += s * tjs1 * tjs2 * Q(k, a, b, c, d);
366 nk4Index out = FormIndex(a, b, c, d);
367 const auto min = std::min({a, b, c, d});
369 const auto tmp = FormIndex(a, d, c, b);
374 const auto tmp = std::min(FormIndex(b, a, d, c), FormIndex(b, c, d, a));
379 const auto tmp = std::min(FormIndex(c, b, a, d), FormIndex(c, d, a, b));
384 const auto tmp = std::min(FormIndex(d, a, b, c), FormIndex(d, c, b, a));
395 const auto tmp1 = FormIndex(a, b, c, d);
396 const auto tmp2 = FormIndex(b, a, d, c);
397 const auto tmp3 = FormIndex(c, d, a, b);
398 const auto tmp4 = FormIndex(d, c, b, a);
399 return std::min({tmp1, tmp2, tmp3, tmp4});
407 const auto tmp1 = FormIndex(a, b, c, d);
408 const auto tmp2 = FormIndex(b, a, d, c);
409 return std::min({tmp1, tmp2});
417 return FormIndex(a, b, c, d);
424 return NormalOrder_impl(a, b, c, d);
438 return FormIndex(a, b, c, d);
466 static_assert(
sizeof(
nkIndex) * 8 == 16);
473std::array<nkIndex, 4>
475 static_assert(
sizeof(
nk4Index) ==
sizeof(std::array<nkIndex, 4>));
476 std::array<nkIndex, 4> set;
477 std::memcpy(&set, &index,
sizeof(
nk4Index));
482 std::swap(set[0], set[3]);
483 std::swap(set[1], set[2]);
489std::array<std::size_t, 4>
491 std::size_t k_cutoff,
493 static_assert(S == Symmetry::Qk);
497 const auto tmp_max_k =
500 (k_cutoff <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cutoff));
502 std::vector<std::size_t> count_non_zero_k_tot(max_k + 1);
503 std::vector<std::size_t> count_non_zero_k_Excited(max_k + 1);
504 std::vector<std::size_t> count_non_zero_k_MBPT(max_k + 1);
506 const auto select_Q_Excited = [eF](int,
const DiracSpinor &s,
513 const auto select_Q_MBPT = [eF](int,
const DiracSpinor &s,
517 return num == 1 || num == 2;
520#pragma omp parallel for schedule(dynamic, 1)
521 for (
auto k = 0ul; k <= max_k; ++k) {
522 const auto ik =
static_cast<int>(k);
523 for (
const auto &a : basis) {
524 for (
const auto &b : basis) {
525 for (
const auto &c : basis) {
528 for (
const auto &d : basis) {
530 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
532 ++count_non_zero_k_tot[k];
534 if (select_Q_Excited(0, a, b, c, d)) {
535 ++count_non_zero_k_Excited[k];
537 if (select_Q_MBPT(0, a, b, c, d)) {
538 ++count_non_zero_k_MBPT[k];
550 const auto count_non_zero_tot = std::accumulate(
551 count_non_zero_k_tot.begin(), count_non_zero_k_tot.end(), 0ul);
553 const auto count_non_zero_Excited = std::accumulate(
554 count_non_zero_k_Excited.begin(), count_non_zero_k_Excited.end(), 0ul);
556 const auto count_non_zero_MBPT = std::accumulate(
557 count_non_zero_k_MBPT.begin(), count_non_zero_k_MBPT.end(), 0ul);
559 return {count_non_zero_tot, count_non_zero_Excited, count_non_zero_MBPT,
567 const YkTable &yk,
int k_cut,
bool print) {
568 static_assert(S == Symmetry::Qk);
589 const auto tmp_max_k =
593 (k_cut <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cut));
595 if (m_data.size() < max_k + 1)
596 m_data.resize(max_k + 1);
599 std::vector<std::size_t> count_non_zero_k(max_k + 1);
600#pragma omp parallel for
601 for (
auto k = 0ul; k <= max_k; ++k) {
602 const auto ik =
static_cast<int>(k);
603 for (
const auto &a : basis) {
604 for (
const auto &b : basis) {
605 for (
const auto &c : basis) {
608 for (
const auto &d : basis) {
610 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
612 ++count_non_zero_k[k];
625 if (already_filled(count_non_zero_k, basis)) {
630#pragma omp parallel for
631 for (
auto ik = 0ul; ik <= max_k; ++ik) {
632 m_data[ik].reserve(count_non_zero_k[ik]);
634 const auto n_existing = count();
637#pragma omp parallel for schedule(dynamic, 1)
638 for (
auto k = 0ul; k <= max_k; ++k) {
639 for (
const auto &a : basis) {
640 for (
const auto &c : basis) {
643 for (
const auto &b : basis) {
644 for (
const auto &d : basis) {
647 const auto normal_index = NormalOrder(a, b, c, d);
648 if (normal_index == CurrentOrder(a, b, c, d)) {
649 m_data[k].insert({normal_index, 0.0});
661 fmt::print(
"Calculating {}{} integrals\n",
662 n_existing == 0 ?
"" :
"(subset of) ", count());
665#pragma omp parallel for schedule(dynamic, 1)
666 for (
auto ia = 0ul; ia < basis.size(); ++ia) {
667 const auto &a = basis[ia];
668 for (
const auto &b : basis) {
669 for (
const auto &c : basis) {
670 for (
const auto &d : basis) {
672 const auto normal_index = NormalOrder(a, b, c, d);
673 if (normal_index != CurrentOrder(a, b, c, d))
676 const auto [kmin, kmax] =
k_minmax_Q(a, b, c, d);
677 for (
int k = kmin; k <= kmax && k <= int(max_k); k += 2) {
678 auto it = m_data[std::size_t(k)].find(normal_index);
679 assert(it != m_data[std::size_t(k)].end());
680 double *ptr = &it->second;
684 *ptr = yk.
Q(k, a, b, c, d);
702 int k_cut,
bool print) {
703 static_assert(S == Symmetry::Qk);
710 const auto tmp_max_k =
714 (k_cut <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cut));
716 if (m_data.size() < max_k + 1)
717 m_data.resize(max_k + 1);
720 std::vector<std::size_t> count_non_zero_k(max_k + 1);
721#pragma omp parallel for
722 for (
auto k = 0ul; k <= max_k; ++k) {
723 const auto ik =
static_cast<int>(k);
724 for (
const auto &a : basis) {
725 for (
const auto &b : basis) {
726 for (
const auto &c : basis) {
729 for (
const auto &d : basis) {
731 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
733 SelectionFunction(ik, a, b, c, d)) {
734 ++count_non_zero_k[k];
744#pragma omp parallel for
745 for (
auto ik = 0ul; ik <= max_k; ++ik) {
746 m_data[ik].reserve(count_non_zero_k[ik]);
748 const auto n_existing = count();
751#pragma omp parallel for
752 for (
auto k = 0ul; k <= max_k; ++k) {
753 for (
const auto &a : basis) {
754 for (
const auto &c : basis) {
757 for (
const auto &b : basis) {
758 for (
const auto &d : basis) {
761 if (!SelectionFunction(
int(k), a, b, c, d))
763 const auto normal_index = NormalOrder(a, b, c, d);
764 if (normal_index == CurrentOrder(a, b, c, d)) {
765 m_data[k].insert({normal_index, 0.0});
777 fmt::print(
"Calculating {}{} integrals\n",
778 n_existing == 0 ?
"" :
"(subset of) ", count());
781#pragma omp parallel for schedule(dynamic, 1)
782 for (
auto ia = 0ul; ia < basis.size(); ++ia) {
783 const auto &a = basis[ia];
784 for (
const auto &b : basis) {
785 for (
const auto &c : basis) {
786 for (
const auto &d : basis) {
788 const auto normal_index = NormalOrder(a, b, c, d);
789 if (normal_index != CurrentOrder(a, b, c, d))
792 const auto [kmin, kmax] =
k_minmax_Q(a, b, c, d);
793 for (
int k = kmin; k <= kmax && k <= int(max_k); k += 2) {
794 if (!SelectionFunction(k, a, b, c, d))
796 auto it = m_data[std::size_t(k)].find(normal_index);
797 assert(it != m_data[std::size_t(k)].end());
798 double *ptr = &it->second;
800 *ptr = yk.
Q(k, a, b, c, d);
840 (k_cut <= 0) ? tmp_max_k : std::min(tmp_max_k, std::size_t(k_cut));
842 if (m_data.size() < max_k + 1)
843 m_data.resize(max_k + 1);
846 std::vector<std::size_t> count_non_zero_k(max_k + 1);
847#pragma omp parallel for
848 for (
auto k = 0ul; k <= max_k; ++k) {
849 const auto ik =
static_cast<int>(k);
850 for (
const auto &a : basis) {
851 for (
const auto &b : basis) {
852 for (
const auto &c : basis) {
853 for (
const auto &d : basis) {
855 if (NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d)) {
856 if (Fk_SR(ik, a, b, c, d)) {
857 ++count_non_zero_k[k];
869#pragma omp parallel for
870 for (
auto ik = 0ul; ik <= max_k; ++ik) {
871 m_data[ik].reserve(count_non_zero_k[ik]);
873 const auto n_existing = count();
876#pragma omp parallel for
877 for (
auto k = 0ul; k <= max_k; ++k) {
878 for (
const auto &a : basis) {
879 for (
const auto &b : basis) {
880 for (
const auto &c : basis) {
881 for (
const auto &d : basis) {
882 if (Fk_SR(
int(k), a, b, c, d)) {
883 const auto normal_index = NormalOrder(a, b, c, d);
884 if (normal_index == CurrentOrder(a, b, c, d)) {
885 m_data[k].insert({normal_index, 0.0});
898 fmt::print(
"Calculating {}{} integrals\n",
899 n_existing == 0 ?
"" :
"(subset of) ", count());
903#pragma omp parallel for schedule(dynamic, 1)
904 for (std::size_t ia = 0; ia < basis.size(); ++ia) {
906 const auto &a = basis[ia];
907 for (
const auto &b : basis) {
908 for (
const auto &c : basis) {
909 for (
const auto &d : basis) {
911 const auto normal_index = NormalOrder(a, b, c, d);
912 if (normal_index != CurrentOrder(a, b, c, d))
915 for (
int k = 0; k <= int(max_k); ++k) {
917 if (!Fk_SR(k, a, b, c, d))
919 auto it = m_data[std::size_t(k)].find(normal_index);
920 assert(it != m_data[std::size_t(k)].end());
921 double *ptr = &it->second;
924 *ptr = Fk(k, a, b, c, d);
941 const std::vector<DiracSpinor> &basis,
const CoulombFunction &Fk,
double damp,
947 const auto max_k = m_data.size() - 1;
952 const auto x = std::clamp(damp, 0.0, 1.0);
953 const auto y = 1.0 - damp;
960 fmt::print(
"Updating {}{} integrals\n", filter ?
"(subset of) " :
"",
964#pragma omp parallel for schedule(dynamic, 1)
965 for (std::size_t ia = 0; ia < basis.size(); ++ia) {
967 const auto &a = basis[ia];
968 for (
const auto &b : basis) {
969 for (
const auto &c : basis) {
970 for (
const auto &d : basis) {
974 const auto c_index = CurrentOrder(a, b, c, d);
975 const auto n_index = NormalOrder(a, b, c, d);
976 if (c_index != n_index)
981 if (filter && !filter(a, b, c, d))
984 for (
int k = 0; k <= int(max_k); ++k) {
985 double *ptr = get(k, n_index);
987 if (ptr !=
nullptr) {
988 *ptr = (*ptr == 0.0 || x == 0.0) ?
990 y * Fk(k, a, b, c, d) + x * *ptr;
1005struct KeyValueBlock {
1009static_assert(std::is_trivially_copyable_v<KeyValueBlock>);
1010static_assert(
sizeof(KeyValueBlock) ==
sizeof(
nk4Index) +
sizeof(
Real));
1013template <Symmetry S>
1015 if (fname ==
"false" || fname ==
"")
1018 std::cout <<
"Writing " << count() <<
" integrals to file: " << fname
1019 <<
".." << std::flush;
1021 const auto rw = IO::FRW::write;
1024 auto size = m_data.size();
1025 rw_binary(f, rw, size);
1026 std::vector<KeyValueBlock> block;
1027 for (
const auto &Q_k : m_data) {
1028 auto size_k = Q_k.size();
1029 rw_binary(f, rw, size_k);
1033 block.reserve(size_k);
1034 for (
const auto &[key, value] : Q_k) {
1035 block.push_back({key, value});
1037 f.write(
reinterpret_cast<const char *
>(block.data()),
1038 std::streamsize(block.size() *
sizeof(KeyValueBlock)));
1041 std::cout <<
"\n" << std::flush;
1045template <Symmetry S>
1047 bool parse_basis_string) {
1048 if (fname ==
"false" || fname.empty())
1052 const auto rw = IO::FRW::read;
1057 std::vector<int> max_n_l;
1063 std::cout <<
"Reading: " << fname <<
"\n" << std::flush;
1065 std::size_t size{0};
1066 rw_binary(f, rw, size);
1067 m_data.resize(size);
1068 if (m_data.size() == 0)
1070 std::vector<KeyValueBlock> block;
1071 for (std::size_t i = 0; i < m_data.size(); ++i) {
1072 auto &Q_k = m_data[i];
1073 std::size_t size_k{0};
1074 rw_binary(f, rw, size_k);
1075 Q_k.reserve(size_k);
1079 block.resize(size_k);
1080 f.read(
reinterpret_cast<char *
>(block.data()),
1081 std::streamsize(size_k *
sizeof(KeyValueBlock)));
1082 for (
const auto &[key, value] : block) {
1086 if (parse_basis_string) {
1087 const auto indexes = UnFormIndex(key);
1088 for (
const auto index : indexes) {
1091 if (max_n_l.size() < l + 1)
1092 max_n_l.resize(l + 1);
1093 if (n > max_n_l.at(l))
1104 std::string basis_str;
1105 for (
const auto &n : max_n_l) {
1107 basis_str += std::to_string(n);
1112 if (!basis_str.empty())
1113 basis_str =
"[" + basis_str +
"] ";
1115 std::cout <<
"Read " << count() <<
" integrals " << basis_str
1116 <<
"from file: " << fname <<
"\n"
Lookup table for Wigner 6j symbols.
Definition SixJTable.hpp:82
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
Base class template to store Coulomb integrals, and similar. 3 specific cases (by template instantiat...
Definition QkTable.hpp:118
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:247
double * get(int k, nk4Index index)
Directly gets one of the stored elements, given normal-ordered nk4Index.
Definition QkTable.ipp:123
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:699
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:238
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:490
void update(const std::vector< DiracSpinor > &basis, const CoulombFunction &Fk, double damp, bool print=true, const std::function< bool(const DiracSpinor &, const DiracSpinor &, const DiracSpinor &, const DiracSpinor &)> &filter={})
Re-calculate all existing table entries using a CoulombFunction.
Definition QkTable.ipp:940
void write(const std::string &fname, bool verbose=true) const
Writes coulomb integrals to disk.
Definition QkTable.ipp:1014
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:105
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:429
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:442
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:451
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:186
std::array< nkIndex, 4 > UnFormIndex(const nk4Index &index) const
Breaks nk4Index back into {ia,ib,ic,id}. Not often used.
Definition QkTable.ipp:474
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:566
bool read(const std::string &fname, bool verbose=true, bool parse_basis_string=false)
Reads coulomb integrals to disk. Returns false if none read in. If parse_basis_string is true,...
Definition QkTable.ipp:1046
void summary() const
For testing: prints details of coulomb integrals stored.
Definition QkTable.ipp:21
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:299
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:53
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:149
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:285
std::size_t count() const
Returns number of stored integrals.
Definition QkTable.ipp:37
Calculates + stores Hartree Y functions + Angular (w/ look-up), taking advantage of symmetry.
Definition YkTable.hpp:46
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:55
static int max_tj(const std::vector< DiracSpinor > &orbs)
Returns maximum (2j) found in {orbs}.
Definition DiracSpinor.cpp:354
Index nk_index() const
(n,kappa) index
Definition DiracSpinor.hpp:143
int twoj() const
2j (twice the total angular momentum)
Definition DiracSpinor.hpp:121
Class that uses std::chrono to easily time code.
Definition ChronoTimer.hpp:35
void start()
Starts (or resumes) timing.
Definition ChronoTimer.hpp:100
Thread-safe progress bar for OpenMP parallel loops.
Definition Widgets.hpp:194
void update()
Atomically increment progress counter and print updated bar.
Definition Widgets.hpp:223
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:111
Functions (+classes) for computing Coulomb integrals.
Definition CoulombBreit.cpp:13
double Real
Data type used to store integrals.
Definition QkTable.hpp:37
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:70
std::string_view to_string(Symmetry s)
Convert Symmetry to string.
Definition QkTable.hpp:22
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
uint64_t nk4Index
index type for set of 4 orbitals {nk,nk,nk,nk} -> nk4Index [max n: 256]
Definition QkTable.hpp:41
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
uint16_t nkIndex
index type for each {nk} (orbital) [max n: 256]
Definition QkTable.hpp:45
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::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:64
void open_binary(std::fstream &stream, const std::string &fname, RoW row)
Opens a binary fstream for reading or writing according to row. update opens existing file for random...
Definition FRW_fileReadWrite.hpp:109