ampsci
High-precision calculations for one- and two-valence atomic systems
Methods.hpp
1#pragma once
2#include <cmath>
3#include <functional>
4#include <utility>
5
6namespace qip {
7
8/*!
9 @brief Numerical derivative of y(x) at point x; returns {dy/dx, error}.
10
11 @details
12 Iteratively halves the step size until
13 |dy/dx_n - dy/dx_{n-1}| < delta_target.
14
15 @tparam Function Callable as `y(x)`, returning a value convertible to Real.
16 @tparam Real Floating-point type.
17
18 @param y Function to differentiate.
19 @param x Point at which to evaluate the derivative.
20 @param delta_target Convergence target (default 1e-6).
21 @param dx Initial step size (default 0.01).
22 @param it_limit Maximum number of iterations (default 250).
23*/
24template <typename Function, typename Real>
25std::pair<Real, Real>
26derivative(Function y, Real x, Real delta_target = Real{1.0e-6},
27 Real dx = Real{0.01}, unsigned it_limit = 250) {
28 Real dydx{0.0};
29 Real delta{1.0};
30 for (auto i = 0u;; ++i) {
31 const auto dydx0 = dydx;
32 const auto dy = 0.5 * (y(x + dx) - y(x - dx));
33 dydx = dy / dx;
34 delta = std::abs(dydx - dydx0);
35 if (1.1 * delta < delta_target || i > it_limit)
36 break;
37 dx *= 0.5;
38 }
39 return {dydx, 1.1 * delta};
40}
41
42/*!
43 @brief Solves f(x) = 0 using Newton's method; returns {root, error}.
44
45 @tparam Function Callable as `f(x)`, returning a value convertible to Real.
46 @tparam Real Floating-point type.
47
48 @param f Function to solve.
49 @param x Initial guess.
50 @param delta_target Convergence target for |x_n - x_{n+1}| (default 1e-6).
51 @param dx Initial step size for derivative (default 0.01).
52 @param it_limit Maximum number of iterations (default 250).
53*/
54template <typename Function, typename Real>
55std::pair<Real, Real> Newtons(Function f, Real x,
56 Real delta_target = Real{1.0e-6},
57 Real dx = Real{0.01}, unsigned it_limit = 250) {
58 Real delta{1.0};
59 for (auto i = 0u;; ++i) {
60 // const auto df = (f(x + dx) - f(x)) / dx;
61 const auto df = derivative(f, x, delta_target, dx, 4).first;
62 delta = f(x) / df;
63 x = x - delta;
64 if (std::abs(delta) < delta_target || i > it_limit)
65 break;
66 }
67 return {x, 1.1 * delta};
68}
69
70/*!
71 @brief Solves f(x) = 0 using Newton's method with bounds; returns {root, error}.
72
73 @details Solution is clamped to [bounds.first, bounds.second].
74
75 @param f Function to solve.
76 @param x Initial guess.
77 @param bounds Allowed range [lower, upper].
78 @param delta_target Convergence target for |x_n - x_{n+1}| (default 1e-6).
79 @param dx Initial step size for derivative (default 0.01).
80 @param it_limit Maximum number of iterations (default 250).
81*/
82template <typename Function, typename Real>
83std::pair<Real, Real> Newtons(Function f, Real x, std::pair<Real, Real> bounds,
84 Real delta_target = Real{1.0e-6},
85 Real dx = Real{0.01}, unsigned it_limit = 250) {
86 Real delta{1.0};
87 for (auto i = 0u;; ++i) {
88 // const auto df = (f(x + dx) - f(x)) / dx;
89 const auto df = derivative(f, x, delta_target, dx, 4).first;
90 delta = f(x) / df;
91 x = x - delta;
92 if (x < bounds.first) {
93 x = bounds.first;
94 break;
95 }
96 if (x > bounds.second) {
97 x = bounds.second;
98 break;
99 }
100 if (std::abs(delta) < delta_target || i > it_limit)
101 break;
102 }
103 return {x, 1.1 * delta};
104}
105
106} // namespace qip
double Real
Data type used to store integrals.
Definition QkTable.hpp:32
double f(RaB r, PrincipalQN n, DiracQN k, Zeff z, AlphaFS a)
Upper radial component.
Definition DiracHydrogen.cpp:71
General-purpose utility library.
Definition Array.hpp:23
std::pair< Real, Real > derivative(Function y, Real x, Real delta_target=Real{1.0e-6}, Real dx=Real{0.01}, unsigned it_limit=250)
Numerical derivative of y(x) at point x; returns {dy/dx, error}.
Definition Methods.hpp:26
std::pair< Real, Real > Newtons(Function f, Real x, Real delta_target=Real{1.0e-6}, Real dx=Real{0.01}, unsigned it_limit=250)
Solves f(x) = 0 using Newton's method; returns {root, error}.
Definition Methods.hpp:55