23#include <unsupported/Eigen/MatrixFunctions>
36#if defined(__GNUC__) && !defined(__clang__)
37 #pragma GCC diagnostic push
38 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
49template<
typename Y,
typename Z, std::
floating_po
int Scalar,
size_t s, std::array<std::array<Scalar, s + 1>, s + 1> butcherTableau>
50inline Y
RungeKuttaExplicit(
const Y& y_n,
const std::array<Z, s>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n)
52 static_assert(gcem::abs(
static_cast<Scalar
>(1.0) - std::accumulate(butcherTableau[s].begin(), butcherTableau[s].end(),
static_cast<Scalar
>(0.0))) < 1e-8,
53 "The sum of the last row in the Butcher tableau has to be 1");
54 for (
size_t r = 0; r <= s; ++r)
56 for (
size_t c = r + 1; c <= s; ++c)
58 INS_ASSERT_USER_ERROR(butcherTableau.at(r).at(c) == 0.0,
"All terms in the upper triangle have to be 0");
68 for (
size_t i = 1; i <= s; ++i)
70 auto b = butcherTableau[s].at(i);
71 auto c = butcherTableau.at(i - 1)[0];
75 for (
size_t j = 2; j <= i; ++j)
77 auto a = butcherTableau.at(i - 1).at(j - 1);
78 if (j == 2) { sum_a = a * k.at(j - 2); }
79 else { sum_a += a * k.at(j - 2); }
88 if (i < 2) { k.at(i - 1) = f(y_n, z.at(i - 1), constParam, t_n + c * h); }
89 else { k.at(i - 1) = f(y_n + sum_a * h, z.at(i - 1), constParam, t_n + c * h); }
95 if (i == 1) { sum_b = b * k.at(i - 1); }
96 else { sum_b += b * k.at(i - 1); }
108 return y_n + h * sum_b;
119template<
typename Derived,
typename Z, std::
floating_po
int Scalar,
size_t s, std::array<std::array<Scalar, s + 1>, s + 1> butcherTableau>
120inline typename Derived::PlainObject
RungeKuttaExplicitQuat(
const Eigen::MatrixBase<Derived>& y_n,
const std::array<Z, s>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n)
122 static_assert(gcem::abs(
static_cast<Scalar
>(1.0) - std::accumulate(butcherTableau[s].begin(), butcherTableau[s].end(),
static_cast<Scalar
>(0.0))) < 1e-8,
123 "The sum of the last row in the Butcher tableau has to be 1");
124 for (
size_t r = 0; r <= s; ++r)
126 for (
size_t c = r + 1; c <= s; ++c)
128 INS_ASSERT_USER_ERROR(butcherTableau.at(r).at(c) == 0.0,
"All terms in the upper triangle have to be 0");
133 using DerivativeVector =
decltype(f(y_n, z.front(), constParam, t_n));
134 Eigen::Index N = y_n.rows() - 4;
139 auto applyDerivative = [&]<
typename Derived2>(
const Eigen::MatrixBase<Derived2>& y_delta) {
140 Eigen::Vector<typename Derived::Scalar, Derived::RowsAtCompileTime> y_nh;
141 if constexpr (Derived::RowsAtCompileTime == Eigen::Dynamic) { y_nh = Eigen::Vector<typename Derived::Scalar, Derived::RowsAtCompileTime>::Zero(y_n.rows()); }
142 y_nh.head(N) = y_n.head(N) + y_delta.head(N);
144 Eigen::Map<Eigen::Quaternion<typename Derived::Scalar>>(y_nh.template tail<4>().data()) =
145 Eigen::Map<
const Eigen::Quaternion<typename Derived::Scalar>>(y_n.template tail<4>().data())
155 DerivativeVector sum_b{};
156 std::array<DerivativeVector, s> k{};
157 for (
size_t i = 1; i <= s; ++i)
159 auto b = butcherTableau[s].at(i);
160 auto c = butcherTableau.at(i - 1)[0];
161 DerivativeVector sum_a{};
164 for (
size_t j = 2; j <= i; ++j)
166 auto a = butcherTableau.at(i - 1).at(j - 1);
167 if (j == 2) { sum_a = a * k.at(j - 2); }
168 else { sum_a += a * k.at(j - 2); }
177 if (i < 2) { k.at(i - 1) = f(y_n, z.at(i - 1), constParam, t_n + c * h); }
178 else { k.at(i - 1) = f(applyDerivative(sum_a * h), z.at(i - 1), constParam, t_n + c * h); }
184 if (i == 1) { sum_b = b * k.at(i - 1); }
185 else { sum_b += b * k.at(i - 1); }
197 return applyDerivative(h * sum_b);
200#if defined(__GNUC__) && !defined(__clang__)
201 #pragma GCC diagnostic pop
205template<
typename Scalar>
206constexpr std::array<std::array<Scalar, 2>, 2>
RK1 = { { { 0.0, },
211template<
typename Scalar>
212constexpr std::array<std::array<Scalar, 3>, 3>
RK2 = { { { 0.0, },
215 { 0.0, 0.0, 1.0 } } };
218template<
typename Scalar>
219constexpr std::array<std::array<Scalar, 3>, 3>
Heun2 = { { { 0.0, },
222 { 0.0, 0.5, 0.5 } } };
225template<
typename Scalar>
226constexpr std::array<std::array<Scalar, 4>, 4>
RK3 = { { { 0.0, },
230 { 0.0, 1.0 / 6.0, 4.0 / 6.0, 1.0 / 6.0 } } };
233template<
typename Scalar>
234constexpr std::array<std::array<Scalar, 4>, 4>
Heun3 = { { { 0.0, },
235 { 1.0 / 3.0, 1.0 / 3.0 },
236 { 2.0 / 3.0, 0.0, 2.0 / 3.0 },
238 { 0.0, 1.0 / 4.0, 0.0, 3.0 / 4.0 } } };
241template<
typename Scalar>
242constexpr std::array<std::array<Scalar, 5>, 5>
RK4 = { { { 0.0, },
245 { 1.0, 0.0, 0.0, 1.0 },
247 { 0.0, 1.0 / 6.0, 1.0 / 3.0, 1.0 / 3.0, 1.0 / 6.0 } } };
269template<
typename Y,
typename Z, std::
floating_po
int Scalar>
270Y
RungeKutta1(
const Y& y_n,
const std::array<Z, 1>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
282template<
typename Y,
typename Z, std::
floating_po
int Scalar>
283Y
RungeKutta1Quat(
const Y& y_n,
const std::array<Z, 1>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
311template<
typename Y,
typename Z, std::
floating_po
int Scalar>
312Y
RungeKutta2(
const Y& y_n,
const std::array<Z, 2>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
324template<
typename Y,
typename Z, std::
floating_po
int Scalar>
325Y
RungeKutta2Quat(
const Y& y_n,
const std::array<Z, 2>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
353template<
typename Y,
typename Z, std::
floating_po
int Scalar>
354Y
Heun2(
const Y& y_n,
const std::array<Z, 2>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
366template<
typename Y,
typename Z, std::
floating_po
int Scalar>
367Y
Heun2Quat(
const Y& y_n,
const std::array<Z, 2>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
397template<
typename Y,
typename Z, std::
floating_po
int Scalar>
398Y
RungeKutta3(
const Y& y_n,
const std::array<Z, 3>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
410template<
typename Y,
typename Z, std::
floating_po
int Scalar>
411Y
RungeKutta3Quat(
const Y& y_n,
const std::array<Z, 3>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
441template<
typename Y,
typename Z, std::
floating_po
int Scalar>
442Y
Heun3(
const Y& y_n,
const std::array<Z, 3>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
454template<
typename Y,
typename Z, std::
floating_po
int Scalar>
455Y
Heun3Quat(
const Y& y_n,
const std::array<Z, 3>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
487template<
typename Y,
typename Z, std::
floating_po
int Scalar>
488Y
RungeKutta4(
const Y& y_n,
const std::array<Z, 4>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
500template<
typename Y,
typename Z, std::
floating_po
int Scalar>
501Y
RungeKutta4Quat(
const Y& y_n,
const std::array<Z, 4>& z,
const Scalar& h,
const auto& f,
const auto& constParam,
const Scalar& t_n = 0)
#define INS_ASSERT_USER_ERROR(_EXP, _MSG)
Assert function with message.
Utility class for logging to console and file.
Derived::PlainObject RungeKuttaExplicitQuat(const Eigen::MatrixBase< Derived > &y_n, const std::array< Z, s > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n)
Calculates explicit Runge-Kutta methods. Order is defined by the Butcher tableau.
constexpr std::array< std::array< Scalar, 5 >, 5 > RK4
Butcher tableau for Runge-Kutta 4th order (explicit)
Y RungeKuttaExplicit(const Y &y_n, const std::array< Z, s > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n)
Calculates explicit Runge-Kutta methods. Order is defined by the Butcher tableau.
constexpr std::array< std::array< Scalar, 4 >, 4 > Heun3
Butcher tableau for Heun's method (3nd order) (explicit)
constexpr std::array< std::array< Scalar, 3 >, 3 > Heun2
Butcher tableau for Heun's method (2nd order) (explicit)
constexpr std::array< std::array< Scalar, 4 >, 4 > RK3
Butcher tableau for Runge-Kutta 3rd order (explicit) / Simpson's rule.
constexpr std::array< std::array< Scalar, 3 >, 3 > RK2
Butcher tableau for Runge-Kutta 2nd order (explicit) / Explicit midpoint method.
constexpr std::array< std::array< Scalar, 2 >, 2 > RK1
Butcher tableau for Runge-Kutta 1st order (explicit) / (Forward) Euler method.
Eigen::Quaternion< typename Derived::Scalar > expMapQuat(const Eigen::MatrixBase< Derived > &v)
Calculates the quaternionic exponential map of the given vector.
Y RungeKutta3(const Y &y_n, const std::array< Z, 3 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 3rd order (explicit) / Simpson's rule .
Y Heun3Quat(const Y &y_n, const std::array< Z, 3 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Heun's method (3nd order) (explicit) with Quaternion as last entry in state.
Y Heun3(const Y &y_n, const std::array< Z, 3 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Heun's method (3nd order) (explicit) .
Y RungeKutta1(const Y &y_n, const std::array< Z, 1 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 1st order (explicit) / (Forward) Euler method .
Y RungeKutta2Quat(const Y &y_n, const std::array< Z, 2 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 2nd order (explicit) / Explicit midpoint method with Quaternion as last entry in state.
Y RungeKutta4(const Y &y_n, const std::array< Z, 4 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 4th order (explicit) .
Y RungeKutta2(const Y &y_n, const std::array< Z, 2 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 2nd order (explicit) / Explicit midpoint method .
Y RungeKutta4Quat(const Y &y_n, const std::array< Z, 4 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 4th order (explicit) with Quaternion as last entry in state.
Y RungeKutta1Quat(const Y &y_n, const std::array< Z, 1 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 1st order (explicit) / (Forward) Euler method with Quaternion as last entry in state.
Y Heun2(const Y &y_n, const std::array< Z, 2 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Heun's method (2nd order) (explicit) .
Y Heun2Quat(const Y &y_n, const std::array< Z, 2 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Heun's method (2nd order) (explicit) with Quaternion as last entry in state.
Y RungeKutta3Quat(const Y &y_n, const std::array< Z, 3 > &z, const Scalar &h, const auto &f, const auto &constParam, const Scalar &t_n=0)
Runge-Kutta 3rd order (explicit) / Simpson's rule with Quaternion as last entry in state.