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}