use crate::events::event::Event;
use crate::events::event_detection::detect_event;
use crate::integrators::integrator_trait::Integrator;
use crate::ode_state::ode_state_trait::OdeState;
use std::ops::Index;
pub struct EventManager<'a, T: OdeState> {
events: Vec<&'a Event<T>>,
pub(crate) num_detections: Vec<usize>,
t_located: Vec<Vec<f64>>,
y_located: Vec<Vec<T>>,
}
impl<'a, T: OdeState> Index<usize> for EventManager<'a, T> {
type Output = Event<T>;
fn index(&self, index: usize) -> &Self::Output {
self.events[index]
}
}
impl<'a, T: OdeState + 'static> EventManager<'a, T> {
pub fn new(events: Vec<&'a Event<T>>) -> EventManager<'a, T> {
let num_events = events.len();
EventManager {
events,
num_detections: vec![0; num_events],
t_located: vec![vec![]; num_events],
y_located: vec![vec![]; num_events],
}
}
}
impl<T: OdeState + 'static> EventManager<'_, T> {
pub(crate) fn detect_events<I: Integrator<T>>(
&mut self,
f: &impl Fn(f64, &T) -> T,
t_prev: f64,
y_prev: &T,
y_curr: &T,
h: f64,
) -> (Option<usize>, Option<f64>) {
let mut h_events: Vec<Option<f64>> = vec![];
let events_fresh = &mut *self.events;
for event in events_fresh {
h_events.push(detect_event::<T, I>(f, event, t_prev, y_prev, y_curr, h));
}
let (idx_event, h_event) = identify_first_event(&h_events);
if let Some(idx_event) = idx_event {
self.num_detections[idx_event] += 1;
}
(idx_event, h_event)
}
pub(crate) fn store(&mut self, t: f64, y: &T, idx_event: usize) {
self.t_located[idx_event].push(t);
self.y_located[idx_event].push(y.clone());
}
}
fn identify_first_event(h_events: &[Option<f64>]) -> (Option<usize>, Option<f64>) {
let mut idx_min: Option<usize> = None;
let mut h_min = None;
for (idx, h) in h_events.iter().enumerate() {
if h.is_none() {
continue;
}
let h = *h.as_ref().unwrap();
if h_min.is_none() || h < h_min.unwrap() {
idx_min = Some(idx);
h_min = Some(h);
}
}
(idx_min, h_min)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::RK4;
use numtest::*;
#[test]
fn test_new() {
let event_1 = Event::new(|t: f64, y: &f64| y * t);
let event_2 = Event::new(|t: f64, y: &f64| y / t);
let event_manager = EventManager::new(vec![&event_1, &event_2]);
assert_eq!(event_manager.events.len(), 2);
assert_eq!(event_manager[0].name, "");
assert_eq!(event_manager[1].name, "");
}
#[test]
fn test_detect_events_both_events_detected() {
let event_1 = Event::new(|t: f64, _y: &f64| t - 0.5);
let event_2 = Event::new(|t: f64, _y: &f64| t - 0.25);
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 mut event_manager = EventManager::new(vec![&event_1, &event_2]);
let (idx_event, h_event) =
event_manager.detect_events::<RK4>(&f, t_prev, &y_prev, &y_curr, h);
let idx_event = idx_event.unwrap();
assert_eq!(idx_event, 1);
assert_equal_to_decimal!(h_event.unwrap(), 0.25, 15);
assert_eq!(event_manager.num_detections[idx_event], 1);
}
#[test]
fn test_store() {
let g = |t: f64, y: &f64| y * t;
let event = Event::new(g);
let mut event_manager = EventManager::new(vec![&event]);
assert_eq!(event_manager.t_located[0], vec![]);
assert_eq!(event_manager.y_located[0], vec![]);
event_manager.store(0.5, &1.5, 0);
assert_eq!(event_manager.t_located[0], vec![0.5]);
assert_eq!(event_manager.y_located[0], vec![1.5]);
event_manager.store(1.0, &5.0, 0);
assert_eq!(event_manager.t_located[0], vec![0.5, 1.0]);
assert_eq!(event_manager.y_located[0], vec![1.5, 5.0]);
}
#[test]
fn test_identify_first_event_1() {
let (idx_event, h_event) = identify_first_event(&[None]);
assert!(idx_event.is_none());
assert!(h_event.is_none());
}
#[test]
fn test_identify_first_event_2() {
let (idx_event, h_event) = identify_first_event(&[Some(1.0)]);
assert_eq!(idx_event, Some(0));
assert_eq!(h_event, Some(1.0));
}
#[test]
fn test_identify_first_event_3() {
let (idx_event, h_event) = identify_first_event(&[None, Some(1.0)]);
assert_eq!(idx_event, Some(1));
assert_eq!(h_event, Some(1.0));
}
#[test]
fn test_identify_first_event_4() {
let (idx_event, h_event) = identify_first_event(&[Some(1.0), None]);
assert_eq!(idx_event, Some(0));
assert_eq!(h_event, Some(1.0));
}
#[test]
fn test_identify_first_event_5() {
let (idx_event, h_event) = identify_first_event(&[Some(1.0), None, Some(0.5)]);
assert_eq!(idx_event, Some(2));
assert_eq!(h_event, Some(0.5));
}
}