diff --git a/mini-odeint/mini-odeint.cpp b/mini-odeint/mini-odeint.cpp index 16c5742..8115d4a 100644 --- a/mini-odeint/mini-odeint.cpp +++ b/mini-odeint/mini-odeint.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include namespace mini_odeint { @@ -63,96 +64,47 @@ template struct DormandPrince { 90730570.0 / 29380423.0, -8293050.0 / 29380423.0}}}; }; -template struct OdeVector { +template struct Vec3 { using value_type = E; - E value; + E x, y, z; - constexpr OdeVector() = default; - constexpr explicit OdeVector(E value) : value(std::move(value)) {} + constexpr Vec3() = default; + constexpr Vec3(E x, E y, E z) : x(x), y(y), z(z) {} - constexpr operator E() const { return value; } + constexpr explicit Vec3(std::array v) : x(v[0]), y(v[1]), z(v[2]) {} - friend constexpr OdeVector operator+(const OdeVector &lhs, - const OdeVector &rhs) { - return OdeVector{lhs.value + rhs.value}; + friend constexpr Vec3 operator+(const Vec3 &lhs, const Vec3 &rhs) { + return Vec3{lhs.x + rhs.x, lhs.y + rhs.y, lhs.z + rhs.z}; } - friend constexpr OdeVector operator*(const OdeVector &lhs, - const value_type &rhs) { - return OdeVector{lhs.value * rhs}; + friend constexpr Vec3 operator*(const Vec3 &lhs, const value_type &rhs) { + return Vec3{lhs.x * rhs, lhs.y * rhs, lhs.z * rhs}; } - friend constexpr OdeVector operator*(const value_type &lhs, - const OdeVector &rhs) { - return OdeVector{lhs * rhs.value}; + friend constexpr Vec3 operator*(const value_type &lhs, const Vec3 &rhs) { + return Vec3{lhs * rhs.x, lhs * rhs.y, lhs * rhs.z}; } - constexpr OdeVector &operator+=(const OdeVector &rhs) { - value += rhs.value; + constexpr Vec3 &operator+=(const Vec3 &rhs) { + x += rhs.x; + y += rhs.y; + z += rhs.z; return *this; } - constexpr OdeVector &operator+=(const value_type &rhs) { - value += rhs; - return *this; - } - value_type inf_norm() const { return std::abs(value); } }; -template struct OdeVector> { - using array_type = std::array; - using value_type = T; - std::array value; +namespace alg { +template inline auto inf_norm(const T &v) { + std::ranges::max_element(v, {}, [](auto n) { return std::abs(n); }); +} - constexpr OdeVector() = default; - constexpr explicit OdeVector(std::array value) - : value(std::move(value)) {} +inline float inf_norm(float v) { return std::abs(v); } - operator std::array() const { return value; } +inline double inf_norm(double v) { return std::abs(v); } - friend constexpr OdeVector operator+(const OdeVector &lhs, - const OdeVector &rhs) { - OdeVector result{lhs}; - for (std::size_t i = 0; i < N; ++i) { - result.value[i] += rhs.value[i]; - } - return result; - } - friend constexpr OdeVector operator*(const OdeVector &lhs, - const value_type &rhs) { - OdeVector result{lhs}; - for (std::size_t i = 0; i < N; ++i) { - result.value[i] *= rhs; - } - return result; - } - friend constexpr OdeVector operator*(const value_type &lhs, - const OdeVector &rhs) { - OdeVector result{rhs}; - for (std::size_t i = 0; i < N; ++i) { - result.value[i] *= lhs; - } - return result; - } - constexpr OdeVector &operator+=(const OdeVector &rhs) { - for (std::size_t i = 0; i < N; ++i) { - value[i] += rhs.value[i]; - } - return *this; - } +template inline E inf_norm(const Vec3 &v) { + return std::max({std::abs(v.x), std::abs(v.y), std::abs(v.z)}); +} - constexpr OdeVector &operator+=(const value_type &rhs) { - for (std::size_t i = 0; i < N; ++i) { - value[i] += rhs; - } - return *this; - } - - value_type inf_norm() const { - auto max = std::abs(value[0]); - for (std::size_t i = 1; i < N; ++i) { - max = std::max(max, std::abs(value[i])); - } - return max; - } -}; +} // namespace alg template , typename Tableau = DormandPrince> @@ -202,7 +154,7 @@ inline std::size_t explicitRungeKutta(std::span ys, const auto last_k_store = k[stages - 1]; k[0] = k[stages - 1]; for (std::size_t i = 1; i < stages; ++i) { - OdeVector sum_ak{}; + Vector sum_ak{}; for (std::size_t j = 0; j < i; ++j) { sum_ak += a[i][j] * k[j]; } @@ -210,8 +162,8 @@ inline std::size_t explicitRungeKutta(std::span ys, } // calculate final value and error - OdeVector error{}; - OdeVector sum_bk{}; + Vector error{}; + Vector sum_bk{}; for (std::size_t i = 0; i < stages; ++i) { sum_bk += b_hat[i] * k[i]; error += (b_hat[i] - b[i]) * k[i]; @@ -219,13 +171,13 @@ inline std::size_t explicitRungeKutta(std::span ys, const auto y_hat_np1 = y_hat_n + h_n * sum_bk; // check if step is successful, ie error is within tolerance - const auto E_hp1 = (h_n * error).inf_norm(); + const auto E_hp1 = alg::inf_norm(h_n * error); if (E_hp1 < tol) { // if moved over any requested times then interpolate their values const auto t_np1 = t_n + h_n; while (it < N && t_np1 >= ts[it]) { const auto sigma = (ts[it] - t_n) / h_n; - OdeVector Phi{}; + Vector Phi{}; for (std::size_t i = 0; i < stages; ++i) { auto term = sigma; auto b_i = term * p[i][0]; @@ -266,22 +218,21 @@ inline std::size_t explicitRungeKutta(std::span ys, int main() { using namespace mini_odeint; - // make vector of doubles from 0.0 to 1.0 by 0.001 + // make vector of floats from 0.0 to 1.0 by 0.001 std::vector times; times.reserve(1001); for (int i = 0; i < 1000; ++i) { times.push_back(i / 1000.0); } - std::vector> ys(times.size()); + std::vector> ys(times.size()); explicitRungeKutta( - std::span(ys), std::span(times), - std::array{1.0, 2.0}, float(1e-6), - [](auto y, auto t) { return std::array{-y[0], -y[1]}; }); + std::span(ys), std::span(times), Vec3{1.0, 1.0, 1.0}, + float(1e-6), [](auto y, auto t) { return Vec3{-y.x, 0.0, 0.0}; }); for (const auto &v : ys) { - std::cout << v[0] << v[1] << '\n'; + std::cout << v.x << '\n'; } }