use super::error::{RadauConfigError, RadauError};
use super::output::RadauOutputPolicy;
use super::telemetry::RadauTelemetryMode;
use crate::symbolic::ivp_telemetry::IvpLambdifyExecutionPolicy;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RadauExecution {
Native,
Lambdify,
Aot,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RadauAssembly {
ExprLegacy,
AtomViewNative,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RadauMatrixLayout {
Dense,
Sparse,
Banded { lower: usize, upper: usize },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum RadauJacobianSource {
Analytic,
Constant,
FiniteDifference,
}
#[derive(Debug, Clone, PartialEq)]
pub(crate) struct RadauConfig {
pub t0: f64,
pub t_bound: f64,
pub rtol: f64,
pub atol: f64,
pub first_step: Option<f64>,
pub max_step: f64,
pub max_steps: usize,
pub max_newton_iterations: usize,
pub max_retries: usize,
pub execution: RadauExecution,
pub assembly: Option<RadauAssembly>,
pub matrix_layout: RadauMatrixLayout,
pub jacobian_source: RadauJacobianSource,
pub telemetry: RadauTelemetryMode,
pub execution_policy: IvpLambdifyExecutionPolicy,
pub output: RadauOutputPolicy,
}
impl Default for RadauConfig {
fn default() -> Self {
Self {
t0: 0.0,
t_bound: 1.0,
rtol: 1e-3,
atol: 1e-6,
first_step: None,
max_step: f64::INFINITY,
max_steps: 1_000_000,
max_newton_iterations: 6,
max_retries: 12,
execution: RadauExecution::Native,
assembly: None,
matrix_layout: RadauMatrixLayout::Dense,
jacobian_source: RadauJacobianSource::Analytic,
telemetry: RadauTelemetryMode::Off,
execution_policy: IvpLambdifyExecutionPolicy::Sequential,
output: RadauOutputPolicy::FinalOnly,
}
}
}
impl RadauConfig {
pub(crate) fn validate(&self) -> Result<(), RadauError> {
if !self.t0.is_finite() || !self.t_bound.is_finite() || self.t0 == self.t_bound {
return Err(RadauConfigError::InvalidTimeBounds.into());
}
if !self.rtol.is_finite() || self.rtol <= 0.0 {
return Err(RadauConfigError::InvalidRelativeTolerance.into());
}
if !self.atol.is_finite() || self.atol <= 0.0 {
return Err(RadauConfigError::InvalidAbsoluteTolerance.into());
}
if !self.max_step.is_finite() && self.max_step != f64::INFINITY {
return Err(RadauConfigError::InvalidMaximumStep.into());
}
if self.max_step <= 0.0 {
return Err(RadauConfigError::InvalidMaximumStep.into());
}
if let Some(first_step) = self.first_step {
if !first_step.is_finite() || first_step <= 0.0 {
return Err(RadauConfigError::InvalidFirstStep.into());
}
}
if self.max_steps == 0 || self.max_newton_iterations == 0 || self.max_retries == 0 {
return Err(RadauConfigError::EmptyIterationBudget.into());
}
if let RadauMatrixLayout::Banded { lower, upper } = self.matrix_layout {
if lower == 0 && upper == 0 {
return Err(RadauConfigError::EmptyBandwidth.into());
}
}
if self.execution == RadauExecution::Native && self.assembly.is_some() {
return Err(RadauConfigError::NativeWithSymbolicAssembly.into());
}
if self.execution != RadauExecution::Native && self.assembly.is_none() {
return Err(RadauConfigError::SymbolicWithoutAssembly.into());
}
Ok(())
}
}