ampsci
c++ program for high-precision atomic structure calculations of single-valence systems
BoundState.hpp
1 #pragma once
2 #include "AdamsMoulton.hpp"
3 #include "Physics/PhysConst_constants.hpp"
4 #include "Wavefunction/DiracSpinor.hpp"
5 #include <memory>
6 #include <utility>
7 #include <vector>
8 class Grid;
9 
10 namespace DiracODE {
11 
12 //==============================================================================
14 
23 void boundState(DiracSpinor &Fa, const double en0, const std::vector<double> &v,
24  const std::vector<double> &H_off_diag = {},
25  const double alpha = PhysConst::alpha, double eps = 1.0e-14,
26  const DiracSpinor *const VxFa = nullptr,
27  const DiracSpinor *const Fa0 = nullptr, double zion = 1,
28  double mass = 1.0);
29 
30 inline DiracSpinor boundState(int n, int kappa, const double en0,
31  const std::shared_ptr<const Grid> &gr,
32  const std::vector<double> &v,
33  const std::vector<double> &H_off_diag = {},
34  const double alpha = PhysConst::alpha,
35  double eps = 1.0e-14,
36  const DiracSpinor *const VxFa = nullptr,
37  const DiracSpinor *const Fa0 = nullptr,
38  double zion = 1, double mass = 1.0) {
39  DiracSpinor Fnk = DiracSpinor(n, kappa, gr);
40  boundState(Fnk, en0, v, H_off_diag, alpha, eps, VxFa, Fa0, zion, mass);
41  return Fnk;
42 }
43 
45 void regularAtOrigin(DiracSpinor &Fa, const double en,
46  const std::vector<double> &v,
47  const std::vector<double> &H_off_diag, const double alpha,
48  const DiracSpinor *const VxFa = nullptr,
49  const DiracSpinor *const Fa0 = nullptr, double zion = 1,
50  double mass = 1.0);
51 
53 void regularAtInfinity(DiracSpinor &Fa, const double en,
54  const std::vector<double> &v,
55  const std::vector<double> &H_off_diag,
56  const double alpha,
57  const DiracSpinor *const VxFa = nullptr,
58  const DiracSpinor *const Fa0 = nullptr, double zion = 1,
59  double mass = 1.0);
60 
61 namespace Internal {
62 
63 //==============================================================================
64 // Parameters used for Adams-Moulton mehtod:
65 namespace Param {
66 
67 // K (# steps) for Adams-Moulton method (between 1 and 12)
68 constexpr std::size_t K_Adams = 7;
69 // Parameter to determine 'assymptotically large r [kinda..]' (=800)
70 constexpr double cALR = 550.0;
71 // Max # attempts at converging [sove bs] (30)
72 constexpr int max_its = 99;
73 // 'large' energy variations (0.1 => 10%)
74 constexpr double lfrac_de = 0.12;
75 // Num points past ctp +/- d_ctp.
76 constexpr int d_ctp = 4;
77 
78 // order of the expansion coeficients in large-r asymptotic expansion (15 orig.)
79 constexpr int nx = 15;
80 // convergance for expansion in asymptotic expansion (10^-8)
81 constexpr double nx_eps = 1.e-12;
82 
83 // weighting function for meshing in/out solutions
84 // nb: must be positive, but i may be negative [ctp - d_ctp]
85 constexpr auto weight = [](std::size_t i) {
86  return 1.0 / static_cast<double>(i * i + 1);
87 };
88 
89 static_assert(
90  Param::K_Adams >= 1 && Param::K_Adams <= AdamsMoulton::K_max,
91  "\nFAIL in DiracODE: parameter K_Adams must be between 5 and 8\n");
92 
93 } // namespace Param
94 
95 //==============================================================================
97 struct DiracDerivative : AdamsMoulton::DerivativeMatrix<std::size_t, double> {
98 
99  DiracDerivative(const Grid &in_grid, const std::vector<double> &in_v,
100  const int in_k, const double in_en, const double in_alpha,
101  const std::vector<double> &V_off_diag = {},
102  const DiracSpinor *const VxFa = nullptr,
103  const DiracSpinor *const iFa0 = nullptr, double zion = 1,
104  double in_mass = 1.0);
105  const Grid *const pgr;
106  const std::vector<double> *const v;
107  const std::vector<double> *const Hmag;
108  const DiracSpinor *const VxFa;
109  const DiracSpinor *const Fa0;
110  const double zion = 1.0;
111  const int k;
112  const double en, alpha, cc;
113  double mass;
114 
115  double a(std::size_t i) const final;
116  double b(std::size_t i) const final;
117  double c(std::size_t i) const final;
118  double d(std::size_t i) const final;
119  double Sf(std::size_t i) const final;
120  double Sg(std::size_t i) const final;
121 
122  DiracDerivative(const DiracDerivative &) = delete;
123  void operator=(const DiracDerivative &) = delete;
124 };
125 
126 //==============================================================================
127 // To keep track of current/previous energy guesses
128 struct TrackEnGuess {
129  // Number of times there was too many/too few nodes:
130  int count_toomany = 0;
131  int count_toofew = 0;
132  // Upper and lower energy window before correct # nodes
133  double high_en = 0.0;
134  double low_en = 0.0;
135 };
136 
137 //==============================================================================
138 // Finds "practical infinity" index, where f(r) drops effectively to zero
139 std::size_t findPracticalInfinity(const double en, const std::vector<double> &v,
140  const std::vector<double> &r,
141  const double alr);
142 
143 // Finds "classical turning point" index, where |V(r)| = |E|
144 std::size_t findClassicalTurningPoint(const double en,
145  const std::vector<double> &v,
146  std::size_t pinf, std::size_t d_ctp);
147 
148 // Finds a trial Dirac solution for given energy that has correct boundary conditions.
149 /*
150 If it's not an exact solution, there will be a 'kink' in the wavefunction
151 around ctp (classical turning point), where the inward and outward solutons
152 were joind. The difference between g for these, dg=(gout-gin), is stored, and
153 is used for PT
154 */
155 void trialDiracSolution(std::vector<double> &f, std::vector<double> &g,
156  std::vector<double> &dg, const double en, const int ka,
157  const std::vector<double> &v,
158  const std::vector<double> &H_off_diag, const Grid &gr,
159  std::size_t ctp, std::size_t d_ctp, std::size_t pinf,
160  const double alpha,
161  const DiracSpinor *const VxFa = nullptr,
162  const DiracSpinor *const Fa0 = nullptr, double zion = 1,
163  double mass = 1.0);
164 
165 // Counts the nodes a given function f
166 int countNodes(const std::vector<double> &f, const std::size_t maxi);
167 
168 // Makes a large update to energy; updates 'TrackEnGuess'
169 void largeEnergyChange(double *en, TrackEnGuess *sofar, double frac_de,
170  bool toomany_nodes);
171 
172 // Makes a small update to energy using perturbation theory, given f and dg
173 double smallEnergyChangePT(const double en, const double anorm,
174  const std::vector<double> &f,
175  const std::vector<double> &dg, std::size_t ctp,
176  std::size_t d_ctp, const double alpha,
177  const TrackEnGuess &sofar);
178 
179 // Solves Dirac equation by integrating outwards from zero.
180 // Integrates only to 'final' (not inclusive). If final=0, goes to f.size()
181 // Solution has correct boundary condition at r=0, but not at large r.
182 void solve_Dirac_outwards(std::vector<double> &f, std::vector<double> &g,
183  const DiracDerivative &Hd, std::size_t final = 0);
184 
185 // Solves Dirac equation by integrating inwards from 'pinf' to 'ctp'
186 // Solution has correct boundary condition at large r, but not at small r.
187 void solve_Dirac_inwards(std::vector<double> &f, std::vector<double> &g,
188  const DiracDerivative &Hd, std::size_t ctp,
189  std::size_t pinf, double mass = 1.0);
190 
191 // Meshes the two solutions from inwards/outwards integration.
192 // Produces solution that has correct boundary conditions at 0 and infinity,
193 // but may not be smooth at the joining point.
194 void joinInOutSolutions(std::vector<double> &f, std::vector<double> &g,
195  std::vector<double> &dg,
196  const std::vector<double> &f_in,
197  const std::vector<double> &g_in, std::size_t ctp,
198  std::size_t d_ctp, std::size_t pinf);
199 
200 } // namespace Internal
201 } // namespace DiracODE
Stores radial Dirac spinor: F_nk = (f, g)
Definition: DiracSpinor.hpp:41
Holds grid, including type + Jacobian (dr/du)
Definition: Grid.hpp:31
Functions and classes used to solve the Dirac equation.
Definition: AsymptoticSpinor.hpp:8
void regularAtInfinity(DiracSpinor &Fa, const double en, const std::vector< double > &v, const std::vector< double > &H_mag, const double alpha, const DiracSpinor *const VxFa, const DiracSpinor *const Fa0, double zion, double mass)
For given energy en, solves (local) DE with correct boundary conditions at infinity.
Definition: BoundState.cpp:170
void regularAtOrigin(DiracSpinor &Fa, const double en, const std::vector< double > &v, const std::vector< double > &H_mag, const double alpha, const DiracSpinor *const VxFa, const DiracSpinor *const Fa0, double zion, double mass)
For given energy en, solves DE with correct boundary conditions at the origin.
Definition: BoundState.cpp:149
void boundState(DiracSpinor &Fn, const double en0, const std::vector< double > &v, const std::vector< double > &H_mag, const double alpha, double eps_goal, const DiracSpinor *const VxFa, const DiracSpinor *const Fa0, double zion, double mass)
Solves bound-state problem for local potential (en < 0)
Definition: BoundState.cpp:23
constexpr double alpha
fine-structure constant
Definition: PhysConst_constants.hpp:13
Pure-virtual struct, holds the derivative matrix for 2x2 system of ODEs. Derive from this,...
Definition: AdamsMoulton.hpp:79
Matrix which defines Dirac derivative: (dF/dr) = D*F.
Definition: BoundState.hpp:97
double a(std::size_t i) const final
a,b,c,d are derivative matrix functions; all must be user implemented
Definition: BoundState.cpp:501
double Sf(std::size_t i) const final
Sf and Sg are optional inhomogenous terms.
Definition: BoundState.cpp:513