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
15//! Stored Sigma matrix, with the parameters it was formed with
16struct SigmaData {
17 //! Dirac quantum number of the state Sigma was formed for
18 int kappa;
19 //! Energy Sigma was formed at
20 double en;
21 //! Sigma matrix, on the sub-grid
23 //! Principal quantum number of the state Sigma was formed for (0: none given)
24 int n{0};
25 //! Scaling factor, Sigma -> lambda*Sigma; not applied to the stored matrix
26 double lambda{1.0};
27 //! fk screening factors used for this Sigma (empty if none)
28 std::vector<double> fk{};
29 //! Coefficient of large-r tail, Sigma = a_eff/r^4 beyond sub-grid (0: none)
30 double a_eff{0.0};
31};
32
33/*!
34 @brief Fits the coefficient a_eff of the large-r polarisation tail of Sigma.
35
36 @details
37 Large-r tail: \f$ \Sigma(r) \to a_{\rm eff}/r^4 \f$.
38
39 Averages \f$ r^4 (\Sigma F_v)(r)/F_v(r) \f$ (large component) over @p n_fit
40 sub-grid points: the outermost ones where
41 \f$ |F_v| \geq f_{\rm cut} \max|F_v| \f$ (stopping at a node). Further out,
42 Fv is exponentially small and the ratio is dominated by numerical noise in
43 Sigma. In the fit region (outside the core, typically a few to ~15 aB)
44 \f$ r^4 (\Sigma F_v)/F_v \f$ is already close to constant.
45
46 @return a_eff; zero if there are no points in the fit region.
47
48 @note Can be numerically unstable, should be treated as a test
49*/
50double fit_tail_coefficient(const GMatrix &Sigma, const DiracSpinor &Fv,
51 std::size_t n_fit = 10, double f_cut = 1.0e-2);
52
53/*!
54 @brief Adds the large-r polarisation tail of Sigma to @p SigmaFn.
55
56 @details
57 Adds \f$ (a_{\rm eff}/r^4) F_n \f$ for r beyond the Sigma sub-grid (where
58 \f$ \Sigma F_n \f$ is zero). Treated as a local potential. Acts on the small
59 component only if @p Sigma includes g parts. Does nothing if @p a_eff is
60 zero.
61*/
62void add_tail(DiracSpinor *SigmaFn, const GMatrix &Sigma, const DiracSpinor &Fn,
63 double a_eff);
64
65/*!
66 @brief Method used to form the direct Sigma diagrams.
67
68 @details
69 Goldstone (basis sum) or Feynman (Green's function). Exchange diagrams
70 always use Goldstone.
71*/
73
74//! Sigma sub-grid parameters: range (aB) and stride (of full grid)
76 double r0{1.0e-4};
77 double rmax{30.0};
78 std::size_t stride{4};
79};
80
81//==============================================================================
82
83/*!
84 @brief Correlation potential, Sigma, for valence states.
85
86 @details
87 Core-valence correlations, stored as a non-local matrix for each kappa, on
88 a radial sub-grid (every stride-th point of the full grid, between r0 and
89 rmax). Formed at a given energy (see formSigma). Read from file if it
90 exists, so it need only be formed once (see write).
91
92 Direct diagrams are formed using either the Goldstone (basis sum) or Feynman
93 (Green's function) technique; the Feynman technique allows all-order
94 inclusion of screening and the hole-particle interaction. Exchange diagrams
95 always use Goldstone, with optional effective screening factors fk.
96
97 The action of Sigma on a state (SigmaFv) includes:
98 - lambda scaling, \f$ \Sigma \to \lambda\Sigma \f$ (see scale_Sigma)
99 - ladder correction, \f$ \Sigma_L \f$, if a ladder file was given
100 - large-r tail, \f$ a_{\rm eff}/r^4 \f$, beyond the sub-grid, if
101 tail_extrapolation is set (experimental; see fit_tail_coefficient)
102
103 Optionally also forms the energy derivative,
104 \f$ \partial\Sigma/\partial\varepsilon \f$ (see dSigmaFv).
105
106 @note Not thread safe: formSigma modifies internal state.
107*/
109 const HF::HartreeFock *m_HF;
110 std::vector<DiracSpinor> m_basis; // so we can delay goldstone construction
111 std::vector<SigmaData> m_Sigmas{};
112 double m_r0, m_rmax;
113 std::size_t m_stride;
114 std::size_t m_i0, m_size; // need?
115
116 SigmaMethod m_method;
117 int m_n_min_core;
118 // int m_n_min_core_F;
119 bool m_includeG;
120 bool m_includeBreit_b2;
121 int m_n_max_breit;
122
123 std::optional<Goldstone> m_Gold{};
124
125 FeynmanOptions m_Foptions;
126 bool m_calculate_fk; // if not, need fk and etak
127 std::vector<double> m_fk;
128 std::vector<double> m_etak;
129 // Apply fk to both Coulomb lines of the exchange diagrams (else outer only)
130 bool m_fk_both_lines;
131
132 std::optional<Feynman> m_Fy{};
133
134 // These are only for calculating fk and eta
135 std::optional<Feynman> m_Fy0{};
136 std::optional<Feynman> m_FyX{};
137 std::optional<Feynman> m_FyH{};
138
139 std::string m_fname{};
140
141 // Ladder correction, Sigma_L: read from file (produced by the Ladder{}
142 // block/driver - see MBPT::ladder). Stored separately from the base Sigma
143 // (may have its own sub-grid and include_G); added in SigmaFv, and scaled
144 // by the same lambda as the base Sigma.
145 std::vector<SigmaData> m_Sigma_L{};
146 std::string m_ladder_file{};
147
148 // Energy derivative, dSigma/dE (forward difference; see m_delta_en).
149 // Formed alongside Sigma when m_form_derivative is set; appended to the
150 // sigma file (older files simply have none)
151 bool m_form_derivative{false};
152 std::vector<SigmaData> m_dSigma{};
153 static constexpr double m_delta_en = 0.01;
154
155 // Experimental: extrapolate Sigma beyond the sub-grid as a_eff/r^4, with
156 // a_eff fitted once for each Sigma from the valence state it was formed for
157 // (see fit_tail_coefficient). Sigmas formed without a valence state get no
158 // tail.
159 bool m_tail_extrapolation{false};
160
161public:
162 /*!
163 @brief Reads Sigma from file if it exists; otherwise sets up to form it.
164
165 @details
166 If @p fname exists, Sigma is read from it. Otherwise, sets up the
167 Goldstone/Feynman method; Sigma itself is only formed by formSigma. The
168 ladder file, if given, is read in either case.
169
170 @param fname Sigma file (read if it exists; see write)
171 @param vHF Hartree-Fock (core, grid, Breit). Pointer is
172 stored: must outlive this object
173 @param basis Basis for the Goldstone sums (and print_de)
174 @param r0 Sub-grid first point (aB)
175 @param rmax Sub-grid last point (aB)
176 @param stride Sub-grid stride: every stride-th point of the
177 full grid
178 @param n_min_core Minimum n of core states included in
179 polarisation (lower core states are frozen)
180 @param method Goldstone or Feynman, for direct diagrams
181 @param include_g Include small-component (fg, gf, gg) parts of
182 Sigma
183 @param include_Breit_b2 Include two-body Breit (B2) correction (only if
184 @p vHF includes Breit)
185 @param n_max_breit Maximum n of excited states in the B2
186 correction (0: all)
187 @param Foptions Options for the Feynman method (screening,
188 hole-particle, etc.)
189 @param calculate_fk Calculate fk screening factors for exchange,
190 for each state (Feynman, with screening); else
191 @p fk used
192 @param fk Effective screening factors, for each
193 multipole k
194 @param etak Effective hole-particle factors, for each k
195 (Goldstone only)
196 @param ladder_file File with ladder correction, Sigma_L (empty:
197 none)
198 @param form_derivative Also form dSigma/dE (see dSigmaFv)
199 @param fk_both_lines Apply fk to both Coulomb lines of the exchange
200 diagrams (else outer only)
201 @param tail_extrapolation Extrapolate Sigma beyond the sub-grid as
202 a_eff/r^4 (experimental; see
203 fit_tail_coefficient)
204
205 @note If read from file, the sub-grid and @p include_g are taken from the
206 file, not the inputs.
207 */
209 const std::string &fname, const HF::HartreeFock *vHF,
210 const std::vector<DiracSpinor> &basis, double r0, double rmax,
211 std::size_t stride, int n_min_core, SigmaMethod method,
212 bool include_g = false, bool include_Breit_b2 = false, int n_max_breit = 0,
213 const FeynmanOptions &Foptions = {}, bool calculate_fk = true,
214 const std::vector<double> &fk = {}, const std::vector<double> &etak = {},
215 const std::string &ladder_file = "", bool form_derivative = false,
216 bool fk_both_lines = false, bool tail_extrapolation = false);
217
218 /*!
219 @brief Forms and stores Sigma for given kappa, at energy @p ev.
220
221 @details
222 If Sigma already exists for @p kappa and @p n (any n if @p n <= 0), it is
223 not re-formed; only the tail fit and dSigma/dE are added if required and
224 missing (e.g., Sigma read from file).
225
226 @param kappa Dirac quantum number
227 @param ev Energy at which Sigma is formed
228 @param n Principal quantum number: allows distinct Sigma for each n
229 of the same kappa
230 @param Fv State Sigma is formed for (optional): used to calculate fk
231 screening factors, fit the large-r tail, and print the
232 energy shift. Must have kappa = @p kappa.
233
234 @warning Not thread safe.
235 */
236 void formSigma(int kappa, double ev, int n, const DiracSpinor *Fv = nullptr);
237
238 //! True if no Sigma matrices are stored
239 bool empty() const { return m_Sigmas.empty(); }
240
241 /*!
242 @brief Pointer to the stored Sigma matrix for given kappa (and n).
243
244 @details
245 See get() for the choice of n.
246
247 @return Pointer to the Sigma matrix; nullptr if not present.
248
249 @note The raw matrix: does not include lambda, the ladder part, or the
250 large-r tail (use SigmaFv for those).
251 */
252 const GMatrix *getSigma(int kappa, int n = 0) const;
253
254 //! Scaling factor, lambda, for given kappa (and n); 1 if not present
255 double getLambda(int kappa, int n = 0) const;
256
257 //! Removes all stored Sigma matrices (not ladder or dSigma/dE)
258 void clear() { m_Sigmas.clear(); }
259
260 /*!
261 @brief Returns Sigma|Fv>, including lambda scaling, ladder, and tail.
262
263 @details
264 \f$ \lambda (\Sigma + \Sigma_L) \ket{F_v} \f$: scaled by lambda, and
265 includes the ladder correction \f$ \Sigma_L \f$ if present. Includes the
266 large-r tail if it was fitted (see tail_extrapolation option).
267
268 @return Sigma|Fv>; |0> if neither Sigma nor Sigma_L exists for kappa_v.
269 */
270 DiracSpinor SigmaFv(const DiracSpinor &Fv) const;
271 //! Same as SigmaFv
272 DiracSpinor operator()(const DiracSpinor &Fv) const { return SigmaFv(Fv); }
273
274 /*!
275 @brief Prints MBPT(2) energy correction for each valence state.
276
277 @details
278 Direct, exchange, and total, and \f$ \langle v|\Sigma|v \rangle \f$ using
279 the stored Sigma matrix.
280 */
281 void print_de(const std::vector<DiracSpinor> &valence);
282
283 /*!
284 @brief Prints a_eff for each valence state with a fitted large-r tail.
285
286 @details
287 Also prints \f$ \langle v|\Sigma|v \rangle \f$ without (S0) and with (S)
288 the tail. Prints nothing if tail_extrapolation is off.
289 */
290 void print_tail(const std::vector<DiracSpinor> &valence) const;
291
292 //! True if any dSigma/dE matrices are present (see form_derivative)
293 bool has_derivative() const { return !m_dSigma.empty(); }
294
295 //! Pointer to dSigma/dE data for given kappa (and n); nullptr if not present
296 const SigmaData *get_derivative(int kappa, int n = 0) const;
297
298 /*!
299 @brief Returns lambda * dSigma/dE |Fv>.
300
301 @details
302 \f$ \lambda \, (\partial\Sigma/\partial\varepsilon) \ket{F_v} \f$.
303 The energy derivative of Sigma, formed by finite difference alongside
304 Sigma itself (option form_derivative), so it corresponds to the actual
305 method used (Goldstone/Feynman, screening, etc.). Scaled by the same
306 lambda as the base Sigma.
307
308 @return lambda * dSigma/dE |Fv>; |0> if no derivative exists for this
309 kappa.
310
311 @note The ladder correction (Sigma_L) has no energy derivative: it is
312 included in SigmaFv() but not here.
313 */
314 DiracSpinor dSigmaFv(const DiracSpinor &Fv) const;
315
316 /*!
317 @brief Stores scaling factors, lambda, for each stored Sigma.
318
319 @details
320 \f$ \Sigma \to \lambda\Sigma \f$. One factor for each stored Sigma, in the
321 order they were formed.
322 */
323 void scale_Sigma(const std::vector<double> &lambdas);
324
325 /*!
326 @brief Stores scaling factor, lambda, for Sigma with given kappa and n.
327
328 @details
329 \f$ \Sigma \to \lambda\Sigma \f$. If @p n <= 0, for all Sigma with given
330 kappa.
331 */
332 void scale_Sigma(double lambda, int kappa, int n = 0);
333
334 //! Prints the scaling factors to screen
335 void print_scaling() const;
336
337 //! Prints kappa, energy, lambda, and if dSigma/dE exists, for each Sigma
338 void print_info() const;
339
340 /*!
341 @brief Short string identifying the method (main differences only).
342
343 @details
344 E.g., "Feynman, all-order" or "Goldstone". Intended for file-cache keys.
345 */
346 std::string method_string() const;
347
348 /*!
349 @brief Fitting (scaling) factors as a string, "kappa=value,".
350
351 @details
352 Rounded to 4 dp; empty if none scaled. For file-cache keys (e.g., the
353 ci-file hash).
354 */
355 std::string lambda_string() const;
356
357 /*!
358 @brief Average of the stored fk screening factors, over l up to @p l_max.
359
360 @details
361 Averaged over the lowest Sigma of each l. For re-use of the Sigma_1
362 screening in Sigma_2 (CI), where there is one effective fk per Coulomb
363 line but no unique state: the low-l factors are the relevant ones for the
364 CI valence space (higher-l factors can differ significantly, e.g., f/g at
365 k = 0, but such states rarely contribute). Weighted by l, not kappa: the
366 fine-structure pair of each l is averaged first, then the mean is taken
367 over the ls (so s counts the same as p, d, ...). Truncated to the shortest
368 stored list.
369
370 @param l_max Maximum l included in the average (CI uses 2: s, p, d).
371
372 @return Averaged fk, for each k; empty if none stored.
373 */
374 std::vector<double> average_fk(int l_max = 2) const;
375
376 //! Prints the sub-grid parameters to screen
377 void print_subGrid() const;
378
379 /*!
380 @brief Writes Sigma matrices to file @p fname.
381
382 @details
383 Includes the sub-grid, dSigma/dE, and fk. Not written: lambda, a_eff
384 (re-fitted in formSigma), or the ladder correction.
385 */
386 void write(const std::string &fname) { read_write(fname, IO::FRW::write); }
387
388 /*!
389 @brief Pointer to the stored Sigma data for given kappa (and n).
390
391 @details
392 If @p n <= 0, the first stored Sigma with given kappa. Otherwise, the one
393 with given n; if none, the nearest lower n, else the first with given
394 kappa.
395
396 @return Pointer to Sigma data (matrix, energy formed at, lambda, etc.);
397 nullptr if not present.
398
399 @note Sigma matrix is raw (no lambda, ladder, or tail; see SigmaFv).
400 */
401 const SigmaData *get(int kappa, int n = 0) const;
402
403private:
404 bool read_write(const std::string &fname, IO::FRW::RoW rw);
405 void setup_Feynman();
406 std::vector<double> calculate_fk(double ev, const DiracSpinor &v) const;
407 std::vector<double> calculate_etak(double ev, const DiracSpinor &v) const;
408 const SigmaData *get_ladder(int kappa, int n = 0) const;
409
410 // given_fk: screening factors to use (from state_fk); if nullptr,
411 // calculated internally (if applicable). print = false: silent (e.g., the
412 // extra evaluation for the derivative - only the used Sigma is reported)
413 GMatrix formSigma_F(int kappa, double ev, const DiracSpinor *Fv = nullptr,
414 const std::vector<double> *given_fk = nullptr,
415 bool print = true);
416 GMatrix formSigma_G(int kappa, double ev, const DiracSpinor *Fv = nullptr,
417 bool print = true);
418
419 // Calculates the fk screening factors for this state, once (with print;
420 // stores first set in m_fk). nullopt if not applicable (not
421 // Feynman-screening, fk given manually, or no Fv)
422 std::optional<std::vector<double>> state_fk(double ev, const DiracSpinor *Fv);
423
424 // Forms dSigma/dE for given kappa by forward finite difference (step
425 // m_delta_en): one extra Sigma evaluation at ev + delta, re-using the
426 // base Sigma matrix and the same fk; stores in m_dSigma
427 void form_derivative(int kappa, double ev, int n, const DiracSpinor *Fv,
428 const GMatrix &Sigma0,
429 const std::vector<double> *given_fk = nullptr);
430
431 // If tail_extrapolation is set and not yet fitted, fits a_eff for this
432 // Sigma from the valence state it was formed for (no tail if Fv is null)
433 void fit_tail(SigmaData *Sig, const DiracSpinor *Fv) const;
434
435public:
436 CorrelationPotential &operator=(const CorrelationPotential &) = default;
438 ~CorrelationPotential() = default;
439
440 //
441};
442
443} // namespace MBPT
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:55
Solves relativistic Hartree-Fock equations for core and valence. Optionally includes Breit and QED ef...
Definition HartreeFock.hpp:114
Correlation potential, Sigma, for valence states.
Definition CorrelationPotential.hpp:108
void print_scaling() const
Prints the scaling factors to screen.
Definition CorrelationPotential.cpp:723
const GMatrix * getSigma(int kappa, int n=0) const
Pointer to the stored Sigma matrix for given kappa (and n).
Definition CorrelationPotential.cpp:632
void print_info() const
Prints kappa, energy, lambda, and if dSigma/dE exists, for each Sigma.
Definition CorrelationPotential.cpp:962
const SigmaData * get(int kappa, int n=0) const
Pointer to the stored Sigma data for given kappa (and n).
Definition CorrelationPotential.cpp:619
void scale_Sigma(const std::vector< double > &lambdas)
Stores scaling factors, lambda, for each stored Sigma.
Definition CorrelationPotential.cpp:705
const SigmaData * get_derivative(int kappa, int n=0) const
Pointer to dSigma/dE data for given kappa (and n); nullptr if not present.
Definition CorrelationPotential.cpp:627
DiracSpinor SigmaFv(const DiracSpinor &Fv) const
Returns Sigma|Fv>, including lambda scaling, ladder, and tail.
Definition CorrelationPotential.cpp:644
double getLambda(int kappa, int n=0) const
Scaling factor, lambda, for given kappa (and n); 1 if not present.
Definition CorrelationPotential.cpp:638
std::vector< double > average_fk(int l_max=2) const
Average of the stored fk screening factors, over l up to l_max.
Definition CorrelationPotential.cpp:902
void formSigma(int kappa, double ev, int n, const DiracSpinor *Fv=nullptr)
Forms and stores Sigma for given kappa, at energy ev.
Definition CorrelationPotential.cpp:160
DiracSpinor operator()(const DiracSpinor &Fv) const
Same as SigmaFv.
Definition CorrelationPotential.hpp:272
DiracSpinor dSigmaFv(const DiracSpinor &Fv) const
Returns lambda * dSigma/dE |Fv>.
Definition CorrelationPotential.cpp:694
bool has_derivative() const
True if any dSigma/dE matrices are present (see form_derivative)
Definition CorrelationPotential.hpp:293
void write(const std::string &fname)
Writes Sigma matrices to file fname.
Definition CorrelationPotential.hpp:386
void print_subGrid() const
Prints the sub-grid parameters to screen.
Definition CorrelationPotential.cpp:742
void print_tail(const std::vector< DiracSpinor > &valence) const
Prints a_eff for each valence state with a fitted large-r tail.
Definition CorrelationPotential.cpp:232
void clear()
Removes all stored Sigma matrices (not ladder or dSigma/dE)
Definition CorrelationPotential.hpp:258
void print_de(const std::vector< DiracSpinor > &valence)
Prints MBPT(2) energy correction for each valence state.
Definition CorrelationPotential.cpp:662
bool empty() const
True if no Sigma matrices are stored.
Definition CorrelationPotential.hpp:239
std::string lambda_string() const
Fitting (scaling) factors as a string, "kappa=value,".
Definition CorrelationPotential.cpp:950
std::string method_string() const
Short string identifying the method (main differences only).
Definition CorrelationPotential.cpp:876
Direct correlation potential diagrams via the Feynman technique.
Definition Feynman.hpp:87
Second-order correlation potential, Sigma, from Goldstone diagrams.
Definition Goldstone.hpp:28
Radial Dirac spinor matrix.
Definition SpinorMatrix.hpp:57
Many-body perturbation theory.
Definition MatrixElements.hpp:12
double a_eff
Coefficient of large-r tail, Sigma = a_eff/r^4 beyond sub-grid (0: none)
Definition CorrelationPotential.hpp:30
void add_tail(DiracSpinor *SigmaFn, const GMatrix &Sigma, const DiracSpinor &Fn, double a_eff)
Adds the large-r polarisation tail of Sigma to SigmaFn.
Definition CorrelationPotential.cpp:289
std::vector< double > fk
fk screening factors used for this Sigma (empty if none)
Definition CorrelationPotential.hpp:28
double lambda
Scaling factor, Sigma -> lambda*Sigma; not applied to the stored matrix.
Definition CorrelationPotential.hpp:26
SpinorMatrix< double > Sigma
Sigma matrix, on the sub-grid.
Definition CorrelationPotential.hpp:22
double fit_tail_coefficient(const GMatrix &Sigma, const DiracSpinor &Fv, std::size_t n_fit, double f_cut)
Fits the coefficient a_eff of the large-r polarisation tail of Sigma.
Definition CorrelationPotential.cpp:254
double en
Energy Sigma was formed at.
Definition CorrelationPotential.hpp:20
int n
Principal quantum number of the state Sigma was formed for (0: none given)
Definition CorrelationPotential.hpp:24
SigmaMethod
Method used to form the direct Sigma diagrams.
Definition CorrelationPotential.hpp:72
int kappa
Dirac quantum number of the state Sigma was formed for.
Definition CorrelationPotential.hpp:18
Options for the Feynman method (see Feynman)
Definition Feynman.hpp:28
Stored Sigma matrix, with the parameters it was formed with.
Definition CorrelationPotential.hpp:16
Sigma sub-grid parameters: range (aB) and stride (of full grid)
Definition CorrelationPotential.hpp:75