Skip to main content

sciforge_hub/engine/simulation/
result.rs

1use super::integrator::IntegrationMethod;
2
3/// Output of a simulation run.
4pub struct SimulationResult {
5    /// Time points.
6    pub times: Vec<f64>,
7    /// State vectors at each time point.
8    pub states: Vec<Vec<f64>>,
9    /// Number of state dimensions.
10    pub dimension: usize,
11    /// Integration method used.
12    pub method: IntegrationMethod,
13    /// Number of steps taken.
14    pub steps_taken: usize,
15}
16
17impl SimulationResult {
18    /// Returns the last state vector.
19    pub fn final_state(&self) -> Option<&[f64]> {
20        self.states.last().map(|v| v.as_slice())
21    }
22
23    /// Returns the state vector at the given index.
24    pub fn state_at(&self, index: usize) -> Option<&[f64]> {
25        self.states.get(index).map(|v| v.as_slice())
26    }
27
28    /// Returns the time at the given index.
29    pub fn time_at(&self, index: usize) -> Option<f64> {
30        self.times.get(index).copied()
31    }
32
33    /// Number of recorded time steps.
34    pub fn len(&self) -> usize {
35        self.times.len()
36    }
37
38    /// Returns `true` if no steps were recorded.
39    pub fn is_empty(&self) -> bool {
40        self.times.is_empty()
41    }
42
43    /// Extracts the time series for a single dimension.
44    pub fn column(&self, dim_index: usize) -> Vec<f64> {
45        self.states
46            .iter()
47            .filter_map(|s| s.get(dim_index).copied())
48            .collect()
49    }
50
51    /// Returns the maximum value in the given dimension.
52    pub fn max_of(&self, dim_index: usize) -> f64 {
53        self.column(dim_index)
54            .into_iter()
55            .fold(f64::NEG_INFINITY, f64::max)
56    }
57
58    /// Returns the minimum value in the given dimension.
59    pub fn min_of(&self, dim_index: usize) -> f64 {
60        self.column(dim_index)
61            .into_iter()
62            .fold(f64::INFINITY, f64::min)
63    }
64}