Janus 2.0.0
High-performance C++20 dual-mode numerical framework
Loading...
Searching...
No Matches
IntegratorStep.hpp
Go to the documentation of this file.
1#pragma once
13
16#include <Eigen/Dense>
17
18namespace janus {
19
28template <typename Scalar> struct SecondOrderStepResult {
31};
32
33// ============================================================================
34// Forward Euler (1st order)
35// ============================================================================
36
61template <typename Scalar, typename Func>
62JanusVector<Scalar> euler_step(Func &&f, const JanusVector<Scalar> &x, Scalar t, Scalar dt) {
63 JanusVector<Scalar> k1 = f(t, x);
64 return (x + dt * k1).eval();
65}
66
67// ============================================================================
68// Heun's Method / RK2 (2nd order)
69// ============================================================================
70
87template <typename Scalar, typename Func>
88JanusVector<Scalar> rk2_step(Func &&f, const JanusVector<Scalar> &x, Scalar t, Scalar dt) {
89 JanusVector<Scalar> k1 = f(t, x);
90 JanusVector<Scalar> x1 = (x + dt * k1).eval();
91 JanusVector<Scalar> k2 = f(t + dt, x1);
92 return (x + (dt / 2.0) * (k1 + k2)).eval();
93}
94
95// ============================================================================
96// Classic Runge-Kutta (4th order)
97// ============================================================================
98
130template <typename Scalar, typename Func>
131JanusVector<Scalar> rk4_step(Func &&f, const JanusVector<Scalar> &x, Scalar t, Scalar dt) {
132 JanusVector<Scalar> k1 = f(t, x);
133 JanusVector<Scalar> x1 = (x + dt * 0.5 * k1).eval();
134 JanusVector<Scalar> k2 = f(t + dt * 0.5, x1);
135 JanusVector<Scalar> x2 = (x + dt * 0.5 * k2).eval();
136 JanusVector<Scalar> k3 = f(t + dt * 0.5, x2);
137 JanusVector<Scalar> x3 = (x + dt * k3).eval();
138 JanusVector<Scalar> k4 = f(t + dt, x3);
139
140 return (x + (dt / 6.0) * (k1 + 2.0 * k2 + 2.0 * k3 + k4)).eval();
141}
142
143// ============================================================================
144// Structure-preserving second-order integrators
145// ============================================================================
146
165template <typename Scalar, typename AccelFunc>
166SecondOrderStepResult<Scalar>
167stormer_verlet_step(AccelFunc &&acceleration, const JanusVector<Scalar> &q,
168 const JanusVector<Scalar> &v, Scalar t, Scalar dt) {
169 JanusVector<Scalar> a0 = acceleration(t, q);
170 JanusVector<Scalar> v_half = (v + 0.5 * dt * a0).eval();
171 JanusVector<Scalar> q_next = (q + dt * v_half).eval();
172 JanusVector<Scalar> a1 = acceleration(t + dt, q_next);
173 JanusVector<Scalar> v_next = (v_half + 0.5 * dt * a1).eval();
174 return SecondOrderStepResult<Scalar>{q_next, v_next};
175}
176
192template <typename Scalar, typename AccelFunc>
194 const JanusVector<Scalar> &v, Scalar t, Scalar dt) {
195 JanusVector<Scalar> k1 = acceleration(t, q);
196
197 JanusVector<Scalar> q2 = (q + 0.5 * dt * v + (dt * dt / 8.0) * k1).eval();
198 JanusVector<Scalar> k2 = acceleration(t + 0.5 * dt, q2);
199
200 JanusVector<Scalar> q3 = (q + 0.5 * dt * v + (dt * dt / 8.0) * k2).eval();
201 JanusVector<Scalar> k3 = acceleration(t + 0.5 * dt, q3);
202
203 JanusVector<Scalar> q4 = (q + dt * v + (dt * dt / 2.0) * k3).eval();
204 JanusVector<Scalar> k4 = acceleration(t + dt, q4);
205
206 JanusVector<Scalar> q_next = (q + dt * v + (dt * dt / 6.0) * (k1 + k2 + k3)).eval();
207 JanusVector<Scalar> v_next = (v + (dt / 6.0) * (k1 + 2.0 * k2 + 2.0 * k3 + k4)).eval();
208 return SecondOrderStepResult<Scalar>{q_next, v_next};
209}
210
211// ============================================================================
212// Dormand-Prince RK45 (Adaptive step with error estimate)
213// ============================================================================
214
220template <typename Scalar> struct RK45Result {
223
226
228 Scalar error;
229};
230
249template <typename Scalar, typename Func>
250RK45Result<Scalar> rk45_step(Func &&f, const JanusVector<Scalar> &x, Scalar t, Scalar dt) {
251 // Dormand-Prince coefficients
252 // a (time) coefficients
253 constexpr double a2 = 1.0 / 5.0;
254 constexpr double a3 = 3.0 / 10.0;
255 constexpr double a4 = 4.0 / 5.0;
256 constexpr double a5 = 8.0 / 9.0;
257 // a6 = 1.0, a7 = 1.0
258
259 // b (state) coefficients - rows of Butcher tableau
260 constexpr double b21 = 1.0 / 5.0;
261
262 constexpr double b31 = 3.0 / 40.0;
263 constexpr double b32 = 9.0 / 40.0;
264
265 constexpr double b41 = 44.0 / 45.0;
266 constexpr double b42 = -56.0 / 15.0;
267 constexpr double b43 = 32.0 / 9.0;
268
269 constexpr double b51 = 19372.0 / 6561.0;
270 constexpr double b52 = -25360.0 / 2187.0;
271 constexpr double b53 = 64448.0 / 6561.0;
272 constexpr double b54 = -212.0 / 729.0;
273
274 constexpr double b61 = 9017.0 / 3168.0;
275 constexpr double b62 = -355.0 / 33.0;
276 constexpr double b63 = 46732.0 / 5247.0;
277 constexpr double b64 = 49.0 / 176.0;
278 constexpr double b65 = -5103.0 / 18656.0;
279
280 constexpr double b71 = 35.0 / 384.0;
281 // b72 = 0
282 constexpr double b73 = 500.0 / 1113.0;
283 constexpr double b74 = 125.0 / 192.0;
284 constexpr double b75 = -2187.0 / 6784.0;
285 constexpr double b76 = 11.0 / 84.0;
286
287 // 5th order weights (for y5)
288 constexpr double c1 = 35.0 / 384.0;
289 // c2 = 0
290 constexpr double c3 = 500.0 / 1113.0;
291 constexpr double c4 = 125.0 / 192.0;
292 constexpr double c5 = -2187.0 / 6784.0;
293 constexpr double c6 = 11.0 / 84.0;
294 // c7 = 0
295
296 // 4th order weights (for y4, error estimation)
297 constexpr double d1 = 5179.0 / 57600.0;
298 // d2 = 0
299 constexpr double d3 = 7571.0 / 16695.0;
300 constexpr double d4 = 393.0 / 640.0;
301 constexpr double d5 = -92097.0 / 339200.0;
302 constexpr double d6 = 187.0 / 2100.0;
303 constexpr double d7 = 1.0 / 40.0;
304
305 // Compute stages (explicitly evaluate intermediate states)
306 JanusVector<Scalar> k1 = f(t, x);
307 JanusVector<Scalar> x2 = (x + dt * b21 * k1).eval();
308 JanusVector<Scalar> k2 = f(t + dt * a2, x2);
309 JanusVector<Scalar> x3 = (x + dt * (b31 * k1 + b32 * k2)).eval();
310 JanusVector<Scalar> k3 = f(t + dt * a3, x3);
311 JanusVector<Scalar> x4 = (x + dt * (b41 * k1 + b42 * k2 + b43 * k3)).eval();
312 JanusVector<Scalar> k4 = f(t + dt * a4, x4);
313 JanusVector<Scalar> x5 = (x + dt * (b51 * k1 + b52 * k2 + b53 * k3 + b54 * k4)).eval();
314 JanusVector<Scalar> k5 = f(t + dt * a5, x5);
316 (x + dt * (b61 * k1 + b62 * k2 + b63 * k3 + b64 * k4 + b65 * k5)).eval();
317 JanusVector<Scalar> k6 = f(t + dt, x6);
319 (x + dt * (b71 * k1 + b73 * k3 + b74 * k4 + b75 * k5 + b76 * k6)).eval();
320 JanusVector<Scalar> k7 = f(t + dt, x7);
321
322 // 5th order solution
323 JanusVector<Scalar> y5 = (x + dt * (c1 * k1 + c3 * k3 + c4 * k4 + c5 * k5 + c6 * k6)).eval();
324
325 // 4th order solution
327 (x + dt * (d1 * k1 + d3 * k3 + d4 * k4 + d5 * k5 + d6 * k6 + d7 * k7)).eval();
328
329 // Error estimate (norm of difference)
330 JanusVector<Scalar> diff = (y5 - y4).eval();
331 Scalar error = diff.norm();
332
333 return RK45Result<Scalar>{y5, y4, error};
334}
335
336} // namespace janus
C++20 concepts constraining valid Janus scalar types.
Core type aliases for numeric and symbolic Eigen/CasADi interop.
Definition Diagnostics.hpp:19
JanusVector< Scalar > rk4_step(Func &&f, const JanusVector< Scalar > &x, Scalar t, Scalar dt)
Classic 4th-order Runge-Kutta integration step.
Definition IntegratorStep.hpp:131
JanusVector< Scalar > rk2_step(Func &&f, const JanusVector< Scalar > &x, Scalar t, Scalar dt)
Heun's method (RK2) integration step.
Definition IntegratorStep.hpp:88
SecondOrderStepResult< Scalar > rkn4_step(AccelFunc &&acceleration, const JanusVector< Scalar > &q, const JanusVector< Scalar > &v, Scalar t, Scalar dt)
Classical 4th-order Runge-Kutta-Nystrom step for q'' = a(t, q).
Definition IntegratorStep.hpp:193
auto diff(const Eigen::MatrixBase< Derived > &v)
Computes adjacent differences of a vector Returns a vector of size N-1 where out[i] = v[i+1] - v[i].
Definition Calculus.hpp:27
auto eval(const Eigen::MatrixBase< Derived > &mat)
Evaluate a symbolic matrix to a numeric Eigen matrix.
Definition JanusIO.hpp:62
RK45Result< Scalar > rk45_step(Func &&f, const JanusVector< Scalar > &x, Scalar t, Scalar dt)
Dormand-Prince RK45 integration step with embedded error estimate.
Definition IntegratorStep.hpp:250
SecondOrderStepResult< Scalar > stormer_verlet_step(AccelFunc &&acceleration, const JanusVector< Scalar > &q, const JanusVector< Scalar > &v, Scalar t, Scalar dt)
Stormer-Verlet / velocity-Verlet step for q'' = a(t, q).
Definition IntegratorStep.hpp:167
JanusVector< Scalar > euler_step(Func &&f, const JanusVector< Scalar > &x, Scalar t, Scalar dt)
Forward Euler integration step.
Definition IntegratorStep.hpp:62
Eigen::Matrix< Scalar, Eigen::Dynamic, 1 > JanusVector
Dynamic-size column vector for both numeric and symbolic backends.
Definition JanusTypes.hpp:49
Result of RK45 step with error estimate.
Definition IntegratorStep.hpp:220
Scalar error
Estimated local truncation error: ||y5 - y4||.
Definition IntegratorStep.hpp:228
JanusVector< Scalar > y4
4th-order solution (used for error estimation)
Definition IntegratorStep.hpp:225
JanusVector< Scalar > y5
5th-order solution (recommended for propagation)
Definition IntegratorStep.hpp:222
Result of a second-order integration step.
Definition IntegratorStep.hpp:28
JanusVector< Scalar > q
Definition IntegratorStep.hpp:29
JanusVector< Scalar > v
Definition IntegratorStep.hpp:30