use crate::events::event::Event;
use crate::events::methods::EventDetectionMethod;
use crate::events::methods::{
exact_event_detection, left_event_detection, linear_event_detection, right_event_detection,
};
use crate::integrators::integrator_trait::Integrator;
use crate::ode_state::ode_state_trait::OdeState;
pub(crate) fn detect_event<T: OdeState, I: Integrator<T>>(
f: &impl Fn(f64, &T) -> T,
event: &Event<T>,
t_prev: f64,
y_prev: &T,
y_curr: &T,
h: f64,
) -> Option<f64> {
if let Some(c) = &event.c
&& !(c)(t_prev, y_curr)
{
return None;
}
match event.method {
EventDetectionMethod::Exact => {
exact_event_detection::<T, I>(&f, event, t_prev, y_prev, y_curr, h)
}
EventDetectionMethod::LinearInterpolation => {
linear_event_detection::<T>(event, t_prev, y_prev, y_curr, h)
}
EventDetectionMethod::LeftInterpolation => {
left_event_detection::<T>(event, t_prev, y_prev, y_curr, h)
}
EventDetectionMethod::RightInterpolation => {
right_event_detection::<T>(event, t_prev, y_prev, y_curr, h)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RK4;
use numtest::*;
#[test]
fn test_detect_event_active() {
let event = Event::new(|t: f64, _y: &f64| t - 0.5);
let f = |_t: f64, y: &f64| *y;
let t_prev = 0.0;
let y_prev = 0.0;
let y_curr: f64 = 1.0;
let h = 1.0;
let h_event = detect_event::<f64, RK4>(&f, &event, t_prev, &y_prev, &y_curr, h).unwrap();
assert_equal_to_decimal!(h_event, 0.5, 15);
}
#[test]
fn test_detect_event_inactive() {
let g = |t: f64, _y: &f64| t - 0.5;
let c = |_t: f64, y: &f64| *y > 10.0;
let event = Event::new(g).c(c);
let f = |_t: f64, y: &f64| *y;
let t_prev = 0.0;
let y_prev = 0.0;
let y_curr: f64 = 1.0;
let h = 1.0;
let h_event = detect_event::<f64, RK4>(&f, &event, t_prev, &y_prev, &y_curr, h);
assert!(h_event.is_none());
}
}