ampsci
High-precision calculations for one- and two-valence atomic systems
AdamsMoulton::ODESolver2D< K, T, Y >

ok

template<std::size_t K, typename T = double, typename Y = double>
class AdamsMoulton::ODESolver2D< K, T, Y >

Solves a 2x2 system of ODEs using a K-step Adams-Moulton method.

The system of ODEs is defined such that:

\[ \frac{dF(t)}{dt} = D(t) * F(t) + S(t) \]

Where F is a 2D set of functions:

\[ F(t) = \begin{pmatrix} f(t)\\ g(t) \end{pmatrix}, \]

D is the 2x2 "derivative matrix":

\[ D(t) = \begin{pmatrix} a(t) & b(t)\\ c(t) & d(t) \end{pmatrix}, \]

and S(t) is the (optional) 2D inhomogenous term:

\[ S(t) = \begin{pmatrix} s_f(t)\\ s_g(t) \end{pmatrix}. \]

See struct DerivativeMatrix - which is a pure virtual struct that must be implmented by the user in order to define the ODE.

The step-size, dt, must remain constant (since it must remain consistant between the K+1 and previous K points). It may be positive or negative, however (or complex). It's perfectly possible to have a non-uniform grid - this just introduces a Jacobian into the Derivative matrix; dt must still be constant.

The template parameter, T, is the type of the argument of the Derivative Matrix (i.e., type of t). This is often double or complex<double>, but may also be an index type (e.g., std::size_t) if the derivative matrix is only known numerically at certain grid points/stored in an array.

The template parameter, Y, is the type of the function value F(t), and the type of dt, and the return value of the Derivative Matrix. This is often double, but may also be another floating-point type, or std::complex.

The first K points of the function F, and derivative dF/dt, must be known. You may directly access the f,g (function) and df,dg (derivative) arrays, to set these points.

Alternatively, you may use the provided function

void solve_initial_K(T t0, Y f0, Y g0);
void solve_initial_K(T t0, Y f0, Y g0)
Sets the first K values of F (and dF) given a single initial condition.
Definition AdamsMoulton.hpp:559

which automatically sets the first K values for F (and dF), given a single initial value for F, f0=f(t0), fg=g(t0), by using successive N-step AM methods, for N={1,2,...,K-1}.

For now, just a 2x2 system. In theory, simple to generalise to an N*N system, though requires a matrix inversion.

Example:** Bessel's differential equation

\[ x^2 \frac{d^2y}{dx^2} + x \frac{dy}{dx} + (x^2-n^2)y = 0 \]

With y(0) = 1.0, the solutions are the Bessel functions, y(x) = J_n(x)

This can be re-written as a pair of coupled first-order ODEs:

\[ \begin{aligned} \frac{dy}{dx} &= p \\ \frac{dp}{dx} &= \left[\left(\frac{n}{x}\right)^2 - 1\right]y - \frac{1}{x}p \end{aligned} \]

Putting this into the notation/form required for the solver we have:

\[ F(x) = \begin{pmatrix} y(x)\\ p(x) \end{pmatrix} \]

with the "derivative matrix":

\[ D(x) = \begin{pmatrix} 0 & 1 \\ \left(\frac{n}{x}\right)^2 - 1 & \frac{-1}{x} \end{pmatrix} \]

i.e.,

for n=1:

struct BesselDerivative : AdamsMoulton::DerivativeMatrix<double, double> {
double a(double) const final { return 0.0; }
double b(double) const final { return 1.0; }
double c(double t) const final { return 1.0/t/t - 1.0; }
double d(double t) const final { return -1.0 / t; }
};
Pure-virtual struct defining the derivative matrix for a 2x2 ODE system.
Definition AdamsMoulton.hpp:47

Or, more generally (for example):

struct BesselDerivative : AdamsMoulton::DerivativeMatrix<double, double> {
int n;
BesselDerivative(int tn) : n(tn) {}
double a(double) const final { return 0.0; }
double b(double) const final { return 1.0; }
double c(double t) const final { return std::pow(n/t,2) - 1.0; }
double d(double t) const final { return -1.0 / t; }
};
constexpr double c
speed of light in a.u. (=1/alpha)
Definition PhysConst_constants.hpp:63

Minimal example: – see full examples included elsewhere

// Construct the Derivative matrix (BesselDerivative defined above) with n=0
int n = 0;
BesselDerivative D{n};
// Set the step size:
double dt = 0.01;
// Construct the Solver, using K=6-step method:
// Since 1/t appears in D, we cannot start at zero. Instead, begin at small t
double t0 = 1.0e-6;
// Set initial points:
// Note: these are *approximate*, since they are technically f(0.0)
double f0 = 1.0;
double g0 = 0.0;
// Use automatic solver for first K points:
ode.solve_initial_K(t0, f0, g0);
// Drive forwards another 100 steps
for (int i = 0; i < 100; ++i) {
ode.drive();
std::cout << ode.last_t() << " " << ode.last_f() << '\n';
}
Solves a 2x2 system of ODEs using a K-step Adams-Moulton method.
Definition AdamsMoulton.hpp:409
Y dt()
Returns the step size.
Definition AdamsMoulton.hpp:475

#include <AdamsMoulton.hpp>

Public Member Functions

 ODESolver2D (Y dt, const DerivativeMatrix< T, Y > *D)
 Constructs the ODE solver with a given step size and derivative matrix.
 
constexpr std::size_t K_steps () const
 Returns the AM order (number of steps), K.
 
last_f ()
 Returns most recent f value. Can also access f array directly.
 
last_g ()
 Returns most recent g value. Can also access g array directly.
 
last_t ()
 Returns most recent t value; last_f() := f(last_t())
 
dt ()
 Returns the step size.
 
dfdt (Y ft, Y gt, T tt) const
 Returns derivative, df/dt(t), given f(t),g(t),t.
 
dgdt (Y ft, Y gt, T tt) const
 Returns derivative, dg/dt(t), given f(t),g(t),t.
 
void drive (T t_next)
 Drives the ODE system one step to t_next, given the K previous values.
 
void drive ()
 Overload of drive(T t) for 'default' case, where next t is defined as last_t + dt (for arithmetic/complex types), or last_t++/last_t– for integral types (grid index).
 
void solve_initial_K (T t0, Y f0, Y g0)
 Sets the first K values of F (and dF) given a single initial condition.
 

Public Attributes

std::array< Y, K > f {}
 Arrays storing the previous K values of f and g.
 
std::array< Y, K > g {}
 
std::array< Y, K > df {}
 Arrays to store the previous K values of derivatives, df and dg.
 
std::array< Y, K > dg {}
 
std::array< T, K > t {}
 Array to store the previous K values of t: f.at(i) = f(t.at(i))
 
S_scale {1.0}
 

Constructor & Destructor Documentation

◆ ODESolver2D()

template<std::size_t K, typename T = double, typename Y = double>
AdamsMoulton::ODESolver2D< K, T, Y >::ODESolver2D ( dt,
const DerivativeMatrix< T, Y > *  D 
)
inline

Constructs the ODE solver with a given step size and derivative matrix.

The step-size dt may be positive (drive forwards), negative (drive backwards), or complex. A raw pointer to D is stored internally and must not be null; it must outlive the ODESolver2D instance.

Parameters
dtConstant step size.
DPointer to the derivative matrix. Must not be null.

Member Function Documentation

◆ K_steps()

template<std::size_t K, typename T = double, typename Y = double>
constexpr std::size_t AdamsMoulton::ODESolver2D< K, T, Y >::K_steps ( ) const
inlineconstexpr

Returns the AM order (number of steps), K.

◆ last_f()

template<std::size_t K, typename T = double, typename Y = double>
Y AdamsMoulton::ODESolver2D< K, T, Y >::last_f ( )
inline

Returns most recent f value. Can also access f array directly.

◆ last_g()

template<std::size_t K, typename T = double, typename Y = double>
Y AdamsMoulton::ODESolver2D< K, T, Y >::last_g ( )
inline

Returns most recent g value. Can also access g array directly.

◆ last_t()

template<std::size_t K, typename T = double, typename Y = double>
T AdamsMoulton::ODESolver2D< K, T, Y >::last_t ( )
inline

Returns most recent t value; last_f() := f(last_t())

◆ dt()

template<std::size_t K, typename T = double, typename Y = double>
Y AdamsMoulton::ODESolver2D< K, T, Y >::dt ( )
inline

Returns the step size.

◆ dfdt()

template<std::size_t K, typename T = double, typename Y = double>
Y AdamsMoulton::ODESolver2D< K, T, Y >::dfdt ( ft,
gt,
tt 
) const
inline

Returns derivative, df/dt(t), given f(t),g(t),t.

◆ dgdt()

template<std::size_t K, typename T = double, typename Y = double>
Y AdamsMoulton::ODESolver2D< K, T, Y >::dgdt ( ft,
gt,
tt 
) const
inline

Returns derivative, dg/dt(t), given f(t),g(t),t.

◆ drive() [1/2]

template<std::size_t K, typename T = double, typename Y = double>
void AdamsMoulton::ODESolver2D< K, T, Y >::drive ( t_next)
inline

Drives the ODE system one step to t_next, given the K previous values.

Assumes the system has already been solved for the K previous values {t-K*dt, ..., t-dt}. The value t_next should satisfy t_next = last_t + dt.

t is passed explicitly to avoid accumulation of floating-point errors: the 10,000th grid point may not equal t0 + 10000*dt exactly, particularly on non-linear grids. The no-argument overload drive() avoids this but should be used with care.

The type T of t_next must match the type expected by DerivativeMatrix; usually T=double for an analytic derivative, or T=std::size_t when the derivative is stored on a discrete grid.

Parameters
t_nextThe target t value for the new step.

◆ drive() [2/2]

template<std::size_t K, typename T = double, typename Y = double>
void AdamsMoulton::ODESolver2D< K, T, Y >::drive ( )
inline

Overload of drive(T t) for 'default' case, where next t is defined as last_t + dt (for arithmetic/complex types), or last_t++/last_t– for integral types (grid index).

◆ solve_initial_K()

template<std::size_t K, typename T = double, typename Y = double>
void AdamsMoulton::ODESolver2D< K, T, Y >::solve_initial_K ( t0,
f0,
g0 
)
inline

Sets the first K values of F (and dF) given a single initial condition.

Uses successive N-step AM methods for N = {1, 2, ..., K-1}:

  • F[0] is set from the supplied initial values.
  • F[1] is determined from F[0] using a 1-step AM method.
  • F[2] is determined from F[0], F[1] using a 2-step AM method.
  • ...
  • F[K-1] is determined from F[0], ..., F[K-2] using a (K-1)-step AM method.
Parameters
t0Initial value of t.
f0Initial value f(t0).
g0Initial value g(t0).

Member Data Documentation

◆ f

template<std::size_t K, typename T = double, typename Y = double>
std::array<Y, K> AdamsMoulton::ODESolver2D< K, T, Y >::f {}

Arrays storing the previous K values of f and g.

Stored in chronological order regardless of the sign of dt (i.e. whether driving forwards or backwards). f[0] is the oldest value, f[K-1] is newest.

◆ df

template<std::size_t K, typename T = double, typename Y = double>
std::array<Y, K> AdamsMoulton::ODESolver2D< K, T, Y >::df {}

Arrays to store the previous K values of derivatives, df and dg.

◆ t

template<std::size_t K, typename T = double, typename Y = double>
std::array<T, K> AdamsMoulton::ODESolver2D< K, T, Y >::t {}

Array to store the previous K values of t: f.at(i) = f(t.at(i))


The documentation for this class was generated from the following file: