use crate::dynamics::{KmPerSecond, KmPerSeconds};
use qtty_core::units::dimensionless::{Ratio, Ratios};
use qtty_core::units::length::{Kilometer, Kilometers};
use qtty_core::Quantity;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct RelativeTolerance(pub Ratios);
impl RelativeTolerance {
#[inline]
pub fn new(value: f64) -> Self {
Self(Quantity::<Ratio>::new(value))
}
#[inline]
pub fn value(self) -> f64 {
self.0.value()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct AbsoluteTolerancePosition<U = Kilometer>(pub Quantity<U>)
where
U: qtty_core::Unit<Dim = qtty_core::Length>;
impl AbsoluteTolerancePosition<Kilometer> {
#[inline]
pub fn new_km(value: f64) -> Self {
Self(Kilometers::new(value))
}
}
impl<U> AbsoluteTolerancePosition<U>
where
U: qtty_core::Unit<Dim = qtty_core::Length>,
{
#[inline]
pub fn new(quantity: Quantity<U>) -> Self {
Self(quantity)
}
#[inline]
pub fn value(self) -> f64
where
U: qtty_core::Unit<Dim = qtty_core::Length>,
{
self.0.value()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct AbsoluteToleranceVelocity<V = KmPerSecond>(pub Quantity<V>)
where
V: qtty_core::Unit<Dim = qtty_core::Velocity>;
impl AbsoluteToleranceVelocity<KmPerSecond> {
#[inline]
pub fn new_km_s(value: f64) -> Self {
Self(KmPerSeconds::new(value))
}
}
impl<V> AbsoluteToleranceVelocity<V>
where
V: qtty_core::Unit<Dim = qtty_core::Velocity>,
{
#[inline]
pub fn new(quantity: Quantity<V>) -> Self {
Self(quantity)
}
#[inline]
pub fn value(self) -> f64 {
self.0.value()
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct IntegratorTolerances {
pub rel: RelativeTolerance,
pub abs_pos: [AbsoluteTolerancePosition; 3],
pub abs_vel: [AbsoluteToleranceVelocity; 3],
}
impl IntegratorTolerances {
pub fn uniform(rel: f64, abs_pos_km: f64, abs_vel_km_s: f64) -> Self {
let abs_p = AbsoluteTolerancePosition::new_km(abs_pos_km);
let abs_v = AbsoluteToleranceVelocity::new_km_s(abs_vel_km_s);
Self {
rel: RelativeTolerance::new(rel),
abs_pos: [abs_p, abs_p, abs_p],
abs_vel: [abs_v, abs_v, abs_v],
}
}
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn relative_tolerance_roundtrip() {
let r = RelativeTolerance::new(1e-9);
assert!((r.value() - 1e-9).abs() < 1e-25);
}
#[test]
fn abs_pos_tolerance_roundtrip() {
let p = AbsoluteTolerancePosition::new_km(1e-6);
assert!((p.value() - 1e-6).abs() < 1e-22);
}
#[test]
fn abs_vel_tolerance_roundtrip() {
let v = AbsoluteToleranceVelocity::new_km_s(1e-9);
assert!((v.value() - 1e-9).abs() < 1e-25);
}
#[test]
fn integrator_tolerances_uniform() {
let tol = IntegratorTolerances::uniform(1e-9, 1e-6, 1e-9);
assert!((tol.rel.value() - 1e-9).abs() < 1e-25);
for p in &tol.abs_pos {
assert!((p.value() - 1e-6).abs() < 1e-22);
}
for v in &tol.abs_vel {
assert!((v.value() - 1e-9).abs() < 1e-25);
}
}
}