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, Y> Solout<T, Y> for DefaultSolout
68where
69    T: Real,
70    Y: State<T>,
71{
72    fn solout<I>(
73        &mut self,
74        t_curr: T,
75        _t_prev: T,
76        y_curr: &Y,
77        _y_prev: &Y,
78        _interpolator: &mut I,
79        solution: &mut Solution<T, Y>,
80    ) -> ControlFlag<T, Y>
81    where
82        I: Interpolation<T, Y>,
83    {
84        // Output the current time and state to the vectors
85        solution.push(t_curr, *y_curr);
86
87        // Continue the integration
88        ControlFlag::Continue
89    }
90}
91
92impl Default for DefaultSolout {
93    fn default() -> Self {
94        Self::new()
95    }
96}
97
98impl DefaultSolout {
99    /// Creates a new DefaultSolout instance.
100    ///
101    /// This is the simplest output handler that captures solution values
102    /// at each step naturally taken by the solver.
103    ///
104    /// # Returns
105    /// * A new `DefaultSolout` instance
106    ///
107    pub fn new() -> Self {
108        DefaultSolout {}
109    }
110}