High-precision calculations for one- and two-valence atomic systems
TDHF.hpp
1#pragma once
2#include "CorePolarisation.hpp"
3#include <string>
4#include <vector>
5class DiracSpinor;
6namespace DiracOperator {
7class TensorOperator;
8}
9namespace MBPT {
10class CorrelationPotential;
11}
12
13namespace HF {
14class HartreeFock;
15class Breit;
16} // namespace HF
17
18namespace ExternalField {
19
20/*!
21 @brief Uses TDHF to include core-polarisation (RPA) corrections to matrix
22 elements of an external field operator.
23
24 @details
25 Solves the TDHF equations for each core orbital \f$ \phi_a \f$,
26 \f[
27 (h_{\rm HF} - \en_a \mp \omega)\varphi^a_\pm
28 = -(t_\pm + \delta V_\pm - \delta\en^a_\pm)\phi_a,
29 \f]
30 self-consistently to determine \f$ \delta V_\pm \f$.
31 See the @ref ExternalField namespace documentation for full physics description.
32
33 Each core orbital acquires both a forward (\f$ \varphi^a_+ \f$, stored as X)
34 and backward (\f$ \varphi^a_- \f$, stored as Y) correction. Both contribute
35 to \f$ \delta V_\pm \f$:
36 \f[
37 \delta V_\pm \phi_i =
38 \sum_a^{\rm core} \left[
39 \matel{\phi_a}{Q}{\varphi^a_+}\phi_i - \matel{\phi_a}{Q}{\phi_i}\varphi^a_+
40 + \matel{\varphi^a_-}{Q}{\phi_a}\phi_i - \matel{\varphi^a_-}{Q}{\phi_i}\phi_a
41 \right].
42 \f]
43 It is via \f$ \delta V_\pm \f$ that the \f$ e^{\pm i\omega t} \f$ terms are mixed.
44
45 \par Construction
46 Requires a pointer to the operator (\f$ t_+ \f$, at \f$ +|\omega| \f$)
47 and a const @ref HF::HartreeFock object. The user is responsible for
48 updating the operator frequency externally before calling solve_core().
49 The backward operator \f$ t_- \f$ (at \f$ -|\omega| \f$) is
50 \f$ t_+ \f$ times TensorOperator::h_minus_sign(): -1 for an operator
51 odd in the frequency (E1v), +1 otherwise.
52
53 \par Usage
54 @ref solve_core (omega) solves the TDHF equations for a given frequency.
55 @ref dV (Fa, Fb) then returns the RPA correction to the reduced matrix element
56 \f$ \redmatel{a}{\delta V}{b} \f$.
57*/
58class TDHF : public CorePolarisation {
59
60protected:
61 // dPhi = X exp(-iwt) + Y exp(+iwt)
62 // (H - e - w)X = -(h + dV - de)Phi
63 // (H - e + w)Y = -(h* + dV* - de)Phi
64 // X_c = sum_x X_x,
65 // j(x)=j(c)-k,...,j(c)+k. And: pi(x) = pi(c)*pi(h)
66 std::vector<std::vector<DiracSpinor>> m_X{};
67 std::vector<std::vector<DiracSpinor>> m_Y{};
68 std::vector<std::vector<DiracSpinor>> m_hFcore{};
69 std::vector<std::vector<DiracSpinor>> m_hFcore_minus{};
70 // can just write these to disk! Read them in, continue as per normal
71
72 const HF::HartreeFock *const p_hf;
73 const std::vector<DiracSpinor> m_core;
74 const double m_alpha;
75 const HF::Breit *const p_VBr;
76 // If true, eps is the relative change |dPsi| (sqrt of the ratio); if false,
77 // the squared ratio. See eps_dPsi().
78 bool m_eps_sqrt{false};
79 // Method of solve_core(): Anderson mixing if true, damped iteration if
80 // false; the other is the fallback
81 bool m_use_anderson{true};
82 // Method of the core mixed-state solves: Anderson mixing
83 // (solveMixedState_Anderson) if true, damped iteration (solveMixedState)
84 // if false
85 bool m_use_anderson_ms{true};
86
87public:
88 /*!
89 @brief Constructs TDHF for operator h.
90
91 @param h_plus The operator \f$ t_+ \f$; must be set to positive
92 frequency before each call to solve_core().
93 @param hf @ref HF::HartreeFock object defining the core.
94 */
95 TDHF(const DiracOperator::TensorOperator *const h_plus,
96 const HF::HartreeFock *const hf);
97
98 /*!
99 @brief Solves TDHF equations self-consistently for core electrons at frequency omega.
100 @details
101 Iterates the TDHF equations until \f$ \delta V_\pm \f$ converges to within
102 eps_target(), or @p max_its iterations have been performed.
103 Can be re-run at a different frequency without restarting from scratch.
104
105 Solved by solve_core_anderson() (default) or solve_core_damped(). If
106 that does not converge, the solve is started again from scratch with the
107 other method, and the better result is kept.
108
109 @param omega External-field frequency \f$ \omega \f$ in atomic units.
110 @param max_its Maximum number of iterations.
111 Set to 1 to get the first-order correction (no damping on
112 first iteration).
113 @param print If true, write convergence progress to screen.
114
115 @note Solved at \f$ |\omega| \f$: both \f$ \varphi^a_+ \f$ and
116 \f$ \varphi^a_- \f$ are found simultaneously (see class docs), so a
117 single call covers both components, \f$ \delta V(\pm|\omega|) \f$;
118 see dV().
119
120 --
121
122 @note Does not update the frequency of the operator itself; for frequency-dependent
123 operators, update the operator frequency externally before calling.
124 */
125 virtual void solve_core(double omega, int max_its = 100,
126 bool print = true) override;
127
128 /*!
129 @brief As solve_core(), by damped iteration only (no fallback).
130 @details
131 Each iteration mixes the new corrections with the previous ones, with
132 damping factor eta().
133
134 @note nb: if the iterations stall, the solve is restarted from scratch with
135 different damping (weaker, then stronger), up to a few times, each with
136 a further max_its iterations; the best attempt is kept. eta() itself is
137 not changed.
138 */
139 void solve_core_damped(double omega, int max_its = 128, bool print = true);
140
141 /*!
142 @brief As solve_core(), by Anderson mixing only (no fallback).
143 @details
144 Self-consistency is driven by Anderson mixing (@ref anderson_coefficients)
145 of all the corrections together, X and Y. Each iteration applies the
146 TDHF map undamped, then extrapolates over the recent iterates. The TDHF
147 equations are linear in the corrections, so this is equivalent to
148 truncated GMRES: there is no damping parameter, and it converges
149 wherever the equations are non-singular.
150 */
151 void solve_core_anderson(double omega, int max_its = 128, bool print = true);
152
153 //! Method of solve_core(): Anderson mixing if true (default), damped
154 //! iteration if false; the other is the fallback
155 void set_anderson(bool andersonQ) { m_use_anderson = andersonQ; }
156
157 virtual Method method() const override { return Method::TDHF; }
158
159 virtual void clear() override;
160
161 //! Returns reduced matrix element <a||dV||b>, or the conjugate
162 //! <a||dV^dag||b> if conj=true.
163 double dV(const DiracSpinor &Fa, const DiracSpinor &Fb,
164 bool conj = false) const override;
165
166 DiracSpinor dV_rhs(int kappa_n, const DiracSpinor &Fm,
167 bool conj = false) const override;
168
169 //! Returns const ref to dPsi orbitals for given core orbital Fc.
170 const std::vector<DiracSpinor> &get_dPsis(const DiracSpinor &Fc,
171 dPsiType XorY) const;
172 //! Returns const ref to dPsi orbital of given kappa.
173 const DiracSpinor &get_dPsi_x(const DiracSpinor &Fc, dPsiType XorY,
174 const int kappa_x) const;
175
176 /*!
177 @brief Forms the mixed states phi^v_+- for valence state Fv (including
178 core pol.): single kappa channel.
179 @details
180 Solves
181 \f[ (h_{\rm HF} + \Sigma - \en_v - \omega)\varphi^v_+
182 = -(t + \delta V - \delta\en^v)\phi_v \f]
183 or
184 \f[ (h_{\rm HF} + \Sigma - \en_v + \omega)\varphi^v_-
185 = -(t^\dagger + \delta V^\dagger - \delta\en^v)\phi_v \f]
186 Returns \f$ \chi_\beta \f$ for given kappa_beta, where
187 \f[ X_{j,m} = (-1)^{j_\beta-m}tjs(j,k,j;-m,0,m)\chi_j \f]
188
189 @param Fv Valence state \f$\phi_v\f$.
190 @param omega Perturbation frequency \f$\omega\f$.
191 @param XorY Selects X or Y solution; see @ref dPsiType.
192 @param kappa_beta Kappa quantum number of the target channel.
193 @param Sigma Optional correlation potential; see @ref MBPT::CorrelationPotential.
194 @param st Bra or ket convention; see @ref StateType.
195 @param incl_dV Include the induced potential \f$\delta V\f$ if true.
196 */
198 solve_dPsi(const DiracSpinor &Fv, const double omega, dPsiType XorY,
199 const int kappa_beta,
200 const MBPT::CorrelationPotential *const Sigma = nullptr,
201 StateType st = StateType::ket, bool incl_dV = true) const;
202
203 //! Forms the mixed states phi^v_+- for all kappa channels; see solve_dPsi.
204 std::vector<DiracSpinor>
205 solve_dPsis(const DiracSpinor &Fv, const double omega, dPsiType XorY,
206 const MBPT::CorrelationPotential *const Sigma = nullptr,
207 StateType st = StateType::ket, bool incl_dV = true) const;
208
209 // //! Writes dPsi (f-component) to textfile
210 // void print(const std::string &ofname = "dPsi.txt") const;
211
212protected:
213 // Forms set of h*Fc for all core orbitals and all projections
214 std::vector<std::vector<DiracSpinor>>
215 form_hFcore(const DiracOperator::TensorOperator *h) const;
216 // The same at -|omega| (for the Y equations), from the set at +|omega|
217 std::vector<std::vector<DiracSpinor>>
218 form_hFcore_minus(const std::vector<std::vector<DiracSpinor>> &hFcore) const;
219
220 // dV_rhs built from explicit correction sets X, Y (indexed as m_X, m_Y)
221 // in place of the members; dV_rhs delegates here with (m_X, m_Y). Lets a
222 // derived class apply the same (real-linear) builder to a second pair of
223 // sets, e.g. the imaginary parts of complex corrections.
224 DiracSpinor dV_rhs_sets(int kappa_n, const DiracSpinor &Fa, bool conj,
225 const std::vector<std::vector<DiracSpinor>> &X,
226 const std::vector<std::vector<DiracSpinor>> &Y) const;
227
228private:
229 void initialise_dPsi();
230
231 // Single iteration of TDHF equations
232 std::pair<double, std::string> tdhf_core_it(double omega, double eta_damp);
233 // Solves the MS equations for all projections, single core state
234 void solve_ms_core(std::vector<DiracSpinor> &dFb, const DiracSpinor &Fb,
235 const std::vector<DiracSpinor> &hFbs, const double omega,
236 dPsiType XorY, double eps_ms = 1.0e-9) const;
237 // As solve_ms_core(), but a single channel (one projection). Thread-safe;
238 // used to parallelise tdhf_core_it() over (orbital x channel x X/Y).
239 void solve_ms_core_b(DiracSpinor &dF_beta, const DiracSpinor &Fb,
240 const DiracSpinor &hFb, const double omega,
241 dPsiType XorY, double eps_ms = 1.0e-9) const;
242
243 // Convergence (eps): the relative L2 change of the (undamped) X spinors,
244 // Sum|dX|^2 / Sum|X_new|^2 (summed over all channels); returns its sqrt
245 // -- the relative change -- if @p relative. Returns {eps, worst-channel}.
246 std::pair<double, std::string>
247 eps_dPsi(const std::vector<std::vector<DiracSpinor>> &Xnew,
248 bool relative) const;
249
250 // True if |omega| exceeds the ionisation threshold of the core, where the
251 // core equations have no bound solution
252 bool above_ionisation_threshold(double omega) const;
253
254 // The corrections X and Y as one real vector, and back: the Anderson
255 // iterate of solve_core_anderson()
256 std::vector<double> dPsi_vector() const;
257 void set_dPsi_vector(const std::vector<double> &state);
258
259public:
260 TDHF &operator=(const TDHF &) = delete;
261 TDHF(const TDHF &) = default;
262 ~TDHF() = default;
263};
264
265} // namespace ExternalField
General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive...
Definition TensorOperator.hpp:198
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:55
Virtual base class for core-polarisation (RPA); computes dV corrections.
Definition CorePolarisation.hpp:147
Uses TDHF to include core-polarisation (RPA) corrections to matrix elements of an external field oper...
Definition TDHF.hpp:58
virtual void clear() override
Clears the internal state back to pre solve_core()
Definition TDHF.cpp:80
void solve_core_damped(double omega, int max_its=128, bool print=true)
As solve_core(), by damped iteration only (no fallback).
Definition TDHF.cpp:397
const DiracSpinor & get_dPsi_x(const DiracSpinor &Fc, dPsiType XorY, const int kappa_x) const
Returns const ref to dPsi orbital of given kappa.
Definition TDHF.cpp:97
double dV(const DiracSpinor &Fa, const DiracSpinor &Fb, bool conj=false) const override
Returns reduced matrix element <a||dV||b>, or the conjugate <a||dV^dag||b> if conj=true.
Definition TDHF.cpp:610
void solve_core_anderson(double omega, int max_its=128, bool print=true)
As solve_core(), by Anderson mixing only (no fallback).
Definition TDHF.cpp:513
void set_anderson(bool andersonQ)
Method of solve_core(): Anderson mixing if true (default), damped iteration if false; the other is th...
Definition TDHF.hpp:155
std::vector< DiracSpinor > solve_dPsis(const DiracSpinor &Fv, const double omega, dPsiType XorY, const MBPT::CorrelationPotential *const Sigma=nullptr, StateType st=StateType::ket, bool incl_dV=true) const
Forms the mixed states phi^v_+- for all kappa channels; see solve_dPsi.
Definition TDHF.cpp:106
const std::vector< DiracSpinor > & get_dPsis(const DiracSpinor &Fc, dPsiType XorY) const
Returns const ref to dPsi orbitals for given core orbital Fc.
Definition TDHF.cpp:87
virtual void solve_core(double omega, int max_its=100, bool print=true) override
Solves TDHF equations self-consistently for core electrons at frequency omega.
Definition TDHF.cpp:357
virtual Method method() const override
Returns RPA method.
Definition TDHF.hpp:157
DiracSpinor dV_rhs(int kappa_n, const DiracSpinor &Fm, bool conj=false) const override
Returns [dV_pm * phi_m]_kappa: RHS of TDHF eq., projected onto kappa (see namespace doc)
Definition TDHF.cpp:616
DiracSpinor solve_dPsi(const DiracSpinor &Fv, const double omega, dPsiType XorY, const int kappa_beta, const MBPT::CorrelationPotential *const Sigma=nullptr, StateType st=StateType::ket, bool incl_dV=true) const
Forms the mixed states phi^v_+- for valence state Fv (including core pol.): single kappa channel.
Definition TDHF.cpp:119
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
Correlation potential, Sigma, for valence states.
Definition CorrelationPotential.hpp:108
Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body)...
Definition SecondOrder.hpp:7
Core-polarisation (RPA) corrections to matrix elements of an external field.
Definition MatrixElements.hpp:9
StateType
Whether the state is a bra or ket.
Definition CorePolarisation.hpp:119
dPsiType
Selects the perturbed orbital: X = varphi_+, Y = varphi_-.
Definition CorePolarisation.hpp:117
Method
Available RPA/core-polarisation methods.
Definition CorePolarisation.hpp:87
Functions and classes for Hartree-Fock.
Definition CI_Integrals.hpp:16
Many-body perturbation theory.
Definition MatrixElements.hpp:12
void Breit(const IO::InputBlock &input, const Wavefunction &wf)
Breit corrections to HF energies.
Definition Breit.cpp:44