use crate::State;
use crate::cosmic::{AstroError, Orbit};
use crate::linalg::allocator::Allocator;
use crate::linalg::{DefaultAllocator, DimName, Matrix3, Matrix4x3, OMatrix, OVector, Vector3};
use anise::almanac::Almanac;
use anise::almanac::planetary::PlanetaryDataError;
use anise::errors::AlmanacError;
use hyperdual::Owned;
use snafu::Snafu;
use std::fmt;
pub use crate::errors::NyxError;
pub mod orbital;
use self::guidance::GuidanceError;
pub use self::orbital::*;
pub mod spacecraft;
pub use self::spacecraft::*;
pub mod guidance;
pub mod deltavctrl;
pub mod solarpressure;
pub use self::solarpressure::*;
pub mod drag;
pub use self::drag::*;
pub mod gravity_field;
pub use self::gravity_field::*;
#[cfg(feature = "premium")]
pub mod solid_tides;
#[cfg(feature = "premium")]
pub use self::solid_tides::*;
pub mod sequence;
#[allow(clippy::type_complexity)]
pub trait Dynamics: Clone + Sync + Send
where
DefaultAllocator: Allocator<<Self::StateType as State>::Size>
+ Allocator<<Self::StateType as State>::VecLength>
+ Allocator<<Self::StateType as State>::Size, <Self::StateType as State>::Size>,
{
type HyperdualSize: DimName;
type StateType: State;
fn eom(
&self,
delta_t: f64,
state_vec: &OVector<f64, <Self::StateType as State>::VecLength>,
state_ctx: &Self::StateType,
almanac: &Almanac,
) -> Result<OVector<f64, <Self::StateType as State>::VecLength>, DynamicsError>
where
DefaultAllocator: Allocator<<Self::StateType as State>::VecLength>;
fn dual_eom(
&self,
_delta_t: f64,
_osculating_state: &Self::StateType,
_almanac: &Almanac,
) -> Result<
(
OVector<f64, <Self::StateType as State>::Size>,
OMatrix<f64, <Self::StateType as State>::Size, <Self::StateType as State>::Size>,
),
DynamicsError,
>
where
DefaultAllocator: Allocator<Self::HyperdualSize>
+ Allocator<<Self::StateType as State>::Size>
+ Allocator<<Self::StateType as State>::Size, <Self::StateType as State>::Size>,
Owned<f64, Self::HyperdualSize>: Copy,
{
Err(DynamicsError::StateTransitionMatrixUnset)
}
fn finally(
&self,
next_state: Self::StateType,
_almanac: &Almanac,
) -> Result<Self::StateType, DynamicsError> {
Ok(next_state)
}
}
pub trait ForceModel: Send + Sync + fmt::Display {
fn estimation_index(&self) -> Option<usize>;
fn eom(&self, ctx: &Spacecraft, almanac: &Almanac) -> Result<Vector3<f64>, DynamicsError>;
fn gradient(
&self,
osc_ctx: &Spacecraft,
almanac: &Almanac,
) -> Result<(Vector3<f64>, Matrix4x3<f64>), DynamicsError>;
}
pub trait AccelModel: Send + Sync + fmt::Display {
fn eom(&self, osc: &Orbit, almanac: &Almanac) -> Result<Vector3<f64>, DynamicsError>;
fn gradient(
&self,
osc_ctx: &Orbit,
almanac: &Almanac,
) -> Result<(Vector3<f64>, Matrix3<f64>), DynamicsError>;
}
#[derive(Debug, PartialEq, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum DynamicsError {
#[snafu(display("spacecraft total mass is zero, cannot compute any force model"))]
MasslessSpacecraft,
#[snafu(display("fuel exhausted at {sc}"))]
FuelExhausted { sc: Box<Spacecraft> },
#[snafu(display("expected STM to be set"))]
StateTransitionMatrixUnset,
#[snafu(display("dynamical model encountered an astro error: {source}"))]
DynamicsAstro { source: AstroError },
#[snafu(display("dynamical model encountered an issue with the guidance: {source}"))]
DynamicsGuidance { source: GuidanceError },
#[snafu(display("dynamical model issue due to Almanac: {action} {source}"))]
DynamicsAlmanacError {
action: &'static str,
#[snafu(source(from(AlmanacError, Box::new)))]
source: Box<AlmanacError>,
},
#[snafu(display("dynamical model issue due to planetary data: {action} {source}"))]
DynamicsPlanetaryError {
action: &'static str,
#[snafu(source(from(PlanetaryDataError, Box::new)))]
source: Box<PlanetaryDataError>,
},
}