High-precision calculations for one- and two-valence atomic systems
StructureRad.hpp
1#pragma once
2#include "Coulomb/include.hpp"
3#include "Coulomb/meTable.hpp"
4#include "IO/FRW_fileReadWrite.hpp"
5#include "Wavefunction/DiracSpinor.hpp"
6#include <memory>
7#include <optional>
8#include <vector>
9class Wavefunction;
10class DiracSpinor;
11namespace DiracOperator {
12class TensorOperator;
13}
14namespace ExternalField {
15class CorePolarisation;
16}
17
18//! Many-body perturbation theory
19namespace MBPT {
20
21/*!
22 @brief Structure Radiation and Normalisation of states, using diagram method.
23
24 @details
25 Two main functions: SR(), norm(), which return the reduced matrix elements
26 for structure radiation and normalisation, respectively.
27
28 Structure radiation is sum of srTB()+srC(); norm() gives normalisation of
29 states.
30
31 * Typically, one should use splines for the 'legs' (outer states) of
32 diagrams. However, code is written such that {w,v} (the valence states)
33 always appear as the _first_ state in the Q integrals; thus those states
34 are always directly integrated (other states may use the existing y^k
35 integrals, which were calculated using the spline states), unless using
36 QkTable (see below).
37
38 * For using spline states as legs: This means you must typically ensure
39 basis is large enough to make relevant valence states "physical"
40
41 * The user should check if the zeroth order <w|t|v> matches closely between
42 valence/spline states. If not, basis/cavity is too small and SR+N probably
43 meaningless
44
45 * Option to use QkTable to calculate SR+N. Otherwise, calculates Coulomb
46 integrals on-the-fly. If QkTable is used, leads to ~10x speed-up, but uses
47 large amount of memory. Also, using QkTable means spline states are used
48 for "legs" of diagrams.
49
50 * norm() works differently: it directly takes in the operator to calculate
51 norm. This is because norm depends only on Coulomb operators.
52 In some sense, would make sense to keep norm in a separate class.
53 However, they are typically calculated together, and use the same Coulomb
54 integrals.
55
56 * Formulas are presented in (for example):
57 * W. R. Johnson, Z. W. Liu, and J. Sapirstein, At. Data Nucl. Data Tables
58 64, 279 (1996),
59 https://www.sciencedirect.com/science/article/pii/S0092640X96900248
60
61 * Specific form of formulas used here are presented in:
62 [Phys. Rev. A **107**, 052812 (2023)](https://arxiv.org/abs/2211.11134)
63
64 @note For Structure Radiation, must call StructureRad::solve_core() first.
65*/
67
68public:
69 /*!
70 @brief Construct a Structure Radiation (MBPT) object.
71
72 @details
73 en_core defines the core boundary: states with e < en_core are treated as
74 core states, while states with e > en_core are treated as excited states.
75 Typically en_core is half-way between max(e_core) and min(e_valence),
76 i.e., wf.FermiLevel().
77
78 nminmax is the pair {nmin, nmax}. Only core states with n >= nmin are used,
79 and only excited states with n <= nmax are included in the summations.
80 Negative-energy states (if in the basis) are always included as excited
81 states.
82
83 Qk_fname is the filename for the QkTable. If provided, the QkTable will be
84 read from / written to this file and then used to calculate SR. This leads
85 to ~10x speedup in the calculation at the cost of significantly higher
86 memory usage.
87
88 fk and etak are effective screening factors for screening and hole-particle.
89 These should only be used as a test.
90
91 @param basis Basis orbitals (typically splines); split into core and
92 excited states by @p en_core
93 @param en_core Core/excited energy boundary
94 @param nminmax {nmin, nmax}: n range of core/excited states included
95 @param Qk_fname QkTable file; if empty, no QkTable (Yk table used)
96 @param k_cut Maximum multipolarity k of the Coulomb integrals (see note)
97 @param fk Effective screening factors, for each k (test only)
98 @param etak Effective hole-particle factors, for each k (test only)
99 @param verbose If true, prints progress to screen
100
101 @note @p k_cut applies to every Coulomb line, including those inside
102 the exchange integrals (all Q^k, P^k, W^k with k > k_cut are zero),
103 whether or not a QkTable is used.
104 */
105 StructureRad(const std::vector<DiracSpinor> &basis, double en_core,
106 std::pair<int, int> nminmax = {0, 999},
107 const std::string &Qk_fname = "", int k_cut = 99,
108 const std::vector<double> &fk = {},
109 const std::vector<double> &etak = {}, bool verbose = true);
110
111private:
112 // Switch to use Qk (rather than Yk) table
113 bool m_use_Qk;
114 // effective screening; sqrt - add to both sides!
115 std::vector<double> m_root_fk;
116 // effective hole-particle
117 std::vector<double> m_etak;
118 int m_k_cut;
119
120 Coulomb::YkTable mY{};
121 std::optional<Coulomb::QkTable> mQ{std::nullopt};
122 // Keeping a local copy is significantly faster
123 std::vector<DiracSpinor> mCore{}, mExcited{}, mBasis{};
124
125 // matrix element table; set by solve_core
127 // Rank of current operator; set by solve_core
128 int m_K{-1};
129
130public:
131 //! const reference to employed _subset_ of core orbitals
132 const std::vector<DiracSpinor> &core() const { return mCore; }
133 //! const reference to employed _subset_ of excited orbitals
134 const std::vector<DiracSpinor> &excited() const { return mExcited; }
135 //! const reference to employed _subset_ of core+excited orbitals
136 const std::vector<DiracSpinor> &basis() const { return mBasis; }
137 //! const reference to underlying matrix element table. May be empty
138 const Coulomb::meTable<double> &me_Table() const { return mTab; }
139
140 //! const reference to Yk table (always formed by the constructor)
141 const Coulomb::YkTable &Yk() const { return mY; }
142 //! const reference to underlying Qk table. Optional; may not be set
143 const std::optional<Coulomb::QkTable> &Qk() const { return mQ; }
144
145 /*!
146 @brief Prepares the operator matrix elements required for SR and BO.
147
148 @details
149 - Pre-computes the full set of <i||T||j> matrix elements
150 - Does for all core-core, core-excited, excited-excited orbitals
151 - Optionally includes core polarisation; dV may be null
152 - h must not be null
153 - For frequency-dependent operators, this assumes operator has already
154 been updated
155 - Assumes Core Polarisation has already been solved
156
157 @param h Operator (must not be null)
158 @param dV Core polarisation (RPA); included in the matrix elements if
159 not null
160 @param omega Transition frequency: selects the dV component on the
161 internal lines (emission if negative); see
162 CorePolarisation::dV
163
164 @note This must be called before structure radiation (or BO) can be
165 calculated
166 */
167 void solve_core(const DiracOperator::TensorOperator *const h,
168 const ExternalField::CorePolarisation *const dV = nullptr,
169 double omega = 0.0);
170
171 /*!
172 @brief Reduced matrix element of structure radiation, <w||h_sr||v>.
173
174 @details
175 Sum of the top, bottom, and centre diagrams, for the operator (and dV)
176 given to solve_core().
177
178 @param w Bra state
179 @param v Ket state
180 @param omega Operator frequency; enters the energy denominators of the
181 top and bottom diagrams
182
183 @note Must call solve_core() first; aborts otherwise.
184 @warning Returns zero if <w||h||v> is not in the solve_core() table: i.e.,
185 if zero by selection rules, or if @p w or @p v (matched by n and
186 kappa) is not in the basis.
187 */
188 double SR(const DiracSpinor &w, const DiracSpinor &v,
189 double omega = 0.0) const {
190 return srTB(w, v, omega) + srC(w, v);
191 }
192
193 /*!
194 @brief Returns Normalisation of states, reduced ME: <w||h||v>_norm.
195
196 @details
197 \f[
198 \redmatel{w}{h}{v}_{\rm norm} = (f_w + f_v) \redmatel{w}{h + \delta V}{v},
199 \f]
200 with f from f_norm(). Does not require solve_core().
201
202 @param w Bra state
203 @param v Ket state
204 @param h Operator (must not be null)
205 @param dV Core polarisation (RPA); included if not null
206 @param conj The dV component: emission (true) for a negative frequency;
207 see CorePolarisation::dV
208 */
209 double norm(const DiracSpinor &w, const DiracSpinor &v,
210 const DiracOperator::TensorOperator *const h,
211 const ExternalField::CorePolarisation *const dV = nullptr,
212 bool conj = false) const;
213
214 //! Normalisation factor; defined: <w||h||v>_norm = <w||h||v>(f_v + f_w)
215 double f_norm(const DiracSpinor &v) const { return -0.5 * (n1(v) + n2(v)); }
216
217 //! Normalisation factor for pair: <w||h||v>_norm = norm_factor(w,v) <w||h||v>
218 double norm_factor(const DiracSpinor &w, const DiracSpinor &v) const;
219
220 /*!
221 @brief Returns sum of SR+Norm diagrams, reduced ME: <w||T+B+C+N||v>.
222
223 @details
224 SR() + norm().
225
226 @param w Bra state
227 @param v Ket state
228 @param h Operator, for norm() only (must not be null)
229 @param dV Core polarisation (RPA), for norm() only; may be null
230 @param omega Operator frequency: for the SR() denominators, and the sign
231 selects the dV component in norm()
232
233 @note Must call solve_core() first (aborts otherwise). h and dV used for
234 norm() only
235 */
236 double srn(const DiracSpinor &w, const DiracSpinor &v,
237 const DiracOperator::TensorOperator *const h,
238 const ExternalField::CorePolarisation *const dV = nullptr,
239 double omega = 0.0) const {
240 const auto tb = srTB(w, v, omega);
241 const auto c = srC(w, v);
242 const auto n = norm(w, v, h, dV, omega < 0.0);
243 return tb + c + n;
244 }
245
246 //! Effective screening factor for each Coulomb line, sqrt(fk); 1 if not set
247 double f_root_scr(int k) const {
248 const auto sk = std::size_t(k);
249 return sk < m_root_fk.size() ? m_root_fk[sk] : 1.0;
250 }
251
252 //! Effective hole-particle factor for polarisation loops; 1 if not set
253 double eta_hp(int k) const {
254 const auto sk = std::size_t(k);
255 return sk < m_etak.size() ? m_etak[sk] : 1.0;
256 }
257
258 /*!
259 @brief Returns Brueckner orbital contribution to the reduced ME.
260
261 @details
262 From 10.1006/adnd.1996.0024:
263 \f[
264 f_v \redmatel{w}{h}{\delta v} + f_w \redmatel{\delta w}{h}{v},
265 \qquad
266 \ket{\delta v} = \sum_{i \neq v}
267 \frac{\ket{i}\matel{i}{\Sigma}{v}}{\varepsilon_v - \varepsilon_i},
268 \f]
269 where \f$ \Sigma \f$ is the second-order correlation potential at energy
270 \f$ \varepsilon_v \f$ (with fk and etak, if given), and the sum runs over
271 core and excited basis states with \f$ \kappa_i = \kappa_v \f$. The
272 \f$ \redmatel{w}{h}{i} \f$ are taken from the solve_core() table (so
273 include dV, if given there).
274
275 @param w Bra state
276 @param v Ket state
277 @param fw Factor multiplying the \f$ \redmatel{\delta w}{h}{v} \f$ term
278 @param fv Factor multiplying the \f$ \redmatel{w}{h}{\delta v} \f$ term
279
280 @note Must call solve_core() first; aborts otherwise.
281 @warning Terms are zero if @p w or @p v (matched by n and kappa) is not
282 in the basis.
283 */
284 double BO(const DiracSpinor &w, const DiracSpinor &v, double fw = 1.0,
285 double fv = 1.0) const;
286
287 //! Second-order <v|Sigma|w>, at E = (e_v + e_w)/2 (fk and etak not applied)
288 double Sigma_vw(const DiracSpinor &v, const DiracSpinor &w) const;
289
290 /*!
291 @brief Constructs an me table of srn() for each pair {a,b}.
292
293 @details
294 For each a in @p as and b in @p tbs (or in @p as, if @p tbs is empty) with
295 non-zero <a||h||b>. The {b,a} element is also stored, using the symmetry
296 of @p h.
297
298 @param h Operator (must not be null): selection rules, symmetry, and
299 norm()
300 @param as First set of states
301 @param tbs Second set of states; if empty, @p as is used
302 @param omega Operator frequency, for SR() only
303 @param dV Core polarisation (RPA), for norm() only; may be null
304
305 @return Table of srn(a, b, h, dV, omega).
306
307 @note Must call solve_core() first.
308 */
311 const std::vector<DiracSpinor> &as,
312 const std::vector<DiracSpinor> &tbs = {}, double omega = 0.0,
313 const ExternalField::CorePolarisation *const dV = nullptr) const;
314
315private:
316 //! Returns sum of Top+Bottom (SR) diagrams, reduced ME: <w||T+B||v>.
317 double srTB(const DiracSpinor &w, const DiracSpinor &v,
318 double omega = 0.0) const;
319
320 //! Centre (SR) diagrams, reduced ME: <w||C||v>. No explicit omega dependence
321 double srC(const DiracSpinor &w, const DiracSpinor &v) const;
322
323 // "Top" diagrams
324 double t1234(int k, const DiracSpinor &w, const DiracSpinor &r,
325 const DiracSpinor &v, const DiracSpinor &c) const;
326 double t1(int k, const DiracSpinor &w, const DiracSpinor &r,
327 const DiracSpinor &v, const DiracSpinor &c) const;
328 double t2(int k, const DiracSpinor &w, const DiracSpinor &r,
329 const DiracSpinor &v, const DiracSpinor &c) const;
330 double t3(int k, const DiracSpinor &w, const DiracSpinor &r,
331 const DiracSpinor &v, const DiracSpinor &c) const;
332 double t4(int k, const DiracSpinor &w, const DiracSpinor &r,
333 const DiracSpinor &v, const DiracSpinor &c) const;
334
335 // "Bottom" diagrams
336 double b1234(int k, const DiracSpinor &w, const DiracSpinor &c,
337 const DiracSpinor &v, const DiracSpinor &r) const;
338
339 // "Centre" diagrams (most important)
340 double c1(int k, const DiracSpinor &w, const DiracSpinor &a,
341 const DiracSpinor &v, const DiracSpinor &c) const;
342 double c2(int k, const DiracSpinor &w, const DiracSpinor &a,
343 const DiracSpinor &v, const DiracSpinor &c) const;
344 double d1(int k, const DiracSpinor &w, const DiracSpinor &r,
345 const DiracSpinor &v, const DiracSpinor &m) const;
346 double d2(int k, const DiracSpinor &w, const DiracSpinor &r,
347 const DiracSpinor &v, const DiracSpinor &m) const;
348
349 // "Normalisation" terms (most important)
350 double n1(const DiracSpinor &v) const;
351 double n2(const DiracSpinor &v) const;
352 double dSigma_dE(const DiracSpinor &v, const DiracSpinor &i,
353 const DiracSpinor &j, const DiracSpinor &k) const;
354
355 double z_bo(const DiracSpinor &w, const DiracSpinor &v,
356 bool transpose = false) const;
357
358 //! Aborts, with message, if solve_core() has not been called
359 void check_solve_core() const;
360
361 //
362 double Q(int k, const DiracSpinor &a, const DiracSpinor &b,
363 const DiracSpinor &c, const DiracSpinor &d) const {
364 // inlcudes effective Coulomb screening
365 if (k > m_k_cut)
366 return 0.0;
367 const auto fk = f_root_scr(k);
368 return m_use_Qk ? fk * mQ->Q(k, a, b, c, d) : fk * mY.Q(k, a, b, c, d);
369 }
370
371 /*!
372 @brief Exchange Coulomb integral, P^k_abcd, built from Q().
373
374 @details
375 \f$ P^k_{abcd} = [k] \sum_l \{a,c,k;b,d,l\}\, Q^l_{abdc} \f$, with
376 Q^l from Q(): includes effective screening, and k_cut applies to the
377 internal Coulomb lines l (and to k).
378 */
379 double P(int k, const DiracSpinor &a, const DiracSpinor &b,
380 const DiracSpinor &c, const DiracSpinor &d) const;
381
382 double W(int k, const DiracSpinor &a, const DiracSpinor &b,
383 const DiracSpinor &c, const DiracSpinor &d) const {
384 // inlcudes effective Coulomb screening
385 return Q(k, a, b, c, d) + P(k, a, b, c, d);
386 }
387};
388
389} // namespace MBPT
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
Look-up table for matrix elements. Note: does not assume any symmetry: (a,b) is stored independantly ...
Definition meTable.hpp:17
General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive...
Definition TensorOperator.hpp:198
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:55
Virtual base class for core-polarisation (RPA); computes dV corrections.
Definition CorePolarisation.hpp:147
Structure Radiation and Normalisation of states, using diagram method.
Definition StructureRad.hpp:66
const std::vector< DiracSpinor > & core() const
const reference to employed subset of core orbitals
Definition StructureRad.hpp:132
const std::vector< DiracSpinor > & excited() const
const reference to employed subset of excited orbitals
Definition StructureRad.hpp:134
Coulomb::meTable< double > srn_table(const DiracOperator::TensorOperator *const h, const std::vector< DiracSpinor > &as, const std::vector< DiracSpinor > &tbs={}, double omega=0.0, const ExternalField::CorePolarisation *const dV=nullptr) const
Constructs an me table of srn() for each pair {a,b}.
Definition StructureRad.cpp:231
double f_root_scr(int k) const
Effective screening factor for each Coulomb line, sqrt(fk); 1 if not set.
Definition StructureRad.hpp:247
double f_norm(const DiracSpinor &v) const
Normalisation factor; defined: <w||h||v>_norm = <w||h||v>(f_v + f_w)
Definition StructureRad.hpp:215
double BO(const DiracSpinor &w, const DiracSpinor &v, double fw=1.0, double fv=1.0) const
Returns Brueckner orbital contribution to the reduced ME.
Definition StructureRad.cpp:787
double norm_factor(const DiracSpinor &w, const DiracSpinor &v) const
Normalisation factor for pair: <w||h||v>_norm = norm_factor(w,v) <w||h||v>
Definition StructureRad.cpp:221
double eta_hp(int k) const
Effective hole-particle factor for polarisation loops; 1 if not set.
Definition StructureRad.hpp:253
double norm(const DiracSpinor &w, const DiracSpinor &v, const DiracOperator::TensorOperator *const h, const ExternalField::CorePolarisation *const dV=nullptr, bool conj=false) const
Returns Normalisation of states, reduced ME: <w||h||v>_norm.
Definition StructureRad.cpp:208
const std::optional< Coulomb::QkTable > & Qk() const
const reference to underlying Qk table. Optional; may not be set
Definition StructureRad.hpp:143
double SR(const DiracSpinor &w, const DiracSpinor &v, double omega=0.0) const
Reduced matrix element of structure radiation, <w||h_sr||v>.
Definition StructureRad.hpp:188
double Sigma_vw(const DiracSpinor &v, const DiracSpinor &w) const
Second-order <v|Sigma|w>, at E = (e_v + e_w)/2 (fk and etak not applied)
Definition StructureRad.cpp:829
const Coulomb::meTable< double > & me_Table() const
const reference to underlying matrix element table. May be empty
Definition StructureRad.hpp:138
double srn(const DiracSpinor &w, const DiracSpinor &v, const DiracOperator::TensorOperator *const h, const ExternalField::CorePolarisation *const dV=nullptr, double omega=0.0) const
Returns sum of SR+Norm diagrams, reduced ME: <w||T+B+C+N||v>.
Definition StructureRad.hpp:236
const Coulomb::YkTable & Yk() const
const reference to Yk table (always formed by the constructor)
Definition StructureRad.hpp:141
const std::vector< DiracSpinor > & basis() const
const reference to employed subset of core+excited orbitals
Definition StructureRad.hpp:136
void solve_core(const DiracOperator::TensorOperator *const h, const ExternalField::CorePolarisation *const dV=nullptr, double omega=0.0)
Prepares the operator matrix elements required for SR and BO.
Definition StructureRad.cpp:94
Stores Wavefunction (set of valence orbitals, grid, HF etc.)
Definition Wavefunction.hpp:48
Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body)...
Definition SecondOrder.hpp:7
Core-polarisation (RPA) corrections to matrix elements of an external field.
Definition MatrixElements.hpp:9
Many-body perturbation theory.
Definition MatrixElements.hpp:12