High-precision calculations for one- and two-valence atomic systems
Ladder.hpp
1#pragma once
2#include "Angular/include.hpp"
3#include "Coulomb/include.hpp"
4#include "MBPT/SpinorMatrix.hpp"
5#include "Wavefunction/DiracSpinor.hpp"
6#include <optional>
7#include <string>
8#include <utility>
9
10namespace MBPT {
11
12/*!
13 @brief Min and max k (multipolarity) allowed for ladder integral L^k_abcd.
14
15 @details
16 Triangle rules {a,c,k} and {b,d,k} apply, plus the combined parity rule
17 (l_a+l_b+l_c+l_d even). Unlike Q^k, there is no individual-pair parity rule
18 linking k to the orbital parities, so k takes both parities: NOT safe to
19 call k+=2.
20
21 @return {k_min, k_max}; an empty range (k_min > k_max) if no k is allowed.
22*/
23inline std::pair<int, int> k_minmax_L(const DiracSpinor &a,
24 const DiracSpinor &b,
25 const DiracSpinor &c,
26 const DiracSpinor &d) {
27 // Combined parity rule: each (direct) Coulomb rung shifts the parity of
28 // both pair lines together, so only the total parity is constrained
29 if ((a.l() + b.l() + c.l() + d.l()) % 2 != 0) {
30 return {1, 0};
31 }
32 const auto [l1, u1] = Coulomb::k_minmax_tj(a.twoj(), c.twoj());
33 const auto [l2, u2] = Coulomb::k_minmax_tj(b.twoj(), d.twoj());
34 return {std::max(l1, l2), std::min(u1, u2)};
35}
36
37/*!
38 @brief Min and max k allowed for ladder integral L^k_abcd (kappa version).
39
40 @details
41 Same rules as the DiracSpinor version (see above). NOT safe to call k+=2.
42*/
43inline std::pair<int, int> k_minmax_L(int kap_a, int kap_b, int kap_c,
44 int kap_d) {
45 if ((Angular::l_k(kap_a) + Angular::l_k(kap_b) + Angular::l_k(kap_c) +
46 Angular::l_k(kap_d)) %
47 2 !=
48 0) {
49 return {1, 0};
50 }
51 const auto [l1, u1] =
53 const auto [l2, u2] =
55 return {std::max(l1, l2), std::min(u1, u2)};
56}
57
58/*!
59 @brief Full ladder integral summed over all diagrams.
60
61 @details
62 Computes
63 \f[
64 L^k_{mnij} = L1^k_{mnij} + L2^k_{mnij} + L3^k_{mnij} [+ L4^k_{mnij}]
65 \f]
66 where \f$ L3^k_{mnij} = L2^k_{nmji} \f$ and \f$ L4 \f$ involves
67 core--core intermediate states. @p Lk points to the ladder table from
68 the previous iteration; pass nullptr on the first iteration.
69
70 @param k Multipole rank
71 @param m,n Excited (particle) orbitals
72 @param i,j Core (hole) or valence orbitals
73 @param qk Coulomb \f$ Q^k \f$ integral table
74 @param core Core orbitals
75 @param excited Excited orbitals
76 @param include_L4 Include the core--core diagram L4
77 @param SJ 6j symbol table
78 @param Lk Ladder table from previous iteration (nullptr on first)
79 @param e_i Optional: used in place of i.en() in energy denominators
80 @param e_m Optional: used in place of m.en() in energy denominators
81 @return \f$ L^k_{mnij} \f$
82 @note To evaluate at a fixed external energy (for a correlation potential),
83 use @p e_i or @p e_m (for external line in the i or m slot): the energy
84 only enters the denominators, never the integral lookups.
85*/
86double Lkmnij(int k, const DiracSpinor &m, const DiracSpinor &n,
87 const DiracSpinor &i, const DiracSpinor &j,
88 const Coulomb::QkTable &qk, const std::vector<DiracSpinor> &core,
89 const std::vector<DiracSpinor> &excited, bool include_L4,
90 const Angular::SixJTable &SJ,
91 const Coulomb::LkTable *const Lk = nullptr,
92 std::optional<double> e_i = {}, std::optional<double> e_m = {});
93
94/*!
95 @brief Particle--particle ladder diagram L1.
96
97 @details
98 \f[
99 L1^k_{mnij} = \sum_{rs,ul} A^{kul}_{mnrsij}
100 \frac{Q^u_{mnrs}\,(Q+L)^l_{rsij}}{\epsilon_{ij} - \epsilon_{rs}}
101 \f]
102 with the angular coefficient
103 \f[
104 A^{kul}_{mnrsij} = (-1)^{m+n+r+s+i+j+1}\,[k]
105 \sixj{m}{i}{k}{l}{u}{r}\sixj{n}{j}{k}{l}{u}{s}
106 \f]
107 Intermediate states \f$ r,s \f$ run over excited orbitals.
108
109 @param k Multipole rank
110 @param m,n Excited (particle) orbitals
111 @param i,j Core (hole) or valence orbitals
112 @param qk Coulomb \f$ Q^k \f$ integral table
113 @param excited Excited orbitals
114 @param SJ 6j symbol table
115 @param Lk Ladder table from previous iteration (nullptr on first)
116 @param e_i Optional: used in place of i.en() in energy denominator
117 @return \f$ L1^k_{mnij} \f$
118*/
119double L1(int k, const DiracSpinor &m, const DiracSpinor &n,
120 const DiracSpinor &i, const DiracSpinor &j,
121 const Coulomb::QkTable &qk, const std::vector<DiracSpinor> &excited,
122 const Angular::SixJTable &SJ,
123 const Coulomb::LkTable *const Lk = nullptr,
124 std::optional<double> e_i = {});
125
126/*!
127 @brief Particle--hole ladder diagram L2.
128
129 @details
130 \f[
131 L2^k_{mnij} = \sum_{rc,ul} (-1)^{k+u+l+1} A^{klu}_{mjcrin}
132 \frac{Q^u_{cnir}\,(Q+L)^l_{mrcj}}{\epsilon_{cj} - \epsilon_{mr}}
133 \f]
134 Intermediate states: \f$ r \f$ runs over excited, \f$ c \f$ over core.
135 The diagram \f$ L3 \f$ is the exchange partner
136 \f$ L3^k_{mnij} = L2^k_{nmji} \f$.
137
138 @param k Multipole rank
139 @param m,n Excited (particle) orbitals
140 @param i,j Core (hole) or valence orbitals
141 @param qk Coulomb \f$ Q^k \f$ integral table
142 @param core Core orbitals
143 @param excited Excited orbitals
144 @param SJ 6j symbol table
145 @param Lk Ladder table from previous iteration (nullptr on first)
146 @param e_j Optional: used in place of j.en() in energy denominator
147 @param e_m Optional: used in place of m.en() in energy denominator
148 @return \f$ L2^k_{mnij} \f$
149*/
150double L2(int k, const DiracSpinor &m, const DiracSpinor &n,
151 const DiracSpinor &i, const DiracSpinor &j,
152 const Coulomb::QkTable &qk, const std::vector<DiracSpinor> &core,
153 const std::vector<DiracSpinor> &excited, const Angular::SixJTable &SJ,
154 const Coulomb::LkTable *const Lk = nullptr,
155 std::optional<double> e_j = {}, std::optional<double> e_m = {});
156
157/*!
158 @brief Exchange partner of L2; equals L2 with m,n and i,j swapped.
159
160 @details
161 \f[ L3^k_{mnij} = L2^k_{nmji} \f]
162 (@p e_i optional: used in place of i.en() in energy denominator)
163*/
164inline double
165L3(int k, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &i,
166 const DiracSpinor &j, const Coulomb::QkTable &qk,
167 const std::vector<DiracSpinor> &core,
168 const std::vector<DiracSpinor> &excited, const Angular::SixJTable &SJ,
169 const Coulomb::LkTable *const Lk = nullptr, std::optional<double> e_i = {}) {
170 return L2(k, n, m, j, i, qk, core, excited, SJ, Lk, e_i);
171}
172
173/*!
174 @brief Core--core (hole--hole) ladder diagram L4.
175
176 @details
177 \f[
178 L4^k_{mnij} = \sum_{cd,ul} A^{klu}_{mncdij}
179 \frac{Q^u_{cdij}\,(Q+L)^l_{mncd}}{\epsilon_{cd} - \epsilon_{mn}}
180 \f]
181 with the angular coefficient \f$ A \f$ as in L1().
182 Intermediate states run over core orbitals only, making this the
183 hole--hole counterpart of the particle--particle diagram L1.
184 Enable via @p include_L4 in Lkmnij().
185
186 @param k Multipole rank
187 @param m,n Excited (particle) orbitals
188 @param i,j Core (hole) or valence orbitals
189 @param qk Coulomb \f$ Q^k \f$ integral table
190 @param core Core orbitals
191 @param SJ 6j symbol table
192 @param Lk Ladder table from previous iteration (nullptr on first)
193 @param e_m Optional: used in place of m.en() in energy denominator
194 @return \f$ L4^k_{mnij} \f$
195*/
196double L4(int k, const DiracSpinor &m, const DiracSpinor &n,
197 const DiracSpinor &i, const DiracSpinor &j,
198 const Coulomb::QkTable &qk, const std::vector<DiracSpinor> &core,
199 const Angular::SixJTable &SJ,
200 const Coulomb::LkTable *const Lk = nullptr,
201 std::optional<double> e_m = {});
202
203/*!
204 @brief Fills the ladder integral table for all _new_ index combinations.
205
206 @details
207 Iterates over all combinations of excited pairs \f$ (m,n) \f$ and
208 orbitals in @p i_orbs, computing \f$ L^k_{mnib} \f$ (with \f$ b \f$ in
209 @p core) and storing results in @p lk.
210 Only calculates new integrals. Only lowest-order.
211
212 @param lk Output ladder table (written in place)
213 @param qk Coulomb \f$ Q^k \f$ integral table
214 @param excited Excited orbitals
215 @param core Core orbitals
216 @param i_orbs Orbitals for the \f$ i \f$ index
217 @param include_L4 Include core-core diagram L4
218 @param sjt 6j symbol table
219 @param max_k Maximum multipolarity; -1 uses qk.max_k()
220 @param print Print progress and timing to screen
221*/
223 const std::vector<DiracSpinor> &excited,
224 const std::vector<DiracSpinor> &core,
225 const std::vector<DiracSpinor> &i_orbs, bool include_L4,
226 const Angular::SixJTable &sjt, int max_k = -1,
227 bool print = true);
228
229/*!
230 @brief Updates the ladder integral table with L(Q,Q) -> L(Q,Q+L)
231
232 @details
233 Re-calculates the existing entries \f$ L^k_{mnib} \f$ of @p lk (those with
234 \f$ i \f$ in @p update_i), using @p lk_prev for the internal (Q+L) rung,
235 and stores results in @p lk. Designed for iterative refinement: pass the
236 previous iteration's table as @p lk_prev.
237
238 @param lk Output ladder table (written in place)
239 @param qk Coulomb \f$ Q^k \f$ integral table
240 @param excited Excited orbitals
241 @param core Core orbitals
242 @param update_i Restrict re-iteration to entries whose i index is in this
243 set (b is always core). Empty => update all. Used to
244 converge core (update_i=core) before valence
245 (update_i=valence).
246 @param include_L4 Include core--core diagram L4
247 @param sjt 6j symbol table
248 @param lk_prev Ladder table from previous iteration
249 @param a_damp Damping factor [0,1) : 0 means no damping.
250 L -> a_damp*L + (1-a_damp)*L_new, where L is the
251 existing entry of @p lk (not @p lk_prev)
252 @param print Print progress and timing to screen
253
254 @note Does not calculate any new integrals - assumes all already present.
255 Just updates them (based on iterative rule: L(Q,Q) -> L(Q,Q+L))
256*/
258 const std::vector<DiracSpinor> &excited,
259 const std::vector<DiracSpinor> &core,
260 const std::vector<DiracSpinor> &update_i, bool include_L4,
261 const Angular::SixJTable &sjt,
262 const Coulomb::LkTable *const lk_prev, double a_damp,
263 bool print);
264
265/*!
266 @brief Second-order (or ladder) correction to the valence energy.
267
268 @details
269 Computes the correlation energy shift
270 \f[
271 \delta\epsilon_v = \frac{1}{[j_v]} \sum_{amn,k}
272 \frac{Q^k_{vamn}\,(L^k_{mnva} + P^k_{nmav})}
273 {[k]\,(\epsilon_v + \epsilon_a - \epsilon_m - \epsilon_n)}
274 + \frac{1}{[j_v]} \sum_{nab,k}
275 \frac{Q^k_{vnab}\,(L^k_{vnab} + P^k_{vnab})}
276 {[k]\,(\epsilon_v + \epsilon_n - \epsilon_a - \epsilon_b)},
277 \f]
278 where \f$ L^k \f$ and its exchange \f$ P^k \f$ (lk.P) both come from
279 @p lk, \f$ a,b \f$ run over core, \f$ m,n \f$ over excited, and \f$ k \f$
280 over the Coulomb-parity range only.
281 When @p lk holds plain Coulomb integrals the result is the
282 MBPT(2) correction; when @p lk holds ladder integrals it is the full
283 ladder correction.
284
285 @param v Valence orbital
286 @param qk Coulomb \f$ Q^k \f$ integral table
287 @param lk \f$ Q^k \f$ or ladder \f$ L^k \f$ integral table
288 @param core Core orbitals
289 @param excited Excited orbitals
290 @return \f$ \delta\epsilon_v \f$
291*/
292template <typename Qintegrals, typename QorLintegrals>
293double de_valence(const DiracSpinor &v, const Qintegrals &qk,
294 const QorLintegrals &lk, const std::vector<DiracSpinor> &core,
295 const std::vector<DiracSpinor> &excited);
296
297/*!
298 @brief Ladder (or MBPT2) valence energy, antisymmetrising the FIRST integral.
299
300 @details
301 Computes
302 \f[
303 \delta\epsilon_v = \sum_{amn,k}
304 \frac{W^k_{vamn}\,L^k_{mnva}}{[k]\,[j_v]\,\Delta\epsilon}
305 + \text{(c+d)},
306 \f]
307 with \f$ W = Q + P \f$ the antisymmetrised Coulomb integral (@p qk.W) and the
308 ladder @p lk entering only through the direct integral @p lk.Q. Equivalent to
309 de_valence() (which instead antisymmetrises the ladder via @p lk.P), since the
310 exchange symmetry holds under the full sum. Unlike de_valence(), this works
311 only with the Coulomb integrals in the first slot (the ladder lacks the
312 required symmetry). No screening/eta is applied.
313
314 @param v Valence orbital
315 @param qk Coulomb integrals supplying \f$ W = Q+P \f$ (first integral)
316 @param lk Ladder \f$ L^k \f$ integrals (second, direct integral)
317 @param core Core orbitals
318 @param excited Excited orbitals
319 @param sj Optional 6j table (speeds up the W exchange sum)
320 @return \f$ \delta\epsilon_v \f$
321*/
322template <typename Qintegrals, typename Lintegrals>
323double de_valence_w(const DiracSpinor &v, const Qintegrals &qk,
324 const Lintegrals &lk, const std::vector<DiracSpinor> &core,
325 const std::vector<DiracSpinor> &excited,
326 const Angular::SixJTable *sj = nullptr);
327
328/*!
329 @brief Second-order (or ladder) correction to the core energy.
330
331 @details
332 Sums the correlation energy shift over all core orbitals. When @p lk holds
333 plain Coulomb integrals the result is the MBPT(2) core correction; when
334 @p lk holds ladder integrals it is the ladder correction.
335
336 @param qk Coulomb \f$ Q^k \f$ integral table
337 @param lk \f$ Q^k \f$ or ladder \f$ L^k \f$ integral table
338 @param core Core orbitals
339 @param excited Excited orbitals
340 @return Total core correlation energy shift
341*/
342template <typename Qintegrals, typename QorLintegrals>
343double de_core(const Qintegrals &qk, const QorLintegrals &lk,
344 const std::vector<DiracSpinor> &core,
345 const std::vector<DiracSpinor> &excited);
346
347/*!
348 @brief Method used to construct the ladder correlation potential, Sigma_L.
349
350 @details
351 - basis : project onto the basis; requires extending Qk (slow)
352 [Sigma_ladder()]
353 - ratio : no projection; rescale each Sigma(2) term by L/Q
354 [Sigma_ladder(), empty projection basis]
355 - direct : no projection; open the external line exactly (ladder vertex)
356 [Sigma_ladder_direct()]
357*/
358enum class SigmaLMethod { basis, ratio, direct };
359
360/*!
361 @brief Converts string (name) to SigmaLMethod enum (case-insensitive).
362
363 @details
364 Also accepts "full" (basis) and "Dzuba" (ratio). Warns and defaults to
365 ratio if unknown.
366*/
367SigmaLMethod parseSigmaLMethod(const std::string &method);
368//! Converts SigmaLMethod enum to string (name)
369std::string parseSigmaLMethod(SigmaLMethod method);
370
371/*!
372 @brief Ladder-diagram correction to the correlation potential, Sigma_L(e_v).
373
374 @details
375 By projection (or, if @p projection is empty, by the L/Q ratio method).
376
377 With a non-empty @p projection basis, forms the ladder correlation potential
378 by projecting the discrete ladder integrals onto the projection states of
379 kappa_v. The exchange is folded into the Coulomb vertex via
380 \f$ W = Q + P \f$ (as in de_valence_w):
381 \f[
382 \Sigma_L = \sum_{i,amn,k} |W^k_{\cdot amn}\rangle\,
383 \frac{L^k_{mn,i,a}}
384 {[k][j_v]\,(\epsilon_v+\epsilon_a-\epsilon_m-\epsilon_n)}\,
385 \langle i|
386 + \sum_{i,nab,k} |W^k_{\cdot nab}\rangle\,
387 \frac{L^k_{i,n,a,b}}
388 {[k][j_v]\,(\epsilon_v+\epsilon_n-\epsilon_a-\epsilon_b)}\,
389 \langle i| ,
390 \f]
391 (particle-particle (a+b) and particle-hole (c+d) diagrams). The bra index
392 \f$ i \f$ runs over the @p projection states of kappa_v (approximating
393 completeness). The ladder integrals are computed on-the-fly via Lkmnij()
394 evaluated at the fixed external energy \f$ \epsilon_v \f$ (via the e_i/e_m
395 energy overrides, since the energy enters only the denominators). Exception:
396 for the valence state itself, the stored table entries are used directly -
397 they are already at the correct energy, so the i = v term is essentially
398 free.
399
400 If @p projection is empty, instead uses the ratio method (following
401 V. A. Dzuba, Phys. Rev. A 78, 042502 (2008)): no projection; each term of
402 the regular second-order correlation potential (cf. Goldstone::Sigma_both)
403 is rescaled by the scalar ratio of ladder to Coulomb integrals:
404 \f[
405 \Sigma_L = \sum_{amn,k} |Q^k_{\cdot amn}\rangle\,
406 \frac{L^k_{mnva}/Q^k_{mnva}}
407 {[k][j_v]\,(\epsilon_v+\epsilon_a-\epsilon_m-\epsilon_n)}\,
408 \langle W^k_{\cdot amn}|
409 + \sum_{nab,k} |Q^k_{\cdot nab}\rangle\,
410 \frac{L^k_{vnab}/Q^k_{vnab}}
411 {[k][j_v]\,(\epsilon_v+\epsilon_n-\epsilon_a-\epsilon_b)}\,
412 \langle W^k_{\cdot nab}| .
413 \f]
414 By construction the diagonal reproduces the ladder energy exactly,
415 <v|Sigma_L|v> = de_valence_w(v), except for the dropped terms (see note).
416 The off-diagonal (radial) structure is approximate: each term keeps the
417 shape of the corresponding second-order term, rescaled by a scalar. All
418 integrals come straight from the stored tables (the L^k entries with i = v
419 are already at the valence energy), so nothing is computed on-the-fly: much
420 faster than projection.
421
422 The sub-grid (@p r0, @p rmax, @p stride) defaults match
423 Wavefunction::formSigma.
424
425 @param v Valence state (basis version; must be in the qk/lk
426 tables)
427 @param core Core (hole) orbitals
428 @param excited Excited orbitals
429 @param projection Projection basis {|i>}; states of kappa_v are used.
430 If empty, the ratio method is used instead (no
431 projection)
432 @param qk Converged Coulomb \f$ Q^k \f$ table
433 @param lk Converged ladder \f$ L^k \f$ table. For projection,
434 it is the internal-rung table forwarded to Lkmnij
435 (nullptr for L(Q,Q)=L^(1)); for ratio, it supplies
436 the L^k integrals (nullptr gives Sigma_L = 0)
437 @param sjt 6j symbol table
438 @param include_L4 Include core--core diagram in on-the-fly Lkmnij
439 (projection only; the ratio method never re-computes
440 L)
441 @param r0,rmax,stride Sub-grid parameters
442 @param include_G Include the lower (g) component of Sigma_L
443 @return Sigma_L as a coordinate-space GMatrix
444
445 @note Ratio method: terms with \f$ Q^k_{mnva} = 0 \f$ (but \f$ L^k \ne 0 \f$)
446 cannot be rescaled and are dropped; inherent to the method. Note that
447 L^k exists at both parities of k (see k_minmax_L) while Q^k
448 exists only at Coulomb parity, so the exchange-only (wrong-parity)
449 k channels are always dropped here; the projection and direct methods
450 include them.
451*/
452GMatrix Sigma_ladder(const DiracSpinor &v, const std::vector<DiracSpinor> &core,
453 const std::vector<DiracSpinor> &excited,
454 const std::vector<DiracSpinor> &projection,
455 const Coulomb::QkTable &qk, const Coulomb::LkTable *lk,
456 const Angular::SixJTable &sjt, bool include_L4 = false,
457 double r0 = 1.0e-4, double rmax = 30.0,
458 std::size_t stride = 4, bool include_G = false);
459
460/*!
461 @brief Vertex (ket) form of ladder integral L^k_mnia over external index i.
462
463 @details
464 Returns the radial spinor \f$ |L^k_{mn \cdot a}\rangle \f$ (kappa of @p v)
465 satisfying
466 \f[ \langle x|L^k_{mn\cdot a}\rangle = L^k_{mnxa}(\epsilon_v) \f]
467 for any \f$ x \f$ with \f$ \kappa_x = \kappa_v \f$, with the external energy
468 fixed at \f$ \epsilon_v \f$ (as the e_i override in Lkmnij).
469
470 In each diagram the external line attaches to a single bare Coulomb line;
471 that line is opened exactly as a radial function (Qkv_bcd). The exception is
472 the L-part of the internal (Q+L) rung in L1 and L3, where the external line
473 attaches to a dressed rung: for that piece we set i = v (scalar coefficient
474 times |v>), which is exact at x = v and is the same level of treatment the
475 scalar table gives it (entries exist only for stored orbitals).
476
477 @param k Multipole rank
478 @param v Valence state: fixes kappa and the external energy, and
479 supplies |v> for the dressed-rung (i = v) piece
480 @param m,n Excited (particle) orbitals
481 @param a Core (hole) orbital
482 @param qk Coulomb \f$ Q^k \f$ integral table (internal lines)
483 @param yk Yk table spanning core+excited (opens the external line)
484 @param core Core orbitals
485 @param excited Excited orbitals
486 @param include_L4 Include core--core diagram L4
487 @param SJ 6j symbol table
488 @param Lk Ladder table for the internal (Q+L) rung (nullptr:
489 lowest order)
490 @return \f$ |L^k_{mn \cdot a}\rangle \f$
491
492 @note All internal lines are Hartree-Fock basis states (from the tables);
493 only the external line is left open. This is the correct structure for
494 acting on Brueckner orbitals.
495*/
496DiracSpinor Lkv_mnia(int k, const DiracSpinor &v, const DiracSpinor &m,
497 const DiracSpinor &n, const DiracSpinor &a,
498 const Coulomb::QkTable &qk, const Coulomb::YkTable &yk,
499 const std::vector<DiracSpinor> &core,
500 const std::vector<DiracSpinor> &excited, bool include_L4,
501 const Angular::SixJTable &SJ,
502 const Coulomb::LkTable *const Lk = nullptr);
503
504/*!
505 @brief Vertex (ket) form of ladder integral L^k_inab over external index i.
506
507 @details
508 The external index i is in the m-slot.
509 Returns the radial spinor \f$ |L^k_{\cdot nab}\rangle \f$ (kappa of @p v)
510 satisfying
511 \f[ \langle x|L^k_{\cdot nab}\rangle = L^k_{xnab}(\epsilon_v) \f]
512 for any \f$ x \f$ with \f$ \kappa_x = \kappa_v \f$, with the external energy
513 fixed at \f$ \epsilon_v \f$ (as the e_m override in Lkmnij).
514
515 Mirror of Lkv_mnia() for the particle-hole (c+d) diagrams: here the external
516 line sits in the m-slot, so it is L2 and L4 whose internal (Q+L) rung
517 contains it (i = v used for the L-part), while L1 and L3 open exactly.
518
519 @param k Multipole rank
520 @param v Valence state: fixes kappa and the external energy, and
521 supplies |v> for the dressed-rung (i = v) piece
522 @param n Excited (particle) orbital
523 @param a,b Core (hole) orbitals
524 @param qk Coulomb \f$ Q^k \f$ integral table (internal lines)
525 @param yk Yk table spanning core+excited (opens the external line)
526 @param core Core orbitals
527 @param excited Excited orbitals
528 @param include_L4 Include core--core diagram L4
529 @param SJ 6j symbol table
530 @param Lk Ladder table for the internal (Q+L) rung (nullptr:
531 lowest order)
532 @return \f$ |L^k_{\cdot nab}\rangle \f$
533*/
534DiracSpinor Lkv_inab(int k, const DiracSpinor &v, const DiracSpinor &n,
535 const DiracSpinor &a, const DiracSpinor &b,
536 const Coulomb::QkTable &qk, const Coulomb::YkTable &yk,
537 const std::vector<DiracSpinor> &core,
538 const std::vector<DiracSpinor> &excited, bool include_L4,
539 const Angular::SixJTable &SJ,
540 const Coulomb::LkTable *const Lk = nullptr);
541
542/*!
543 @brief Ladder correlation potential Sigma_L via the direct method.
544
545 @details
546 Forms the ladder correlation potential with the external line opened
547 exactly, rather than projected onto a basis:
548 \f[
549 \Sigma_L = \sum_{amn,k} |W^k_{\cdot amn}\rangle\,
550 \frac{1}{[k][j_v]\,(\epsilon_v+\epsilon_a-\epsilon_m-\epsilon_n)}\,
551 \langle L^k_{mn \cdot a}|
552 + \sum_{nab,k} |W^k_{\cdot nab}\rangle\,
553 \frac{1}{[k][j_v]\,(\epsilon_v+\epsilon_n-\epsilon_a-\epsilon_b)}\,
554 \langle L^k_{\cdot nab}| ,
555 \f]
556 with the bra-side ladder vertices from Lkv_mnia() / Lkv_inab(). All internal
557 lines are Hartree-Fock basis states; the external line is exact wherever it
558 attaches to a bare Coulomb line (everything at lowest order in L), and is
559 taken as |v><v| only for the dressed-rung (internal-L) attachment, which
560 enters the energy at 4th order. Consequently Sigma_L acts correctly on
561 Brueckner orbitals: (H + Sigma + Sigma_L)|psi_B> = e|psi_B>, rather than
562 merely shifting by <v|Sigma_L|v>.
563
564 <v|Sigma_L|v> reproduces the ladder energy de_valence_w (up to iteration
565 convergence of the L table). No projection basis, no Qk extension.
566
567 @param v Valence state (basis version; supplies kappa_v,
568 en_v, and the i=v dressed-rung piece)
569 @param core Core (hole) orbitals
570 @param excited Excited orbitals
571 @param qk Converged Coulomb \f$ Q^k \f$ table
572 @param yk Yk table spanning core+excited (radial vertex
573 functions)
574 @param lk Converged ladder \f$ L^k \f$ table (nullptr:
575 lowest-order L)
576 @param sjt 6j symbol table
577 @param include_L4 Include core--core diagram L4
578 @param r0,rmax,stride Sub-grid parameters
579 @param include_G Include the lower (g) component of Sigma_L
580 @return Sigma_L as a coordinate-space GMatrix
581*/
582GMatrix Sigma_ladder_direct(
583 const DiracSpinor &v, const std::vector<DiracSpinor> &core,
584 const std::vector<DiracSpinor> &excited, const Coulomb::QkTable &qk,
585 const Coulomb::YkTable &yk, const Coulomb::LkTable *lk,
586 const Angular::SixJTable &sjt, bool include_L4 = false, double r0 = 1.0e-4,
587 double rmax = 30.0, std::size_t stride = 4, bool include_G = false);
588
589//==============================================================================
590
591/*!
592 @brief Ladder correlation potential matrix, Sigma_L, for a single state.
593
594 @details
595 For a single (kappa, n) state, evaluated at energy en.
596*/
598 //! Dirac quantum number of the state Sigma_L was formed for
599 int kappa;
600 //! Principal quantum number of the state Sigma_L was formed for
601 int n;
602 //! Energy Sigma_L was evaluated at
603 double en;
604 //! Sigma_L matrix, on its own sub-grid
606};
607
608/*!
609 @brief Writes Sigma_L (ladder) matrices to binary file.
610
611 @details
612 File contains the full-grid parameters (for checking on read), followed by
613 each Sigma_L matrix with its own sub-grid parameters and include_G flag.
614
615 @return True if written; false (and writes nothing) if @p fname is empty or
616 'false', or @p SLs is empty.
617*/
618bool write_SigmaL(const std::string &fname, const std::vector<SigmaLData> &SLs,
619 const Grid &grid);
620
621/*!
622 @brief Reads Sigma_L (ladder) matrices from binary file.
623
624 @details
625 @p grid must match the full radial grid the matrices were calculated on.
626 Each matrix carries its own sub-grid parameters and include_G flag (they
627 need not match those of the base Sigma).
628
629 @return The Sigma_L matrices. Empty vector if @p fname is empty or 'false',
630 the file doesn't exist, or on grid mismatch.
631*/
632std::vector<SigmaLData> read_SigmaL(const std::string &fname,
633 const std::shared_ptr<const Grid> &grid);
634
635// template implementations:
636#include "Ladder.ipp"
637
638} // namespace MBPT
Lookup table for Wigner 6j symbols.
Definition SixJTable.hpp:82
Base class template to store Coulomb integrals, and similar. 3 specific cases (by template instantiat...
Definition QkTable.hpp:118
Calculates + stores Hartree Y functions + Angular (w/ look-up), taking advantage of symmetry.
Definition YkTable.hpp:46
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:55
int twoj() const
2j (twice the total angular momentum)
Definition DiracSpinor.hpp:121
int l() const
Orbital angular momentum Q number.
Definition DiracSpinor.hpp:117
Non-uniform radial grid with Jacobian, suitable for atomic structure calculations.
Definition Grid.hpp:85
constexpr int l_k(int ka)
returns l given kappa
Definition Wigner369j.hpp:44
constexpr int twoj_k(int ka)
returns 2j given kappa
Definition Wigner369j.hpp:46
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
Many-body perturbation theory.
Definition MatrixElements.hpp:12
double de_valence_w(const DiracSpinor &v, const Qintegrals &qk, const Lintegrals &lk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, const Angular::SixJTable *sj=nullptr)
Ladder (or MBPT2) valence energy, antisymmetrising the FIRST integral.
double en
Energy Sigma_L was evaluated at.
Definition Ladder.hpp:603
GMatrix SL
Sigma_L matrix, on its own sub-grid.
Definition Ladder.hpp:605
int kappa
Dirac quantum number of the state Sigma_L was formed for.
Definition Ladder.hpp:599
double L2(int k, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &i, const DiracSpinor &j, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk, std::optional< double > e_j, std::optional< double > e_m)
Particle–hole ladder diagram L2.
Definition Ladder.cpp:400
DiracSpinor Lkv_inab(int k, const DiracSpinor &v, const DiracSpinor &n, const DiracSpinor &a, const DiracSpinor &b, const Coulomb::QkTable &qk, const Coulomb::YkTable &yk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, bool include_L4, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk)
Vertex (ket) form of ladder integral L^k_inab over external index i.
Definition Ladder.cpp:1060
SigmaLMethod parseSigmaLMethod(const std::string &method)
Converts string (name) to SigmaLMethod enum (case-insensitive).
Definition Ladder.cpp:24
void update_Lk_mnib(Coulomb::LkTable *lk, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &excited, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &update_i, bool include_L4, const Angular::SixJTable &sjt, const Coulomb::LkTable *const lk_prev, double a_damp, bool print)
Updates the ladder integral table with L(Q,Q) -> L(Q,Q+L)
Definition Ladder.cpp:1429
GMatrix Sigma_ladder_direct(const DiracSpinor &v, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, const Coulomb::QkTable &qk, const Coulomb::YkTable &yk, const Coulomb::LkTable *lk, const Angular::SixJTable &sjt, bool include_L4, double r0, double rmax, std::size_t stride, bool include_G)
Ladder correlation potential Sigma_L via the direct method.
Definition Ladder.cpp:1341
std::pair< int, int > k_minmax_L(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)
Min and max k (multipolarity) allowed for ladder integral L^k_abcd.
Definition Ladder.hpp:23
double L1(int k, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &i, const DiracSpinor &j, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &excited, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk, std::optional< double > e_i)
Particle–particle ladder diagram L1.
Definition Ladder.cpp:126
GMatrix Sigma_ladder(const DiracSpinor &v, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, const std::vector< DiracSpinor > &projection, const Coulomb::QkTable &qk, const Coulomb::LkTable *lk, const Angular::SixJTable &sjt, bool include_L4, double r0, double rmax, std::size_t stride, bool include_G)
Ladder-diagram correction to the correlation potential, Sigma_L(e_v).
Definition Ladder.cpp:574
std::vector< SigmaLData > read_SigmaL(const std::string &fname, const std::shared_ptr< const Grid > &grid)
Reads Sigma_L (ladder) matrices from binary file.
Definition Ladder.cpp:1528
DiracSpinor Lkv_mnia(int k, const DiracSpinor &v, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &a, const Coulomb::QkTable &qk, const Coulomb::YkTable &yk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, bool include_L4, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk)
Vertex (ket) form of ladder integral L^k_mnia over external index i.
Definition Ladder.cpp:777
double Lkmnij(int k, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &i, const DiracSpinor &j, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, bool include_L4, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk, std::optional< double > e_i, std::optional< double > e_m)
Full ladder integral summed over all diagrams.
Definition Ladder.cpp:107
double de_core(const Qintegrals &qk, const QorLintegrals &lk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited)
Second-order (or ladder) correction to the core energy.
void fill_Lk_mnib(Coulomb::LkTable *lk, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &excited, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &i_orbs, bool include_L4, const Angular::SixJTable &sjt, int max_k, bool print)
Fills the ladder integral table for all new index combinations.
Definition Ladder.cpp:499
int n
Principal quantum number of the state Sigma_L was formed for.
Definition Ladder.hpp:601
SigmaLMethod
Method used to construct the ladder correlation potential, Sigma_L.
Definition Ladder.hpp:358
bool write_SigmaL(const std::string &fname, const std::vector< SigmaLData > &SLs, const Grid &grid)
Writes Sigma_L (ladder) matrices to binary file.
Definition Ladder.cpp:1479
double L3(int k, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &i, const DiracSpinor &j, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk=nullptr, std::optional< double > e_i={})
Exchange partner of L2; equals L2 with m,n and i,j swapped.
Definition Ladder.hpp:165
double de_valence(const DiracSpinor &v, const Qintegrals &qk, const QorLintegrals &lk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited)
Second-order (or ladder) correction to the valence energy.
double L4(int k, const DiracSpinor &m, const DiracSpinor &n, const DiracSpinor &i, const DiracSpinor &j, const Coulomb::QkTable &qk, const std::vector< DiracSpinor > &core, const Angular::SixJTable &SJ, const Coulomb::LkTable *const Lk, std::optional< double > e_m)
Core–core (hole–hole) ladder diagram L4.
Definition Ladder.cpp:272
Ladder correlation potential matrix, Sigma_L, for a single state.
Definition Ladder.hpp:597