38 using state_type =
typename base_type::state_type;
39 using time_type =
typename base_type::time_type;
40 using value_type =
typename base_type::value_type;
41 using system_function =
typename base_type::system_function;
44 time_type rtol =
static_cast<time_type
>(1e-3),
45 time_type atol =
static_cast<time_type
>(1e-6),
48 max_order_((max_order < MAX_ORDER) ? max_order : MAX_ORDER),
50 newton_tolerance_(
static_cast<time_type
>(1e-3)),
51 is_initialized_(
false),
52 h_abs_(
static_cast<time_type
>(0.0)),
53 h_abs_old_(
static_cast<time_type
>(0.0)),
54 error_norm_old_(
static_cast<time_type
>(0.0)),
58 initialize_bdf_coefficients();
61 void step(state_type& state, time_type dt)
override {
62 adaptive_step(state, dt);
65 void fixed_step(state_type& state, time_type dt) {
67 if (!is_initialized_) {
68 initialize_history(state, dt);
69 is_initialized_ =
true;
75 bool success = bdf_step(state, y_new, error, dt);
79 this->advance_time(dt);
83 this->sys_(this->current_time_, state, f);
84 for (std::size_t i = 0; i < state.size(); ++i) {
85 state[i] += dt * f[i];
87 this->advance_time(dt);
91 time_type adaptive_step(state_type& state, time_type dt)
override {
92 if (!is_initialized_) {
93 initialize_history(state, dt);
94 is_initialized_ =
true;
98 time_type t = this->current_time_;
99 time_type max_step = this->dt_max_;
100 time_type min_step = (this->dt_min_ >
static_cast<time_type
>(1e-10)) ? this->dt_min_ :
static_cast<time_type
>(1e-10);
102 time_type h_abs = h_abs_;
103 if (h_abs > max_step) {
105 change_D(current_order_, max_step / h_abs_);
107 }
else if (h_abs < min_step) {
109 change_D(current_order_, min_step / h_abs_);
113 bool step_accepted =
false;
115 const int max_attempts = 10;
117 while (!step_accepted && attempts < max_attempts) {
120 if (h_abs < min_step) {
121 return fallback_step(state, dt);
125 time_type t_new = t + h;
128 if (t_new > this->current_time_ + dt) {
129 t_new = this->current_time_ + dt;
130 change_D(current_order_, std::abs(t_new - t) / h_abs);
140 time_type factor =
static_cast<time_type
>(1.0);
142 bool bdf_success = bdf_step(state, y_new, error, h);
146 for (std::size_t i = 0; i < scale.size(); ++i) {
147 scale[i] = this->atol_ + this->rtol_ * std::abs(y_new[i]);
150 time_type error_norm =
static_cast<time_type
>(0.0);
151 for (std::size_t i = 0; i < error.size(); ++i) {
152 time_type scaled_error = error[i] / scale[i];
153 error_norm += scaled_error * scaled_error;
155 error_norm = std::sqrt(error_norm /
static_cast<time_type
>(error.size()));
157 if (error_norm <=
static_cast<time_type
>(1.0)) {
159 step_accepted =
true;
163 this->advance_time(h);
169 adjust_order(error_norm, scale);
172 time_type safety =
static_cast<time_type
>(0.8);
173 time_type factor = safety * std::pow(error_norm,
static_cast<time_type
>(-1.0) /
static_cast<time_type
>(current_order_ + 1));
176 time_type max_factor_limit =
static_cast<time_type
>(1.5);
177 if (factor > max_factor_limit) factor = max_factor_limit;
178 if (factor <
static_cast<time_type
>(MIN_FACTOR)) factor =
static_cast<time_type
>(MIN_FACTOR);
181 change_D(current_order_, factor);
185 factor =
static_cast<time_type
>(0.5);
187 change_D(current_order_, factor);
192 factor =
static_cast<time_type
>(0.25);
194 change_D(current_order_, factor);
200 if (!step_accepted) {
201 return fallback_step(state, dt);
207 void set_newton_parameters(
int max_iterations, time_type tolerance) {
209 newton_tolerance_ = tolerance;
215 time_type newton_tolerance_;
216 bool is_initialized_;
218 time_type h_abs_old_;
219 time_type error_norm_old_;
223 std::vector<state_type> D_;
226 std::array<time_type, MAX_ORDER + 2> gamma_;
227 std::array<time_type, MAX_ORDER + 2> alpha_;
228 std::array<time_type, MAX_ORDER + 2> error_const_;
230 void initialize_bdf_coefficients() {
232 std::array<time_type, MAX_ORDER + 1> kappa = {
233 static_cast<time_type
>(0),
234 static_cast<time_type
>(-0.1850),
235 static_cast<time_type
>(-1.0/9.0),
236 static_cast<time_type
>(-0.0823),
237 static_cast<time_type
>(-0.0415),
238 static_cast<time_type
>(0)
242 gamma_[0] =
static_cast<time_type
>(0.0);
243 for (
int k = 1; k <= MAX_ORDER; ++k) {
244 gamma_[k] = gamma_[k-1] +
static_cast<time_type
>(1.0) /
static_cast<time_type
>(k);
248 for (
int k = 0; k <= MAX_ORDER; ++k) {
249 alpha_[k] = (
static_cast<time_type
>(1.0) - kappa[k]) * gamma_[k];
253 for (
int k = 0; k <= MAX_ORDER; ++k) {
254 error_const_[k] = kappa[k] * gamma_[k] +
static_cast<time_type
>(1.0) /
static_cast<time_type
>(k + 1);
259 std::vector<std::vector<time_type>> compute_R(
int order, time_type factor) {
260 std::vector<std::vector<time_type>> M(order + 1, std::vector<time_type>(order + 1,
static_cast<time_type
>(0.0)));
263 for (
int i = 1; i <= order; ++i) {
264 for (
int j = 1; j <= order; ++j) {
265 M[i][j] = (
static_cast<time_type
>(i - 1) - factor *
static_cast<time_type
>(j)) /
static_cast<time_type
>(i);
268 M[0][0] =
static_cast<time_type
>(1.0);
271 std::vector<std::vector<time_type>> R(order + 1, std::vector<time_type>(order + 1,
static_cast<time_type
>(0.0)));
272 for (
int i = 0; i <= order; ++i) {
274 for (
int j = 1; j <= order; ++j) {
275 R[i][j] = R[i][j-1] * M[i][j];
282 void change_D(
int order, time_type factor) {
283 auto R = compute_R(order, factor);
284 auto U = compute_R(order,
static_cast<time_type
>(1.0));
287 std::vector<std::vector<time_type>> RU(order + 1, std::vector<time_type>(order + 1,
static_cast<time_type
>(0.0)));
288 for (
int i = 0; i <= order; ++i) {
289 for (
int j = 0; j <= order; ++j) {
290 for (
int k = 0; k <= order; ++k) {
291 RU[i][j] += R[i][k] * U[k][j];
297 std::vector<state_type> D_new(order + 1);
298 for (
int i = 0; i <= order; ++i) {
300 for (std::size_t k = 0; k < D_[0].size(); ++k) {
301 D_new[i][k] =
static_cast<time_type
>(0.0);
302 for (
int j = 0; j <= order; ++j) {
303 D_new[i][k] += RU[j][i] * D_[j][k];
309 for (
int i = 0; i <= order; ++i) {
314 void initialize_history(
const state_type& y0, time_type dt) {
317 D_.resize(MAX_ORDER + 3);
319 for (
int i = 0; i < MAX_ORDER + 3; ++i) {
322 for (std::size_t j = 0; j < y0.size(); ++j) {
323 D_[i][j] =
static_cast<time_type
>(0.0);
332 this->sys_(this->current_time_, y0, f0);
333 for (std::size_t i = 0; i < y0.size(); ++i) {
334 D_[1][i] = dt * f0[i];
342 void update_history(
const state_type& y_new, time_type dt) {
348 void adjust_order(time_type error_norm,
const state_type& scale) {
350 if (n_equal_steps_ < current_order_ + 1) {
355 time_type error_m_norm = std::numeric_limits<time_type>::infinity();
356 time_type error_p_norm = std::numeric_limits<time_type>::infinity();
358 if (current_order_ > 1) {
360 time_type error_m =
static_cast<time_type
>(0.0);
361 for (std::size_t i = 0; i < D_[0].size(); ++i) {
362 time_type err = error_const_[current_order_ - 1] * D_[current_order_][i] / scale[i];
363 error_m += err * err;
365 error_m_norm = std::sqrt(error_m /
static_cast<time_type
>(D_[0].size()));
368 if (current_order_ < max_order_ && current_order_ + 2 <
static_cast<int>(D_.size())) {
370 time_type error_p =
static_cast<time_type
>(0.0);
371 for (std::size_t i = 0; i < D_[0].size(); ++i) {
372 time_type err = error_const_[current_order_ + 1] * D_[current_order_ + 2][i] / scale[i];
373 error_p += err * err;
375 error_p_norm = std::sqrt(error_p /
static_cast<time_type
>(D_[0].size()));
379 std::array<time_type, 3> error_norms = {error_m_norm, error_norm, error_p_norm};
380 std::array<time_type, 3> factors;
382 for (
int i = 0; i < 3; ++i) {
383 if (error_norms[i] >
static_cast<time_type
>(0) && std::isfinite(error_norms[i])) {
384 factors[i] = std::pow(error_norms[i],
static_cast<time_type
>(-1.0) /
static_cast<time_type
>(current_order_ + i - 1));
386 factors[i] =
static_cast<time_type
>(0.0);
391 int best_order_idx = 1;
392 for (
int i = 0; i < 3; ++i) {
393 if (factors[i] > factors[best_order_idx]) {
398 int delta_order = best_order_idx - 1;
399 int new_order = current_order_ + delta_order;
402 new_order = (new_order < 1) ? 1 : ((new_order > max_order_) ? max_order_ : new_order);
404 if (new_order != current_order_) {
405 current_order_ = new_order;
411 struct NewtonResult {
418 NewtonResult solve_bdf_system(time_type t_new,
const state_type& y_predict,
419 time_type c,
const state_type& psi,
const state_type& scale) {
421 result.converged =
false;
422 result.iterations = 0;
423 result.y = y_predict;
427 for (std::size_t i = 0; i < result.d.size(); ++i) {
428 result.d[i] =
static_cast<time_type
>(0.0);
432 for (
int k = 0; k < NEWTON_MAXITER; ++k) {
433 result.iterations = k + 1;
437 this->sys_(t_new, result.y, f);
440 bool f_finite =
true;
441 for (std::size_t i = 0; i < f.size(); ++i) {
442 if (!std::isfinite(f[i])) {
447 if (!f_finite)
break;
451 for (std::size_t i = 0; i < residual.size(); ++i) {
452 residual[i] = result.d[i] - c * f[i] + psi[i];
456 time_type norm =
static_cast<time_type
>(0.0);
457 for (std::size_t i = 0; i < residual.size(); ++i) {
458 time_type scaled_res = residual[i] / scale[i];
459 norm += scaled_res * scaled_res;
461 norm = std::sqrt(norm /
static_cast<time_type
>(residual.size()));
463 if (norm < newton_tolerance_) {
464 result.converged =
true;
471 for (std::size_t i = 0; i < result.d.size(); ++i) {
473 time_type jac_diag = estimate_jacobian_diagonal(i, result.y, t_new);
474 time_type denominator =
static_cast<time_type
>(1.0) - c * jac_diag;
475 if (std::abs(denominator) >
static_cast<time_type
>(1e-12)) {
476 dd[i] = -residual[i] / denominator;
478 dd[i] = -residual[i];
480 result.d[i] += dd[i];
481 result.y[i] = y_predict[i] + result.d[i];
488 bool bdf_step(
const state_type& y_current, state_type& y_new, state_type& error, time_type dt) {
490 time_type t_new = this->current_time_ + dt;
495 this->sys_(this->current_time_, D_[0], f_current);
496 for (std::size_t i = 0; i < D_[0].size(); ++i) {
497 D_[1][i] = dt * f_current[i];
502 for (std::size_t i = 0; i < y_predict.size(); ++i) {
503 y_predict[i] =
static_cast<time_type
>(0.0);
504 for (
int j = 0; j <= current_order_; ++j) {
505 y_predict[i] += D_[j][i];
511 for (std::size_t i = 0; i < scale.size(); ++i) {
512 scale[i] = this->atol_ + this->rtol_ * std::abs(y_predict[i]);
517 for (std::size_t i = 0; i < psi.size(); ++i) {
518 psi[i] =
static_cast<time_type
>(0.0);
519 for (
int j = 1; j <= current_order_; ++j) {
520 psi[i] += D_[j][i] * gamma_[j];
522 psi[i] /= alpha_[current_order_];
526 time_type c = dt / alpha_[current_order_];
529 auto result = solve_bdf_system(t_new, y_predict, c, psi, scale);
530 if (!result.converged) {
535 for (std::size_t i = 0; i < error.size(); ++i) {
536 error[i] = error_const_[current_order_] * result.d[i];
540 time_type error_norm =
static_cast<time_type
>(0.0);
541 for (std::size_t i = 0; i < error.size(); ++i) {
542 time_type scaled_error = error[i] / scale[i];
543 error_norm += scaled_error * scaled_error;
545 error_norm = std::sqrt(error_norm /
static_cast<time_type
>(error.size()));
547 if (error_norm >
static_cast<time_type
>(1.0)) {
560 if (current_order_ + 2 <
static_cast<int>(D_.size())) {
561 for (std::size_t i = 0; i < result.d.size(); ++i) {
562 D_[current_order_ + 2][i] = result.d[i] - D_[current_order_ + 1][i];
565 D_[current_order_ + 1] = result.d;
568 for (
int i = current_order_; i >= 1; --i) {
569 for (std::size_t j = 0; j < D_[i].size(); ++j) {
570 D_[i][j] += D_[i + 1][j];
577 time_type estimate_jacobian_diagonal(std::size_t i,
const state_type& y, time_type t) {
579 time_type epsilon = (
static_cast<time_type
>(1e-8) > std::abs(y[i]) *
static_cast<time_type
>(1e-8)) ?
static_cast<time_type
>(1e-8) : std::abs(y[i]) *
static_cast<time_type
>(1e-8);
585 this->sys_(t, y, f_orig);
589 y_pert[i] += epsilon;
590 this->sys_(t, y_pert, f_pert);
593 time_type jac = (f_pert[i] - f_orig[i]) / epsilon;
597 return (
static_cast<time_type
>(-100.0) > jac) ?
static_cast<time_type
>(-100.0) : ((jac >
static_cast<time_type
>(100.0)) ?
static_cast<time_type
>(100.0) : jac);
602 time_type fallback_step(state_type& state, time_type dt) {
604 time_type small_dt = (this->dt_min_ *
static_cast<time_type
>(2.0) > dt *
static_cast<time_type
>(0.1)) ? this->dt_min_ *
static_cast<time_type
>(2.0) : dt *
static_cast<time_type
>(0.1);
609 this->sys_(this->current_time_, state, f_current);
611 for (std::size_t i = 0; i < state.size(); ++i) {
612 state[i] = state[i] + small_dt * f_current[i];
616 this->advance_time(small_dt);