44#include < integrators/ode/dop853_coefficients.hpp>
55#include < cmath>
66#include < stdexcept>
7- #include < iostream>
87
98namespace diffeq ::integrators::ode {
109
@@ -90,6 +89,38 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
9089 int nfcn_ = 0 ;
9190
9291private:
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) {
94+ // Check for NaN/Inf in all vectors and scalars
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]));
98+ }
99+ }
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]));
103+ }
104+ }
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]));
108+ }
109+ }
110+ if (std::isnan (dt) || std::isinf (dt)) {
111+ throw std::runtime_error (" DOP853: NaN/Inf detected in " + context + " dt=" + std::to_string (dt));
112+ }
113+ if (std::isnan (err) || std::isinf (err)) {
114+ throw std::runtime_error (" DOP853: NaN/Inf detected in " + context + " err=" + std::to_string (err));
115+ }
116+ if (std::isnan (err2) || std::isinf (err2)) {
117+ throw std::runtime_error (" DOP853: NaN/Inf detected in " + context + " err2=" + std::to_string (err2));
118+ }
119+ if (std::isnan (deno) || std::isinf (deno)) {
120+ throw std::runtime_error (" DOP853: NaN/Inf detected in " + context + " deno=" + std::to_string (deno));
121+ }
122+ }
123+
93124 // Compute a good initial step size (HINIT from Fortran)
94125 time_type compute_initial_step (const state_type& y, time_type t, const system_function& sys, time_type t_end) const {
95126 // Compute f0 = f(t, y)
@@ -166,17 +197,18 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
166197 current_dt = compute_initial_step (state, t, this ->sys_ , t_end);
167198 // Clamp to allowed min/max
168199 current_dt = std::max (dt_min_, std::min (dt_max_, current_dt));
169- std::cout << " [DOP853 DEBUG] Initial step computed: dt=" << current_dt << std::endl;
170200 }
171201 int attempt = 0 ;
172202 for (; attempt < nmax_; ++attempt) {
173- std::cout << " [DOP853 DEBUG] Step " << attempt << " : t=" << t << " , dt=" << current_dt << std::endl;
174203
175204 state_type y_new = StateCreator<state_type>::create (state);
176205 state_type error = StateCreator<state_type>::create (state);
177206 dop853_step (state, y_new, error, current_dt);
178207 nfcn_ += 12 ; // 12 stages per step
179208
209+ // Check for NaN/Inf in step computation
210+ check_nan_inf (" step_computation" , state, y_new, error, current_dt, 0.0 , 0.0 , 0.0 );
211+
180212 // Fortran error norm (ERR, ERR2, DENO, etc.)
181213 time_type err = 0.0 , err2 = 0.0 ;
182214 for (std::size_t i = 0 ; i < state.size (); ++i) {
@@ -188,17 +220,15 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
188220 }
189221 time_type deno = err + 0.01 * err2;
190222 if (deno <= 0.0 || std::isnan (deno) || std::isinf (deno)) {
191- std::cout << " [DOP853 DEBUG] WARNING: Invalid deno in error norm: " << deno << " , setting to 1.0" << std::endl;
192223 deno = 1.0 ;
193224 }
194225 err = std::abs (current_dt) * err * std::sqrt (1.0 / (state.size () * deno));
195226 if (std::isnan (err) || std::isinf (err)) {
196- std::cout << " [DOP853 DEBUG] WARNING: Invalid err in error norm: " << err << " , setting to 1.0" << std::endl;
197227 err = 1.0 ;
198228 }
199229
200- std::cout << " [DOP853 DEBUG] Error norms: err= " << err << " , err2= " << err2 << " , deno= " << deno << std::endl;
201- std::cout << " [DOP853 DEBUG] Final error: " << err << " (target: 1.0) " << std::endl ;
230+ // Check for NaN/Inf in error norm calculation
231+ check_nan_inf ( " error_norm " , state, y_new, error, current_dt, err, err2, deno) ;
202232
203233 // Fortran: FAC11 = ERR**EXPO1, FAC = FAC11 / FACOLD**BETA
204234 time_type expo1 = 1.0 / 8.0 - beta_ * 0.2 ;
@@ -207,25 +237,20 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
207237 // Clamp fac between fac1_ (min, <1) and fac2_ (max, >1)
208238 fac = std::min (fac2_, std::max (fac1_, fac / safety_factor_));
209239 if (std::isnan (fac) || std::isinf (fac)) {
210- std::cout << " [DOP853 DEBUG] WARNING: Invalid fac in step control: " << fac << " , setting to 1.0" << std::endl;
211240 fac = 1.0 ;
212241 }
213242 time_type next_dt = current_dt / fac;
214243 if (next_dt <= 0.0 || std::isnan (next_dt) || std::isinf (next_dt)) {
215- std::cout << " [DOP853 DEBUG] WARNING: Invalid next_dt: " << next_dt << " , setting to dt_min_=" << dt_min_ << std::endl;
216244 next_dt = dt_min_;
217245 }
218246
219- std::cout << " [DOP853 DEBUG] Step control: expo1=" << expo1 << " , fac11=" << fac11 << " , fac=" << fac << std::endl;
220- std::cout << " [DOP853 DEBUG] Next dt: " << next_dt << " (current: " << current_dt << " )" << std::endl;
221-
222247 if (err <= 1.0 ) {
223- std::cout << " [DOP853 DEBUG] Step ACCEPTED" << std::endl;
224248 facold_ = std::max (err, static_cast <time_type>(1e-4 ));
225249 naccpt_++;
226250 nstep_++;
227251 state = y_new;
228252 this ->advance_time (current_dt);
253+
229254 // stiffness detection (Fortran HLAMB)
230255 if (nstiff_ > 0 && (naccpt_ % nstiff_ == 0 || iastiff_ > 0 )) {
231256 // Compute HLAMB = |h| * sqrt(stnum / stden)
@@ -248,29 +273,13 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
248273 }
249274 // Clamp next step size
250275 next_dt = std::max (dt_min_, std::min (dt_max_, next_dt));
251- std::cout << " [DOP853 DEBUG] Final next dt: " << next_dt << std::endl;
252- // Accept and return next step size
253276 return next_dt;
254277 } else {
255278 // Step rejected
256- std::cout << " [DOP853 DEBUG] Step REJECTED" << std::endl;
257279 nrejct_++;
258280 nstep_++;
259281 next_dt = current_dt / std::min (fac1_, fac11 / safety_factor_);
260282 current_dt = std::max (dt_min_, next_dt);
261- std::cout << " [DOP853 DEBUG] New dt after rejection: " << current_dt << std::endl;
262-
263- // Check if step size is too small
264- if (current_dt <= dt_min_) {
265- std::cout << " [DOP853 DEBUG] WARNING: Step size at minimum (" << dt_min_ << " )" << std::endl;
266- std::cout << " [DOP853 DEBUG] Error was " << err << " (needs to be <= 1.0)" << std::endl;
267- std::cout << " [DOP853 DEBUG] Current state: " ;
268- for (std::size_t i = 0 ; i < std::min (state.size (), size_t (3 )); ++i) {
269- std::cout << state[i] << " " ;
270- }
271- if (state.size () > 3 ) std::cout << " ..." ;
272- std::cout << std::endl;
273- }
274283 }
275284 }
276285 throw std::runtime_error (" DOP853: Maximum number of step size reductions or steps exceeded" );
@@ -356,12 +365,6 @@ class DOP853Integrator : public AdaptiveIntegrator<S, T> {
356365 for (std::size_t i = 0 ; i < y.size (); ++i) {
357366 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]);
358367 }
359-
360- // Debug output for error estimation
361- if (y.size () > 0 ) {
362- std::cout << " [DOP853 DEBUG] Error estimate sample: error[0]=" << error[0 ] << " , y[0]=" << y[0 ] << " , y_new[0]=" << y_new[0 ] << std::endl;
363- std::cout << " [DOP853 DEBUG] E5 coefficients used: " << get_e5 (0 ) << " , " << get_e5 (5 ) << " , " << get_e5 (6 ) << " , " << get_e5 (7 ) << " , " << get_e5 (8 ) << " , " << get_e5 (9 ) << " , " << get_e5 (10 ) << " , " << get_e5 (11 ) << std::endl;
364- }
365368 }
366369};
367370
0 commit comments