differential_equations/solout/
default.rs

1//! Default Solout Implementation, e.g. outputting solutions at calculated steps.
2//!
3//! This module provides the default output strategy, which returns solution points
4//! at each step taken by the solver without any interpolation.
5
6use super::*;
7
8/// The default output handler that returns solution values at each solver step.
9///
10/// # Overview
11///
12/// `DefaultSolout` is the simplest output handler that captures the solution
13/// at each internal step calculated by the solver. It doesn't perform any
14/// interpolation or filtering - it simply records the exact points that the
15/// solver naturally computes during integration.
16///
17/// # Features
18///
19/// - Captures all solver steps in the output
20/// - No interpolation overhead
21/// - Gives the raw, unmodified solver trajectory
22///
23/// # Example
24///
25/// ```
26/// use differential_equations::prelude::*;
27/// use differential_equations::solout::DefaultSolout;
28/// use nalgebra::{Vector1, vector};
29///
30/// // Simple exponential growth
31/// struct ExponentialGrowth;
32///
33/// impl ODE<f64, Vector1<f64>> for ExponentialGrowth {
34///     fn diff(&self, _t: f64, y: &Vector1<f64>, dydt: &mut Vector1<f64>) {
35///         dydt[0] = y[0]; // dy/dt = y
36///     }
37/// }
38///
39/// // Create the system and solver
40/// let system = ExponentialGrowth;
41/// let t0 = 0.0;
42/// let tf = 2.0;
43/// let y0 = vector![1.0];
44/// let mut solver = ExplicitRungeKutta::dop853().rtol(1e-6).atol(1e-8);
45///
46/// // Use the default output handler explicitly
47/// let mut default_output = DefaultSolout::new();
48///
49/// // Solve with default output
50/// let problem = ODEProblem::new(system, t0, tf, y0);
51/// let solution = problem.solout(&mut default_output).solve(&mut solver).unwrap();
52///
53/// // Note: This is equivalent to the default behavior
54/// let solution2 = problem.solve(&mut solver).unwrap();
55/// ```
56///
57/// # Output Characteristics
58///
59/// The output will contain only the actual steps computed by the solver,
60/// which may not be evenly spaced in time. The spacing depends on the solver's
61/// adaptive step size control.
62///
63/// For evenly spaced output points, consider using `EvenSolout` instead.
64///
65pub struct DefaultSolout {}
66
67impl<T, V, D> Solout<T, V, D> for DefaultSolout
68where
69    T: Real,
70    V: State<T>,
71    D: CallBackData,
72{
73    fn solout<I>(
74        &mut self,
75        t_curr: T,
76        _t_prev: T,
77        y_curr: &V,
78        _y_prev: &V,
79        _interpolator: &mut I,
80        solution: &mut Solution<T, V, D>,
81    ) -> ControlFlag<T, V, D>
82    where
83        I: Interpolation<T, V>,
84    {
85        // Output the current time and state to the vectors
86        solution.push(t_curr, *y_curr);
87
88        // Continue the integration
89        ControlFlag::Continue
90    }
91}
92
93impl Default for DefaultSolout {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99impl DefaultSolout {
100    /// Creates a new DefaultSolout instance.
101    ///
102    /// This is the simplest output handler that captures solution values
103    /// at each step naturally taken by the solver.
104    ///
105    /// # Returns
106    /// * A new `DefaultSolout` instance
107    ///
108    pub fn new() -> Self {
109        DefaultSolout {}
110    }
111}