0.2.0
Loading...
Searching...
No Matches
NumericalIntegration.hpp
Go to the documentation of this file.
1// This file is part of INSTINCT, the INS Toolkit for Integrated
2// Navigation Concepts and Training by the Institute of Navigation of
3// the University of Stuttgart, Germany.
4//
5// This Source Code Form is subject to the terms of the Mozilla Public
6// License, v. 2.0. If a copy of the MPL was not distributed with this
7// file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
13
14#pragma once
15
16#include <array>
17#include <numeric>
18#include <type_traits>
19#include <gcem.hpp>
20
21#include "util/Assert.h"
22#include "util/Logger.hpp"
23
24namespace NAV
25{
26
27namespace ButcherTableau
28{
29
30#pragma GCC diagnostic push
31#if !defined(__clang__)
32 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // NOLINT(clang-diagnostic-unknown-warning-option)
33#endif
34
43template<typename Y, typename Z, typename Scalar, size_t s, std::array<std::array<Scalar, s + 1>, s + 1> butcherTableau,
44 typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
45inline 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)
46{
47 static_assert(gcem::abs(static_cast<Scalar>(1.0) - std::accumulate(butcherTableau[s].begin(), butcherTableau[s].end(), static_cast<Scalar>(0.0))) < 1e-8,
48 "The sum of the last row in the Butcher tableau has to be 1");
49 for (size_t r = 0; r <= s; ++r)
50 {
51 for (size_t c = r + 1; c <= s; ++c)
52 {
53 INS_ASSERT_USER_ERROR(butcherTableau.at(r).at(c) == 0.0, "All terms in the upper triangle have to be 0");
54 }
55 }
56
57 // std::string result = "y_(n+1) = y_n";
58
59 // std::string sum_b_str;
60 // std::string sum_b_val;
61 Y sum_b{};
62 std::array<Y, s> k{};
63 for (size_t i = 1; i <= s; ++i)
64 {
65 auto b = butcherTableau[s].at(i);
66 auto c = butcherTableau.at(i - 1)[0];
67 Y sum_a{};
68 // std::string sum_a_str;
69 // std::string sum_a_val;
70 for (size_t j = 2; j <= i; ++j)
71 {
72 auto a = butcherTableau.at(i - 1).at(j - 1);
73 if (j == 2) { sum_a = a * k.at(j - 2); }
74 else { sum_a += a * k.at(j - 2); }
75 // sum_a_str += fmt::format("a{}{} * k{}", i, j-1, j-1);
76 // sum_a_val += fmt::format("{:^3.1f} * k{}", a, j - 1);
77 // if (j < i) {
78 // sum_a_str += " + ";
79 // sum_a_val += " + ";
80 // }
81 }
82
83 if (i < 2) { k.at(i - 1) = f(y_n, z.at(i - 1), constParam, t_n + c * h); } // Do not add sum_a, because can have nan values
84 else { k.at(i - 1) = f(y_n + sum_a * h, z.at(i - 1), constParam, t_n + c * h); }
85 // if (sum_a_str.empty()) { sum_a_str = "0"; }
86 // if (sum_a_val.empty()) { sum_a_val = "0"; }
87 // fmt::println("k{} = f(t_n + c{} * h, y_n + ({}) * h)", i, i, sum_a_str);
88 // fmt::println("k{} = f(t_n + {:^3.1f} * h, y_n + ({:^{w}}) * h)", i, c, sum_a_val, fmt::arg("w",sum_a_str.length()));
89
90 if (i == 1) { sum_b = b * k.at(i - 1); }
91 else { sum_b += b * k.at(i - 1); }
92 // sum_b_str += fmt::format("b{} * k{}", i, i);
93 // sum_b_val += fmt::format("{:.2f} * k{}", butcherTableau[s].at(i), i);
94 // if (i < s)
95 // {
96 // sum_b_str += " + ";
97 // sum_b_val += " + ";
98 // }
99 }
100
101 // std::cout << result + fmt::format(" + h * ({})", sum_b_str) << std::endl;
102 // std::cout << result + fmt::format(" + h * ({})", sum_b_val) << std::endl;
103 return y_n + h * sum_b;
104}
105
106#pragma GCC diagnostic pop
107
109template<typename Scalar>
110constexpr std::array<std::array<Scalar, 2>, 2> RK1 = { { { 0.0, /*|*/ },
111 //------------------
112 { 0.0, /*|*/ 1.0 } } };
113
115template<typename Scalar>
116constexpr std::array<std::array<Scalar, 3>, 3> RK2 = { { { 0.0, /*|*/ },
117 { 0.5, /*|*/ 0.5 },
118 //-----------------------
119 { 0.0, /*|*/ 0.0, 1.0 } } };
120
122template<typename Scalar>
123constexpr std::array<std::array<Scalar, 3>, 3> Heun2 = { { { 0.0, /*|*/ },
124 { 1.0, /*|*/ 1.0 },
125 //-----------------------
126 { 0.0, /*|*/ 0.5, 0.5 } } };
127
129template<typename Scalar>
130constexpr std::array<std::array<Scalar, 4>, 4> RK3 = { { { 0.0, /*|*/ },
131 { 0.5, /*|*/ 0.5 },
132 { 1.0, /*|*/ -1.0, 2.0 },
133 //----------------------------------------------
134 { 0.0, /*|*/ 1.0 / 6.0, 4.0 / 6.0, 1.0 / 6.0 } } };
135
137template<typename Scalar>
138constexpr std::array<std::array<Scalar, 4>, 4> Heun3 = { { { 0.0, /* |*/ },
139 { 1.0 / 3.0, /*|*/ 1.0 / 3.0 },
140 { 2.0 / 3.0, /*|*/ 0.0, 2.0 / 3.0 },
141 //----------------------------------------
142 { 0.0, /*|*/ 1.0 / 4.0, 0.0, 3.0 / 4.0 } } };
143
145template<typename Scalar>
146constexpr std::array<std::array<Scalar, 5>, 5> RK4 = { { { 0.0, /*|*/ },
147 { 0.5, /*|*/ 0.5 },
148 { 0.5, /*|*/ 0.0, 0.5 },
149 { 1.0, /*|*/ 0.0, 0.0, 1.0 },
150 //------------------
151 { 0.0, /*|*/ 1.0 / 6.0, 1.0 / 3.0, 1.0 / 3.0, 1.0 / 6.0 } } };
152
153} // namespace ButcherTableau
154
173template<typename Y, typename Z, typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
174Y 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)
175{
176 return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 1, ButcherTableau::RK1<Scalar>>(y_n, z, h, f, constParam, t_n);
177}
178
202template<typename Y, typename Z, typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
203Y 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)
204{
205 return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 2, ButcherTableau::RK2<Scalar>>(y_n, z, h, f, constParam, t_n);
206}
207
231template<typename Y, typename Z, typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
232Y 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)
233{
234 return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 2, ButcherTableau::Heun2<Scalar>>(y_n, z, h, f, constParam, t_n);
235}
236
262template<typename Y, typename Z, typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
263Y 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)
264{
265 return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 3, ButcherTableau::RK3<Scalar>>(y_n, z, h, f, constParam, t_n);
266}
267
293template<typename Y, typename Z, typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
294Y 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)
295{
296 return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 3, ButcherTableau::Heun3<Scalar>>(y_n, z, h, f, constParam, t_n);
297}
298
326template<typename Y, typename Z, typename Scalar, typename = std::enable_if_t<std::is_floating_point_v<Scalar>>>
327Y 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)
328{
329 return ButcherTableau::RungeKuttaExplicit<Y, Z, Scalar, 4, ButcherTableau::RK4<Scalar>>(y_n, z, h, f, constParam, t_n);
330}
331
332} // namespace NAV
Assertion helpers.
#define INS_ASSERT_USER_ERROR(_EXP, _MSG)
Assert function with message.
Definition Assert.h:21
Utility class for logging to console and file.
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 .
Definition NumericalIntegration.hpp:263
constexpr std::array< std::array< Scalar, 5 >, 5 > RK4
Butcher tableau for Runge-Kutta 4th order (explicit)
Definition NumericalIntegration.hpp:146
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 .
Definition NumericalIntegration.hpp:174
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.
Definition NumericalIntegration.hpp:45
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) .
Definition NumericalIntegration.hpp:327
constexpr std::array< std::array< Scalar, 4 >, 4 > Heun3
Butcher tableau for Heun's method (3nd order) (explicit)
Definition NumericalIntegration.hpp:138
constexpr std::array< std::array< Scalar, 3 >, 3 > Heun2
Butcher tableau for Heun's method (2nd order) (explicit)
Definition NumericalIntegration.hpp:123
constexpr std::array< std::array< Scalar, 4 >, 4 > RK3
Butcher tableau for Runge-Kutta 3rd order (explicit) / Simpson's rule.
Definition NumericalIntegration.hpp:130
constexpr std::array< std::array< Scalar, 3 >, 3 > RK2
Butcher tableau for Runge-Kutta 2nd order (explicit) / Explicit midpoint method.
Definition NumericalIntegration.hpp:116
constexpr std::array< std::array< Scalar, 2 >, 2 > RK1
Butcher tableau for Runge-Kutta 1st order (explicit) / (Forward) Euler method.
Definition NumericalIntegration.hpp:110
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 .
Definition NumericalIntegration.hpp:203