9 for (
idx i = 0; i < x.size(); ++i)
14 return 1
e-14 * std::abs(t1);
26void EulerSteps::advance() {
27 if (t_ >= t1_ - eps_guard(t1_)) {
31 real dt = std::min(h_, t1_ - t_);
33 axpy_vec(dt, dydt_, y_);
42 return {std::move(y_), t1_, steps_,
true};
58void RK4Steps::advance() {
59 if (t_ >= t1_ - eps_guard(t1_)) {
64 const real dt = std::min(h_, t1_ - t_);
67 for (
idx i = 0; i < n; ++i) {
68 ytmp_[i] = y_[i] + (0.5 * dt * k1_[i]);
70 f_(t_ + (0.5 * dt), ytmp_, k2_);
71 for (
idx i = 0; i < n; ++i) {
72 ytmp_[i] = y_[i] + (0.5 * dt * k2_[i]);
74 f_(t_ + (0.5 * dt), ytmp_, k3_);
75 for (
idx i = 0; i < n; ++i) {
76 ytmp_[i] = y_[i] + (dt * k3_[i]);
78 f_(t_ + dt, ytmp_, k4_);
79 for (
idx i = 0; i < n; ++i) {
80 y_[i] += (dt / 6.0) * (k1_[i] + (2 * k2_[i]) + (2 * k3_[i]) + k4_[i]);
90 return {std::move(y_), t1_, steps_,
true};
98static constexpr real rk45_a21 = 1.0 / 5.0;
99static constexpr real rk45_a31 = 3.0 / 40.0, rk45_a32 = 9.0 / 40.0;
100static constexpr real rk45_a41 = 44.0 / 45.0, rk45_a42 = -56.0 / 15.0,
101 rk45_a43 = 32.0 / 9.0;
102static constexpr real rk45_a51 = 19372.0 / 6561.0, rk45_a52 = -25360.0 / 2187.0,
103 rk45_a53 = 64448.0 / 6561.0, rk45_a54 = -212.0 / 729.0;
104static constexpr real rk45_a61 = 9017.0 / 3168.0, rk45_a62 = -355.0 / 33.0,
105 rk45_a63 = 46732.0 / 5247.0, rk45_a64 = 49.0 / 176.0,
106 rk45_a65 = -5103.0 / 18656.0;
108static constexpr real rk45_b1 = 35.0 / 384.0, rk45_b3 = 500.0 / 1113.0,
109 rk45_b4 = 125.0 / 192.0, rk45_b5 = -2187.0 / 6784.0,
110 rk45_b6 = 11.0 / 84.0;
112static constexpr real rk45_e1 = 71.0 / 57600.0, rk45_e3 = -71.0 / 16695.0,
113 rk45_e4 = 71.0 / 1920.0, rk45_e5 = -17253.0 / 339200.0,
114 rk45_e6 = 22.0 / 525.0, rk45_e7 = -1.0 / 40.0;
130 h_(std::min(p.h, p.tf - p.t0)),
133 max_steps_(p.max_steps) {
137void RK45Steps::advance() {
138 if (t_ >= t1_ - eps_guard(t1_)) {
142 if (steps_ >= max_steps_) {
151 h_ = std::min(h_, t1_ - t_);
153 for (
idx i = 0; i < n; ++i) {
154 ytmp_[i] = y_[i] + (h_ * rk45_a21 * k1_[i]);
156 f_(t_ + (h_ / 5.0), ytmp_, k2_);
158 for (
idx i = 0; i < n; ++i) {
159 ytmp_[i] = y_[i] + (h_ * ((rk45_a31 * k1_[i]) + (rk45_a32 * k2_[i])));
161 f_(t_ + (3 * h_ / 10.0), ytmp_, k3_);
163 for (
idx i = 0; i < n; ++i) {
167 * ((rk45_a41 * k1_[i]) + (rk45_a42 * k2_[i]) + (rk45_a43 * k3_[i])));
169 f_(t_ + (4 * h_ / 5.0), ytmp_, k4_);
171 for (
idx i = 0; i < n; ++i) {
174 * ((rk45_a51 * k1_[i]) + (rk45_a52 * k2_[i])
175 + (rk45_a53 * k3_[i]) + (rk45_a54 * k4_[i])));
177 f_(t_ + (8 * h_ / 9.0), ytmp_, k5_);
179 for (
idx i = 0; i < n; ++i) {
183 * ((rk45_a61 * k1_[i]) + (rk45_a62 * k2_[i]) + (rk45_a63 * k3_[i])
184 + (rk45_a64 * k4_[i]) + (rk45_a65 * k5_[i])));
186 f_(t_ + h_, ytmp_, k6_);
188 for (
idx i = 0; i < n; ++i) {
191 * ((rk45_b1 * k1_[i]) + (rk45_b3 * k3_[i]) + (rk45_b4 * k4_[i])
192 + (rk45_b5 * k5_[i]) + (rk45_b6 * k6_[i])));
194 f_(t_ + h_, ytmp_, k7_);
196 for (
idx i = 0; i < n; ++i) {
198 * ((k1_[i] * rk45_e1) + (rk45_e3 * k3_[i]) + (rk45_e4 * k4_[i])
199 + (k5_[i] * rk45_e5) + (rk45_e6 * k6_[i]) + (rk45_e7 * k7_[i]));
203 for (
idx i = 0; i < n; ++i) {
204 real sc = (rtol_ * max(std::abs(y_[i]), std::abs(ytmp_[i]))) + atol_;
205 err_norm = std::max(err_norm, std::abs(err_[i] / sc));
208 real factor = 0.9 * std::pow(err_norm + 1
e-10, -0.2);
209 factor = std::max(
real(0.1), std::min(
real(10.0), factor));
211 if (err_norm <= 1.0) {
227 return {std::move(y_), t_, steps_, converged_};
231 : accel_(std::move(accel)),
242void VerletSteps::advance() {
243 if (t_ >= t1_ - eps_guard(t1_)) {
248 const real dt = std::min(h_, t1_ - t_);
250 for (
idx i = 0; i < n; ++i) {
251 q_[i] += (dt * v_[i]) + (0.5 * dt * dt * a_cur_[i]);
256 for (
idx i = 0; i < n; ++i) {
257 v_[i] += 0.5 * dt * (a_cur_[i] + a_next_[i]);
260 std::swap(a_cur_, a_next_);
269 return {std::move(q_), std::move(v_), t_, steps_};
273 : accel_(std::move(accel)),
282void Yoshida4Steps::advance() {
283 if (t_ >= t1_ - eps_guard(t1_)) {
287 static const real w1 = 1.0 / (2.0 - std::cbrt(2.0));
288 static const real w0 = 1.0 - 2.0 * w1;
289 static const real c1 = w1 * 0.5;
290 static const real c2 = (w0 + w1) * 0.5;
291 static const real d1 = w1;
292 static const real d2 = w0;
295 const real dt = std::min(h_, t1_ - t_);
297 for (
idx i = 0; i < n; ++i)
298 q_[i] += c1 * dt * v_[i];
300 for (
idx i = 0; i < n; ++i)
301 v_[i] += d1 * dt * acc_[i];
302 for (
idx i = 0; i < n; ++i)
303 q_[i] += c2 * dt * v_[i];
305 for (
idx i = 0; i < n; ++i)
306 v_[i] += d2 * dt * acc_[i];
307 for (
idx i = 0; i < n; ++i)
308 q_[i] += c2 * dt * v_[i];
310 for (
idx i = 0; i < n; ++i)
311 v_[i] += d1 * dt * acc_[i];
312 for (
idx i = 0; i < n; ++i)
313 q_[i] += c1 * dt * v_[i];
322 return {std::move(q_), std::move(v_), t_, steps_};
326 : accel_(std::move(accel)),
339void RK4_2ndSteps::advance() {
340 if (t_ >= t1_ - eps_guard(t1_)) {
345 const real dt = std::min(h_, t1_ - t_);
348 for (
idx i = 0; i < n; ++i)
349 qtmp_[i] = q_[i] + 0.5 * dt * v_[i];
351 for (
idx i = 0; i < n; ++i)
352 qtmp_[i] = q_[i] + 0.5 * dt * (v_[i] + 0.5 * dt * a1_[i]);
354 for (
idx i = 0; i < n; ++i)
355 qtmp_[i] = q_[i] + dt * (v_[i] + 0.5 * dt * a2_[i]);
358 for (
idx i = 0; i < n; ++i) {
359 q_[i] += dt * v_[i] + (dt * dt / 6.0) * (a1_[i] + a2_[i] + a3_[i]);
360 v_[i] += (dt / 6.0) * (a1_[i] + 2.0 * a2_[i] + 2.0 * a3_[i] + a4_[i]);
369 return {std::move(q_), std::move(v_), t_, steps_};
373 return EulerSteps(std::move(f), std::move(y0), p);
376 return RK4Steps(std::move(f), std::move(y0), p);
379 return RK45Steps(std::move(f), std::move(y0), p);
383 return VerletSteps(std::move(a), std::move(q0), std::move(v0), p);
386 return Yoshida4Steps(std::move(a), std::move(q0), std::move(v0), p);
389 return RK4_2ndSteps(std::move(a), std::move(q0), std::move(v0), p);
393 auto s =
euler(std::move(f), std::move(y0), p);
400 auto s =
rk4(std::move(f), std::move(y0), p);
407 auto s =
rk45(std::move(f), std::move(y0), p);
418 auto s =
verlet(std::move(a), std::move(q0), std::move(v0), p);
421 obs(step.t, step.q, step.v);
429 auto s =
yoshida4(std::move(a), std::move(q0), std::move(v0), p);
432 obs(step.t, step.q, step.v);
440 auto s =
rk4_2nd(std::move(a), std::move(q0), std::move(v0), p);
443 obs(step.t, step.q, step.v);
constexpr idx size() const noexcept
EulerSteps(ODERhsFn f, Vector y0, ODEParams p)
RK45Steps(ODERhsFn f, Vector y0, ODEParams p)
RK4Steps(ODERhsFn f, Vector y0, ODEParams p)
RK4_2ndSteps(AccelFn accel, Vector q0, Vector v0, ODEParams p)
VerletSteps(AccelFn accel, Vector q0, Vector v0, ODEParams p)
Yoshida4Steps(AccelFn accel, Vector q0, Vector v0, ODEParams p)
EulerSteps euler(ODERhsFn f, Vector y0, ODEParams p={})
ODEResult ode_rk4(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Classic 4th-order Runge-Kutta, fixed step.
Yoshida4Steps yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
std::function< void(real t, const Vector &q, const Vector &v)> SympObserverFn
std::function< void(real t, const Vector &y, Vector &dydt)> ODERhsFn
SymplecticResult ode_verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p={}, SympObserverFn obs=nullptr)
Velocity Verlet, 2nd-order symplectic, 1 force evaluation per step.
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.
std::function< void(real t, const Vector &y)> ObserverFn
RK4Steps rk4(ODERhsFn f, Vector y0, ODEParams p={})
BasicVector< real > Vector
Real-valued dense vector with full backend dispatch (CPU + GPU)
std::function< void(const Vector &q, Vector &acc)> AccelFn
RK4_2ndSteps rk4_2nd(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
ODEResult ode_euler(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Forward Euler, 1st-order, fixed step.
SymplecticResult ode_yoshida4(AccelFn accel, Vector q0, Vector v0, ODEParams p={}, SympObserverFn obs=nullptr)
Yoshida 4th-order symplectic, 3 force evaluations per step.
RK45Steps rk45(ODERhsFn f, Vector y0, ODEParams p={})
VerletSteps verlet(AccelFn accel, Vector q0, Vector v0, ODEParams p={})
ODEResult ode_rk45(ODERhsFn f, Vector y0, ODEParams p={}, ObserverFn obs=nullptr)
Adaptive Dormand-Prince RK45 with FSAL and PI step-size control.
ODE and symplectic integrators.