numerics 0.1.0
Loading...
Searching...
No Matches
ode.hpp
Go to the documentation of this file.
1/// @file ode/ode.hpp
2/// @brief ODE integrators: Euler, RK4, adaptive RK45 (Dormand-Prince), and
3/// symplectic Velocity Verlet / Yoshida-4 for Hamiltonian systems.
4///
5/// General ODE solvers advance \f$ \dot{y} = f(t,y) \f$:
6/// - ode_euler -- forward Euler, O(h)
7/// - ode_rk4 -- classic 4th-order Runge-Kutta, O(h^4)
8/// - ode_rk45 -- adaptive Dormand-Prince with PI step control, O(h^5)
9///
10/// Symplectic integrators for separable \f$ H(q,p) = T(p) + V(q) \f$:
11/// - ode_verlet -- velocity Verlet, 2nd-order symplectic, 1 force eval/step
12/// - ode_yoshida4 -- Yoshida (1990) 4th-order symplectic, 3 force evals/step
13/// - ode_rk4_2nd -- non-symplectic RK4 in Nystrom form, for comparison
14///
15/// Each integrator has a corresponding lazy-range factory (rk4, rk45, verlet,
16/// etc.). Iterate with a range-based for to observe intermediate states, or
17/// call .run() / use the ode_*() wrappers to obtain only the final result.
18///
19/// Parameters are passed via ODEParams using C++20 designated initializers:
20/// \code
21/// rk45(f, y0, {.tf = 50.0, .rtol = 1e-8, .atol = 1e-10})
22/// \endcode
23#pragma once
24
25#include "core/types.hpp"
26#include "core/vector.hpp"
27#include "ode/implicit.hpp"
28#include <functional>
29
30namespace num {
31
32using ODERhsFn = std::function<void(real t, const Vector& y, Vector& dydt)>;
33using AccelFn = std::function<void(const Vector& q, Vector& acc)>;
34using ObserverFn = std::function<void(real t, const Vector& y)>;
36 std::function<void(real t, const Vector& q, const Vector& v)>;
37
38struct Step {
39 real t = 0.0;
41};
42
44 real t = 0.0;
47};
48
49struct ODEResult {
51 real t = 0.0;
53 bool converged = false;
54};
55
62
63/// Parameters for all ODE integrators. Set only the fields you need.
64struct ODEParams {
65 real t0 = 0.0;
66 real tf = 1.0;
67 real h = 1e-3; ///< step size (fixed-step) or initial hint (adaptive)
68 real rtol = 1e-6; ///< relative tolerance (adaptive only)
69 real atol = 1e-9; ///< absolute tolerance (adaptive only)
70 idx max_steps = 1000000; ///< step cap (adaptive only)
71};
72
73struct StepEnd {};
74
76 ODERhsFn f_ = nullptr;
77 Vector y_, dydt_;
78 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
79 idx steps_ = 0;
80 bool done_ = false;
81
82 void advance();
83
84 public:
85 explicit EulerSteps(ODERhsFn f, Vector y0, ODEParams p);
86
87 struct iterator {
89 Step operator*() const {
90 return {owner_->t_, owner_->y_};
91 }
93 owner_->advance();
94 return *this;
95 }
96 bool operator!=(StepEnd) const {
97 return !owner_->done_;
98 }
99 bool operator==(StepEnd) const {
100 return owner_->done_;
101 }
102 };
103
105 advance();
106 return {this};
107 }
108 StepEnd end() const {
109 return {};
110 }
111 ODEResult run();
112};
113
114class RK4Steps {
115 ODERhsFn f_ = nullptr;
116 Vector y_, k1_, k2_, k3_, k4_, ytmp_;
117 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
118 idx steps_ = 0;
119 bool done_ = false;
120
121 void advance();
122
123 public:
124 explicit RK4Steps(ODERhsFn f, Vector y0, ODEParams p);
125
126 struct iterator {
128 Step operator*() const {
129 return {owner_->t_, owner_->y_};
130 }
132 owner_->advance();
133 return *this;
134 }
135 bool operator!=(StepEnd) const {
136 return !owner_->done_;
137 }
138 bool operator==(StepEnd) const {
139 return owner_->done_;
140 }
141 };
142
144 advance();
145 return {this};
146 }
147 StepEnd end() const {
148 return {};
149 }
150 ODEResult run();
151};
152
154 ODERhsFn f_ = nullptr;
155 Vector y_, k1_, k2_, k3_, k4_, k5_, k6_, k7_, ytmp_, err_;
156 real t_ = 0.0, t1_ = 0.0, h_ = 0.0, rtol_ = 0.0, atol_ = 0.0;
157 idx steps_ = 0, max_steps_ = 0;
158 bool done_ = false, converged_ = true;
159
160 void advance();
161
162 public:
163 explicit RK45Steps(ODERhsFn f, Vector y0, ODEParams p);
164
165 struct iterator {
167 Step operator*() const {
168 return {owner_->t_, owner_->y_};
169 }
171 owner_->advance();
172 return *this;
173 }
174 bool operator!=(StepEnd) const {
175 return !owner_->done_;
176 }
177 bool operator==(StepEnd) const {
178 return owner_->done_;
179 }
180 };
181
183 advance();
184 return {this};
185 }
186 StepEnd end() const {
187 return {};
188 }
189 ODEResult run();
190};
191
193 AccelFn accel_ = nullptr;
194 Vector q_, v_, a_cur_, a_next_;
195 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
196 idx steps_ = 0;
197 bool done_ = false;
198
199 void advance();
200
201 public:
202 explicit VerletSteps(AccelFn accel, Vector q0, Vector v0, ODEParams p);
203
204 struct iterator {
207 return {owner_->t_, owner_->q_, owner_->v_};
208 }
210 owner_->advance();
211 return *this;
212 }
213 bool operator!=(StepEnd) const {
214 return !owner_->done_;
215 }
216 bool operator==(StepEnd) const {
217 return owner_->done_;
218 }
219 };
220
222 advance();
223 return {this};
224 }
225 StepEnd end() const {
226 return {};
227 }
229};
230
232 AccelFn accel_ = nullptr;
233 Vector q_, v_, acc_;
234 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
235 idx steps_ = 0;
236 bool done_ = false;
237
238 void advance();
239
240 public:
241 explicit Yoshida4Steps(AccelFn accel, Vector q0, Vector v0, ODEParams p);
242
243 struct iterator {
246 return {owner_->t_, owner_->q_, owner_->v_};
247 }
249 owner_->advance();
250 return *this;
251 }
252 bool operator!=(StepEnd) const {
253 return !owner_->done_;
254 }
255 bool operator==(StepEnd) const {
256 return owner_->done_;
257 }
258 };
259
261 advance();
262 return {this};
263 }
264 StepEnd end() const {
265 return {};
266 }
268};
269
271 AccelFn accel_ = nullptr;
272 Vector q_, v_, a1_, a2_, a3_, a4_, qtmp_;
273 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
274 idx steps_ = 0;
275 bool done_ = false;
276
277 void advance();
278
279 public:
280 explicit RK4_2ndSteps(AccelFn accel, Vector q0, Vector v0, ODEParams p);
281
282 struct iterator {
285 return {owner_->t_, owner_->q_, owner_->v_};
286 }
288 owner_->advance();
289 return *this;
290 }
291 bool operator!=(StepEnd) const {
292 return !owner_->done_;
293 }
294 bool operator==(StepEnd) const {
295 return owner_->done_;
296 }
297 };
298
300 advance();
301 return {this};
302 }
303 StepEnd end() const {
304 return {};
305 }
307};
308
309// Lazy-range factories
310
311EulerSteps euler(ODERhsFn f, Vector y0, ODEParams p = {});
312RK4Steps rk4(ODERhsFn f, Vector y0, ODEParams p = {});
313RK45Steps rk45(ODERhsFn f, Vector y0, ODEParams p = {});
314
315VerletSteps verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p = {});
316Yoshida4Steps yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p = {});
317RK4_2ndSteps rk4_2nd(AccelFn accel, Vector q0, Vector v0, ODEParams p = {});
318
319// High-level integrators — return final state only
320
321/// @brief Forward Euler, 1st-order, fixed step.
322ODEResult ode_euler(ODERhsFn f,
323 Vector y0,
324 ODEParams p = {},
325 ObserverFn obs = nullptr);
326
327/// @brief Classic 4th-order Runge-Kutta, fixed step.
328ODEResult ode_rk4(ODERhsFn f,
329 Vector y0,
330 ODEParams p = {},
331 ObserverFn obs = nullptr);
332
333/// @brief Adaptive Dormand-Prince RK45 with FSAL and PI step-size control.
334ODEResult ode_rk45(ODERhsFn f,
335 Vector y0,
336 ODEParams p = {},
337 ObserverFn obs = nullptr);
338
339/// @brief Velocity Verlet, 2nd-order symplectic, 1 force evaluation per step.
340SymplecticResult ode_verlet(AccelFn accel,
341 Vector q0,
342 Vector v0,
343 ODEParams p = {},
344 SympObserverFn obs = nullptr);
345
346/// @brief Yoshida 4th-order symplectic, 3 force evaluations per step.
347SymplecticResult ode_yoshida4(AccelFn accel,
348 Vector q0,
349 Vector v0,
350 ODEParams p = {},
351 SympObserverFn obs = nullptr);
352
353/// @brief RK4 for second-order systems q'' = accel(q), Nystrom form.
354/// @note Not symplectic. Prefer ode_verlet or ode_yoshida4 for long Hamiltonian
355/// runs.
356SymplecticResult ode_rk4_2nd(AccelFn accel,
357 Vector q0,
358 Vector v0,
359 ODEParams p = {},
360 SympObserverFn obs = nullptr);
361
362} // namespace num
StepEnd end() const
Definition ode.hpp:108
ODEResult run()
Definition ode.cpp:31
iterator begin()
Definition ode.hpp:104
ODEResult run()
Definition ode.cpp:183
iterator begin()
Definition ode.hpp:182
StepEnd end() const
Definition ode.hpp:186
iterator begin()
Definition ode.hpp:143
StepEnd end() const
Definition ode.hpp:147
ODEResult run()
Definition ode.cpp:66
iterator begin()
Definition ode.hpp:299
StepEnd end() const
Definition ode.hpp:303
SymplecticResult run()
Definition ode.cpp:301
SymplecticResult run()
Definition ode.cpp:216
StepEnd end() const
Definition ode.hpp:225
iterator begin()
Definition ode.hpp:221
SymplecticResult run()
Definition ode.cpp:263
iterator begin()
Definition ode.hpp:260
StepEnd end() const
Definition ode.hpp:264
Core type definitions.
Implicit time integration via a user-supplied LinearSolver.
EulerSteps euler(ODERhsFn f, Vector y0, ODEParams p={})
Definition ode.cpp:309
ODEResult ode_rk4(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Classic 4th-order Runge-Kutta, fixed step.
Definition ode.cpp:339
double real
Definition types.hpp:10
Yoshida4Steps yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
Definition ode.cpp:322
std::function< void(real t, const Vector &q, const Vector &v)> SympObserverFn
Definition ode.hpp:36
std::function< void(real t, const Vector &y, Vector &dydt)> ODERhsFn
Definition ode.hpp:32
SymplecticResult ode_verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p={}, SympObserverFn obs=nullptr)
Velocity Verlet, 2nd-order symplectic, 1 force evaluation per step.
Definition ode.cpp:353
SymplecticResult ode_rk4_2nd(AccelFn accel, Vector q0, Vector v0, ODEParams p={}, SympObserverFn obs=nullptr)
RK4 for second-order systems q'' = accel(q), Nystrom form.
Definition ode.cpp:369
std::size_t idx
Definition types.hpp:11
std::function< void(real t, const Vector &y)> ObserverFn
Definition ode.hpp:34
constexpr real e
Definition math.hpp:43
RK4Steps rk4(ODERhsFn f, Vector y0, ODEParams p={})
Definition ode.cpp:312
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:130
std::function< void(const Vector &q, Vector &acc)> AccelFn
Definition ode.hpp:33
RK4_2ndSteps rk4_2nd(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
Definition ode.cpp:325
ODEResult ode_euler(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Forward Euler, 1st-order, fixed step.
Definition ode.cpp:332
SymplecticResult ode_yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p={}, SympObserverFn obs=nullptr)
Yoshida 4th-order symplectic, 3 force evaluations per step.
Definition ode.cpp:361
RK45Steps rk45(ODERhsFn f, Vector y0, ODEParams p={})
Definition ode.cpp:315
VerletSteps verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
Definition ode.cpp:319
ODEResult ode_rk45(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Adaptive Dormand-Prince RK45 with FSAL and PI step-size control.
Definition ode.cpp:346
EulerSteps * owner_
Definition ode.hpp:88
bool operator==(StepEnd) const
Definition ode.hpp:99
bool operator!=(StepEnd) const
Definition ode.hpp:96
Step operator*() const
Definition ode.hpp:89
iterator & operator++()
Definition ode.hpp:92
Parameters for all ODE integrators. Set only the fields you need.
Definition ode.hpp:64
real rtol
relative tolerance (adaptive only)
Definition ode.hpp:68
real h
step size (fixed-step) or initial hint (adaptive)
Definition ode.hpp:67
real atol
absolute tolerance (adaptive only)
Definition ode.hpp:69
idx max_steps
step cap (adaptive only)
Definition ode.hpp:70
Vector y
Definition ode.hpp:50
bool converged
Definition ode.hpp:53
Step operator*() const
Definition ode.hpp:167
RK45Steps * owner_
Definition ode.hpp:166
bool operator!=(StepEnd) const
Definition ode.hpp:174
iterator & operator++()
Definition ode.hpp:170
bool operator==(StepEnd) const
Definition ode.hpp:177
Step operator*() const
Definition ode.hpp:128
bool operator==(StepEnd) const
Definition ode.hpp:138
RK4Steps * owner_
Definition ode.hpp:127
bool operator!=(StepEnd) const
Definition ode.hpp:135
iterator & operator++()
Definition ode.hpp:131
bool operator!=(StepEnd) const
Definition ode.hpp:291
iterator & operator++()
Definition ode.hpp:287
RK4_2ndSteps * owner_
Definition ode.hpp:283
bool operator==(StepEnd) const
Definition ode.hpp:294
SymplecticStep operator*() const
Definition ode.hpp:284
real t
Definition ode.hpp:39
Vector y
Definition ode.hpp:40
bool operator!=(StepEnd) const
Definition ode.hpp:213
iterator & operator++()
Definition ode.hpp:209
VerletSteps * owner_
Definition ode.hpp:205
bool operator==(StepEnd) const
Definition ode.hpp:216
SymplecticStep operator*() const
Definition ode.hpp:206
bool operator!=(StepEnd) const
Definition ode.hpp:252
SymplecticStep operator*() const
Definition ode.hpp:245
bool operator==(StepEnd) const
Definition ode.hpp:255
iterator & operator++()
Definition ode.hpp:248
Yoshida4Steps * owner_
Definition ode.hpp:244
Vector operations.