ampsci
High-precision calculations for one- and two-valence atomic systems
CorePolarisation.hpp
1#pragma once
2#include "DiracOperator/TensorOperator.hpp"
3#include "qip/String.hpp"
4#include <cassert>
5#include <string>
6#include <vector>
7class DiracSpinor;
8namespace DiracOperator {
9class TensorOperator;
10}
11
12/*!
13 @brief Core-polarisation (RPA) corrections to matrix elements of an external field.
14 @details
15 Provides classes and functions for computing all-order core-polarisation
16 corrections to matrix elements of an external field operator.
17
18 In the presence of an external field of frequency \f$ \omega \f$, the
19 time-dependent operator is
20 \f[
21 T(t) = t_+ e^{-i\omega t} + t_- e^{+i\omega t},
22 \f]
23 where \f$ t_+ = t^k_q(\omega) \f$ is an irreducible tensor operator of rank \f$ k \f$
24 and \f$ t_- = t_+^\dag(-\omega) \f$.
25 Each orbital, including those in the core, acquires a first-order perturbation,
26 \f[
27 \delta\phi_a(t) = \varphi^a_+ e^{-i\omega t} + \varphi^a_- e^{+i\omega t}.
28 \f]
29 Since the core orbitals are perturbed, the Hartree-Fock potential is also perturbed:
30 \f[
31 \delta V_\pm \phi_i =
32 \sum_a^{\rm core} \left[
33 \matel{\phi_a}{Q}{\varphi^a_+}\phi_i - \matel{\phi_a}{Q}{\phi_i}\varphi^a_+
34 + \matel{\varphi^a_-}{Q}{\phi_a}\phi_i - \matel{\varphi^a_-}{Q}{\phi_i}\phi_a
35 \right].
36 \f]
37
38 The resulting
39 core-polarisation corrections to matrix elements are given by
40 \f[
41 \matel{b}{t_\pm}{a} \to \matel{b}{t_\pm + \delta V_\pm}{a},
42 \f]
43 where \f$ \delta V_\pm \f$ is the correction to the HF potential arising
44 from the perturbed core orbitals \f$ \{\varphi^a_\pm\} \f$.
45
46 Since \f$ \delta V \f$ is solved self-consistently, this accounts for core
47 polarisation to all orders in the Coulomb interaction.
48
49 Two equivalent methods are implemented:
50
51 - TDHF (@ref TDHF, @ref TDHFbasis): solves the TDHF equations
52 \f[
53 (h_{\rm HF} - \en_a \mp \omega)\varphi^a_\pm
54 = -(t_\pm + \delta V_\pm - \delta\en^a_\pm)\phi_a
55 \f]
56 self-consistently for all core orbitals. The corrections can also be
57 found via the basis expansion
58 \f[
59 \varphi^a_\pm = \sum_n \frac{\ket{n}\matel{n}{t_\pm + \delta V_\pm}{a}}
60 {\en_a - \en_n \pm \omega}.
61 \f]
62 See Dzuba et al. (1984).
63
64 - Diagram/Goldstone (@ref DiagramRPA): evaluates the four core-polarisation
65 diagrams directly,
66 \f[
67 \redmatel{w}{\delta V_\pm}{v} =
68 \sum_{na} \frac{(-1)^{k+w-n}}{[k]} \left(
69 \frac{T_{na}\,W^k_{wavn}}{\en_a - \en_n \pm \omega}
70 + \frac{(-1)^{a-n} T_{an}\,W^k_{wnva}}{\en_a - \en_n \mp \omega}
71 \right),
72 \f]
73 with \f$ T_{ij} = t_{ij} + \redmatel{i}{\delta V_\pm}{j} \f$ iterated to
74 convergence. See Johnson et al., Phys. Rev. A 21, 409 (1980).
75
76 Use @ref make_rpa to construct the appropriate object from a method string,
77 and @ref calcMatrixElements to compute matrix elements including the correction.
78*/
79namespace ExternalField {
80
81//! Available RPA/core-polarisation methods
82enum class Method { TDHF, basis, diagram, none, Error };
83
84//! Parses method string to Method enum (case-insensitive)
85inline Method ParseMethod(std::string_view str) {
86 return qip::ci_compare(str, "TDHF") ? Method::TDHF :
87 qip::ci_compare(str, "true") ? Method::TDHF :
88 qip::ci_compare(str, "default") ? Method::TDHF :
89 qip::ci_compare(str, "basis") ? Method::basis :
90 qip::ci_compare(str, "tdhf_basis") ? Method::basis :
91 qip::ci_compare(str, "tdhfbasis") ? Method::basis :
92 qip::ci_compare(str, "diagram") ? Method::diagram :
93 qip::ci_compare(str, "diagramRPA") ? Method::diagram :
94 qip::ci_compare(str, "rpad") ? Method::diagram :
95 qip::ci_compare(str, "rpa(d)") ? Method::diagram :
96 qip::ci_compare(str, "none") ? Method::none :
97 qip::ci_compare(str, "false") ? Method::none :
98 qip::ci_compare(str, "") ? Method::none :
99 Method::Error;
100}
101
102/*!
103 @brief Selects the perturbed orbital: X = varphi_+, Y = varphi_-.
104 @details
105 Corresponds to the two first-order corrections to a core orbital,
106 \f[ \delta\phi_a(t) = \varphi^a_+ e^{-i\omega t} + \varphi^a_- e^{+i\omega t}. \f]
107 X selects \f$ \varphi^a_+ \f$ (absorption/forward), Y selects
108 \f$ \varphi^a_- \f$ (emission/backward).
109*/
110enum class dPsiType { X, Y };
111//! Whether the state is a bra or ket
112enum class StateType { bra, ket }; // lhs, rhs
113
114/*!
115 @brief Virtual base class for core-polarisation (RPA); computes dV corrections.
116 @details
117 Defines the interface for all RPA/core-polarisation methods. Concrete
118 implementations are @ref TDHF, @ref TDHFbasis, and @ref DiagramRPA.
119 See the @ref ExternalField namespace documentation for notation and physics.
120
121 @note
122 Stores a raw pointer to the external-field operator @p h passed at
123 construction. That operator must remain alive for the lifetime of this object.
124
125 ---
126
127 @note
128 For frequency-dependent operators, updating the operator frequency externally
129 will affect results. @ref solve_core() should be re-called after any such update.
130
131 ---
132
133 @note
134 Calling @ref solve_core() with a different freuqnecy will _only_ chnage the frequency used
135 to solve the TDHF/RPA equations. It wil **not** change the frequency of the operator itself.
136 For frequency-dependent operators, you must update the freuqency of the operator first.
137 See @ref DiracOperator::TensorOperator .
138 Since this class stores just a pointer to the operator, that's all you need to do.
139*/
141
142protected:
144 : m_h(h), m_rank(h->rank()), m_pi(h->parity()), m_imag(h->imaginaryQ()) {}
145
146protected:
148 double m_core_eps{1.0};
149 int m_core_its{0};
150 double m_core_omega{0.0};
151 int m_rank;
152 int m_pi;
153 bool m_imag;
154
155 double m_eta{0.4};
156 double m_eps{1.0e-10};
157
158public:
159 //! Returns eps (convergance) of last solve_core run
160 double last_eps() const { return m_core_eps; }
161 //! Returns its (# of iterations) of last solve_core run
162 double last_its() const { return m_core_its; }
163 //! Returns omega (frequency) of last solve_core run
164 double last_omega() const { return m_core_omega; }
165 //! Rank of the operator
166 int rank() const { return m_rank; }
167 //! Parity of the operator
168 int parity() const { return m_pi; }
169 //! Returns true if the operator is imaginary
170 bool imagQ() const { return m_imag; }
171
172 //! Convergance target
173 double &eps_target() { return m_eps; }
174 //! Convergance target
175 double eps_target() const { return m_eps; }
176
177 //! Damping factor; 0 means no damping. Must have 0 <= eta < 1
178 double eta() const { return m_eta; }
179 //! Set/update damping factor; 0 means no damping. Must have 0 <= eta < 1
180 void set_eta(double eta) {
181 assert(eta >= 0.0 && eta < 1 && "Must have 0 <= eta < 1");
182 m_eta = eta;
183 }
184
185 //! Returns RPA method
186 virtual Method method() const = 0;
187
188 /*!
189 @brief Solve for delta_V_pm self-consistently for all core orbitals at frequency omega.
190 @details
191 Iterates the RPA equations (TDHF or diagram, depending on the implementation)
192 until the correction \f$ \delta V_\pm(\omega) \f$ converges to within
193 eps_target(), or @p max_its iterations are reached.
194
195 @param omega External-field frequency \f$ \omega \f$ in atomic units.
196 May be zero (static limit) or negative.
197 @param max_its Maximum number of iterations.
198 - 0: no iterations; dV() returns 0.
199 - 1: single iteration; dV() returns lowest-order correction.
200 @param print If true, print convergence progress to stdout.
201
202 @note Does not update the frequency of the operator itself; for frequency-dependent
203 operators, update the operator frequency externally before calling.
204 */
205 virtual void solve_core(double omega, int max_its = 100,
206 bool print = true) = 0;
207
208 //! @brief Clears the internal state back to pre solve_core()
209 virtual void clear() = 0;
210
211 //! @brief Returns reduced matrix element <n||dV_pm||m> (see namespace doc for dV_pm)
212 virtual double dV(const DiracSpinor &Fn, const DiracSpinor &Fm) const = 0;
213
214 //! @brief Returns [dV_pm * phi_m]_kappa: RHS of TDHF eq., projected onto kappa (see namespace doc)
215 virtual DiracSpinor dV_rhs(int kappa, const DiracSpinor &Fm,
216 bool conj = false) const {
217 // XXX Remove this implementation (make pure virtual) once j_L killed
218 (void)kappa;
219 (void)Fm;
220 (void)conj;
221 assert(false && "This should be made pure virtual");
222 return Fm;
223 }
224
225public:
226 CorePolarisation &operator=(const CorePolarisation &) = delete;
227 CorePolarisation(const CorePolarisation &) = default;
228 virtual ~CorePolarisation() = default;
229};
230
231} // namespace ExternalField
General tensor operator (virtual base class); all single-particle (one-body) tenosor operators derive...
Definition TensorOperator.hpp:198
bool imaginaryQ() const
returns true if operator is imaginary (has imag MEs)
Definition TensorOperator.hpp:324
int parity() const
returns parity, as integer (+1 or -1)
Definition TensorOperator.hpp:330
int rank() const
Rank k of operator.
Definition TensorOperator.hpp:327
Stores radial Dirac spinor: F_nk = (f, g)
Definition DiracSpinor.hpp:42
Virtual base class for core-polarisation (RPA); computes dV corrections.
Definition CorePolarisation.hpp:140
virtual void clear()=0
Clears the internal state back to pre solve_core()
virtual double dV(const DiracSpinor &Fn, const DiracSpinor &Fm) const =0
Returns reduced matrix element <n||dV_pm||m> (see namespace doc for dV_pm)
virtual DiracSpinor dV_rhs(int kappa, const DiracSpinor &Fm, bool conj=false) const
Returns [dV_pm * phi_m]_kappa: RHS of TDHF eq., projected onto kappa (see namespace doc)
Definition CorePolarisation.hpp:215
int rank() const
Rank of the operator.
Definition CorePolarisation.hpp:166
double last_eps() const
Returns eps (convergance) of last solve_core run.
Definition CorePolarisation.hpp:160
double last_omega() const
Returns omega (frequency) of last solve_core run.
Definition CorePolarisation.hpp:164
void set_eta(double eta)
Set/update damping factor; 0 means no damping. Must have 0 <= eta < 1.
Definition CorePolarisation.hpp:180
double eps_target() const
Convergance target.
Definition CorePolarisation.hpp:175
bool imagQ() const
Returns true if the operator is imaginary.
Definition CorePolarisation.hpp:170
virtual Method method() const =0
Returns RPA method.
double eta() const
Damping factor; 0 means no damping. Must have 0 <= eta < 1.
Definition CorePolarisation.hpp:178
double last_its() const
Returns its (# of iterations) of last solve_core run.
Definition CorePolarisation.hpp:162
double & eps_target()
Convergance target.
Definition CorePolarisation.hpp:173
virtual void solve_core(double omega, int max_its=100, bool print=true)=0
Solve for delta_V_pm self-consistently for all core orbitals at frequency omega.
int parity() const
Parity of the operator.
Definition CorePolarisation.hpp:168
Uses TDHF to include core-polarisation (RPA) corrections to matrix elements of an external field oper...
Definition TDHF.hpp:59
Dirac operators: TensorOperator base class and derived implementations for single-particle (one-body)...
Definition GenerateOperator.cpp:6
Core-polarisation (RPA) corrections to matrix elements of an external field.
Definition calcMatrixElements.cpp:14
Method ParseMethod(std::string_view str)
Parses method string to Method enum (case-insensitive)
Definition CorePolarisation.hpp:85
StateType
Whether the state is a bra or ket.
Definition CorePolarisation.hpp:112
dPsiType
Selects the perturbed orbital: X = varphi_+, Y = varphi_-.
Definition CorePolarisation.hpp:110
Method
Available RPA/core-polarisation methods.
Definition CorePolarisation.hpp:82
bool ci_compare(std::string_view s1, std::string_view s2)
Case-insensitive string comparison; equivalent to tolower(s1) == tolower(s2).
Definition String.hpp:143