High-precision calculations for one- and two-valence atomic systems
ContinuumState.hpp
1#pragma once
2#include "AdamsMoulton.hpp"
3#include "Physics/PhysConst_constants.hpp"
4#include <utility>
5#include <vector>
6class DiracSpinor;
7class Grid;
8
9namespace DiracODE {
10
11/*!
12 @brief Solves Dirac equation for a continuum state (en > 0) with energy normalisation.
13 @details
14 Normalisation is achieved by continuing the ODE integration to very large r and
15 comparing the asymptotic amplitude to that of the analytic solution.
16 Only the solution on the regular grid is kept; the extended part is discarded.
17 The solution is solved and stored only up to the radius where the grid
18 resolves the oscillations (at least ~10 points per wavelength); Fa.max_pt()
19 is set accordingly and the tail is zeroed. For high energies this may be
20 well inside the grid; for low energies it is the entire grid.
21 @param Fa Output spinor (result stored here).
22 @param en Continuum energy (must be > 0).
23 @param v Local potential v(r).
24 @param alpha Fine-structure constant.
25 @param VxFa Optional exchange potential. If nullptr, ignored.
26 @param Fa0 Optional inhomogeneous source spinor. If nullptr, ignored.
27 @param average_tail Optionally fill the unresolved (zeroed) tail with a
28 local average (see averageTail()).
29*/
30void solveContinuum(DiracSpinor &Fa, double en, const std::vector<double> &v,
31 double alpha, const DiracSpinor *const VxFa = nullptr,
32 const DiracSpinor *const Fa0 = nullptr,
33 bool average_tail = false);
34
35//! Grid requirements returned by RequiredContinuumGrid
37 //! num_points required, keeping r0, rmax, and b unchanged
38 std::size_t num_points;
39 //! largest sufficient b, keeping num_points unchanged (clamped to >= 0.05)
40 double b;
41 //! num_points required at the returned b (== current num_points, unless
42 //! b was clamped)
43 std::size_t num_points_b;
44};
45
46/*!
47 @brief Grid parameters required to safely store (pointwise) a continuum state of energy en on the entire grid.
48 @details
49 A continuum state is stored pointwise only where the grid spacing gives
50 at least N_ppw points per wavelength; beyond that solveContinuum() zeroes
51 the solution (see Fa.max_pt()). This checks the grid against the largest
52 spacing (the last point) - the constraint is always at large r, where
53 the grid is coarsest. Each returned value assumes the other grid
54 parameters are unchanged. The b formula assumes a loglinear grid; b is
55 clamped from below at 0.05 (below that, even a nearly-linear grid is too
56 coarse) - when clamped, num_points_b (the num_points required at the
57 clamped b) will exceed the current num_points.
58 Uses the relativistic wavelength, 2*pi/k with k^2 = en*(2 + alpha^2*en);
59 at high energy this is much shorter than the non-relativistic estimate
60 (e.g., 1.9x shorter at en = 1e5 au).
61 @param en Continuum energy (should be the largest energy required).
62 @param gr The radial grid.
63 @param N_ppw Required points per wavelength (default 20, as used by
64 solveContinuum).
65 @param alpha Fine-structure constant.
66*/
68 double N_ppw = 20.0,
69 double alpha = PhysConst::alpha);
70
71/*!
72 @brief Optionally fills the zeroed high-r tail of a continuum state with a locally-averaged solution, so radial integrals against smooth functions remain accurate.
73 @details
74 solveContinuum() stores the solution only up to the radius where the grid
75 resolves the oscillations (Fa.max_pt()), and zeroes the rest; radial
76 integrals then silently omit any contribution from beyond that radius.
77 This routine replaces the tail with the local Gaussian average of a
78 finely-integrated solution. The average is smooth enough to store on the
79 coarse grid, and preserves radial integrals against functions that are
80 smooth on the oscillation scale (bound orbitals, r^k, ...), since
81 Int[B f_avg] = Int[B_avg f] ~ Int[B f]. It does not preserve integrals
82 against co-factors that oscillate on a comparable scale (e.g. jL(qr)
83 with q ~ k), and the stored tail is a local average, not the pointwise
84 wavefunction. Exchange is neglected in the tail. Sets Fa.max_pt() to
85 num_points.
86 @param Fa Continuum state from solveContinuum() (modified in place).
87 @param v Local potential v(r) (as used to solve Fa).
88 @param alpha Fine-structure constant.
89 @return Index of the first averaged point; num_points if nothing was done.
90*/
91std::size_t averageTail(DiracSpinor &Fa, const std::vector<double> &v,
92 double alpha);
93
94/*!
95 @brief
96 Builds the irregular continuum partner F_irr of a regular continuum orbital F_reg.
97
98 @details
99 Given the regular (energy-normalised) continuum orbital F_reg at energy
100 en > 0 in the local potential v, constructs the linearly independent
101 irregular solution F_irr of the same homogeneous equation: the quarter-wave
102 phase-shifted partner (F_reg ~ sin, F_irr ~ -cos at large r), so that
103
104 \f[
105 F_reg + i F_irr
106 \f]
107
108 is the outgoing wave.
109
110 It plays the role of the "regular at infinity" solution of the
111 continuum Green's function, in place of the decaying bound solution.
112
113 The outermost grid points are seeded by projecting F_reg onto the
114 energy-normalised asymptotic Dirac-Coulomb pair {F^C, G^C}
115 ( @ref AsymptoticSpinorContinuum ), F_reg = a F^C + b G^C, so
116
117 \f[
118 F_irr = b F^C - a G^C
119 \f]
120
121 (the short-range phase shift is in a, b);
122 the homogeneous equation is then integrated inwards to the origin. If the
123 asymptotic series has not converged at the box edge (a barely-open channel,
124 small p*r_max), F_reg is first continued outward on a fine grid with the
125 Coulomb tail potential until it has; F_irr is seeded there and integrated
126 back to the box. As a last resort (non-Coulomb tail) the seed is the
127 leading-order component swap, f_irr = -g_reg/beta, g_irr = beta f_reg.
128
129 The result has the Wronskian f_reg g_irr - f_irr g_reg = alpha/pi (times
130 a^2 + b^2, which is 1 when the projection is exact). It need not be
131 normalised: the overall scale cancels in the Green's-function prefactor.
132
133 @param Firr Output: the irregular partner (kappa from Freg).
134 @param Freg The regular, energy-normalised continuum orbital.
135 @param en Continuum energy (> 0; should equal Freg.en()).
136 @param v Local potential (as used to solve Freg); its tail sets the
137 residual-ion charge of the Coulomb series.
138 @param alpha Fine-structure constant.
139
140 @warning Requires en > 0 and a grid dense enough at large r that F_reg is
141 resolved there (same condition as solveContinuum).
142*/
143void solveContinuumIrregular(DiracSpinor &Firr, const DiracSpinor &Freg,
144 double en, const std::vector<double> &v,
145 double alpha);
146
147/*!
148 @brief
149 Solves the inhomogeneous continuum equation (h_r - en) phi = S
150 (en > 0) with the standing-wave boundary condition, by outward integration
151 plus subtraction of the regular solution.
152
153 @details
154 Outward integration from the origin with regular initial conditions gives
155 a particular solution, determined only up to an admixture of F_reg (itself
156 regular at the origin). Beyond the (short-ranged) source it equals
157 c F_reg + K F_irr exactly; c and K are read off pointwise over an outer
158 window from the two spinor components (local Wronskian; no phase fit) and
159 averaged, and then
160 \f[
161 \varphi = \tilde\varphi - c\,F_{\rm reg} \to K\,F_{\rm irr} ,
162 \f]
163 the Green's-function solution with the standing-wave Green's function. The
164 outgoing solution is phi - i K F_reg.
165
166 Where the main grid no longer resolves the oscillations (high energy), phi
167 is continued through that band by variation of parameters on the pair,
168 phi = u F_reg + w F_irr, with the quadratures done on the grid; the
169 extraction window lies inside the resolved region.
170
171 @param phi Output: the standing-wave particular solution (kappa from Freg).
172 @param Freg Regular homogeneous solution at en (energy-normalised).
173 @param Firr Irregular partner (see solveContinuumIrregular).
174 @param en Continuum energy (> 0).
175 @param v Local potential (as used for Freg and Firr).
176 @param alpha Fine-structure constant.
177 @param Sr Source spinor S.
178
179 @return K: phi -> K F_irr at large r (K = -pi <Freg|S> for the exact
180 solution; +pi <Freg|S> in the TDHF convention (h - en) phi = -S). Returns 0 if no valid extraction window exists (the
181 resolved region ends inside the source).
182*/
183double solveContinuumForward(DiracSpinor &phi, const DiracSpinor &Freg,
184 const DiracSpinor &Firr, double en,
185 const std::vector<double> &v, double alpha,
186 const DiracSpinor &Sr);
187
188/*!
189 @brief Analytic amplitude of f(r) at very large r for an H-like Dirac continuum state.
190 @param en Continuum energy.
191 @param alpha Fine-structure constant.
192 @return Analytic asymptotic amplitude.
193*/
194double analytic_f_amplitude(double en, double alpha);
195
196/*!
197 @brief
198 Finds the numerical amplitude of f(r) for a continuum Dirac solution at large r.
199
200 @details
201 Continues ODE integration beyond the regular grid, assuming an H-like
202 potential (-Zeff/r) and a linearly-spaced extension grid with step dr.
203 The amplitude estimate sqrt(f^2 + c_g^2 g^2) is averaged over full
204 oscillation cycles (delimited by zero-crossings of f, located to sub-step
205 accuracy), and the cycle means are extrapolated to r -> infinity by
206 fitting A_inf + c2/r^2 + c3/r^3 + c4/r^4. Converged when the extrapolated
207 estimates from the full and half integration ranges agree.
208
209 @param en Continuum energy.
210 @param kappa Orbital kappa quantum number.
211 @param alpha Fine-structure constant.
212 @param Zeff Effective nuclear charge.
213 @param f_final Value of f at the end of the regular grid.
214 @param g_final Value of g at the end of the regular grid.
215 @param r_final Radial position at the end of the regular grid.
216 @param dr Step size for the extended linear grid.
217 @return {amplitude, eps} - extrapolated asymptotic amplitude of f(r), and
218 relative difference between the last two estimates (convergence measure).
219*/
220std::pair<double, double> numerical_f_amplitude(double en, int kappa,
221 double alpha, double Zeff,
222 double f_final, double g_final,
223 double r_final, double dr);
224
225/*!
226 @brief H-like Dirac derivative matrix for continuum states at large r.
227 @details
228 Implements AdamsMoulton::DerivativeMatrix<double, double>, using r directly
229 as the argument type. Valid for H-like potential (-Zeff/r); used to extend
230 continuum integration beyond the regular grid for normalisation.
231 @note Non-copyable.
232*/
234 : AdamsMoulton::DerivativeMatrix<double, double> {
235
236 /*!
237 @brief Constructs the H-like continuum derivative matrix.
238 @param in_Zeff Effective nuclear charge.
239 @param in_kappa Orbital kappa quantum number.
240 @param in_en Continuum energy.
241 @param in_alpha Fine-structure constant.
242 */
243 DiracContinuumDerivative(double in_Zeff, const int in_kappa,
244 const double in_en, const double in_alpha)
245 : Zeff(in_Zeff),
246 kappa(in_kappa),
247 en(in_en),
248 alpha(in_alpha),
249 cc(1.0 / alpha) {}
250
251 double Zeff = 1.0;
252 int kappa;
253 double en, alpha, cc;
254
255 double a(double r) const final { return double(-kappa) / r; }
256 double b(double r) const final {
257 return (alpha * en + 2.0 * cc + Zeff * alpha / r);
258 }
259 double c(double r) const final { return -alpha * (Zeff / r + en); }
260 double d(double r) const final { return -a(r); }
261};
262
263/*!
264 @brief Fits a quadratic to three points and returns the interpolated maximum.
265 @details
266 Assumes |y2| = max(|y1|, |y2|, |y3|); used to find the amplitude of a
267 sinusoidal oscillation. The three points must be close to the maximum.
268 @param x1, x2, x3 x-coordinates of the three points.
269 @param y1, y2, y3 y-coordinates of the three points.
270 @return Interpolated maximum value.
271*/
272double fitQuadratic(double x1, double x2, double x3, double y1, double y2,
273 double y3);
274
275} // namespace DiracODE
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
Functions and classes used to solve the Dirac equation.
Definition AsymptoticSpinor.hpp:10
double solveContinuumForward(DiracSpinor &phi, const DiracSpinor &Freg, const DiracSpinor &Firr, double en, const std::vector< double > &v, double alpha, const DiracSpinor &Sr)
Solves the inhomogeneous continuum equation (h_r - en) phi = S (en > 0) with the standing-wave bounda...
Definition ContinuumState.cpp:574
std::size_t num_points_b
num_points required at the returned b (== current num_points, unless b was clamped)
Definition ContinuumState.hpp:43
double fitQuadratic(double x1, double x2, double x3, double y1, double y2, double y3)
Fits a quadratic to three points and returns the interpolated maximum.
Definition ContinuumState.cpp:850
GridRequirements RequiredContinuumGrid(double en, const Grid &gr, double N_ppw, double alpha)
Grid parameters required to safely store (pointwise) a continuum state of energy en on the entire gri...
Definition ContinuumState.cpp:201
std::pair< double, double > numerical_f_amplitude(double en, int kappa, double alpha, double Zeff, double f_final, double g_final, double r_final, double dr)
Finds the numerical amplitude of f(r) for a continuum Dirac solution at large r.
Definition ContinuumState.cpp:677
std::size_t num_points
num_points required, keeping r0, rmax, and b unchanged
Definition ContinuumState.hpp:38
double b
largest sufficient b, keeping num_points unchanged (clamped to >= 0.05)
Definition ContinuumState.hpp:40
void solveContinuum(DiracSpinor &Fa, double en, const std::vector< double > &v, double alpha, const DiracSpinor *const VxFa, const DiracSpinor *const Fa0, bool average_tail)
Solves Dirac equation for a continuum state (en > 0) with energy normalisation.
Definition ContinuumState.cpp:52
double analytic_f_amplitude(double en, double alpha)
Analytic amplitude of f(r) at very large r for an H-like Dirac continuum state.
Definition ContinuumState.cpp:840
std::size_t averageTail(DiracSpinor &Fa, const std::vector< double > &v, double alpha)
Optionally fills the zeroed high-r tail of a continuum state with a locally-averaged solution,...
Definition ContinuumState.cpp:249
void solveContinuumIrregular(DiracSpinor &Firr, const DiracSpinor &Freg, double en, const std::vector< double > &v, double alpha)
Builds the irregular continuum partner F_irr of a regular continuum orbital F_reg.
Definition ContinuumState.cpp:352
Grid requirements returned by RequiredContinuumGrid.
Definition ContinuumState.hpp:36
constexpr double alpha
Fine-structure constant: alpha = 1/137.035 999 177(21) [CODATA 2022].
Definition PhysConst_constants.hpp:24
Pure-virtual struct defining the derivative matrix for a 2x2 ODE system.
Definition AdamsMoulton.hpp:47
H-like Dirac derivative matrix for continuum states at large r.
Definition ContinuumState.hpp:234
DiracContinuumDerivative(double in_Zeff, const int in_kappa, const double in_en, const double in_alpha)
Constructs the H-like continuum derivative matrix.
Definition ContinuumState.hpp:243
double a(double r) const final
a,b,c,d are derivative matrix functions; all must be user implemented
Definition ContinuumState.hpp:255