High-precision calculations for one- and two-valence atomic systems
HartreeFock.hpp
1#pragma once
2#include "Coulomb/YkTable.hpp"
3#include "HF/Breit.hpp"
4#include "Physics/PhysConst_constants.hpp"
5#include "Potentials/Parametric_potentials.hpp"
6#include "Potentials/RadPot.hpp"
7#include <cmath>
8#include <memory>
9#include <optional>
10#include <string>
11#include <vector>
12class Wavefunction;
13class DiracSpinor;
14class Grid;
15namespace MBPT {
16class CorrelationPotential;
17}
18
19//! Functions and classes for Hartree-Fock
20namespace HF {
21
22//==============================================================================
23/*!
24 @brief Convergence results of for each self-consistent-field solve.
25 @details
26 Holds the output of solving for an orbital (core or valence) via an
27 iterative HF-like method: the convergence metric, iteration count, and
28 orbital identification symbol for reporting.
29 @param eps Convergence metric: relative change in orbital norm, or similar,
30 from the previous iteration.
31 @param its Number of iterations performed.
32 @param symbol Orbital identification (e.g. "2p-", "1s+") for labelling
33 output tables.
34*/
35struct EpsIts {
36 double eps{0.0};
37 int its{0};
38 std::string symbol{};
39 // nan (failed solve) is ordered as the largest, i.e., worst, eps
40 friend bool operator<(const EpsIts &l, const EpsIts &r) {
41 return !std::isnan(l.eps) &&
42 (std::isnan(r.eps) || std::abs(l.eps) < std::abs(r.eps));
43 }
44};
45
46//==============================================================================
47/*! @brief Methods available for self-consistant field model
48 @details
49 - HartreeFock: Self-consistent Hartree-Fock method
50 - ApproxHF : Approximate (localised) Hartree-Fock method
51 - Hartree : Core-Hartree method. No exchange, Vdir includes self-interaction
52 - KohnSham : Kohn-Sham (Density functional), includes Latter correction
53 - Local : Uses a local parameteric potential. [NOT self-consistant field]
54 */
55enum class Method { HartreeFock, ApproxHF, Hartree, KohnSham, Local };
56
57//! Convers string (name) of method (e.g., HartreeFock) to HF::Method enum
58Method parseMethod(const std::string &in_method);
59//! Convers HF::Method enum to string (name) of method (e.g., HartreeFock)
60std::string parseMethod(const Method &in_method);
61//! Convers HF::Method enum to short string (name) of method (e.g., HF)
62std::string parseMethod_short(const Method &in_method);
63
64//==============================================================================
65//! Forms approx (localised) exchange potential, from scratch
66//! @details Needs existing orbital Fa, and the core orbitals.
67//! k_cut is max multipolarity to sum over for exchange term [can limit to ~1
68//! (e.g.) for speed when high accuracy is not required]
69std::vector<double> vex_approx(const DiracSpinor &Fa,
70 const std::vector<DiracSpinor> &core,
71 int k_cut = 99, double lambda_cut = 0.003);
72
73//! @brief Calculates V_exch * Fa, for any orbital Fa (calculates Coulomb
74//! integral from scratch).
75//! @details k_cut is max multipolarity to sum over for exchange term [can
76//! limit to ~1 (e.g.) for speed when high accuracy is not required]
77DiracSpinor vexFa(const DiracSpinor &Fa, const std::vector<DiracSpinor> &core,
78 int k_cut = 99);
79
80//! @brief Density-based (Kohn-Sham/Slater) local exchange potential, ~rho^1/3.
81//! @details Does not depend on the orbital, so it
82//! conditions all symmetries uniformly -- useful as the local-exchange term on
83//! the LHS of the mixed-states iteration (where vex_approx, which divides by
84//! the perturbation, is poorly conditioned). Grid is taken from @p core.
85std::vector<double> vex_KS(const std::vector<DiracSpinor> &core);
86
87/*!
88 @brief Exchange of a single electron in orbital Fa, acting on Fv: X_a Fv.
89 @details
90
91 \f[ X_a F_v = -\frac{1}{[j_v]\,[j_a]}\sum_k C^k_{va}{}^2\, y^k_{av}(r)\,F_a \f]
92
93 - The b=Fa term of vexFa(), scaled to ONE electron (weight 1/[j_a] rather
94 than the subshell occupancy): the spherically-averaged one-electron
95 self-exchange.
96 - Used for the V^{N-1} (residual ion) potential: removing one electron from
97 subshell a removes y^0_aa from the direct potential and removes this term
98 from the exchange, V^{N-1}_a = V_HF - (y^0_aa + X_a).
99
100 @note All multipoles k allowed by the (v,a) triangle/parity rules are
101 included; the occupation fraction of Fa is NOT applied (exactly one
102 electron is removed).
103*/
104DiracSpinor vexFa_1el(const DiracSpinor &Fv, const DiracSpinor &Fa);
105
106//==============================================================================
107//==============================================================================
108//==============================================================================
109
110//! Solves relativistic Hartree-Fock equations for core and valence. Optionally
111//! includes Breit and QED effects. Can include Sigma (correlations) for valence
112//! states. Class stores nuc. and direct potentials, a set of yk integrals, and
113//! QED potential. Stores the core orbitals.
115
116private:
117 std::shared_ptr<const Grid> m_rgrid;
118 std::vector<DiracSpinor> m_core;
119 std::vector<double> m_vnuc;
120 std::optional<QED::RadPot> m_vrad;
121 std::optional<HF::Breit> m_VBr;
122 double m_alpha;
123 Method m_method;
124 double m_eps_HF;
125 std::vector<double> m_vdir;
126 Coulomb::YkTable m_Yab;
127 int m_max_hf_its = 256;
128
129public:
130 //! @brief Method is enum class, eps_HF is convergence goal.
131 /*! @details
132 Required:
133 - rgrid: Radial grid (shared pointer)
134 - (This is required to allow no core orbitals)
135 - Assumed to be same grid as for core orbitals
136 - vnuc - nuclear potential
137 - Assumed to be same length as radial grid
138 - A copy is stored. May be updated
139 Optional:
140 - alpha (fine structure constant). default = true value
141 - method default = HartreeFock
142 - breit_params - Breit scaling factors. If std::nullopt (default), no Breit.
143 If present, a Breit object is constructed from the params.
144 - eps_HF: convergence goal
145 - potential: which parametric potential used for initial Potential
146 - h and d (or g and t) are parameters for above (if left zero, default
147 will be chosen)
148 - Note: Parametric::Type potential (and parameters H,d) are for
149 initial approx. Usually doesn't matter at all, and defaults should be used.
150 If using local potential [method=Local], these are the final parameters. If
151 any are set to zero - will be looked up.
152 */
153 HartreeFock(std::shared_ptr<const Grid> rgrid, std::vector<double> vnuc,
154 std::vector<DiracSpinor> core,
155 std::optional<QED::RadPot> vrad = std::nullopt,
156 double m_alpha = PhysConst::alpha,
157 Method method = Method::HartreeFock,
158 std::optional<Breit::Params> breit_params = std::nullopt,
159 double eps_HF = 0.0,
160 Parametric::Type potential = Parametric::Type::Green,
161 double H_g = 0.0, double d_t = 0.0);
162
163 //! Solves HF equations self-consitantly for core orbs. Returns epsilon.
164 EpsIts solve_core(bool print = true);
165
166 //! Solves HF for given valence list. They need not already be solutions.
167 //! @details Note: If given energy is set to zero, states assumed to not be
168 //! existing solutions; initial energy is guessed and solved from scratch. If
169 //! initial energy is non-zero, that energy is used and states are assumed to
170 //! already be (approximate) solutions.
171 void
172 solve_valence(std::vector<DiracSpinor> *valence, bool print = true,
173 const MBPT::CorrelationPotential *const Sigma = nullptr) const;
174
175 //! Solves HF equation (+ Sigma) for single valence state.
177 const MBPT::CorrelationPotential *const Sigma = nullptr,
178 std::optional<double> eta = std::nullopt,
179 std::optional<int> prev_its = std::nullopt) const;
180
181 //! Solves HF equation (+ Sigma) for single valence state, alternative method
183 const MBPT::CorrelationPotential *const Sigma) const;
184
185 //! Calculates the HF core energy (including Breit, if present)
186 double calculateCoreEnergy() const;
187
188 //! Calculates exchange term Vex*Fa
189 DiracSpinor vexFa(const DiracSpinor &Fa) const {
190 // calls static version with HF core
191 return ::HF::vexFa(Fa, m_core, 99);
192 }
193
194 //! Breit interaction V_Br*Fa
195 DiracSpinor VBr(const DiracSpinor &Fv) const;
196
197 //---------------------------
198
199 //! Resturns a const reference to the radial grid
200 const Grid &grid() const { return *m_rgrid; };
201 //! Resturns copy of shared_ptr to grid [shared resource] - used when we want
202 //! to construct a new object that shares this grid
203 std::shared_ptr<const Grid> grid_sptr() const { return m_rgrid; };
204
205 //! Returns reference to Vdir (direct HF potential)
206 const std::vector<double> &vdir() const { return m_vdir; }
207 std::vector<double> &vdir() { return m_vdir; }
208
209 //! Returns reference to Vnuc (nuclear potential)
210 const std::vector<double> &vnuc() const { return m_vnuc; }
211 std::vector<double> &vnuc() { return m_vnuc; }
212
213 //! Electric part of radiative potential
214 std::vector<double> Hrad_el(int l = 0) const;
215 //! Magnetic (off-diagonal) part of radiative potential. Doesn't currently
216 //! depend on l
217 std::vector<double> Hmag(int l = 0) const;
218
219 //! vlocal = vnuc + vrad_el + vdir
220 std::vector<double> vlocal(int l = 0) const;
221
222 //! Which method used to solve HF
223 Method method() const { return m_method; }
224
225 //! Effective charge at large Z : zion = Z - num_core_electrons
226 double zion() const;
227
228 //! Returns true if exchange not included
229 bool is_localQ() const {
230 return m_core.empty() ||
231 !(m_method == Method::HartreeFock || m_method == Method::ApproxHF);
232 }
233
234 //! vector of core orbitals
235 const std::vector<DiracSpinor> &core() const { return m_core; }
236
237 //! Value of fine-structure constant used
238 double alpha() const { return m_alpha; }
239
240 //! Update the Vrad used inside HF (only used if we want QED into valence but
241 // not core, for testing)
242 void set_Vrad(QED::RadPot in_vrad) { m_vrad = std::move(in_vrad); } // XXX
243 //! Get (const) ptr to Vrad - may be null
244 const QED::RadPot *Vrad() const { return m_vrad ? &*m_vrad : nullptr; }
245 QED::RadPot *Vrad() { return m_vrad ? &*m_vrad : nullptr; }
246
247 //! pointer to Breit - may be nullptr if no breit
248 const HF::Breit *vBreit() const { return m_VBr ? &*m_VBr : nullptr; }
249 //! Breit scale factor (usualy 0 or 1)
250 double x_Breit() const { return m_VBr ? m_VBr->scale_factor() : 0.0; }
251
252 //! Number of electrons in the core
253 int num_core_electrons() const;
254
255private:
256 // Solve Dirac equation for core states (just once) using existing vdir
257 // (usually, vdir set to parametric potential beforehand)
258 EpsIts solve_initial_core(const double eps);
259 // Solve equations self-consistantly for core, using local method (either
260 // core-Hartree or Kohn-Sham)
261 EpsIts selfcon_local_core(const double eps_target_HF);
262 // Solve HF equations self-consistantly for core, using approximate HF method
263 EpsIts hf_approx_core(const double eps_target_HF);
264 // Solve HF equations self-consistantly for core, using Hartree-Fock method.
265 EpsIts hartree_fock_core(bool print);
266 // Solves HF equation for valence state, assuming local potential (Hartree,
267 // Local, Kohn-Sham or approxHF)
268 EpsIts local_valence(DiracSpinor &Fa) const;
269
270 // Prints a warning for each orbital that does not have n-l-1 nodes (i.e.,
271 // converged to the wrong state)
272 void check_nodes(const std::vector<DiracSpinor> &orbitals,
273 const std::string &label) const;
274
275 /*
276 // same as hf_valence, but uses Green method
277 EpsIts hf_valence_Green(
278 DiracSpinor &Fv,
279 const MBPT::CorrelationPotential *const Sigma = nullptr) const;
280 */
281
282 // Solves HF equation for given state, using non-local Green's method for
283 // inhomogeneous ODE (used for hartree_fock_core()).
284 // Solve Dirac Equation (Eigenvalue):
285 // (H0 + Vl + Vx)Fa = 0
286 // (H0 + Vl)Fa = -VxFa
287 // Vl is local (e.g., Vnuc + fVdir), Vx is non-local (e.g., (1-f)Vdir + Vex)
288 // where v0 = (1-f)Vdir [f=1 for valence states!, so v0 may be empty]
289 // Vx also includes Breit, and Sigma
290 // Small energy adjustmenets (and wfs), solve:
291 // (Hl - e) dF = de * F -VxFa
292 // e -> e+de, F->F+dF
293 // Core is input so can call in a thread-safe way! (with a 'old_core' copy)
294 // Only used in dE from dF
295 void hf_orbital_green(
296 DiracSpinor &Fa, double en, const std::vector<double> &vl,
297 const std::vector<double> &H_mag, const DiracSpinor &VxF,
298 const std::vector<DiracSpinor> &static_core,
299 const std::vector<double> &dv0 = {}, const HF::Breit *const VBr = nullptr,
300 const MBPT::CorrelationPotential *const Sigma = nullptr) const;
301
302 // Calc's Vex*Fa, for Fa in the core. Fa must be in the core
303 void vex_Fa_core(const DiracSpinor &Fa, DiracSpinor &vexFa) const;
304
305 // Option to re-scale diract potential so that V(r)~-zion/r at large r
306 enum class ReScale { yes = true, no = false };
307 // Forms direct potential
308 void update_vdir(ReScale re_scale = ReScale::no);
309 // Adds the additional Kohn-Sham parts to Vdir
310 void add_KohnSham_vdir_addition();
311
312 // Sets Vdir to be parametric potential. By default, Greens potential
313 void
314 set_parametric_potential(bool print = true,
315 Parametric::Type potential = Parametric::Type::Green,
316 double H_g = 0.0, double d_t = 0.0);
317
318 // Forms approximate vex for all core states
319 void form_approx_vex_core(std::vector<std::vector<double>> &vex) const;
320 std::vector<std::vector<double>> form_approx_vex_core() const;
321 // Forms approximate vex for given core states
322 void form_approx_vex_core_a(const DiracSpinor &Fa,
323 std::vector<double> &vex_a) const;
324 std::vector<double> form_approx_vex_core_a(const DiracSpinor &Fa) const;
325
326 // Energy guess for core states
327 double enGuessCore(int n, int ka) const;
328 // Energy guess for valence states
329 double enGuessVal(int n, int ka) const;
330};
331
332} // namespace HF
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
Non-uniform radial grid with Jacobian, suitable for atomic structure calculations.
Definition Grid.hpp:85
Breit potentials for one- (Hartree-Fock Breit) and two-body Breit integrals.
Definition Breit.hpp:88
Solves relativistic Hartree-Fock equations for core and valence. Optionally includes Breit and QED ef...
Definition HartreeFock.hpp:114
const std::vector< double > & vnuc() const
Returns reference to Vnuc (nuclear potential)
Definition HartreeFock.hpp:210
const Grid & grid() const
Resturns a const reference to the radial grid.
Definition HartreeFock.hpp:200
double x_Breit() const
Breit scale factor (usualy 0 or 1)
Definition HartreeFock.hpp:250
std::vector< double > Hrad_el(int l=0) const
Electric part of radiative potential.
Definition HartreeFock.cpp:1277
double calculateCoreEnergy() const
Calculates the HF core energy (including Breit, if present)
Definition HartreeFock.cpp:792
double zion() const
Effective charge at large Z : zion = Z - num_core_electrons.
Definition HartreeFock.cpp:1362
void set_Vrad(QED::RadPot in_vrad)
Update the Vrad used inside HF (only used if we want QED into valence but.
Definition HartreeFock.hpp:242
EpsIts hf_valence_Green(DiracSpinor &Fa, const MBPT::CorrelationPotential *const Sigma) const
Solves HF equation (+ Sigma) for single valence state, alternative method.
Definition HartreeFock.cpp:737
double alpha() const
Value of fine-structure constant used.
Definition HartreeFock.hpp:238
std::vector< double > Hmag(int l=0) const
Magnetic (off-diagonal) part of radiative potential. Doesn't currently depend on l.
Definition HartreeFock.cpp:1280
Method method() const
Which method used to solve HF.
Definition HartreeFock.hpp:223
DiracSpinor vexFa(const DiracSpinor &Fa) const
Calculates exchange term Vex*Fa.
Definition HartreeFock.hpp:189
EpsIts hf_valence(DiracSpinor &Fv, const MBPT::CorrelationPotential *const Sigma=nullptr, std::optional< double > eta=std::nullopt, std::optional< int > prev_its=std::nullopt) const
Solves HF equation (+ Sigma) for single valence state.
Definition HartreeFock.cpp:650
const HF::Breit * vBreit() const
pointer to Breit - may be nullptr if no breit
Definition HartreeFock.hpp:248
const std::vector< double > & vdir() const
Returns reference to Vdir (direct HF potential)
Definition HartreeFock.hpp:206
int num_core_electrons() const
Number of electrons in the core.
Definition HartreeFock.cpp:859
void solve_valence(std::vector< DiracSpinor > *valence, bool print=true, const MBPT::CorrelationPotential *const Sigma=nullptr) const
Solves HF for given valence list. They need not already be solutions.
Definition HartreeFock.cpp:180
DiracSpinor VBr(const DiracSpinor &Fv) const
Breit interaction V_Br*Fa.
Definition HartreeFock.cpp:851
bool is_localQ() const
Returns true if exchange not included.
Definition HartreeFock.hpp:229
EpsIts solve_core(bool print=true)
Solves HF equations self-consitantly for core orbs. Returns epsilon.
Definition HartreeFock.cpp:98
const std::vector< DiracSpinor > & core() const
vector of core orbitals
Definition HartreeFock.hpp:235
std::shared_ptr< const Grid > grid_sptr() const
Resturns copy of shared_ptr to grid [shared resource] - used when we want to construct a new object t...
Definition HartreeFock.hpp:203
const QED::RadPot * Vrad() const
Get (const) ptr to Vrad - may be null.
Definition HartreeFock.hpp:244
std::vector< double > vlocal(int l=0) const
vlocal = vnuc + vrad_el + vdir
Definition HartreeFock.cpp:845
Correlation potential, Sigma, for valence states.
Definition CorrelationPotential.hpp:108
Constructs and stores the Flambaum-Ginges QED Radiative Potential.
Definition RadPot.hpp:16
Stores Wavefunction (set of valence orbitals, grid, HF etc.)
Definition Wavefunction.hpp:48
Functions and classes for Hartree-Fock.
Definition CI_Integrals.hpp:16
std::vector< double > vex_KS(const std::vector< DiracSpinor > &core)
Density-based (Kohn-Sham/Slater) local exchange potential, ~rho^1/3.
Definition HartreeFock.cpp:1158
DiracSpinor vexFa_1el(const DiracSpinor &Fv, const DiracSpinor &Fa)
Exchange of a single electron in orbital Fa, acting on Fv: X_a Fv.
Definition HartreeFock.cpp:1250
std::string parseMethod_short(const Method &in_method)
Convers HF::Method enum to short string (name) of method (e.g., HF)
Definition HartreeFock.cpp:61
std::vector< double > vex_approx(const DiracSpinor &Fa, const std::vector< DiracSpinor > &core, int k_cut, const double lambda_cut)
Forms approx (localised) exchange potential, from scratch.
Definition HartreeFock.cpp:1096
Method
Methods available for self-consistant field model.
Definition HartreeFock.hpp:55
DiracSpinor vexFa(const DiracSpinor &Fa, const std::vector< DiracSpinor > &core, int k_cut)
Calculates V_exch * Fa, for any orbital Fa (calculates Coulomb integral from scratch).
Definition HartreeFock.cpp:1215
Method parseMethod(const std::string &in_method)
Convers string (name) of method (e.g., HartreeFock) to HF::Method enum.
Definition HartreeFock.cpp:28
Many-body perturbation theory.
Definition MatrixElements.hpp:12
Type
Parametric potential type.
Definition Parametric_potentials.hpp:14
constexpr double alpha
Fine-structure constant: alpha = 1/137.035 999 177(21) [CODATA 2022].
Definition PhysConst_constants.hpp:24
Convergence results of for each self-consistent-field solve.
Definition HartreeFock.hpp:35