catlog/stdlib/analyses/ode/
mod.rs1use std::collections::HashMap;
4
5use derivative::Derivative;
6use derive_more::Constructor;
7use indexmap::IndexMap;
8use ode_solvers::dop_shared::IntegrationError;
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12#[cfg(feature = "serde-wasm")]
13use tsify::Tsify;
14
15use crate::simulate::ode::{ODEProblem, ODESystem};
16use crate::zero::{QualifiedName, alg::Polynomial};
17
18pub type Parameter<Id> = Polynomial<Id, f32, i8>;
20
21#[derive(Clone, Derivative)]
23#[derivative(Default(bound = ""))]
24#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
25#[cfg_attr(feature = "serde-wasm", derive(Tsify))]
26#[cfg_attr(feature = "serde-wasm", tsify(into_wasm_abi, from_wasm_abi))]
27pub struct ODESolution {
28 pub(in crate::stdlib::analyses) time: Vec<f32>,
30
31 pub(in crate::stdlib::analyses) states: HashMap<QualifiedName, Vec<f32>>,
33}
34
35#[derive(Constructor)]
37pub struct ODEAnalysis<Sys> {
38 pub problem: ODEProblem<Sys>,
40
41 pub variable_index: IndexMap<QualifiedName, usize>,
43}
44
45impl<Sys> ODEAnalysis<Sys> {
46 pub fn solve_with_defaults(self) -> Result<ODESolution, IntegrationError>
48 where
49 Sys: ODESystem,
50 {
51 if self.variable_index.is_empty() {
53 return Ok(Default::default());
54 }
55
56 let duration = self.problem.end_time - self.problem.start_time;
57 let output_step_size = (duration / 100.0).min(0.01f32);
58 let result = self.problem.solve_dopri5(output_step_size)?;
59
60 let (t_out, x_out) = result.get();
61 Ok(ODESolution {
62 time: t_out.clone(),
63 states: self
64 .variable_index
65 .into_iter()
66 .map(|(ob, i)| (ob, x_out.iter().map(|x| x[i]).collect()))
67 .collect(),
68 })
69 }
70}
71
72pub mod kuramoto;
73pub mod linear_ode;
74pub mod lotka_volterra;
75pub mod mass_action;
76pub mod polynomial_ode;
77pub mod signed_coefficients;
78
79pub use kuramoto::*;
80pub use linear_ode::*;
81pub use lotka_volterra::*;
82pub use mass_action::*;
83pub use polynomial_ode::*;
84pub use signed_coefficients::*;