use crate::{
ode_solver::problem::OdeSolverSolution, scalar::scale, DenseMatrix, OdeBuilder, OdeEquations,
OdeSolverProblem, Vector,
};
use nalgebra::ComplexField;
use num_traits::{One, Zero};
use std::ops::MulAssign;
#[allow(unused_mut)]
fn exponential_decay_with_algebraic<M: DenseMatrix>(
x: &M::V,
p: &M::V,
_t: M::T,
mut y: &mut M::V,
) {
y.copy_from(x);
y.mul_assign(scale(-p[0]));
let nstates = y.len();
y[nstates - 1] = x[nstates - 1] - x[nstates - 2];
}
#[allow(unused_mut)]
fn exponential_decay_with_algebraic_sens<M: DenseMatrix>(
x: &M::V,
_p: &M::V,
_t: M::T,
v: &M::V,
mut y: &mut M::V,
) {
y.copy_from(x);
y.mul_assign(scale(-v[0]));
let nstates = y.len();
y[nstates - 1] = M::T::zero();
}
#[allow(unused_mut)]
fn exponential_decay_with_algebraic_jacobian<M: DenseMatrix>(
_x: &M::V,
p: &M::V,
_t: M::T,
v: &M::V,
mut y: &mut M::V,
) {
y.copy_from(v);
y.mul_assign(scale(-p[0]));
let nstates = y.len();
y[nstates - 1] = v[nstates - 1] - v[nstates - 2];
}
fn exponential_decay_with_algebraic_mass<M: DenseMatrix>(
x: &M::V,
_p: &M::V,
_t: M::T,
beta: M::T,
y: &mut M::V,
) {
let nstates = y.len();
let yn = beta * y[nstates - 1];
y.axpy(M::T::one(), x, beta);
y[nstates - 1] = yn;
}
fn exponential_decay_with_algebraic_mass_sens<M: DenseMatrix>(
_x: &M::V,
_p: &M::V,
_t: M::T,
_v: &M::V,
y: &mut M::V,
) {
y.fill(M::T::zero());
}
fn exponential_decay_with_algebraic_init<M: DenseMatrix>(_p: &M::V, _t: M::T) -> M::V {
M::V::from_vec(vec![1.0.into(), 1.0.into(), 0.0.into()])
}
fn exponential_decay_with_algebraic_init_sens<M: DenseMatrix>(
_p: &M::V,
_t: M::T,
_v: &M::V,
y: &mut M::V,
) {
y.fill(M::T::zero());
}
pub fn exponential_decay_with_algebraic_problem<M: DenseMatrix + 'static>(
use_coloring: bool,
) -> (
OdeSolverProblem<impl OdeEquations<M = M, V = M::V, T = M::T>>,
OdeSolverSolution<M::V>,
) {
let p = M::V::from_vec(vec![0.1.into()]);
let problem = OdeBuilder::new()
.p([0.1])
.use_coloring(use_coloring)
.build_ode_with_mass(
exponential_decay_with_algebraic::<M>,
exponential_decay_with_algebraic_jacobian::<M>,
exponential_decay_with_algebraic_mass::<M>,
exponential_decay_with_algebraic_init::<M>,
)
.unwrap();
let mut soln = OdeSolverSolution::default();
for i in 0..10 {
let t = M::T::from(i as f64 / 10.0);
let y0 = M::V::from_vec(vec![1.0.into(), 1.0.into(), 1.0.into()]);
let y: M::V = y0 * scale(M::T::exp(-p[0] * t));
soln.push(y, t);
}
(problem, soln)
}
pub fn exponential_decay_with_algebraic_problem_sens<M: DenseMatrix + 'static>(
use_coloring: bool,
) -> (
OdeSolverProblem<impl OdeEquations<M = M, V = M::V, T = M::T>>,
OdeSolverSolution<M::V>,
) {
let p = M::V::from_vec(vec![0.1.into()]);
let problem = OdeBuilder::new()
.p([0.1])
.use_coloring(use_coloring)
.sensitivities_error_control(true)
.build_ode_with_mass_and_sens(
exponential_decay_with_algebraic::<M>,
exponential_decay_with_algebraic_jacobian::<M>,
exponential_decay_with_algebraic_sens::<M>,
exponential_decay_with_algebraic_mass::<M>,
exponential_decay_with_algebraic_mass_sens::<M>,
exponential_decay_with_algebraic_init::<M>,
exponential_decay_with_algebraic_init_sens::<M>,
)
.unwrap();
let mut soln = OdeSolverSolution::default();
for i in 0..10 {
let t = M::T::from(i as f64 / 10.0);
let y0 = M::V::from_vec(vec![1.0.into(), 1.0.into(), 1.0.into()]);
let y: M::V = y0.clone() * scale(M::T::exp(-p[0] * t));
let yp = y0 * scale(-t * M::T::exp(-p[0] * t));
soln.push_sens(y, t, &[yp]);
}
(problem, soln)
}