High-precision calculations for one- and two-valence atomic systems
CorrelationPotential.hpp
1#pragma once
2#include "Angular/CkTable.hpp"
3#include "Angular/SixJTable.hpp"
4#include "Coulomb/YkTable.hpp"
5#include "IO/FRW_fileReadWrite.hpp"
6#include "MBPT/Feynman.hpp"
7#include "MBPT/Goldstone.hpp"
8#include "MBPT/SpinorMatrix.hpp"
9#include "Wavefunction/DiracSpinor.hpp"
10#include <optional>
11#include <vector>
12
13namespace MBPT {
14
15struct SigmaData {
16 int kappa;
17 double en;
18 SpinorMatrix<double> Sigma;
19 int n{0};
20 double lambda{1.0};
21 //! fk screening factors used for this Sigma (empty if none)
22 std::vector<double> fk{};
23};
24
25enum class SigmaMethod { Goldstone, Feynman };
26
27struct rgrid_params {
28 double r0{1.0e-4};
29 double rmax{30.0};
30 std::size_t stride{4};
31};
32
33//==============================================================================
34
35class CorrelationPotential {
36 const HF::HartreeFock *m_HF;
37 std::vector<DiracSpinor> m_basis; // so we can delay goldstone construction
38 std::vector<SigmaData> m_Sigmas{};
39 double m_r0, m_rmax;
40 std::size_t m_stride;
41 std::size_t m_i0, m_size; // need?
42
43 SigmaMethod m_method;
44 int m_n_min_core;
45 // int m_n_min_core_F;
46 bool m_includeG;
47 bool m_includeBreit_b2;
48 int m_n_max_breit;
49
50 std::optional<Goldstone> m_Gold{};
51
52 FeynmanOptions m_Foptions;
53 bool m_calculate_fk; // if not, need fk and etak
54 std::vector<double> m_fk;
55 std::vector<double> m_etak;
56 // Apply fk to both Coulomb lines of the exchange diagrams (else outer only)
57 bool m_fk_both_lines;
58
59 std::optional<Feynman> m_Fy{};
60
61 // These are only for calculating fk and eta
62 std::optional<Feynman> m_Fy0{};
63 std::optional<Feynman> m_FyX{};
64 std::optional<Feynman> m_FyH{};
65
66 std::string m_fname{};
67
68 // Ladder correction, Sigma_L: read from file (produced by the Ladder{}
69 // block/driver - see MBPT::ladder). Stored separately from the base Sigma
70 // (may have its own sub-grid and include_G); added in SigmaFv, and scaled
71 // by the same lambda as the base Sigma.
72 std::vector<SigmaData> m_Sigma_L{};
73 std::string m_ladder_file{};
74
75 // Energy derivative, dSigma/dE (forward difference; see m_delta_en).
76 // Formed alongside Sigma when m_form_derivative is set; appended to the
77 // sigma file (older files simply have none)
78 bool m_form_derivative{false};
79 std::vector<SigmaData> m_dSigma{};
80 static constexpr double m_delta_en = 0.01;
81
82public:
83 CorrelationPotential(
84 const std::string &fname, const HF::HartreeFock *vHF,
85 const std::vector<DiracSpinor> &basis, double r0, double rmax,
86 std::size_t stride, int n_min_core, SigmaMethod method,
87 bool include_g = false, bool include_Breit_b2 = false, int n_max_breit = 0,
88 const FeynmanOptions &Foptions = {}, bool calculate_fk = true,
89 const std::vector<double> &fk = {}, const std::vector<double> &etak = {},
90 const std::string &ladder_file = "", bool form_derivative = false,
91 bool fk_both_lines = false);
92
93 // // not thread safe!
94 // void formSigma(int kappa, double en, int n = 0) {}
95 // not thread safe!
96 void formSigma(int kappa, double ev, int n, const DiracSpinor *Fv = nullptr);
97
98 bool empty() const { return m_Sigmas.empty(); }
99
100 const GMatrix *getSigma(int kappa, int n = 0) const;
101
102 double getLambda(int kappa, int n = 0) const;
103
104 void clear() { m_Sigmas.clear(); }
105
106 //! returns Spinor: Sigma|Fv>
107 //! @details If Sigma for kappa_v doesn't exist, returns |0>.
108 DiracSpinor SigmaFv(const DiracSpinor &Fv) const;
109 DiracSpinor operator()(const DiracSpinor &Fv) const { return SigmaFv(Fv); }
110
111 //! For each valence state, prints MBPT(2) energy correction (direct,
112 //! exchange, total), and <v|Sigma|v> using the stored Sigma matrix.
113 void print_de(const std::vector<DiracSpinor> &valence);
114
115 //! True if any dSigma/dE matrices are present (see form_derivative)
116 bool has_derivative() const { return !m_dSigma.empty(); }
117
118 //! Pointer to dSigma/dE data for given kappa (and n); nullptr if not present
119 const SigmaData *get_derivative(int kappa, int n = 0) const;
120
121 /*!
122 @brief Returns lambda * dSigma/dE |Fv>; returns |0> if no derivative
123 exists for this kappa.
124 @details
125 The energy derivative of Sigma, formed by finite difference alongside
126 Sigma itself (option form_derivative), so it corresponds to the actual
127 method used (Goldstone/Feynman, screening, etc.). Scaled by the same
128 lambda as the base Sigma.
129
130 @note The ladder correction (Sigma_L) has no energy derivative: it is
131 included in SigmaFv() but not here.
132 */
133 DiracSpinor dSigmaFv(const DiracSpinor &Fv) const;
134
135 //! Stores scaling factors, lambda, for each kappa (Sigma -> lamda*Sigma)
136 void scale_Sigma(const std::vector<double> &lambdas);
137
138 // if n=0, scales _all_
139 void scale_Sigma(double lambda, int kappa, int n = 0);
140
141 //! Prints the scaling factors to screen
142 void print_scaling() const;
143
144 //! Prints the scaling factors to screen
145 void print_info() const;
146
147 //! Short string identifying the method (main differences only), e.g.,
148 //! "Feynman, all-order" or "Goldstone". Intended for file-cache keys.
149 std::string method_string() const;
150
151 //! Fitting (scaling) factors as a string, "kappa=value," rounded to 4 dp;
152 //! empty if none scaled. For file-cache keys (e.g., the ci-file hash).
153 std::string lambda_string() const;
154
155 /*!
156 @brief Average of the stored fk screening factors over the lowest Sigma
157 of each l up to @p l_max; empty if none stored.
158 @details
159 For re-use of the Sigma_1 screening in Sigma_2 (CI), where there is one
160 effective fk per Coulomb line but no unique state: the low-l factors are
161 the relevant ones for the CI valence space (higher-l factors can differ
162 significantly, e.g., f/g at k = 0, but such states rarely contribute).
163 Weighted by l, not kappa: the fine-structure pair of each l is averaged
164 first, then the mean is taken over the ls (so s counts the same as p,
165 d, ...). Truncated to the shortest stored list.
166
167 @param l_max Maximum l included in the average (CI uses 2: s, p, d).
168 */
169 std::vector<double> average_fk(int l_max = 2) const;
170
171 //! Prints the sub-grid parameters to screen
172 void print_subGrid() const;
173
174 void write(const std::string &fname) { read_write(fname, IO::FRW::write); }
175
176 //! Pointer to the stored Sigma data (matrix, energy formed at, lambda) for
177 //! given kappa (and n); nullptr if not present
178 const SigmaData *get(int kappa, int n = 0) const;
179
180private:
181 bool read_write(const std::string &fname, IO::FRW::RoW rw);
182 void setup_Feynman();
183 std::vector<double> calculate_fk(double ev, const DiracSpinor &v) const;
184 std::vector<double> calculate_etak(double ev, const DiracSpinor &v) const;
185 const SigmaData *get_ladder(int kappa, int n = 0) const;
186
187 // given_fk: screening factors to use (from state_fk); if nullptr,
188 // calculated internally (if applicable). print = false: silent (e.g., the
189 // extra evaluation for the derivative - only the used Sigma is reported)
190 GMatrix formSigma_F(int kappa, double ev, const DiracSpinor *Fv = nullptr,
191 const std::vector<double> *given_fk = nullptr,
192 bool print = true);
193 GMatrix formSigma_G(int kappa, double ev, const DiracSpinor *Fv = nullptr,
194 bool print = true);
195
196 // Calculates the fk screening factors for this state, once (with print;
197 // stores first set in m_fk). nullopt if not applicable (not
198 // Feynman-screening, fk given manually, or no Fv)
199 std::optional<std::vector<double>> state_fk(double ev, const DiracSpinor *Fv);
200
201 // Forms dSigma/dE for given kappa by forward finite difference (step
202 // m_delta_en): one extra Sigma evaluation at ev + delta, re-using the
203 // base Sigma matrix and the same fk; stores in m_dSigma
204 void form_derivative(int kappa, double ev, int n, const DiracSpinor *Fv,
205 const GMatrix &Sigma0,
206 const std::vector<double> *given_fk = nullptr);
207
208public:
209 CorrelationPotential &operator=(const CorrelationPotential &) = default;
210 CorrelationPotential(const CorrelationPotential &) = default;
211 ~CorrelationPotential() = default;
212
213 //
214};
215
216} // namespace MBPT
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:44
Solves relativistic Hartree-Fock equations for core and valence. Optionally includes Breit and QED ef...
Definition HartreeFock.hpp:111
Many-body perturbation theory.
Definition MatrixElements.hpp:12