use super::*;
pub struct EvenSolout<T: Real> {
dt: T,
t0: T,
tf: T,
direction: T,
last_output_t: Option<T>,
}
impl<T, Y> Solout<T, Y> for EvenSolout<T>
where
T: Real,
Y: State<T>,
{
fn solout<I>(
&mut self,
t_curr: T,
t_prev: T,
y_curr: &Y,
y_prev: &Y,
interpolator: &mut I,
solution: &mut Solution<T, Y>,
) -> ControlFlag<T, Y>
where
I: Interpolation<T, Y>,
{
let offset = self.t0 % self.dt;
let tol = self.dt.abs() * T::from_f64(1e-12).unwrap_or(T::default_epsilon())
+ T::default_epsilon() * T::from_f64(10.0).unwrap_or(T::one());
let start_t = match self.last_output_t {
Some(t) => t + self.dt * self.direction,
None => {
if (t_prev - self.t0).abs() < T::default_epsilon() {
solution.push(self.t0, *y_prev);
self.last_output_t = Some(self.t0);
self.t0 + self.dt * self.direction
} else {
let rem = (t_prev - offset) % self.dt;
if self.direction > T::zero() {
if rem.abs() < T::default_epsilon() {
t_prev
} else {
t_prev + (self.dt - rem)
}
} else {
if rem.abs() < T::default_epsilon() {
t_prev
} else {
t_prev - rem
}
}
}
}
};
let mut ti = start_t;
while (self.direction > T::zero() && ti <= t_curr)
|| (self.direction < T::zero() && ti >= t_curr)
{
if (self.direction > T::zero() && ti >= t_prev && ti <= t_curr)
|| (self.direction < T::zero() && ti <= t_prev && ti >= t_curr)
{
if self
.last_output_t
.map(|t_last| (ti - t_last).abs() <= tol)
.unwrap_or(false)
{
} else {
let yi = interpolator.interpolate(ti).unwrap();
solution.push(ti, yi);
self.last_output_t = Some(ti);
}
}
ti += self.dt * self.direction;
}
if t_curr == self.tf {
match self.last_output_t {
Some(t_last) => {
if (t_last - self.tf).abs() <= tol {
let _ = solution.pop();
solution.push(self.tf, *y_curr);
self.last_output_t = Some(self.tf);
} else if t_last != self.tf {
solution.push(self.tf, *y_curr);
self.last_output_t = Some(self.tf);
}
}
None => {
solution.push(self.tf, *y_curr);
self.last_output_t = Some(self.tf);
}
}
}
ControlFlag::Continue
}
}
impl<T: Real> EvenSolout<T> {
pub fn new(dt: T, t0: T, tf: T) -> Self {
EvenSolout {
dt,
t0,
tf,
direction: (tf - t0).signum(),
last_output_t: None,
}
}
}