78template <
typename T =
double,
typename Y =
double>
81 virtual Y
a(T t)
const = 0;
82 virtual Y b(T t)
const = 0;
83 virtual Y c(T t)
const = 0;
84 virtual Y d(T t)
const = 0;
86 virtual Y
Sf(T)
const {
return Y(0); };
87 virtual Y Sg(T)
const {
return Y(0); };
88 virtual ~DerivativeMatrix() =
default;
95struct is_complex : std::false_type {};
98struct is_complex<std::complex<T>> : std::true_type {};
121template <
typename T,
typename U, std::
size_t N, std::
size_t M>
123 const std::array<U, M> &b) {
124 static_assert(std::is_convertible_v<U, T>,
125 "In inner_product, type of second array (U) must be "
126 "convertable to that of dirst (T)");
127 constexpr std::size_t Size = std::min(N, M);
129 if constexpr (Size == 0) {
131 }
else if constexpr (!std::is_same_v<T, U> && is_complex_v<T>) {
134 T res = a[0] *
static_cast<typename T::value_type
>(b[0]);
135 for (std::size_t i = 1; i < Size; ++i) {
136 res += a[i] *
static_cast<typename T::value_type
>(b[i]);
140 T res = a[0] *
static_cast<T
>(b[0]);
141 for (std::size_t i = 1; i < Size; ++i) {
142 res += a[i] *
static_cast<T
>(b[i]);
167template <std::
size_t K>
170 std::array<long, K> bk;
182static constexpr auto ADAMS_data = std::tuple{
184 AdamsB<1>{2, {1}, 1},
185 AdamsB<2>{12, {-1, 8}, 5},
186 AdamsB<3>{24, {1, -5, 19}, 9},
187 AdamsB<4>{720, {-19, 106, -264, 646}, 251},
188 AdamsB<5>{1440, {27, -173, 482, -798, 1427}, 475},
189 AdamsB<6>{60480, {-863, 6312, -20211, 37504, -46461, 65112}, 19087},
191 120960, {1375, -11351, 41499, -88547, 123133, -121797, 139849}, 36799},
194 {-33953, 312874, -1291214, 3146338, -5033120, 5595358, -4604594, 4467094},
197 {57281, -583435, 2687864, -7394032, 13510082, -17283646, 16002320,
200 AdamsB<10>{479001600,
201 {-3250433, 36284876, -184776195, 567450984, -1170597042,
202 1710774528, -1823311566, 1446205080, -890175549, 656185652},
204 AdamsB<11>{958003200,
205 {5675265, -68928781, 384709327, -1305971115, 3007739418,
206 -4963166514, 6043521486, -5519460582, 3828828885, -2092490673,
209 AdamsB<12>{2615348736000,
210 {-13695779093, 179842822566, -1092096992268, 4063327863170,
211 -10344711794985, 19058185652796, -26204344465152, 27345870698436,
212 -21847538039895, 13465774256510, -6616420957428, 3917551216986},
221static constexpr std::size_t K_max =
222 std::tuple_size_v<
decltype(helper::ADAMS_data)> - 1;
241template <std::
size_t K,
typename = std::enable_if_t<(K > 0)>,
242 typename = std::enable_if_t<(K <= K_max)>>
247 static constexpr std::array<double, K> make_ak() {
248 const auto &am = std::get<K>(helper::ADAMS_data);
251 "Kth Entry in ADAMS_data must correspond to K-order AM method");
252 std::array<double, K> tak{};
253 for (std::size_t i = 0; i < K; ++i) {
254 tak.at(i) = double(am.bk.at(i)) / double(am.denom);
260 static constexpr double make_aK() {
261 const auto &am = std::get<K>(helper::ADAMS_data);
262 return (
double(am.bK) /
double(am.denom));
267 static constexpr std::array<double, K>
ak{make_ak()};
269 static constexpr double aK{make_aK()};
434template <std::
size_t K,
typename T =
double,
typename Y =
double>
436 static_assert(K > 0,
"Order (K) for Adams method must be K>0");
437 static_assert(K <= K_max,
438 "Order (K) requested for Adams method too "
439 "large. Adams coefficients are implemented up to K_max-1 only");
441 is_complex_v<Y> || std::is_floating_point_v<Y>,
442 "Template parameter Y (function values and dt) must be floating point "
444 static_assert(is_complex_v<Y> || std::is_floating_point_v<Y> ||
445 std::is_integral_v<T>,
446 "Template parameter T (derivative matrix argument) must be "
447 "floating point, complex, or integral");
466 std::array<Y, K>
f{}, g{};
469 std::array<Y, K>
df{}, dg{};
472 std::array<T, K>
t{};
487 assert(
dt != Y{0.0} &&
"Cannot have zero step-size in ODESolver2D");
488 assert(D !=
nullptr &&
"Cannot have null Derivative Matrix in ODESolver2D");
492 constexpr std::size_t
K_steps()
const {
return K; }
501 Y
dt() {
return m_dt; }
504 Y
dfdt(Y ft, Y gt, T tt)
const {
505 return m_D->
a(tt) * ft + m_D->b(tt) * gt + S_scale * m_D->
Sf(tt);
508 Y
dgdt(Y ft, Y gt, T tt)
const {
509 return m_D->c(tt) * ft + m_D->d(tt) * gt + S_scale * m_D->Sg(tt);
532 am.aK * S_scale * m_D->
Sf(t_next));
533 const auto sg = g.back() + m_dt * (
inner_product(dg, am.ak) +
534 am.aK * S_scale * m_D->Sg(t_next));
536 const auto a = m_D->
a(t_next);
537 const auto b = m_D->b(t_next);
538 const auto c = m_D->c(t_next);
539 const auto d = m_D->d(t_next);
541 const auto a0 = m_dt *
static_cast<Y
>(am.aK);
542 const auto a02 = a0 * a0;
544 Y{1.0} / (Y{1.0} - (a02 * (b * c - a * d) + a0 * (a + d)));
545 const auto fi = (sf - a0 * (d * sf - b * sg)) * det_inv;
546 const auto gi = (sg - a0 * (-c * sf + a * sg)) * det_inv;
550 std::rotate(
f.begin(),
f.begin() + 1,
f.end());
551 std::rotate(g.begin(), g.begin() + 1, g.end());
552 std::rotate(
df.begin(),
df.begin() + 1,
df.end());
553 std::rotate(dg.begin(), dg.begin() + 1, dg.end());
554 std::rotate(
t.begin(),
t.begin() + 1,
t.end());
560 df.back() =
dfdt(fi, gi, t_next);
561 dg.back() =
dgdt(fi, gi, t_next);
584 df.at(0) =
dfdt(f0, g0, t0);
585 dg.at(0) =
dgdt(f0, g0, t0);
586 first_k_i<1>(next_t(t0));
594 if constexpr (std::is_integral_v<T> && is_complex_v<Y>) {
596 }
else if constexpr (std::is_integral_v<T>) {
604 template <std::
size_t ik>
605 void first_k_i(T t_next) {
606 if constexpr (ik >= K) {
610 constexpr AM_Coefs<ik> ai{};
613 am.aK * S_scale * m_D->
Sf(t_next));
614 const auto sg = g.at(ik - 1) + m_dt * (
inner_product(dg, ai.ak) +
615 am.aK * S_scale * m_D->Sg(t_next));
616 const auto a0 = m_dt *
static_cast<Y
>(ai.aK);
617 const auto a02 = a0 * a0;
618 const auto a = m_D->
a(t_next);
619 const auto b = m_D->b(t_next);
620 const auto c = m_D->c(t_next);
621 const auto d = m_D->d(t_next);
623 Y{1.0} / (Y{1.0} - (a02 * (b *
c - a * d) + a0 * (a + d)));
624 const auto fi = (sf - a0 * (d * sf - b * sg)) * det_inv;
625 const auto gi = (sg - a0 * (-
c * sf + a * sg)) * det_inv;
630 df.at(ik) =
dfdt(fi, gi, t_next);
631 dg.at(ik) =
dgdt(fi, gi, t_next);
633 first_k_i<ik + 1>(next_t(t_next));
Solves a 2D system of ODEs using a K-step Adams-Moulton method.
Definition AdamsMoulton.hpp:435
T last_t()
Returns most recent t value; last_f() := f(last_t())
Definition AdamsMoulton.hpp:499
Y last_g()
Returns most recent g value. Can also access g array directly.
Definition AdamsMoulton.hpp:497
std::array< T, K > t
Array to store the previous K values of t: f.at(i) = f(t.at(i))
Definition AdamsMoulton.hpp:472
constexpr std::size_t K_steps() const
Returns the AM order (number of steps), K.
Definition AdamsMoulton.hpp:492
void drive(T t_next)
Drives the DE system to next value, F(t), assuming system has already been solved for the K previous ...
Definition AdamsMoulton.hpp:526
Y last_f()
Returns most recent f value. Can also access f array directly.
Definition AdamsMoulton.hpp:495
void solve_initial_K(T t0, Y f0, Y g0)
Automatically sets the first K values for F (and dF), given a single initial value for F,...
Definition AdamsMoulton.hpp:580
Y dgdt(Y ft, Y gt, T tt) const
Returns derivative, dg/dt(t), given f(t),g(t),t.
Definition AdamsMoulton.hpp:508
Y dfdt(Y ft, Y gt, T tt) const
Returns derivative, df/dt(t), given f(t),g(t),t.
Definition AdamsMoulton.hpp:504
void drive()
Overload of drive(T t) for 'default' case, where next t is defined as last_t + dt (for arithmetic/com...
Definition AdamsMoulton.hpp:567
ODESolver2D(Y dt, const DerivativeMatrix< T, Y > *D)
Construct the solver. dt is the (constant) step size.
Definition AdamsMoulton.hpp:486
std::array< Y, K > df
Arrays to store the previous K values of derivatives, df and dg.
Definition AdamsMoulton.hpp:469
std::array< Y, K > f
Arrays to store the previous K values of f and g.
Definition AdamsMoulton.hpp:466
Y dt()
Returns the step size.
Definition AdamsMoulton.hpp:501
Contains classes and functions which use general N-step Adams Moulton method to solve systems of 2x2 ...
Definition AdamsMoulton.hpp:11
constexpr bool is_complex_v
User-defined type-trait: Checks whether T is a std::complex type.
Definition AdamsMoulton.hpp:109
constexpr T inner_product(const std::array< T, N > &a, const std::array< U, M > &b)
Inner product of two std::arrays.
Definition AdamsMoulton.hpp:122
constexpr double c
speed of light in a.u. (=1/alpha)
Definition PhysConst_constants.hpp:63
Holds the K+1 Adams-Moulton ak coefficients for the K-step AM method. Final one, aK,...
Definition AdamsMoulton.hpp:243
static constexpr std::array< double, K > ak
First K coefficients: ak for k={0,1,...,K-1}.
Definition AdamsMoulton.hpp:267
static constexpr double aK
Final aK coefficients: ak for k=K.
Definition AdamsMoulton.hpp:269
Pure-virtual struct, holds the derivative matrix for 2x2 system of ODEs. Derive from this,...
Definition AdamsMoulton.hpp:79
virtual Y a(T t) const =0
a,b,c,d are derivative matrix functions; all must be user implemented
virtual Y Sf(T) const
Sf and Sg are optional inhomogenous terms.
Definition AdamsMoulton.hpp:86