ode_solvers 0.3.7

Numerical methods to solve ordinary differential equations (ODEs) in Rust.
Documentation
//! Adaptive step size control.

/// Used for adaptive step size control
pub struct Controller {
    alpha: f64,
    beta: f64,
    facc1: f64,
    facc2: f64,
    fac_old: f64,
    h_max: f64,
    reject: bool,
    safety_factor: f64,
    posneg: f64,
}

impl Controller {
    /// Creates a controller responsible for adaptive step size control.
    ///
    /// # Arguments
    ///
    /// * `alpha`   - α coefficient of the PI controller
    /// * `beta`    - β coefficient of the PI controller
    /// * `fac_max` - Maximum factor between two successive steps
    /// * `fac_min` - Minimum factor between two successive steps
    /// * `h_max`   - Maximum step size
    /// * `safety_factor`   - Safety factor of the PI controller
    ///
    pub fn new(
        alpha: f64,
        beta: f64,
        fac_max: f64,
        fac_min: f64,
        h_max: f64,
        safety_factor: f64,
        posneg: f64,
    ) -> Controller {
        Controller {
            alpha,
            beta,
            facc1: 1.0 / fac_min,
            facc2: 1.0 / fac_max,
            fac_old: 1.0E-4,
            h_max: h_max.abs(),
            reject: false,
            safety_factor,
            posneg,
        }
    }

    /// Determines if the step must be accepted or rejected and adapts the step size accordingly.
    pub fn accept(&mut self, err: f64, h: f64, h_new: &mut f64) -> bool {
        let fac11 = err.powf(self.alpha);
        let mut fac = fac11 * self.fac_old.powf(-self.beta);
        fac = (self.facc2).max((self.facc1).min(fac / self.safety_factor));
        *h_new = h / fac;

        if err <= 1.0 {
            // Accept step
            self.fac_old = err.max(1.0E-4);

            if h_new.abs() > self.h_max {
                *h_new = self.posneg * self.h_max;
            }
            if self.reject {
                *h_new = self.posneg * h_new.abs().min(h.abs());
            }

            self.reject = false;
            true
        } else {
            // Reject step
            *h_new = h / ((self.facc1).min(fac11 / self.safety_factor));
            self.reject = true;
            false
        }
    }

    /// Returns the maximum step size allowed.
    pub fn h_max(&self) -> f64 {
        self.h_max
    }
}