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 and symplectic integrators.
3#pragma once
4
5#include "core/types.hpp"
6#include "core/vector.hpp"
7#include "ode/implicit.hpp"
8#include <functional>
9
10namespace num {
11
12using ODERhsFn = std::function<void(real t, const Vector& y, Vector& dydt)>;
13using AccelFn = std::function<void(const Vector& q, Vector& acc)>;
14using ObserverFn = std::function<void(real t, const Vector& y)>;
15using SympObserverFn = std::function<void(real t, const Vector& q, const Vector& v)>;
16
17struct Step {
18 real t = 0.0;
20};
21
23 real t = 0.0;
26};
27
28struct ODEResult {
30 real t = 0.0;
32 bool converged = false;
33};
34
41
42struct ODEParams {
43 real t0 = 0.0;
44 real tf = 1.0;
45 real h = 1e-3;
46 real rtol = 1e-6;
47 real atol = 1e-9;
48 idx max_steps = 1000000;
49};
50
51struct StepEnd {};
52
54 ODERhsFn f_ = nullptr;
55 Vector y_, dydt_;
56 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
57 idx steps_ = 0;
58 bool done_ = false;
59
60 void advance();
61
62 public:
63 explicit EulerSteps(ODERhsFn f, Vector y0, ODEParams p);
64
65 struct iterator {
67 Step operator*() const { return {owner_->t_, owner_->y_}; }
69 owner_->advance();
70 return *this;
71 }
72 bool operator!=(StepEnd) const { return !owner_->done_; }
73 bool operator==(StepEnd) const { return owner_->done_; }
74 };
75
77 advance();
78 return {this};
79 }
80 StepEnd end() const { return {}; }
81 ODEResult run();
82};
83
84class RK4Steps {
85 ODERhsFn f_ = nullptr;
86 Vector y_, k1_, k2_, k3_, k4_, ytmp_;
87 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
88 idx steps_ = 0;
89 bool done_ = false;
90
91 void advance();
92
93 public:
94 explicit RK4Steps(ODERhsFn f, Vector y0, ODEParams p);
95
96 struct iterator {
98 Step operator*() const { return {owner_->t_, owner_->y_}; }
100 owner_->advance();
101 return *this;
102 }
103 bool operator!=(StepEnd) const { return !owner_->done_; }
104 bool operator==(StepEnd) const { return owner_->done_; }
105 };
106
108 advance();
109 return {this};
110 }
111 StepEnd end() const { return {}; }
112 ODEResult run();
113};
114
116 ODERhsFn f_ = nullptr;
117 Vector y_, k1_, k2_, k3_, k4_, k5_, k6_, k7_, ytmp_, err_;
118 real t_ = 0.0, t1_ = 0.0, h_ = 0.0, rtol_ = 0.0, atol_ = 0.0;
119 idx steps_ = 0, max_steps_ = 0;
120 bool done_ = false, converged_ = true;
121
122 void advance();
123
124 public:
125 explicit RK45Steps(ODERhsFn f, Vector y0, ODEParams p);
126
127 struct iterator {
129 Step operator*() const { return {owner_->t_, owner_->y_}; }
131 owner_->advance();
132 return *this;
133 }
134 bool operator!=(StepEnd) const { return !owner_->done_; }
135 bool operator==(StepEnd) const { return owner_->done_; }
136 };
137
139 advance();
140 return {this};
141 }
142 StepEnd end() const { return {}; }
143 ODEResult run();
144};
145
147 AccelFn accel_ = nullptr;
148 Vector q_, v_, a_cur_, a_next_;
149 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
150 idx steps_ = 0;
151 bool done_ = false;
152
153 void advance();
154
155 public:
156 explicit VerletSteps(AccelFn accel, Vector q0, Vector v0, ODEParams p);
157
158 struct iterator {
160 SymplecticStep operator*() const { return {owner_->t_, owner_->q_, owner_->v_}; }
162 owner_->advance();
163 return *this;
164 }
165 bool operator!=(StepEnd) const { return !owner_->done_; }
166 bool operator==(StepEnd) const { return owner_->done_; }
167 };
168
170 advance();
171 return {this};
172 }
173 StepEnd end() const { return {}; }
175};
176
178 AccelFn accel_ = nullptr;
179 Vector q_, v_, acc_;
180 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
181 idx steps_ = 0;
182 bool done_ = false;
183
184 void advance();
185
186 public:
187 explicit Yoshida4Steps(AccelFn accel, Vector q0, Vector v0, ODEParams p);
188
189 struct iterator {
191 SymplecticStep operator*() const { return {owner_->t_, owner_->q_, owner_->v_}; }
193 owner_->advance();
194 return *this;
195 }
196 bool operator!=(StepEnd) const { return !owner_->done_; }
197 bool operator==(StepEnd) const { return owner_->done_; }
198 };
199
201 advance();
202 return {this};
203 }
204 StepEnd end() const { return {}; }
206};
207
209 AccelFn accel_ = nullptr;
210 Vector q_, v_, a1_, a2_, a3_, a4_, qtmp_;
211 real t_ = 0.0, t1_ = 0.0, h_ = 0.0;
212 idx steps_ = 0;
213 bool done_ = false;
214
215 void advance();
216
217 public:
218 explicit RK4_2ndSteps(AccelFn accel, Vector q0, Vector v0, ODEParams p);
219
220 struct iterator {
222 SymplecticStep operator*() const { return {owner_->t_, owner_->q_, owner_->v_}; }
224 owner_->advance();
225 return *this;
226 }
227 bool operator!=(StepEnd) const { return !owner_->done_; }
228 bool operator==(StepEnd) const { return owner_->done_; }
229 };
230
232 advance();
233 return {this};
234 }
235 StepEnd end() const { return {}; }
237};
238
239// Lazy-range factories
240
241EulerSteps euler(ODERhsFn f, Vector y0, ODEParams p = {});
242RK4Steps rk4(ODERhsFn f, Vector y0, ODEParams p = {});
243RK45Steps rk45(ODERhsFn f, Vector y0, ODEParams p = {});
244
245VerletSteps verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p = {});
246Yoshida4Steps yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p = {});
247RK4_2ndSteps rk4_2nd(AccelFn accel, Vector q0, Vector v0, ODEParams p = {});
248
249// High-level integrators return final state only.
250
251/// @brief Forward Euler, 1st-order, fixed step.
252ODEResult ode_euler(ODERhsFn f, Vector y0, ODEParams p = {}, ObserverFn obs = nullptr);
253
254/// @brief Classic 4th-order Runge-Kutta, fixed step.
255ODEResult ode_rk4(ODERhsFn f, Vector y0, ODEParams p = {}, ObserverFn obs = nullptr);
256
257/// @brief Adaptive Dormand-Prince RK45 with FSAL and PI step-size control.
258ODEResult ode_rk45(ODERhsFn f, Vector y0, ODEParams p = {}, ObserverFn obs = nullptr);
259
260/// @brief Velocity Verlet, 2nd-order symplectic, 1 force evaluation per step.
261SymplecticResult ode_verlet(AccelFn accel,
262 Vector q0,
263 Vector v0,
264 ODEParams p = {},
265 SympObserverFn obs = nullptr);
266
267/// @brief Yoshida 4th-order symplectic, 3 force evaluations per step.
268SymplecticResult ode_yoshida4(AccelFn accel,
269 Vector q0,
270 Vector v0,
271 ODEParams p = {},
272 SympObserverFn obs = nullptr);
273
274/// @brief RK4 for second-order systems q'' = accel(q), Nystrom form.
275/// @note Not symplectic. Prefer ode_verlet or ode_yoshida4 for long Hamiltonian
276/// runs.
277SymplecticResult ode_rk4_2nd(AccelFn accel,
278 Vector q0,
279 Vector v0,
280 ODEParams p = {},
281 SympObserverFn obs = nullptr);
282
283} // namespace num
StepEnd end() const
Definition ode.hpp:80
ODEResult run()
Definition ode.cpp:38
iterator begin()
Definition ode.hpp:76
ODEResult run()
Definition ode.cpp:223
iterator begin()
Definition ode.hpp:138
StepEnd end() const
Definition ode.hpp:142
iterator begin()
Definition ode.hpp:107
StepEnd end() const
Definition ode.hpp:111
ODEResult run()
Definition ode.cpp:86
iterator begin()
Definition ode.hpp:231
StepEnd end() const
Definition ode.hpp:235
SymplecticResult run()
Definition ode.cpp:366
SymplecticResult run()
Definition ode.cpp:265
StepEnd end() const
Definition ode.hpp:173
iterator begin()
Definition ode.hpp:169
SymplecticResult run()
Definition ode.cpp:319
iterator begin()
Definition ode.hpp:200
StepEnd end() const
Definition ode.hpp:204
Core type definitions.
Implicit time integration via a user-supplied LinearSolver.
EulerSteps euler(ODERhsFn f, Vector y0, ODEParams p={})
Definition ode.cpp:372
ODEResult ode_rk4(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Classic 4th-order Runge-Kutta, fixed step.
Definition ode.cpp:399
double real
Definition types.hpp:10
Yoshida4Steps yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
Definition ode.cpp:385
std::function< void(real t, const Vector &q, const Vector &v)> SympObserverFn
Definition ode.hpp:15
std::function< void(real t, const Vector &y, Vector &dydt)> ODERhsFn
Definition ode.hpp:12
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:413
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:435
std::size_t idx
Definition types.hpp:11
std::function< void(real t, const Vector &y)> ObserverFn
Definition ode.hpp:14
constexpr real e
Definition math.hpp:44
RK4Steps rk4(ODERhsFn f, Vector y0, ODEParams p={})
Definition ode.cpp:375
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
Definition vector.hpp:129
std::function< void(const Vector &q, Vector &acc)> AccelFn
Definition ode.hpp:13
RK4_2ndSteps rk4_2nd(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
Definition ode.cpp:388
ODEResult ode_euler(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Forward Euler, 1st-order, fixed step.
Definition ode.cpp:392
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:424
RK45Steps rk45(ODERhsFn f, Vector y0, ODEParams p={})
Definition ode.cpp:378
VerletSteps verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
Definition ode.cpp:382
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:406
EulerSteps * owner_
Definition ode.hpp:66
bool operator==(StepEnd) const
Definition ode.hpp:73
bool operator!=(StepEnd) const
Definition ode.hpp:72
Step operator*() const
Definition ode.hpp:67
iterator & operator++()
Definition ode.hpp:68
real rtol
Definition ode.hpp:46
real atol
Definition ode.hpp:47
idx max_steps
Definition ode.hpp:48
Vector y
Definition ode.hpp:29
bool converged
Definition ode.hpp:32
Step operator*() const
Definition ode.hpp:129
RK45Steps * owner_
Definition ode.hpp:128
bool operator!=(StepEnd) const
Definition ode.hpp:134
iterator & operator++()
Definition ode.hpp:130
bool operator==(StepEnd) const
Definition ode.hpp:135
Step operator*() const
Definition ode.hpp:98
bool operator==(StepEnd) const
Definition ode.hpp:104
RK4Steps * owner_
Definition ode.hpp:97
bool operator!=(StepEnd) const
Definition ode.hpp:103
iterator & operator++()
Definition ode.hpp:99
bool operator!=(StepEnd) const
Definition ode.hpp:227
iterator & operator++()
Definition ode.hpp:223
RK4_2ndSteps * owner_
Definition ode.hpp:221
bool operator==(StepEnd) const
Definition ode.hpp:228
SymplecticStep operator*() const
Definition ode.hpp:222
real t
Definition ode.hpp:18
Vector y
Definition ode.hpp:19
bool operator!=(StepEnd) const
Definition ode.hpp:165
iterator & operator++()
Definition ode.hpp:161
VerletSteps * owner_
Definition ode.hpp:159
bool operator==(StepEnd) const
Definition ode.hpp:166
SymplecticStep operator*() const
Definition ode.hpp:160
bool operator!=(StepEnd) const
Definition ode.hpp:196
SymplecticStep operator*() const
Definition ode.hpp:191
bool operator==(StepEnd) const
Definition ode.hpp:197
iterator & operator++()
Definition ode.hpp:192
Yoshida4Steps * owner_
Definition ode.hpp:190
Dense vector storage and operations.