use core::ops::ControlFlow;
use crate::{DynamicalSystem, IntegrationError, IntegrationOutcome, OdeState};
pub trait Integrator {
fn step<S: DynamicalSystem>(&self, system: &S, t: f64, state: &S::State, dt: f64) -> S::State;
fn integrate<S, F>(
&self,
system: &S,
initial: S::State,
t0: f64,
t_end: f64,
dt: f64,
mut callback: F,
) -> S::State
where
S: DynamicalSystem,
F: FnMut(f64, &S::State),
{
let mut state = initial;
let mut t = t0;
while t < t_end {
let h = dt.min(t_end - t);
state = self.step(system, t, &state, h);
t += h;
callback(t, &state);
}
state
}
#[allow(clippy::too_many_arguments)]
fn integrate_with_events<S, F, E, B>(
&self,
system: &S,
initial: S::State,
t0: f64,
t_end: f64,
dt: f64,
mut callback: F,
event_check: E,
) -> IntegrationOutcome<S::State, B>
where
S: DynamicalSystem,
F: FnMut(f64, &S::State),
E: Fn(f64, &S::State) -> ControlFlow<B>,
{
let mut state = initial;
let mut t = t0;
while t < t_end {
let h = dt.min(t_end - t);
state = self.step(system, t, &state, h);
t += h;
if !state.is_finite() {
return IntegrationOutcome::Error(IntegrationError::NonFiniteState { t });
}
callback(t, &state);
if let ControlFlow::Break(reason) = event_check(t, &state) {
return IntegrationOutcome::Terminated { state, t, reason };
}
}
IntegrationOutcome::Completed(state)
}
}