Worked out lazy interp
This commit is contained in:
@@ -13,6 +13,16 @@ pub trait Integrator<const D: usize> {
|
||||
const STAGES: usize;
|
||||
const ADAPTIVE: bool;
|
||||
const DENSE: bool;
|
||||
|
||||
/// Number of main stages stored in dense output (default: same as STAGES)
|
||||
const MAIN_STAGES: usize = Self::STAGES;
|
||||
|
||||
/// Number of extra stages for full-order dense output (default: 0, no extra stages)
|
||||
const EXTRA_STAGES: usize = 0;
|
||||
|
||||
/// Total stages when full dense output is computed
|
||||
const TOTAL_DENSE_STAGES: usize = Self::MAIN_STAGES + Self::EXTRA_STAGES;
|
||||
|
||||
/// Returns a new y value, then possibly an error value, and possibly a dense output
|
||||
/// coefficient set
|
||||
fn step<P>(
|
||||
@@ -20,6 +30,7 @@ pub trait Integrator<const D: usize> {
|
||||
ode: &ODE<D, P>,
|
||||
h: f64,
|
||||
) -> (SVector<f64, D>, Option<f64>, Option<Vec<SVector<f64, D>>>);
|
||||
|
||||
fn interpolate(
|
||||
&self,
|
||||
t_start: f64,
|
||||
@@ -27,6 +38,35 @@ pub trait Integrator<const D: usize> {
|
||||
dense: &[SVector<f64, D>],
|
||||
t: f64,
|
||||
) -> SVector<f64, D>;
|
||||
|
||||
/// Compute extra stages for full-order dense output (lazy computation).
|
||||
///
|
||||
/// Most integrators don't need this and return an empty vector by default.
|
||||
/// High-order methods like Vern7 override this to compute additional stages
|
||||
/// needed for full-order interpolation accuracy.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `ode` - The ODE problem (provides derivative function)
|
||||
/// * `t_start` - Start time of the integration step
|
||||
/// * `y_start` - State at the start of the step
|
||||
/// * `h` - Step size
|
||||
/// * `main_stages` - The main k-stages from step()
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// Vector of extra k-stages (empty for most integrators)
|
||||
fn compute_extra_stages<P>(
|
||||
&self,
|
||||
_ode: &ODE<D, P>,
|
||||
_t_start: f64,
|
||||
_y_start: SVector<f64, D>,
|
||||
_h: f64,
|
||||
_main_stages: &[SVector<f64, D>],
|
||||
) -> Vec<SVector<f64, D>> {
|
||||
// Default implementation: no extra stages needed
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -12,6 +12,16 @@ pub trait Vern7Integrator<'a> {
|
||||
const R: &'a [f64]; // Interpolation coefficients
|
||||
}
|
||||
|
||||
/// Verner 7 extra stages trait for lazy dense output
|
||||
///
|
||||
/// These coefficients define the 6 additional Runge-Kutta stages (k11-k16)
|
||||
/// needed for full 7th order dense output interpolation. They are computed
|
||||
/// lazily only when interpolation is requested.
|
||||
pub trait Vern7ExtraStages<'a> {
|
||||
const C_EXTRA: &'a [f64]; // Time nodes for extra stages (c11-c16)
|
||||
const A_EXTRA: &'a [f64]; // A-matrix entries for extra stages (flattened)
|
||||
}
|
||||
|
||||
/// Verner's "Most Efficient" 7(6) method
|
||||
///
|
||||
/// A 7th order explicit Runge-Kutta method with an embedded 6th order method for
|
||||
@@ -171,15 +181,103 @@ impl<'a, const D: usize> Vern7Integrator<'a> for Vern7<D> {
|
||||
const R: &'a [f64] = &[];
|
||||
}
|
||||
|
||||
impl<'a, const D: usize> Vern7ExtraStages<'a> for Vern7<D> {
|
||||
// Time nodes for extra stages
|
||||
const C_EXTRA: &'a [f64] = &[
|
||||
1.0, // c11
|
||||
0.29, // c12
|
||||
0.125, // c13
|
||||
0.25, // c14
|
||||
0.53, // c15
|
||||
0.79, // c16
|
||||
];
|
||||
|
||||
// A-matrix coefficients for extra stages (flattened)
|
||||
// Each stage uses only k1, k4-k9 from main stages, plus previously computed extra stages
|
||||
//
|
||||
// Stage 11: uses k1, k4, k5, k6, k7, k8, k9
|
||||
// Stage 12: uses k1, k4, k5, k6, k7, k8, k9, k11
|
||||
// Stage 13: uses k1, k4, k5, k6, k7, k8, k9, k11, k12
|
||||
// Stage 14: uses k1, k4, k5, k6, k7, k8, k9, k11, k12, k13
|
||||
// Stage 15: uses k1, k4, k5, k6, k7, k8, k9, k11, k12, k13
|
||||
// Stage 16: uses k1, k4, k5, k6, k7, k8, k9, k11, k12, k13
|
||||
const A_EXTRA: &'a [f64] = &[
|
||||
// Stage 11 (7 coefficients): a1101, a1104, a1105, a1106, a1107, a1108, a1109
|
||||
0.04715561848627222,
|
||||
0.25750564298434153,
|
||||
0.2621665397741262,
|
||||
0.15216092656738558,
|
||||
0.49399691700324844,
|
||||
-0.29430311714032503,
|
||||
0.0813174723249511,
|
||||
// Stage 12 (8 coefficients): a1201, a1204, a1205, a1206, a1207, a1208, a1209, a1211
|
||||
0.0523222769159969,
|
||||
0.22495861826705715,
|
||||
0.017443709248776376,
|
||||
-0.007669379876829393,
|
||||
0.03435896044073285,
|
||||
-0.0410209723009395,
|
||||
0.025651133005205617,
|
||||
-0.0160443457,
|
||||
// Stage 13 (9 coefficients): a1301, a1304, a1305, a1306, a1307, a1308, a1309, a1311, a1312
|
||||
0.053053341257859085,
|
||||
0.12195301011401886,
|
||||
0.017746840737602496,
|
||||
-0.0005928372667681495,
|
||||
0.008381833970853752,
|
||||
-0.01293369259698612,
|
||||
0.009412056815253861,
|
||||
-0.005353253107275676,
|
||||
-0.06666729992455811,
|
||||
// Stage 14 (10 coefficients): a1401, a1404, a1405, a1406, a1407, a1408, a1409, a1411, a1412, a1413
|
||||
0.03887903257436304,
|
||||
-0.0024403203308301317,
|
||||
-0.0013928917214672623,
|
||||
-0.00047446291558680135,
|
||||
0.00039207932413159514,
|
||||
-0.00040554733285128004,
|
||||
0.00019897093147716726,
|
||||
-0.00010278198793179169,
|
||||
0.03385661513870267,
|
||||
0.1814893063199928,
|
||||
// Stage 15 (10 coefficients): a1501, a1504, a1505, a1506, a1507, a1508, a1509, a1511, a1512, a1513
|
||||
0.05723681204690013,
|
||||
0.22265948066761182,
|
||||
0.12344864200186899,
|
||||
0.04006332526666491,
|
||||
-0.05269894848581452,
|
||||
0.04765971214244523,
|
||||
-0.02138895885042213,
|
||||
0.015193891064036402,
|
||||
0.12060546716289655,
|
||||
-0.022779423016187374,
|
||||
// Stage 16 (10 coefficients): a1601, a1604, a1605, a1606, a1607, a1608, a1609, a1611, a1612, a1613
|
||||
0.051372038802756814,
|
||||
0.5414214473439406,
|
||||
0.350399806692184,
|
||||
0.14193112269692182,
|
||||
0.10527377478429423,
|
||||
-0.031081847805874016,
|
||||
-0.007401883149519145,
|
||||
-0.006377932504865363,
|
||||
-0.17325495908361865,
|
||||
-0.18228156777622026,
|
||||
];
|
||||
}
|
||||
|
||||
impl<'a, const D: usize> Integrator<D> for Vern7<D>
|
||||
where
|
||||
Vern7<D>: Vern7Integrator<'a>,
|
||||
Vern7<D>: Vern7Integrator<'a> + Vern7ExtraStages<'a>,
|
||||
{
|
||||
const ORDER: usize = 7;
|
||||
const STAGES: usize = 10;
|
||||
const ADAPTIVE: bool = true;
|
||||
const DENSE: bool = true;
|
||||
|
||||
// Lazy dense output configuration
|
||||
const MAIN_STAGES: usize = 10;
|
||||
const EXTRA_STAGES: usize = 6;
|
||||
|
||||
fn step<P>(
|
||||
&self,
|
||||
ode: &ODE<D, P>,
|
||||
@@ -235,8 +333,10 @@ where
|
||||
t: f64,
|
||||
) -> SVector<f64, D> {
|
||||
// Vern7 uses 7th order polynomial interpolation
|
||||
// The full implementation would compute 6 extra stages (k11-k16) lazily
|
||||
// For now, we use a simplified version with just the main 10 stages
|
||||
// Check if extra stages (k11-k16) are available
|
||||
// Dense array format: [y0, y1, k1, k2, ..., k10, k11, ..., k16]
|
||||
// With main stages only: length = 2 + 10 = 12
|
||||
// With all stages: length = 2 + 10 + 6 = 18
|
||||
|
||||
let theta = (t - t_start) / (t_end - t_start);
|
||||
let theta2 = theta * theta;
|
||||
@@ -256,10 +356,6 @@ where
|
||||
let k9 = &dense[10]; // k9
|
||||
// k10 is at dense[11] but not used in interpolation
|
||||
|
||||
// Interpolation polynomial coefficients (from Julia source)
|
||||
// b1Θ = Θ * evalpoly(Θ, [r011, r012, ..., r017])
|
||||
// b4Θ through b9Θ = Θ² * evalpoly(Θ, [coeffs])
|
||||
|
||||
// Helper to evaluate polynomial using Horner's method
|
||||
#[inline]
|
||||
fn evalpoly(x: f64, coeffs: &[f64]) -> f64 {
|
||||
@@ -336,15 +432,197 @@ where
|
||||
-52.85010499525706,
|
||||
]);
|
||||
|
||||
// Compute interpolated value
|
||||
// Full implementation would also include k11-k16 with their own polynomials
|
||||
y0 + h * (k1 * b1_theta +
|
||||
// Compute base interpolation with main stages
|
||||
let mut result = y0 + h * (k1 * b1_theta +
|
||||
k4 * b4_theta +
|
||||
k5 * b5_theta +
|
||||
k6 * b6_theta +
|
||||
k7 * b7_theta +
|
||||
k8 * b8_theta +
|
||||
k9 * b9_theta)
|
||||
k9 * b9_theta);
|
||||
|
||||
// If extra stages are available, add their contribution for full 7th order accuracy
|
||||
if dense.len() >= 2 + Self::TOTAL_DENSE_STAGES {
|
||||
// Extra stages are at indices 12-17
|
||||
let k11 = &dense[12];
|
||||
let k12 = &dense[13];
|
||||
let k13 = &dense[14];
|
||||
let k14 = &dense[15];
|
||||
let k15 = &dense[16];
|
||||
let k16 = &dense[17];
|
||||
|
||||
// Stages 11-16: all start at degree 2
|
||||
let b11_theta = theta2 * evalpoly(theta, &[
|
||||
-2.1696320280163506,
|
||||
22.016696037569876,
|
||||
-86.90152427798948,
|
||||
159.22388973861476,
|
||||
-135.9618306534588,
|
||||
43.792401183280006,
|
||||
]);
|
||||
|
||||
let b12_theta = theta2 * evalpoly(theta, &[
|
||||
-4.890070188793804,
|
||||
22.75407737425176,
|
||||
-30.78034218537731,
|
||||
-2.797194317207249,
|
||||
31.369456637508403,
|
||||
-15.655927320381801,
|
||||
]);
|
||||
|
||||
let b13_theta = theta2 * evalpoly(theta, &[
|
||||
10.862170929551967,
|
||||
-50.542971417827104,
|
||||
68.37148040407511,
|
||||
6.213326521632409,
|
||||
-69.68006323194157,
|
||||
34.776056794509195,
|
||||
]);
|
||||
|
||||
let b14_theta = theta2 * evalpoly(theta, &[
|
||||
-11.37286691922923,
|
||||
130.79058078246717,
|
||||
-488.65113677785604,
|
||||
832.2148793276441,
|
||||
-664.7743368554426,
|
||||
201.79288044241662,
|
||||
]);
|
||||
|
||||
let b15_theta = theta2 * evalpoly(theta, &[
|
||||
-5.919778732715007,
|
||||
63.27679965889219,
|
||||
-265.432682088738,
|
||||
520.1009254140611,
|
||||
-467.412109533902,
|
||||
155.3868452824017,
|
||||
]);
|
||||
|
||||
let b16_theta = theta2 * evalpoly(theta, &[
|
||||
-10.492146197961823,
|
||||
105.35538525188011,
|
||||
-409.43975011988937,
|
||||
732.831448907654,
|
||||
-606.3044574733512,
|
||||
188.0495196316683,
|
||||
]);
|
||||
|
||||
// Add contribution from extra stages
|
||||
result += h * (k11 * b11_theta +
|
||||
k12 * b12_theta +
|
||||
k13 * b13_theta +
|
||||
k14 * b14_theta +
|
||||
k15 * b15_theta +
|
||||
k16 * b16_theta);
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn compute_extra_stages<P>(
|
||||
&self,
|
||||
ode: &ODE<D, P>,
|
||||
t_start: f64,
|
||||
y_start: SVector<f64, D>,
|
||||
h: f64,
|
||||
main_stages: &[SVector<f64, D>],
|
||||
) -> Vec<SVector<f64, D>> {
|
||||
// Extract main stages that are used in extra stage computation
|
||||
// From Julia: extra stages use k1, k4, k5, k6, k7, k8, k9
|
||||
let k1 = &main_stages[0];
|
||||
let k4 = &main_stages[3];
|
||||
let k5 = &main_stages[4];
|
||||
let k6 = &main_stages[5];
|
||||
let k7 = &main_stages[6];
|
||||
let k8 = &main_stages[7];
|
||||
let k9 = &main_stages[8];
|
||||
|
||||
let mut extra_stages = Vec::with_capacity(Self::EXTRA_STAGES);
|
||||
|
||||
// Stage 11: uses k1, k4-k9 (7 coefficients)
|
||||
let mut y11 = y_start;
|
||||
y11 += k1 * Self::A_EXTRA[0] * h;
|
||||
y11 += k4 * Self::A_EXTRA[1] * h;
|
||||
y11 += k5 * Self::A_EXTRA[2] * h;
|
||||
y11 += k6 * Self::A_EXTRA[3] * h;
|
||||
y11 += k7 * Self::A_EXTRA[4] * h;
|
||||
y11 += k8 * Self::A_EXTRA[5] * h;
|
||||
y11 += k9 * Self::A_EXTRA[6] * h;
|
||||
let k11 = (ode.f)(t_start + Self::C_EXTRA[0] * h, y11, &ode.params);
|
||||
extra_stages.push(k11);
|
||||
|
||||
// Stage 12: uses k1, k4-k9, k11 (8 coefficients)
|
||||
let mut y12 = y_start;
|
||||
y12 += k1 * Self::A_EXTRA[7] * h;
|
||||
y12 += k4 * Self::A_EXTRA[8] * h;
|
||||
y12 += k5 * Self::A_EXTRA[9] * h;
|
||||
y12 += k6 * Self::A_EXTRA[10] * h;
|
||||
y12 += k7 * Self::A_EXTRA[11] * h;
|
||||
y12 += k8 * Self::A_EXTRA[12] * h;
|
||||
y12 += k9 * Self::A_EXTRA[13] * h;
|
||||
y12 += &extra_stages[0] * Self::A_EXTRA[14] * h; // k11
|
||||
let k12 = (ode.f)(t_start + Self::C_EXTRA[1] * h, y12, &ode.params);
|
||||
extra_stages.push(k12);
|
||||
|
||||
// Stage 13: uses k1, k4-k9, k11, k12 (9 coefficients)
|
||||
let mut y13 = y_start;
|
||||
y13 += k1 * Self::A_EXTRA[15] * h;
|
||||
y13 += k4 * Self::A_EXTRA[16] * h;
|
||||
y13 += k5 * Self::A_EXTRA[17] * h;
|
||||
y13 += k6 * Self::A_EXTRA[18] * h;
|
||||
y13 += k7 * Self::A_EXTRA[19] * h;
|
||||
y13 += k8 * Self::A_EXTRA[20] * h;
|
||||
y13 += k9 * Self::A_EXTRA[21] * h;
|
||||
y13 += &extra_stages[0] * Self::A_EXTRA[22] * h; // k11
|
||||
y13 += &extra_stages[1] * Self::A_EXTRA[23] * h; // k12
|
||||
let k13 = (ode.f)(t_start + Self::C_EXTRA[2] * h, y13, &ode.params);
|
||||
extra_stages.push(k13);
|
||||
|
||||
// Stage 14: uses k1, k4-k9, k11, k12, k13 (10 coefficients)
|
||||
let mut y14 = y_start;
|
||||
y14 += k1 * Self::A_EXTRA[24] * h;
|
||||
y14 += k4 * Self::A_EXTRA[25] * h;
|
||||
y14 += k5 * Self::A_EXTRA[26] * h;
|
||||
y14 += k6 * Self::A_EXTRA[27] * h;
|
||||
y14 += k7 * Self::A_EXTRA[28] * h;
|
||||
y14 += k8 * Self::A_EXTRA[29] * h;
|
||||
y14 += k9 * Self::A_EXTRA[30] * h;
|
||||
y14 += &extra_stages[0] * Self::A_EXTRA[31] * h; // k11
|
||||
y14 += &extra_stages[1] * Self::A_EXTRA[32] * h; // k12
|
||||
y14 += &extra_stages[2] * Self::A_EXTRA[33] * h; // k13
|
||||
let k14 = (ode.f)(t_start + Self::C_EXTRA[3] * h, y14, &ode.params);
|
||||
extra_stages.push(k14);
|
||||
|
||||
// Stage 15: uses k1, k4-k9, k11, k12, k13 (10 coefficients, reuses k13 not k14)
|
||||
let mut y15 = y_start;
|
||||
y15 += k1 * Self::A_EXTRA[34] * h;
|
||||
y15 += k4 * Self::A_EXTRA[35] * h;
|
||||
y15 += k5 * Self::A_EXTRA[36] * h;
|
||||
y15 += k6 * Self::A_EXTRA[37] * h;
|
||||
y15 += k7 * Self::A_EXTRA[38] * h;
|
||||
y15 += k8 * Self::A_EXTRA[39] * h;
|
||||
y15 += k9 * Self::A_EXTRA[40] * h;
|
||||
y15 += &extra_stages[0] * Self::A_EXTRA[41] * h; // k11
|
||||
y15 += &extra_stages[1] * Self::A_EXTRA[42] * h; // k12
|
||||
y15 += &extra_stages[2] * Self::A_EXTRA[43] * h; // k13
|
||||
let k15 = (ode.f)(t_start + Self::C_EXTRA[4] * h, y15, &ode.params);
|
||||
extra_stages.push(k15);
|
||||
|
||||
// Stage 16: uses k1, k4-k9, k11, k12, k13 (10 coefficients, reuses k13 not k14 or k15)
|
||||
let mut y16 = y_start;
|
||||
y16 += k1 * Self::A_EXTRA[44] * h;
|
||||
y16 += k4 * Self::A_EXTRA[45] * h;
|
||||
y16 += k5 * Self::A_EXTRA[46] * h;
|
||||
y16 += k6 * Self::A_EXTRA[47] * h;
|
||||
y16 += k7 * Self::A_EXTRA[48] * h;
|
||||
y16 += k8 * Self::A_EXTRA[49] * h;
|
||||
y16 += k9 * Self::A_EXTRA[50] * h;
|
||||
y16 += &extra_stages[0] * Self::A_EXTRA[51] * h; // k11
|
||||
y16 += &extra_stages[1] * Self::A_EXTRA[52] * h; // k12
|
||||
y16 += &extra_stages[2] * Self::A_EXTRA[53] * h; // k13
|
||||
let k16 = (ode.f)(t_start + Self::C_EXTRA[5] * h, y16, &ode.params);
|
||||
extra_stages.push(k16);
|
||||
|
||||
extra_stages
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use nalgebra::SVector;
|
||||
use roots::{find_root_brent, SimpleConvergency};
|
||||
use std::cell::RefCell;
|
||||
|
||||
use super::callback::Callback;
|
||||
use super::controller::{Controller, PIController, TryStep};
|
||||
@@ -29,14 +30,14 @@ where
|
||||
callbacks: Vec::new(),
|
||||
}
|
||||
}
|
||||
pub fn solve(&mut self) -> Solution<S, D> {
|
||||
pub fn solve(&mut self) -> Solution<'_, S, D, P> {
|
||||
let mut convergency = SimpleConvergency {
|
||||
eps: 1e-12,
|
||||
max_iter: 1000,
|
||||
};
|
||||
let mut times: Vec<f64> = vec![self.ode.t];
|
||||
let mut states: Vec<SVector<f64, D>> = vec![self.ode.y];
|
||||
let mut dense_coefficients: Vec<Vec<SVector<f64, D>>> = Vec::new();
|
||||
let mut dense_coefficients: Vec<RefCell<Vec<SVector<f64, D>>>> = Vec::new();
|
||||
while self.ode.t < self.ode.t_end {
|
||||
if self.ode.t + self.controller.next_step_guess.extract() > self.ode.t_end {
|
||||
// If the next step would go past the end, then just set it to the end
|
||||
@@ -100,9 +101,10 @@ where
|
||||
times.push(self.ode.t);
|
||||
states.push(self.ode.y);
|
||||
// TODO: Implement third order interpolation for non-dense algorithms
|
||||
dense_coefficients.push(dense_option.unwrap());
|
||||
dense_coefficients.push(RefCell::new(dense_option.unwrap()));
|
||||
}
|
||||
Solution {
|
||||
ode: &self.ode,
|
||||
integrator: self.integrator,
|
||||
times,
|
||||
states,
|
||||
@@ -121,17 +123,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Solution<S, const D: usize>
|
||||
pub struct Solution<'a, S, const D: usize, P>
|
||||
where
|
||||
S: Integrator<D>,
|
||||
{
|
||||
pub ode: &'a ODE<'a, D, P>,
|
||||
pub integrator: S,
|
||||
pub times: Vec<f64>,
|
||||
pub states: Vec<SVector<f64, D>>,
|
||||
pub dense: Vec<Vec<SVector<f64, D>>>,
|
||||
pub dense: Vec<RefCell<Vec<SVector<f64, D>>>>,
|
||||
}
|
||||
|
||||
impl<S, const D: usize> Solution<S, D>
|
||||
impl<'a, S, const D: usize, P> Solution<'a, S, D, P>
|
||||
where
|
||||
S: Integrator<D>,
|
||||
{
|
||||
@@ -153,11 +156,47 @@ where
|
||||
match times.binary_search_by(|x| x.total_cmp(&t)) {
|
||||
Ok(index) => self.states[index],
|
||||
Err(end_index) => {
|
||||
// Then send that to the integrator
|
||||
let t_start = times[end_index - 1];
|
||||
let t_end = times[end_index];
|
||||
self.integrator
|
||||
.interpolate(t_start, t_end, &self.dense[end_index - 1], t)
|
||||
let y_start = self.states[end_index - 1];
|
||||
let h = t_end - t_start;
|
||||
|
||||
// Check if we need to compute extra stages for lazy dense output
|
||||
let dense_cell = &self.dense[end_index - 1];
|
||||
|
||||
if S::EXTRA_STAGES > 0 {
|
||||
let needs_extra = {
|
||||
let borrowed = dense_cell.borrow();
|
||||
// Dense array format: [y0, y1, k1, k2, ..., k_main]
|
||||
// If we have main stages only: 2 + MAIN_STAGES elements
|
||||
// If we have all stages: 2 + MAIN_STAGES + EXTRA_STAGES elements
|
||||
borrowed.len() < 2 + S::TOTAL_DENSE_STAGES
|
||||
};
|
||||
|
||||
if needs_extra {
|
||||
// Compute extra stages and append to dense output
|
||||
let mut dense = dense_cell.borrow_mut();
|
||||
|
||||
// Extract main stages (skip y0 and y1 at indices 0 and 1)
|
||||
let main_stages = &dense[2..2 + S::MAIN_STAGES];
|
||||
|
||||
// Compute extra stages lazily
|
||||
let extra_stages = self.integrator.compute_extra_stages(
|
||||
self.ode,
|
||||
t_start,
|
||||
y_start,
|
||||
h,
|
||||
main_stages,
|
||||
);
|
||||
|
||||
// Append extra stages to dense output (cached for future interpolations)
|
||||
dense.extend(extra_stages);
|
||||
}
|
||||
}
|
||||
|
||||
// Now interpolate with the (possibly augmented) dense output
|
||||
let dense = dense_cell.borrow();
|
||||
self.integrator.interpolate(t_start, t_end, &dense, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user