use crate::{
error::Error,
interpolate::Interpolation,
ode::{ODE, OrdinaryNumericalMethod, solve_ode},
solout::*,
solution::Solution,
traits::{Real, State},
};
#[derive(Clone, Debug)]
pub struct ODEProblem<'a, T, Y, F>
where
T: Real,
Y: State<T>,
F: ODE<T, Y>,
{
pub ode: &'a F,
pub t0: T,
pub tf: T,
pub y0: Y,
}
impl<'a, T, Y, F> ODEProblem<'a, T, Y, F>
where
T: Real,
Y: State<T>,
F: ODE<T, Y>,
{
pub fn new(ode: &'a F, t0: T, tf: T, y0: Y) -> Self {
ODEProblem { ode, t0, tf, y0 }
}
pub fn solve<S>(&self, solver: &mut S) -> Result<Solution<T, Y>, Error<T, Y>>
where
S: OrdinaryNumericalMethod<T, Y> + Interpolation<T, Y>,
{
let mut default_solout = DefaultSolout::new();
solve_ode(
solver,
self.ode,
self.t0,
self.tf,
&self.y0,
&mut default_solout,
)
}
pub fn solout<O: Solout<T, Y>>(
&'a self,
solout: &'a mut O,
) -> ODEProblemMutRefSoloutPair<'a, T, Y, F, O> {
ODEProblemMutRefSoloutPair::new(self, solout)
}
pub fn even(&self, dt: T) -> ODEProblemSoloutPair<'_, T, Y, F, EvenSolout<T>> {
let even_solout = EvenSolout::new(dt, self.t0, self.tf);
ODEProblemSoloutPair::new(self, even_solout)
}
pub fn dense(&self, n: usize) -> ODEProblemSoloutPair<'_, T, Y, F, DenseSolout> {
let dense_solout = DenseSolout::new(n);
ODEProblemSoloutPair::new(self, dense_solout)
}
pub fn t_eval(
&self,
points: impl AsRef<[T]>,
) -> ODEProblemSoloutPair<'_, T, Y, F, TEvalSolout<T>> {
let t_eval_solout = TEvalSolout::new(points, self.t0, self.tf);
ODEProblemSoloutPair::new(self, t_eval_solout)
}
pub fn crossing(
&self,
component_idx: usize,
threshhold: T,
direction: CrossingDirection,
) -> ODEProblemSoloutPair<'_, T, Y, F, CrossingSolout<T>> {
let crossing_solout =
CrossingSolout::new(component_idx, threshhold).with_direction(direction);
ODEProblemSoloutPair::new(self, crossing_solout)
}
pub fn hyperplane_crossing<Y1>(
&self,
point: Y1,
normal: Y1,
extractor: fn(&Y) -> Y1,
direction: CrossingDirection,
) -> ODEProblemSoloutPair<'_, T, Y, F, HyperplaneCrossingSolout<T, Y1, Y>>
where
Y1: State<T>,
{
let solout =
HyperplaneCrossingSolout::new(point, normal, extractor).with_direction(direction);
ODEProblemSoloutPair::new(self, solout)
}
pub fn event<E>(
&'a self,
event: &'a E,
) -> ODEProblemSoloutPair<'a, T, Y, F, EventSolout<'a, T, Y, E>>
where
E: Event<T, Y>,
{
let solout = EventSolout::new(event, self.t0, self.tf);
ODEProblemSoloutPair::new(self, solout)
}
}
pub struct ODEProblemMutRefSoloutPair<'a, T, Y, F, O>
where
T: Real,
Y: State<T>,
F: ODE<T, Y>,
O: Solout<T, Y>,
{
pub problem: &'a ODEProblem<'a, T, Y, F>,
pub solout: &'a mut O,
}
impl<'a, T, Y, F, O> ODEProblemMutRefSoloutPair<'a, T, Y, F, O>
where
T: Real,
Y: State<T>,
F: ODE<T, Y>,
O: Solout<T, Y>,
{
pub fn new(problem: &'a ODEProblem<T, Y, F>, solout: &'a mut O) -> Self {
ODEProblemMutRefSoloutPair { problem, solout }
}
pub fn solve<S>(&mut self, solver: &mut S) -> Result<Solution<T, Y>, Error<T, Y>>
where
S: OrdinaryNumericalMethod<T, Y> + Interpolation<T, Y>,
{
solve_ode(
solver,
self.problem.ode,
self.problem.t0,
self.problem.tf,
&self.problem.y0,
self.solout,
)
}
}
#[derive(Clone, Debug)]
pub struct ODEProblemSoloutPair<'a, T, Y, F, O>
where
T: Real,
Y: State<T>,
F: ODE<T, Y>,
O: Solout<T, Y>,
{
pub problem: &'a ODEProblem<'a, T, Y, F>,
pub solout: O,
}
impl<'a, T, Y, F, O> ODEProblemSoloutPair<'a, T, Y, F, O>
where
T: Real,
Y: State<T>,
F: ODE<T, Y>,
O: Solout<T, Y>,
{
pub fn new(problem: &'a ODEProblem<T, Y, F>, solout: O) -> Self {
ODEProblemSoloutPair { problem, solout }
}
pub fn solve<S>(mut self, solver: &mut S) -> Result<Solution<T, Y>, Error<T, Y>>
where
S: OrdinaryNumericalMethod<T, Y> + Interpolation<T, Y>,
{
solve_ode(
solver,
self.problem.ode,
self.problem.t0,
self.problem.tf,
&self.problem.y0,
&mut self.solout,
)
}
pub fn event<E>(
self,
event: &'a E,
) -> ODEProblemSoloutPair<'a, T, Y, F, EventWrappedSolout<'a, T, Y, O, E>>
where
E: Event<T, Y>,
{
let wrapped = EventWrappedSolout::new(self.solout, event, self.problem.t0, self.problem.tf);
ODEProblemSoloutPair {
problem: self.problem,
solout: wrapped,
}
}
}