ampsci
High-precision calculations for one- and two-valence atomic systems
QkTable.hpp
1#pragma once
2#include "Angular/SixJTable.hpp"
3#include "Wavefunction/DiracSpinor.hpp"
4#include "YkTable.hpp"
5#include <array>
6#include <cstdint>
7#include <functional>
8#include <unordered_map>
9
10namespace Coulomb {
11
12//! Symmetry (state index order) for tables.
13enum class Symmetry { Qk, Wk, Lk, none };
14//! Data type used to store integrals
15using Real = double;
16
17//! index type for set of 4 orbitals {nk,nk,nk,nk} -> nk4Index [max n: 256]
18//! @details @warning Requires 0<n<256, see \ref Angular::nk_to_index
19using nk4Index = uint64_t;
20
21//! index type for each {nk} (orbital) [max n: 256]
22//! @details @warning Requires 0<n<256, see \ref Angular::nk_to_index
23using nkIndex = uint16_t;
24
25static_assert(sizeof(nkIndex) == sizeof(DiracSpinor::Index));
26
27//! Function type for calculating Coulomb(-like) integrals.
28//! Takes k and 4 DiracSpinors, returns a double
30 std::function<double(int, const DiracSpinor &a, const DiracSpinor &b,
31 const DiracSpinor &c, const DiracSpinor &d)>;
32
33//! Function type for determining Coulomb(-like) integral selection rules.
34//! Takes k and 4 DiracSpinors, returns a true if integral is allowed.
36 std::function<bool(int, const DiracSpinor &a, const DiracSpinor &b,
37 const DiracSpinor &c, const DiracSpinor &d)>;
38
39//==============================================================================
40/*!
41@brief
42Base (pure virtual) class to store Coulomb integrals, and similar. 3 derived
43classes, which account for symmetry.
44 @details
45Mostly, a wrapper for std::unordered_map.
46Stores data in a std::vector of maps, each element (map) for each k
47(multipolarity).
48The symmetry is taken into account by defining a "Normal Ordering" of set of
49orbitals {a,b,c,d}. How this is defined depends on the specific symmetry in
50question.
51 Qk symmetry:
52 {abcd} = cbad = adcb = cdab = badc = bcda = dabc = dcba.
53 Normal ordering: i = min(a,b,c,d) is first index.
54 Two options (second and fourth may be swapped): choose 2nd to be smallest
55 Wk symmetry (same as g):
56 {abcd} = badc = cdab = dcba
57 Lk symmetry:
58 {abcd} = badc
59
60 @warning
61 Requires 0<n<256, see \ref Angular::nk_to_index
62*/
63template <Symmetry S>
65
66private:
67 // each vector element corresponds to a 'k'
68 std::vector<std::unordered_map<nk4Index, Real>> m_data{};
69
70public:
71 // 'Rule of zero' (except virtual destructor)
72 // virtual ~CoulombTable() = default;
73
74 //! Takes a constructed YkTable, and fills Coulomb table with all possible
75 //! non-zero Qk Coulomb integrals, accounting for symmetry (only allowed
76 //! for QkTable), up to maximum k, k_cut (set k_cut to <=0 to use all k)
77 void fill(const std::vector<DiracSpinor> &basis, const YkTable &yk,
78 int k_cut = -1, bool print = true);
79
80 //! Takes a constructed YkTable, and fills Coulomb table with all possible
81 //! non-zero Qk Coulomb integrals that are allowed by the SelectionFunction,
82 //! accounting for symmetry (only allowed for QkTable), up to maximum k,
83 //! k_cut (set k_cut to <=0 to use all k)
84 void fill_if(const std::vector<DiracSpinor> &basis, const YkTable &yk,
85 const SelectionRules &SelectionFunction, int k_cut = -1,
86 bool print = true);
87
88 void fill(const std::vector<DiracSpinor> &basis, const CoulombFunction &Fk,
89 const SelectionRules &Fk_SR, int k_cut = -1, bool print = true);
90
91 //! Gives arrow access to all underlying vector<unordered_map> functions
92 auto operator->() { return &m_data; }
93
94 //! For testing: prints details of coulomb integrals stored
95 void summary() const;
96 //! Returns number of stored integrals
97 std::size_t count() const;
98
99 //! adds a new value. Note: does nothing if {k,a,b,c,d} already exists
100 void add(int k, const DiracSpinor &a, const DiracSpinor &b,
101 const DiracSpinor &c, const DiracSpinor &d, Real value);
102 //! adds a new value. Note: does nothing if {k,a,b,c,d} already exists
103 void add(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d, Real value);
104 //! adds a new value. Note: does nothing if {k,a,b,c,d} already exists
105 void add(int k, nk4Index index, Real value);
106
107 //! Updates value in table. If not present, adds new value
108 void update(int k, const DiracSpinor &a, const DiracSpinor &b,
109 const DiracSpinor &c, const DiracSpinor &d, Real value);
110 //! Updates value in table. If not present, adds new value
111 void update(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d, Real value);
112 //! Updates value in table. If not present, adds new value
113 void update(int k, nk4Index index, Real value);
114
115 //! Checks if given {k,a,b,c,d} is in the table
116 bool contains(int k, const DiracSpinor &a, const DiracSpinor &b,
117 const DiracSpinor &c, const DiracSpinor &d) const;
118 //! Checks if given {k,a,b,c,d} is in the table
119 bool contains(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d) const;
120 //! Checks if given {k,a,b,c,d} is in the table
121 bool contains(int k, nk4Index index) const;
122
123 //! Returns true if table is empty
124 bool emptyQ() const {
125 return (m_data.size() == 0);
126 // nb: possible to be empty if size > 0... (but doesn't matter..)
127 }
128
129 /*! Counts number of non-zero Coulomb integrals, accounting for symmetry
130 @details
131
132 @note Specifically assumes Qk selection rules, and therefore only works for Qk.
133
134 In theory, easily updated for general symmetry/selection rules,
135 but this is usually the bottle-neck!
136 */
137 std::array<std::size_t, 4>
138 count_non_zero_integrals(const std::vector<DiracSpinor> &basis,
139 std::size_t max_k = 99, double eF = 0.0) const;
140
141 //! Retrieve a stored Q. If not present, returns 0. (Returns exactly as
142 //! stored in table.)
143 Real Q(int k, const DiracSpinor &a, const DiracSpinor &b,
144 const DiracSpinor &c, const DiracSpinor &d) const;
145
146 //! Retrieve a stored Q. If not present, returns 0. (Returns exactly as
147 //! stored in table.)
148 Real Q(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d) const;
149 //! Retrieve a stored Q. If not present, returns 0. (Returns exactly as
150 //! stored in table.)
151 Real Q(int k, nk4Index index) const;
152
153 //! Returns 'R', defined via: R := Q / (angular_coef)
154 Real R(int k, const DiracSpinor &a, const DiracSpinor &b,
155 const DiracSpinor &c, const DiracSpinor &d) const;
156 //! Returns 'R', defined via: R := Q / (angular_coef)
157 Real R(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d) const;
158
159 //! 'Exchange-only', defined via W = Q + P. Optionally, takes pointer to 6J
160 //! table (faster eval of 6J symbols)
161 Real P(int k, const DiracSpinor &a, const DiracSpinor &b,
162 const DiracSpinor &c, const DiracSpinor &d,
163 const Angular::SixJTable *const sj = nullptr) const;
164 //! 'Exchange-only', defined via W = Q + P. Optionally, takes pointer to 6J
165 //! table (faster eval of 6J symbols)
166 Real P(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d,
167 const Angular::SixJTable *const sj = nullptr) const;
168
169 //! 'Exchange-only', defined via W = Q + P. Optionally, takes pointer to 6J
170 //! table (faster eval of 6J symbols) - with screening
171 Real P2(int k, const DiracSpinor &a, const DiracSpinor &b,
172 const DiracSpinor &c, const DiracSpinor &d,
173 const Angular::SixJTable &sj, const std::vector<double> &fk) const;
174
175 //! W^k_abcd = Q^k_abcd + \sum_l [k] 6j * Q^l_abdc. Optionally, takes
176 //! pointer to 6J table (faster eval of 6J symbols)
177 Real W(int k, const DiracSpinor &a, const DiracSpinor &b,
178 const DiracSpinor &c, const DiracSpinor &d,
179 const Angular::SixJTable *const sj = nullptr) const;
180
181 //! W^k_abcd = Q^k_abcd + \sum_l [k] 6j * Q^l_abdc.
182 //! Optionally, takes pointer to 6J table (faster eval of 6J symbols)
183 Real W(int k, nkIndex a, nkIndex b, nkIndex c, nkIndex d,
184 const Angular::SixJTable *const sj = nullptr) const;
185
186 //! Returns 'g_abcd'
187 Real g(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c,
188 const DiracSpinor &d, int tma, int tmb, int tmc, int tmd) const;
189
190 //! Creates single 'nk4Index' corresponding to 'NormalOrder' symmetry of
191 //! {a,b,c,d}
192 nk4Index NormalOrder(const DiracSpinor &a, const DiracSpinor &b,
193 const DiracSpinor &c, const DiracSpinor &d) const;
194 //! Creates single 'nk4Index' corresponding to 'NormalOrder' symmetry of
195 //! {a,b,c,d}
197
198 //! Checks if set {a,b,c,d} are already in NormalOrder
200 return NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d);
201 }
202 //! Checks if set {a,b,c,d} are already in NormalOrder
203 bool is_NormalOrdered(const DiracSpinor &a, const DiracSpinor &b,
204 const DiracSpinor &c, const DiracSpinor &d) const {
205 return NormalOrder(a, b, c, d) == CurrentOrder(a, b, c, d);
206 }
207
208 //! Writes coulomb integrals to disk
209 void write(const std::string &fname, bool verbose = true) const;
210 //! Reads coulomb integrals to disk. Returns false if none read in
211 bool read(const std::string &fname, bool verbose = true);
212
213 //! Directly gets one of the stored elements, given normal-ordered nk4Index
214 double *get(int k, nk4Index index);
215
216 //! Creates single 'nk4Index', WITHOUT accounting for 'NormalOrder'. Can be
217 //! used to check if {a,b,c,d} are already in 'NormalOrder'
218 nk4Index CurrentOrder(const DiracSpinor &a, const DiracSpinor &b,
219 const DiracSpinor &c, const DiracSpinor &d) const;
220
221 //! Creates single 'nk4Index', WITHOUT accounting for 'NormalOrder'. Can be
222 //! used to check if {a,b,c,d} are already in 'NormalOrder'
224
225 //! Converts given set of nkIndex's (in any order) to nk4Index
226 static nk4Index FormIndex(nkIndex a, nkIndex b, nkIndex c, nkIndex d);
227
228 //! Breaks nk4Index back into {ia,ib,ic,id}. Not used.
229 std::array<nkIndex, 4> UnFormIndex(const nk4Index &index) const;
230
231private:
232 // Returns the "NormalOrder" nk4Index for given set. Implemented by
233 // specific symmetries
234 static inline nk4Index NormalOrder_impl(nkIndex a, nkIndex b, nkIndex c,
235 nkIndex d);
236};
237
238//! Stores Coulomb(-like) integrals, assuming Q-like symmetry
240//! Stores Coulomb(-like) integrals, assuming W-like symmetry
242//! Stores Coulomb(-like) integrals, assuming L-like symmetry
244//! Stores Coulomb(-like) integrals, assuming no symmetry
246
247//==============================================================================
248//==============================================================================
249//==============================================================================
250void estimate_memory_usage(const std::string &basis_string,
251 const std::string &core_string, int k_cut = 999);
252
253//! Estimate memory required for a Qk table
254double estimate_memory_GB(std::size_t number_of_integrals,
255 double efficiency = 0.65);
256
257} // namespace Coulomb
258
259#include "QkTable.ipp"
Lookup table for Wigner 6J symbols.
Definition SixJTable.hpp:47
Base (pure virtual) class to store Coulomb integrals, and similar. 3 derived classes,...
Definition QkTable.hpp:64
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-only', defined via W = Q + P. Optionally, takes pointer to 6J table (faster eval of 6J symb...
Definition QkTable.ipp:232
double * get(int k, nk4Index index)
Directly gets one of the stored elements, given normal-ordered nk4Index.
Definition QkTable.ipp:118
void fill_if(const std::vector< DiracSpinor > &basis, const YkTable &yk, const SelectionRules &SelectionFunction, int k_cut=-1, bool print=true)
Takes a constructed YkTable, and fills Coulomb table with all possible non-zero Qk Coulomb integrals ...
Definition QkTable.ipp:656
Real P(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, const Angular::SixJTable *const sj=nullptr) const
'Exchange-only', defined via W = Q + P. Optionally, takes pointer to 6J table (faster eval of 6J symb...
Definition QkTable.ipp:223
bool is_NormalOrdered(nkIndex a, nkIndex b, nkIndex c, nkIndex d) const
Checks if set {a,b,c,d} are already in NormalOrder.
Definition QkTable.hpp:199
bool is_NormalOrdered(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d) const
Checks if set {a,b,c,d} are already in NormalOrder.
Definition QkTable.hpp:203
bool read(const std::string &fname, bool verbose=true)
Reads coulomb integrals to disk. Returns false if none read in.
Definition QkTable.ipp:921
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:458
void write(const std::string &fname, bool verbose=true) const
Writes coulomb integrals to disk.
Definition QkTable.ipp:895
void update(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, Real value)
Updates value in table. If not present, adds new value.
Definition QkTable.ipp:74
auto operator->()
Gives arrow access to all underlying vector<unordered_map> functions.
Definition QkTable.hpp:92
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:100
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:397
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:410
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:419
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:181
std::array< nkIndex, 4 > UnFormIndex(const nk4Index &index) const
Breaks nk4Index back into {ia,ib,ic,id}. Not used.
Definition QkTable.ipp:442
void fill(const std::vector< DiracSpinor > &basis, const YkTable &yk, int k_cut=-1, bool print=true)
Takes a constructed YkTable, and fills Coulomb table with all possible non-zero Qk Coulomb integrals,...
Definition QkTable.ipp:532
void summary() const
For testing: prints details of coulomb integrals stored.
Definition QkTable.ipp:18
Real g(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, int tma, int tmb, int tmc, int tmd) const
Returns 'g_abcd'.
Definition QkTable.ipp:274
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:48
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:144
Real W(int k, const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d, const Angular::SixJTable *const sj=nullptr) const
W^k_abcd = Q^k_abcd + \sum_l [k] 6j * Q^l_abdc. Optionally, takes pointer to 6J table (faster eval of...
Definition QkTable.ipp:260
std::size_t count() const
Returns number of stored integrals.
Definition QkTable.ipp:32
bool emptyQ() const
Returns true if table is empty.
Definition QkTable.hpp:124
Calculates + stores Hartree Y functions + Angular (w/ look-up), taking advantage of symmetry.
Definition YkTable.hpp:26
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:42
Functions (+classes) for computing Coulomb integrals.
Definition CoulombIntegrals.cpp:13
double Real
Data type used to store integrals.
Definition QkTable.hpp:15
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:37
uint64_t nk4Index
index type for set of 4 orbitals {nk,nk,nk,nk} -> nk4Index [max n: 256]
Definition QkTable.hpp:19
uint16_t nkIndex
index type for each {nk} (orbital) [max n: 256]
Definition QkTable.hpp:23
double estimate_memory_GB(std::size_t number_of_integrals, double load_factor)
Estimate memory required for a Qk table.
Definition QkTable.cpp:76
Symmetry
Symmetry (state index order) for tables.
Definition QkTable.hpp:13
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:31