use crate::{
error::Error,
traits::{Real, State},
};
pub fn constrain_step_size<T: Real>(h: T, h_min: T, h_max: T) -> T {
let sign = h.signum();
if h.abs() < h_min {
sign * h_min
} else if h.abs() > h_max {
sign * h_max
} else {
h
}
}
pub fn validate_step_size_parameters<T: Real, Y: State<T>>(
h0: T,
h_min: T,
h_max: T,
t0: T,
tf: T,
) -> Result<T, Error<T, Y>> {
if tf == t0 {
return Err(Error::BadInput {
msg: format!(
"Invalid input: tf ({:?}) cannot be equal to t0 ({:?})",
tf, t0
),
});
}
let sign = (tf - t0).signum();
if h0.signum() != sign {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Initial step size ({:?}) must have the same sign as the integration direction (sign of tf - t0 = {:?})",
h0,
tf - t0
),
});
}
if h_min < T::zero() {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Minimum step size ({:?}) must be non-negative",
h_min
),
});
}
if h_max < T::zero() {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Maximum step size ({:?}) must be non-negative",
h_max
),
});
}
if h_min > h_max {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Minimum step size ({:?}) must be less than or equal to maximum step size ({:?})",
h_min, h_max
),
});
}
if h0.abs() < h_min {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Absolute value of initial step size ({:?}) must be greater than or equal to minimum step size ({:?})",
h0.abs(),
h_min
),
});
}
if h0.abs() > h_max {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Absolute value of initial step size ({:?}) must be less than or equal to maximum step size ({:?})",
h0.abs(),
h_max
),
});
}
if h0.abs() > (tf - t0).abs() {
return Err(Error::BadInput {
msg: format!(
"Invalid input: Absolute value of initial step size ({:?}) must be less than or equal to the absolute value of the integration interval (tf - t0 = {:?})",
h0.abs(),
(tf - t0).abs()
),
});
}
if h0 == T::zero() {
return Err(Error::BadInput {
msg: format!("Invalid input: Initial step size ({:?}) cannot be zero", h0),
});
}
Ok(h0)
}