56 using state_type =
typename base_type::state_type;
57 using time_type =
typename base_type::time_type;
58 using value_type =
typename base_type::value_type;
59 using system_function =
typename base_type::system_function;
62 static constexpr time_type fortran_safety =
static_cast<time_type
>(0.9);
63 static constexpr time_type fortran_fac1 =
static_cast<time_type
>(0.333);
64 static constexpr time_type fortran_fac2 =
static_cast<time_type
>(6.0);
65 static constexpr time_type fortran_beta =
static_cast<time_type
>(0.0);
66 static constexpr time_type fortran_dt_max =
static_cast<time_type
>(1e100);
67 static constexpr time_type fortran_dt_min =
static_cast<time_type
>(1e-16);
68 static constexpr int fortran_nmax = 100000;
69 static constexpr int fortran_nstiff = 1000;
72 time_type safety_factor_ = fortran_safety;
73 time_type fac1_ = fortran_fac1;
74 time_type fac2_ = fortran_fac2;
75 time_type beta_ = fortran_beta;
76 time_type dt_max_ = fortran_dt_max;
77 time_type dt_min_ = fortran_dt_min;
78 int nmax_ = fortran_nmax;
79 int nstiff_ = fortran_nstiff;
80 time_type facold_ =
static_cast<time_type
>(1e-4);
92 void check_nan_inf(
const std::string& context,
const state_type& state,
const state_type& y_new,
93 const state_type& error, time_type dt, time_type err, time_type err2, time_type deno) {
95 for (std::size_t i = 0; i < state.size(); ++i) {
96 if (std::isnan(state[i]) || std::isinf(state[i])) {
97 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" state[" + std::to_string(i) +
"]=" + std::to_string(state[i]));
100 for (std::size_t i = 0; i < y_new.size(); ++i) {
101 if (std::isnan(y_new[i]) || std::isinf(y_new[i])) {
102 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" y_new[" + std::to_string(i) +
"]=" + std::to_string(y_new[i]));
105 for (std::size_t i = 0; i < error.size(); ++i) {
106 if (std::isnan(error[i]) || std::isinf(error[i])) {
107 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" error[" + std::to_string(i) +
"]=" + std::to_string(error[i]));
110 if (std::isnan(dt) || std::isinf(dt)) {
111 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" dt=" + std::to_string(dt));
113 if (std::isnan(err) || std::isinf(err)) {
114 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" err=" + std::to_string(err));
116 if (std::isnan(err2) || std::isinf(err2)) {
117 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" err2=" + std::to_string(err2));
119 if (std::isnan(deno) || std::isinf(deno)) {
120 throw std::runtime_error(
"DOP853: NaN/Inf detected in " + context +
" deno=" + std::to_string(deno));
125 time_type compute_initial_step(
const state_type& y, time_type t,
const system_function& sys, time_type t_end)
const {
131 time_type dnf = 0.0, dny = 0.0;
132 for (std::size_t i = 0; i < y.size(); ++i) {
133 time_type sk = this->atol_ + this->rtol_ * std::abs(y[i]);
134 dnf += (f0[i] / sk) * (f0[i] / sk);
135 dny += (y[i] / sk) * (y[i] / sk);
138 if (dnf > 1e-10 && dny > 1e-10) {
139 h = std::sqrt(dny / dnf) * 0.01;
141 h = std::min<time_type>(h, std::abs(t_end - t));
142 h = std::copysign(h, t_end - t);
146 for (std::size_t i = 0; i < y.size(); ++i)
147 y1[i] = y[i] + h * f0[i];
152 time_type der2 = 0.0;
153 for (std::size_t i = 0; i < y.size(); ++i) {
154 time_type sk = this->atol_ + this->rtol_ * std::abs(y[i]);
155 der2 += ((f1[i] - f0[i]) / sk) * ((f1[i] - f0[i]) / sk);
157 der2 = std::sqrt(der2) / h;
160 time_type der12 = std::max<time_type>(std::abs(der2), std::sqrt(dnf));
163 h1 = std::pow(0.01 / der12, 1.0 / 8.0);
165 h1 = std::max<time_type>(1e-6, std::abs(h) * 1e-3);
168 time_type hmax = 100 * std::abs(h);
169 time_type htmp = (h1 < hmax) ? h1 : hmax;
170 htmp = (htmp < std::abs(t_end - t)) ? htmp : std::abs(t_end - t);
171 h = std::copysign(htmp, t_end - t);
177 time_type rtol =
static_cast<time_type
>(1e-8),
178 time_type atol =
static_cast<time_type
>(1e-10))
179 :
base_type(std::move(sys), rtol, atol) {}
181 void step(state_type& state, time_type dt)
override {
182 adaptive_step(state, dt);
187 time_type target_time_ = 0;
189 time_type adaptive_step(state_type& state, time_type dt)
override {
191 time_type t = this->current_time_;
192 time_type t_end = target_time_;
193 if (t_end == t) t_end = t + 1.0;
194 time_type current_dt = dt;
195 if (current_dt <= 0) {
197 current_dt = compute_initial_step(state, t, this->sys_, t_end);
199 current_dt = std::max<time_type>(dt_min_, std::min<time_type>(dt_max_, current_dt));
202 for (; attempt < nmax_; ++attempt) {
206 dop853_step(state, y_new, error, current_dt);
210 check_nan_inf(
"step_computation", state, y_new, error, current_dt, 0.0, 0.0, 0.0);
213 time_type err = 0.0, err2 = 0.0;
214 for (std::size_t i = 0; i < state.size(); ++i) {
215 time_type sk = this->atol_ + this->rtol_ * std::max<time_type>(std::abs(state[i]), std::abs(y_new[i]));
218 err2 += (error[i] / sk) * (error[i] / sk);
219 err += (error[i] / sk) * (error[i] / sk);
221 time_type deno = err + 0.01 * err2;
222 if (deno <= 0.0 || std::isnan(deno) || std::isinf(deno)) {
225 err = std::abs(current_dt) * err * std::sqrt(1.0 / (state.size() * deno));
226 if (std::isnan(err) || std::isinf(err)) {
231 check_nan_inf(
"error_norm", state, y_new, error, current_dt, err, err2, deno);
234 time_type expo1 = 1.0 / 8.0 - beta_ * 0.2;
235 time_type fac11 = std::pow(std::max<time_type>(err,
static_cast<time_type
>(1e-16)), expo1);
236 time_type fac = fac11 / std::pow(facold_, beta_);
238 fac = std::min<time_type>(fac2_, std::max<time_type>(fac1_, fac / safety_factor_));
239 if (std::isnan(fac) || std::isinf(fac)) {
242 time_type next_dt = current_dt / fac;
243 if (next_dt <= 0.0 || std::isnan(next_dt) || std::isinf(next_dt)) {
248 facold_ = std::max<time_type>(err,
static_cast<time_type
>(1e-4));
252 this->advance_time(current_dt);
255 if (nstiff_ > 0 && (naccpt_ % nstiff_ == 0 || iastiff_ > 0)) {
257 time_type stnum = 0, stden = 0;
258 for (std::size_t i = 0; i < state.size(); ++i) {
259 stnum += (error[i]) * (error[i]);
260 stden += (y_new[i] - state[i]) * (y_new[i] - state[i]);
262 if (stden > 0) hlamb_ = std::abs(current_dt) * std::sqrt(stnum / stden);
266 if (iastiff_ == 15) {
267 throw std::runtime_error(
"DOP853: Problem seems to become stiff");
271 if (nonsti_ == 6) iastiff_ = 0;
275 next_dt = std::max<time_type>(dt_min_, std::min<time_type>(dt_max_, next_dt));
281 next_dt = current_dt / std::min<time_type>(fac1_, fac11 / safety_factor_);
282 current_dt = std::max<time_type>(dt_min_, next_dt);
285 throw std::runtime_error(
"DOP853: Maximum number of step size reductions or steps exceeded");
290 static constexpr time_type get_c(
int i) {
return diffeq::integrators::ode::dop853::C<time_type>[i]; }
291 static constexpr time_type get_a(
int i,
int j) {
return diffeq::integrators::ode::dop853::A<time_type>[i][j]; }
292 static constexpr time_type get_b(
int i) {
return diffeq::integrators::ode::dop853::B<time_type>[i]; }
293 static constexpr time_type get_e5(
int i) {
return diffeq::integrators::ode::dop853::E5<time_type>[i]; }
295 void dop853_step(
const state_type& y, state_type& y_new, state_type& error, time_type dt) {
299 time_type t = this->current_time_;
302 this->sys_(t, y, k[0]);
305 for (std::size_t i = 0; i < y.size(); ++i)
306 temp[i] = y[i] + dt * get_a(1, 0) * k[0][i];
307 this->sys_(t + get_c(1) * dt, temp, k[1]);
310 for (std::size_t i = 0; i < y.size(); ++i)
311 temp[i] = y[i] + dt * (get_a(2, 0) * k[0][i] + get_a(2, 1) * k[1][i]);
312 this->sys_(t + get_c(2) * dt, temp, k[2]);
315 for (std::size_t i = 0; i < y.size(); ++i)
316 temp[i] = y[i] + dt * (get_a(3, 0) * k[0][i] + get_a(3, 2) * k[2][i]);
317 this->sys_(t + get_c(3) * dt, temp, k[3]);
320 for (std::size_t i = 0; i < y.size(); ++i)
321 temp[i] = y[i] + dt * (get_a(4, 0) * k[0][i] + get_a(4, 2) * k[2][i] + get_a(4, 3) * k[3][i]);
322 this->sys_(t + get_c(4) * dt, temp, k[4]);
325 for (std::size_t i = 0; i < y.size(); ++i)
326 temp[i] = y[i] + dt * (get_a(5, 0) * k[0][i] + get_a(5, 3) * k[3][i] + get_a(5, 4) * k[4][i]);
327 this->sys_(t + get_c(5) * dt, temp, k[5]);
330 for (std::size_t i = 0; i < y.size(); ++i)
331 temp[i] = y[i] + dt * (get_a(6, 0) * k[0][i] + get_a(6, 3) * k[3][i] + get_a(6, 4) * k[4][i] + get_a(6, 5) * k[5][i]);
332 this->sys_(t + get_c(6) * dt, temp, k[6]);
335 for (std::size_t i = 0; i < y.size(); ++i)
336 temp[i] = y[i] + dt * (get_a(7, 0) * k[0][i] + get_a(7, 3) * k[3][i] + get_a(7, 4) * k[4][i] + get_a(7, 5) * k[5][i] + get_a(7, 6) * k[6][i]);
337 this->sys_(t + get_c(7) * dt, temp, k[7]);
340 for (std::size_t i = 0; i < y.size(); ++i)
341 temp[i] = y[i] + dt * (get_a(8, 0) * k[0][i] + get_a(8, 3) * k[3][i] + get_a(8, 4) * k[4][i] + get_a(8, 5) * k[5][i] + get_a(8, 6) * k[6][i] + get_a(8, 7) * k[7][i]);
342 this->sys_(t + get_c(8) * dt, temp, k[8]);
345 for (std::size_t i = 0; i < y.size(); ++i)
346 temp[i] = y[i] + dt * (get_a(9, 0) * k[0][i] + get_a(9, 3) * k[3][i] + get_a(9, 4) * k[4][i] + get_a(9, 5) * k[5][i] + get_a(9, 6) * k[6][i] + get_a(9, 7) * k[7][i] + get_a(9, 8) * k[8][i]);
347 this->sys_(t + get_c(9) * dt, temp, k[9]);
350 for (std::size_t i = 0; i < y.size(); ++i)
351 temp[i] = y[i] + dt * (get_a(10, 0) * k[0][i] + get_a(10, 3) * k[3][i] + get_a(10, 4) * k[4][i] + get_a(10, 5) * k[5][i] + get_a(10, 6) * k[6][i] + get_a(10, 7) * k[7][i] + get_a(10, 8) * k[8][i] + get_a(10, 9) * k[9][i]);
352 this->sys_(t + get_c(10) * dt, temp, k[10]);
355 for (std::size_t i = 0; i < y.size(); ++i)
356 temp[i] = y[i] + dt * (get_a(11, 0) * k[0][i] + get_a(11, 3) * k[3][i] + get_a(11, 4) * k[4][i] + get_a(11, 5) * k[5][i] + get_a(11, 6) * k[6][i] + get_a(11, 7) * k[7][i] + get_a(11, 8) * k[8][i] + get_a(11, 9) * k[9][i] + get_a(11, 10) * k[10][i]);
357 this->sys_(t + dt, temp, k[11]);
360 for (std::size_t i = 0; i < y.size(); ++i) {
361 y_new[i] = y[i] + dt * (get_b(0) * k[0][i] + get_b(5) * k[5][i] + get_b(6) * k[6][i] + get_b(7) * k[7][i] + get_b(8) * k[8][i] + get_b(9) * k[9][i] + get_b(10) * k[10][i] + get_b(11) * k[11][i]);
365 for (std::size_t i = 0; i < y.size(); ++i) {
366 error[i] = dt * (get_e5(0) * k[0][i] + get_e5(5) * k[5][i] + get_e5(6) * k[6][i] + get_e5(7) * k[7][i] + get_e5(8) * k[8][i] + get_e5(9) * k[9][i] + get_e5(10) * k[10][i] + get_e5(11) * k[11][i]);