ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
Loading...
Searching...
No Matches
Ladder.ipp
1#pragma once
2#include "Angular/Angular.hpp"
3#include "Coulomb/Coulomb.hpp"
4#include "Wavefunction/DiracSpinor.hpp"
5#include <type_traits>
6// namespace MBPT
7
8//==============================================================================
9// Calculate energy shift (either ladder, or sigma2)
10// nb: set lk to qk to det de(2)
11template <typename Qintegrals, typename QorLintegrals>
12double de_valence(const DiracSpinor &v, const Qintegrals &qk,
13 const QorLintegrals &lk, const std::vector<DiracSpinor> &core,
14 const std::vector<DiracSpinor> &excited,
15 const std::vector<double> &v_fk,
16 const std::vector<double> &v_eta) {
17
18 // XXX Fix this!
19 // static_assert(std::is_same_v<Qintegrals, Coulomb::YkTable> ||
20 // std::is_base_of_v<Coulomb::CoulombTable, Qintegrals>,
21 // "Qintegrals must be YkTable or CoulombTable
22 // (QkTable/LkTable)");
23 // static_assert(
24 // std::is_same_v<QorLintegrals, Coulomb::YkTable> ||
25 // std::is_base_of_v<Coulomb::CoulombTable, QorLintegrals>,
26 // "QorLintegrals must be YkTable or CoulombTable (QkTable/LkTable)");
27
28 const bool LisQ = [&]() {
29 if constexpr (std::is_same_v<Qintegrals, QorLintegrals>)
30 return &qk == &lk;
31 else
32 return false;
33 }();
34
35 // screening factors:
36 auto Fk = [&v_fk](int k) {
37 return k < (int)v_fk.size() ? v_fk[std::size_t(k)] : 1.0;
38 };
39 // hole-particle
40 auto Eta = [&v_eta](int k) {
41 return k < (int)v_eta.size() ? v_eta[std::size_t(k)] : 1.0;
42 };
43
44 auto de_v = 0.0;
45
46 // nb: always put 'v' in correct* position. This ensures that actual state v
47 // is used when evaluating Q/W integrals [as opposed to the excited basis
48 // version of v]. Note: only matters when using YkTable for integrals
49 // *correct == 1st or 3rd in Q, 1st or 4th in P
50
51#pragma omp parallel for reduction(+ : de_v)
52 for (auto in = 0ul; in < excited.size(); ++in) {
53 const auto &n = excited[in];
54 for (const auto &a : core) {
55
56 // Diagrams (a) + (b)
57 for (const auto &m : excited) {
58 const auto inv_de = 1.0 / (v.en() + a.en() - m.en() - n.en());
59 const auto [k0, kI] = Coulomb::k_minmax_Q(v, a, m, n);
60 for (int k = k0; k <= kI; k += 2) {
61
62 const auto fk = Fk(k);
63 const auto etak = Eta(k);
64
65 const auto Q_kvamn = qk.Q(k, v, a, m, n);
66 const auto L_kvamn = LisQ ? fk * Q_kvamn : lk.Q(k, m, n, v, a);
67 const auto P_kvamn = lk.P(k, n, m, a, v); // \propto Q_mnva
68
69 // diagram (a). xxx include fk here? I though no...
70 de_v += /*fk **/ etak * Q_kvamn * L_kvamn * inv_de / (2 * k + 1);
71 // diagram (b) [exchange]
72 de_v += fk * Q_kvamn * P_kvamn * inv_de / (2 * k + 1);
73 } // k
74 } // m
75
76 // Diagrams (c) + (d)
77 for (const auto &b : core) {
78 const auto inv_de = 1.0 / (v.en() + n.en() - a.en() - b.en());
79 const auto [k0, kI] = Coulomb::k_minmax_Q(v, n, a, b);
80 for (int k = k0; k <= kI; k += 2) {
81
82 const auto fk = Fk(k);
83 const auto etak = Eta(k);
84
85 const auto Q_kvnab = qk.Q(k, v, n, a, b);
86 const auto L_kvnab = LisQ ? fk * Q_kvnab : lk.Q(k, v, n, a, b);
87 const auto P_kvnab = lk.P(k, v, n, a, b);
88
89 // diagram (c). xxx include fk here? I though no...
90 de_v += /*fk **/ etak * Q_kvnab * L_kvnab * inv_de / (2 * k + 1);
91 // diagram (d) [exchange]
92 de_v += fk * Q_kvnab * P_kvnab * inv_de / (2 * k + 1);
93 } // k
94 } // b
95
96 //
97 } // a
98 } // n
99
100 return de_v / v.twojp1();
101}
102
103//------------------------------------------------------------------------------
104// Calculate energy shift (either ladder, or sigma2) for CORE
105// lk may be regular Coulomb integrals [in which case this returns MBPT(2)
106// correction], or Ladder diagrams [in which case this returns the ladder
107// diagram correction]
108template <typename Qintegrals, typename QorLintegrals>
109double de_core(const Qintegrals &qk, const QorLintegrals &lk,
110 const std::vector<DiracSpinor> &core,
111 const std::vector<DiracSpinor> &excited) {
112
113 // XXX Fix this
114 // static_assert(std::is_same_v<Qintegrals, Coulomb::YkTable> ||
115 // std::is_base_of_v<Coulomb::CoulombTable, QorLintegrals>,
116 // "Qintegrals must be YkTable or CoulombTable
117 // (QkTable/LkTable)");
118
119 const bool LisQ = [&]() {
120 if constexpr (std::is_same_v<Qintegrals, QorLintegrals>)
121 return &qk == &lk;
122 else
123 return false;
124 }();
125
126 auto de_c = 0.0;
127#pragma omp parallel for reduction(+ : de_c)
128 for (auto in = 0ul; in < excited.size(); ++in) {
129 const auto &n = excited[in];
130 for (const auto &m : excited) {
131 for (const auto &a : core) {
132 for (const auto &b : core) {
133 const auto inv_de = 1.0 / (a.en() + b.en() - m.en() - n.en());
134 const auto [k0, kI] = Coulomb::k_minmax_Q(a, b, m, n);
135 for (int k = k0; k <= kI; k += 2) {
136 const auto Q_kabmn = qk.Q(k, a, b, m, n);
137 const auto L_kmnab = LisQ ? Q_kabmn : lk.Q(k, m, n, a, b);
138 const auto P_kmnab = lk.P(k, m, n, a, b);
139 de_c += 0.5 * Q_kabmn * (L_kmnab + P_kmnab) * inv_de / (2 * k + 1);
140 }
141 }
142 }
143 }
144 }
145 return de_c;
146}
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:41
int twojp1() const
2j+1
Definition DiracSpinor.hpp:91
double en() const
Single-particle energy, not including rest energy.
Definition DiracSpinor.hpp:113
std::pair< int, int > k_minmax_Q(const DiracSpinor &a, const DiracSpinor &b, const DiracSpinor &c, const DiracSpinor &d)
Returns min and max k (multipolarity) allowed for Q^k_abcd. Parity rule is included,...
Definition CoulombIntegrals.cpp:556
double de_core(const Qintegrals &qk, const QorLintegrals &lk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited)
Calculate energy shift (either ladder, or sigma2) for CORE.
double de_valence(const DiracSpinor &v, const Qintegrals &qk, const QorLintegrals &lk, const std::vector< DiracSpinor > &core, const std::vector< DiracSpinor > &excited, const std::vector< double > &fk={}, const std::vector< double > &etak={})
Calculate energy shift (either ladder, or sigma2) for valence.