/*
* Copyright (c) 2026 Jakub Górnikowski
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
*/
#include "kutta.hpp"
std::vector RK4_step(
std::function(std::vector)> f,
const std::vector& p,
const double dt
) {
const size_t N = p.size();
// p is the value of the vector at the previous step,
// q is the new value
const std::vector k1 = f(p);
std::vector p_midpoint(N, 0.0);
for (size_t i = 0; i < N; i++) {
p_midpoint[i] = p[i] + 0.5 * dt * k1[i];
}
const std::vector k2 = f(p_midpoint);
std::vector p_midpoint_refined(N, 0.0);
for (size_t i = 0; i < N; i++) {
p_midpoint_refined[i] = p[i] + 0.5 * dt * k2[i];
}
const std::vector k3 = f(p_midpoint_refined);
std::vector p_endpoint(N, 0.0);
for (size_t i = 0; i < N; i++) {
p_endpoint[i] = p[i] + dt * k3[i];
}
const std::vector k4 = f(p_endpoint);
// output
std::vector q(N, 0.0);
for (size_t i = 0; i < N; i++) {
q[i] = p[i] + (1.0 / 6.0) * dt * (
k1[i] + 2.0 * k2[i] + 2.0 * k3[i] + k4[i]
);
}
return q;
}
std::vector> RK4(
// function on the RHS of the runge kutta problem
std::function(std::vector)> f,
const std::vector& initial_condition,
const double dt,
const size_t steps
) {
// vector dimension (number of equations)
const size_t N = initial_condition.size();
std::vector> matrix(
steps, std::vector(N, 0.0)
);
// assign the first step to the 0-th row
for (size_t i = 0; i < N; i++) {
matrix[0][i] = initial_condition[i];
}
for (size_t i = 0; i < steps - 1; i++) {
matrix[i+1] = RK4_step(
f, matrix[i], dt
);
}
return matrix;
}