Skip to content

Commit 333cab7

Browse files
committed
parameters default to be those values of classical FORTRAN implementation
1 parent c6a421b commit 333cab7

File tree

1 file changed

+49
-17
lines changed

1 file changed

+49
-17
lines changed

include/integrators/ode/dop853.hpp

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,44 @@ class DOP853DenseOutputHelper {
4949
template<system_state S, can_be_time T = double>
5050
class DOP853Integrator : public AdaptiveIntegrator<S, T> {
5151

52+
5253
public:
5354
using base_type = AdaptiveIntegrator<S, T>;
5455
using state_type = typename base_type::state_type;
5556
using time_type = typename base_type::time_type;
5657
using value_type = typename base_type::value_type;
5758
using system_function = typename base_type::system_function;
5859

60+
// Fortran default parameters (do not change unless you know what you are doing)
61+
static constexpr time_type fortran_safety = static_cast<time_type>(0.9); // SAFE
62+
static constexpr time_type fortran_fac1 = static_cast<time_type>(0.333); // FAC1
63+
static constexpr time_type fortran_fac2 = static_cast<time_type>(6.0); // FAC2
64+
static constexpr time_type fortran_beta = static_cast<time_type>(0.0); // BETA
65+
static constexpr time_type fortran_dt_max = static_cast<time_type>(1e100); // HMAX
66+
static constexpr time_type fortran_dt_min = static_cast<time_type>(1e-16); // practical min
67+
static constexpr int fortran_nmax = 100000; // NMAX
68+
static constexpr int fortran_nstiff = 1000; // NSTIFF
69+
70+
// Internal state (Fortran default values)
71+
time_type safety_factor_ = fortran_safety;
72+
time_type fac1_ = fortran_fac1;
73+
time_type fac2_ = fortran_fac2;
74+
time_type beta_ = fortran_beta;
75+
time_type dt_max_ = fortran_dt_max;
76+
time_type dt_min_ = fortran_dt_min;
77+
int nmax_ = fortran_nmax;
78+
int nstiff_ = fortran_nstiff;
79+
time_type facold_ = static_cast<time_type>(1e-4); // Fortran FACOLD
80+
// Stiffness detection state
81+
int iastiff_ = 0;
82+
int nonsti_ = 0;
83+
time_type hlamb_ = 0;
84+
// For statistics (optional)
85+
int nstep_ = 0;
86+
int naccpt_ = 0;
87+
int nrejct_ = 0;
88+
int nfcn_ = 0;
89+
5990
// Step size control parameters (modern C++ style, with defaults)
6091
time_type safety_factor_ = static_cast<time_type>(0.9); // Fortran SAFE
6192
time_type fac1_ = static_cast<time_type>(0.333); // Fortran FAC1 (min step size factor)
@@ -133,18 +164,8 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
133164
public:
134165
explicit DOP853Integrator(system_function sys,
135166
time_type rtol = static_cast<time_type>(1e-8),
136-
time_type atol = static_cast<time_type>(1e-10),
137-
time_type safety = static_cast<time_type>(0.9),
138-
time_type fac1 = static_cast<time_type>(0.333),
139-
time_type fac2 = static_cast<time_type>(6.0),
140-
time_type beta = static_cast<time_type>(0.0),
141-
time_type dt_max = static_cast<time_type>(1e100),
142-
time_type dt_min = static_cast<time_type>(1e-16),
143-
int nmax = 100000,
144-
int nstiff = 1000)
145-
: base_type(std::move(sys), rtol, atol),
146-
safety_factor_(safety), fac1_(fac1), fac2_(fac2), beta_(beta),
147-
dt_max_(dt_max), dt_min_(dt_min), nmax_(nmax), nstiff_(nstiff) {}
167+
time_type atol = static_cast<time_type>(1e-10))
168+
: base_type(std::move(sys), rtol, atol) {}
148169

149170
void step(state_type& state, time_type dt) override {
150171
adaptive_step(state, dt);
@@ -172,17 +193,29 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
172193
state_type error = StateCreator<state_type>::create(state);
173194
dop853_step(state, y_new, error, current_dt);
174195
nfcn_ += 12; // 12 stages per step
175-
time_type err_norm = this->error_norm(error, y_new);
196+
197+
// Fortran error norm (ERR, ERR2, DENO, etc.)
198+
time_type err = 0.0, err2 = 0.0;
199+
for (std::size_t i = 0; i < state.size(); ++i) {
200+
time_type sk = this->atol_ + this->rtol_ * std::max(std::abs(state[i]), std::abs(y_new[i]));
201+
// Fortran: ERRI=K4(I)-BHH1*K1(I)-BHH2*K9(I)-BHH3*K3(I) (here, error[i] is 8th-5th order diff)
202+
// We use error[i] as the embedded error estimate, so for full Fortran, you may need to store all k's
203+
err2 += (error[i] / sk) * (error[i] / sk); // proxy for Fortran's ERR2
204+
err += (error[i] / sk) * (error[i] / sk); // Fortran's ERR
205+
}
206+
time_type deno = err + 0.01 * err2;
207+
if (deno <= 0.0) deno = 1.0;
208+
err = std::abs(current_dt) * err * std::sqrt(1.0 / (state.size() * deno));
176209

177210
// Fortran: FAC11 = ERR**EXPO1, FAC = FAC11 / FACOLD**BETA
178211
time_type expo1 = 1.0 / 8.0 - beta_ * 0.2;
179-
time_type fac11 = std::pow(std::max(err_norm, 1e-16), expo1);
212+
time_type fac11 = std::pow(std::max(err, 1e-16), expo1);
180213
time_type fac = fac11 / std::pow(facold_, beta_);
181214
fac = std::max(fac2_, std::min(fac1_, fac / safety_factor_));
182215
time_type next_dt = current_dt / fac;
183216

184-
if (err_norm <= 1.0) {
185-
facold_ = std::max(err_norm, static_cast<time_type>(1e-4));
217+
if (err <= 1.0) {
218+
facold_ = std::max(err, static_cast<time_type>(1e-4));
186219
naccpt_++;
187220
nstep_++;
188221
state = y_new;
@@ -192,7 +225,6 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
192225
// Compute HLAMB = |h| * sqrt(stnum / stden)
193226
time_type stnum = 0, stden = 0;
194227
for (std::size_t i = 0; i < state.size(); ++i) {
195-
// Use error and state difference as proxy (not exact Fortran, but close)
196228
stnum += (error[i]) * (error[i]);
197229
stden += (y_new[i] - state[i]) * (y_new[i] - state[i]);
198230
}

0 commit comments

Comments
 (0)