use super::*;
pub struct TEvalSolout<T: Real> {
t_evals: Vec<T>,
next_eval_idx: usize,
integration_direction: T,
}
impl<T, Y> Solout<T, Y> for TEvalSolout<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 mut idx = self.next_eval_idx;
while idx < self.t_evals.len() {
let t_eval = self.t_evals[idx];
let in_range = if self.integration_direction > T::zero() {
(t_eval == t_prev && idx == 0) || (t_eval > t_prev && t_eval <= t_curr)
} else {
(t_eval == t_prev && idx == 0) || (t_eval < t_prev && t_eval >= t_curr)
};
if in_range {
if t_eval == t_curr {
solution.push(t_eval, *y_curr);
} else {
let y_eval = interpolator.interpolate(t_eval).unwrap();
solution.push(t_eval, y_eval);
}
idx += 1;
} else {
if (self.integration_direction > T::zero() && t_eval > t_curr)
|| (self.integration_direction < T::zero() && t_eval < t_curr)
{
break;
}
idx += 1;
}
}
self.next_eval_idx = idx;
ControlFlag::Continue
}
}
impl<T: Real> TEvalSolout<T> {
pub fn new(t_evals: impl AsRef<[T]>, t0: T, tf: T) -> Self {
let integration_direction = (tf - t0).signum();
let mut sorted_t_evals: Vec<T> = t_evals.as_ref().to_vec();
if integration_direction > T::zero() {
sorted_t_evals.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
} else {
sorted_t_evals.sort_by(|a, b| b.partial_cmp(a).unwrap_or(std::cmp::Ordering::Equal));
}
TEvalSolout {
t_evals: sorted_t_evals,
next_eval_idx: 0,
integration_direction,
}
}
}