Updated the way that steps are handled
This commit is contained in:
@@ -1,5 +1,31 @@
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum TryStep {
|
||||
Accepted(f64, f64),
|
||||
NotYetAccepted(f64),
|
||||
}
|
||||
|
||||
impl TryStep {
|
||||
pub fn extract(&self) -> f64 {
|
||||
match self {
|
||||
TryStep::Accepted(h, _) => *h,
|
||||
TryStep::NotYetAccepted(h) => *h,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_accepted(&self) -> bool {
|
||||
matches!(self, TryStep::Accepted(_, _))
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) -> Result<TryStep, &str> {
|
||||
match self {
|
||||
TryStep::Accepted(_, h) => Ok(TryStep::NotYetAccepted(*h)),
|
||||
TryStep::NotYetAccepted(_) => Err("Cannot reset a NotYetAccepted TryStep"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Controller<const D: usize> {
|
||||
fn determine_step(&mut self, h: f64, err: f64) -> (bool, f64);
|
||||
fn determine_step(&mut self, h: f64, err: f64) -> TryStep;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
@@ -11,32 +37,30 @@ pub struct PIController {
|
||||
pub factor_old: f64,
|
||||
pub h_max: f64,
|
||||
pub safety_factor: f64,
|
||||
pub old_h: f64,
|
||||
pub next_step_guess: TryStep,
|
||||
}
|
||||
|
||||
impl<const D: usize> Controller<D> for PIController {
|
||||
/// Determines if the previously run step size and error were valid or not. Either way, it also
|
||||
/// returns what the next step size should be
|
||||
fn determine_step(&mut self, h: f64, err: f64) -> (bool, f64) {
|
||||
fn determine_step(&mut self, prev_step: f64, err: f64) -> TryStep {
|
||||
let factor_11 = err.powf(self.alpha);
|
||||
let factor = self.factor_c2.max(
|
||||
self.factor_c1
|
||||
.min(factor_11 * self.factor_old.powf(-self.beta) / self.safety_factor),
|
||||
);
|
||||
let mut h_new = h / factor;
|
||||
if err <= 1.0 {
|
||||
// Accept the stepsize
|
||||
let mut h = prev_step / factor;
|
||||
// Accept the stepsize and provide what the next step size should be
|
||||
self.factor_old = err.max(1.0e-4);
|
||||
if h_new.abs() > self.h_max {
|
||||
// If the step is too big
|
||||
h_new = self.h_max.copysign(h_new);
|
||||
if h.abs() > self.h_max {
|
||||
// If the step goes past the maximum allowed, though, we shrink it
|
||||
h = self.h_max.copysign(h);
|
||||
}
|
||||
(true, h_new)
|
||||
// (true, h_new)
|
||||
TryStep::Accepted(prev_step, h)
|
||||
} else {
|
||||
// Reject the stepsize and propose a smaller one
|
||||
h_new = h / (self.factor_c1.min(factor_11 / self.safety_factor));
|
||||
(false, h_new)
|
||||
// Reject the stepsize and propose a smaller one for the current step
|
||||
TryStep::NotYetAccepted(prev_step / (self.factor_c1.min(factor_11 / self.safety_factor)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,7 +83,7 @@ impl PIController {
|
||||
factor_old: 1.0e-4,
|
||||
h_max: h_max.abs(),
|
||||
safety_factor,
|
||||
old_h: initial_h,
|
||||
next_step_guess: TryStep::NotYetAccepted(initial_h),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,6 +109,6 @@ mod tests {
|
||||
assert!(controller.factor_old == 1.0e-4);
|
||||
assert!(controller.h_max == 10.0);
|
||||
assert!(controller.safety_factor == 0.9);
|
||||
assert!(controller.old_h == 1e-4);
|
||||
assert!(controller.next_step_guess == TryStep::NotYetAccepted(1e-4));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user