nyx_space/dynamics/mod.rs
1/*
2 Nyx, blazing fast astrodynamics
3 Copyright (C) 2018-onwards Christopher Rabotin <christopher.rabotin@gmail.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19use crate::State;
20use crate::cosmic::{AstroError, Orbit};
21use crate::linalg::allocator::Allocator;
22use crate::linalg::{DefaultAllocator, DimName, Matrix3, Matrix4x3, OMatrix, OVector, Vector3};
23use anise::almanac::Almanac;
24use anise::almanac::planetary::PlanetaryDataError;
25use anise::errors::AlmanacError;
26use hyperdual::Owned;
27use snafu::Snafu;
28
29use std::fmt;
30use std::sync::Arc;
31
32pub use crate::errors::NyxError;
33
34/// The orbital module handles all Cartesian based orbital dynamics.
35///
36/// It is up to the engineer to ensure that the coordinate frames of the different dynamics borrowed
37/// from this module match, or perform the appropriate coordinate transformations.
38pub mod orbital;
39use self::guidance::GuidanceError;
40pub use self::orbital::*;
41
42/// The spacecraft module allows for simulation of spacecraft dynamics in general, including propulsion/maneuvers.
43pub mod spacecraft;
44pub use self::spacecraft::*;
45
46/// Defines a few examples of guidance laws.
47pub mod guidance;
48
49/// Defines some velocity change controllers.
50pub mod deltavctrl;
51
52/// Defines solar radiation pressure models
53pub mod solarpressure;
54pub use self::solarpressure::*;
55
56/// The drag module handles drag in a very basic fashion. Do not use for high fidelity dynamics.
57pub mod drag;
58pub use self::drag::*;
59
60/// Define the gravity field models.
61/// This module allows loading gravity models from [PDS](http://pds-geosciences.wustl.edu/), [EGM2008](http://earth-info.nga.mil/GandG/wgs84/gravitymod/egm2008/) and GMAT's own COF files.
62pub mod gravity_field;
63pub use self::gravity_field::*;
64
65/// Define the solid tide models.
66#[cfg(feature = "premium")]
67pub mod solid_tides;
68#[cfg(feature = "premium")]
69pub use self::solid_tides::*;
70
71pub mod sequence;
72
73/// The `Dynamics` trait handles and stores any equation of motion *and* the state is integrated.
74///
75/// Its design is such that several of the provided dynamics can be combined fairly easily. However,
76/// when combining the dynamics (e.g. integrating both the attitude of a spaceraft and its orbital
77/// parameters), it is up to the implementor to handle time and state organization correctly.
78/// For time management, I highly recommend using `hifitime` which is thoroughly validated.
79#[allow(clippy::type_complexity)]
80pub trait Dynamics: Clone + Sync + Send
81where
82 DefaultAllocator: Allocator<<Self::StateType as State>::Size>
83 + Allocator<<Self::StateType as State>::VecLength>
84 + Allocator<<Self::StateType as State>::Size, <Self::StateType as State>::Size>,
85{
86 /// The state of the associated hyperdual state, almost always StateType + U1
87 type HyperdualSize: DimName;
88 type StateType: State;
89
90 /// Defines the equations of motion for these dynamics, or a combination of provided dynamics.
91 /// The time delta_t is in **seconds** PAST the context epoch. The state vector is the state which
92 /// changes for every intermediate step of the integration. The state context is the state of
93 /// what is being propagated, it should allow rebuilding a new state context from the
94 /// provided state vector.
95 fn eom(
96 &self,
97 delta_t: f64,
98 state_vec: &OVector<f64, <Self::StateType as State>::VecLength>,
99 state_ctx: &Self::StateType,
100 almanac: Arc<Almanac>,
101 ) -> Result<OVector<f64, <Self::StateType as State>::VecLength>, DynamicsError>
102 where
103 DefaultAllocator: Allocator<<Self::StateType as State>::VecLength>;
104
105 /// Defines the equations of motion for Dual numbers for these dynamics.
106 /// _All_ dynamics need to allow for automatic differentiation. However, if differentiation is not supported,
107 /// then the dynamics should prevent initialization with a context which has an STM defined.
108 fn dual_eom(
109 &self,
110 _delta_t: f64,
111 _osculating_state: &Self::StateType,
112 _almanac: Arc<Almanac>,
113 ) -> Result<
114 (
115 OVector<f64, <Self::StateType as State>::Size>,
116 OMatrix<f64, <Self::StateType as State>::Size, <Self::StateType as State>::Size>,
117 ),
118 DynamicsError,
119 >
120 where
121 DefaultAllocator: Allocator<Self::HyperdualSize>
122 + Allocator<<Self::StateType as State>::Size>
123 + Allocator<<Self::StateType as State>::Size, <Self::StateType as State>::Size>,
124 Owned<f64, Self::HyperdualSize>: Copy,
125 {
126 Err(DynamicsError::StateTransitionMatrixUnset)
127 }
128
129 /// Optionally performs some final changes after each successful integration of the equations of motion.
130 /// For example, this can be used to update the Guidance mode.
131 /// NOTE: This function is also called just prior to very first integration step in order to update the initial state if needed.
132 fn finally(
133 &self,
134 next_state: Self::StateType,
135 _almanac: Arc<Almanac>,
136 ) -> Result<Self::StateType, DynamicsError> {
137 Ok(next_state)
138 }
139}
140
141/// The `ForceModel` trait handles immutable dynamics which return a force. Those will be divided by the mass of the spacecraft to compute the acceleration (F = ma).
142///
143/// Examples include Solar Radiation Pressure, drag, etc., i.e. forces which do not need to save the current state, only act on it.
144pub trait ForceModel: Send + Sync + fmt::Display {
145 /// If a parameter of this force model is stored in the spacecraft state, then this function should return the index where this parameter is being affected
146 fn estimation_index(&self) -> Option<usize>;
147
148 /// Defines the equations of motion for this force model from the provided osculating state.
149 fn eom(&self, ctx: &Spacecraft, almanac: Arc<Almanac>) -> Result<Vector3<f64>, DynamicsError>;
150
151 /// Force models must implement their partials, although those will only be called if the propagation requires the
152 /// computation of the STM. The `osc_ctx` is the osculating context, i.e. it changes for each sub-step of the integrator.
153 /// The last row corresponds to the partials of the parameter of this force model wrt the position, i.e. this only applies to conservative forces.
154 fn gradient(
155 &self,
156 osc_ctx: &Spacecraft,
157 almanac: Arc<Almanac>,
158 ) -> Result<(Vector3<f64>, Matrix4x3<f64>), DynamicsError>;
159}
160
161/// The `AccelModel` trait handles immutable dynamics which return an acceleration. Those can be added directly to Orbital Dynamics for example.
162///
163/// Examples include spherical harmonics, i.e. accelerations which do not need to save the current state, only act on it.
164pub trait AccelModel: Send + Sync + fmt::Display {
165 /// Defines the equations of motion for this force model from the provided osculating state in the integration frame.
166 fn eom(&self, osc: &Orbit, almanac: Arc<Almanac>) -> Result<Vector3<f64>, DynamicsError>;
167
168 /// Acceleration models must implement their partials, although those will only be called if the propagation requires the
169 /// computation of the STM.
170 fn gradient(
171 &self,
172 osc_ctx: &Orbit,
173 almanac: Arc<Almanac>,
174 ) -> Result<(Vector3<f64>, Matrix3<f64>), DynamicsError>;
175}
176
177/// Stores dynamical model errors
178#[derive(Debug, PartialEq, Snafu)]
179#[snafu(visibility(pub(crate)))]
180pub enum DynamicsError {
181 #[snafu(display("spacecraft total mass is zero, cannot compute any force model"))]
182 MasslessSpacecraft,
183 /// Fuel exhausted at the provided spacecraft state
184 #[snafu(display("fuel exhausted at {sc}"))]
185 FuelExhausted { sc: Box<Spacecraft> },
186 #[snafu(display("expected STM to be set"))]
187 StateTransitionMatrixUnset,
188 #[snafu(display("dynamical model encountered an astro error: {source}"))]
189 DynamicsAstro { source: AstroError },
190 #[snafu(display("dynamical model encountered an issue with the guidance: {source}"))]
191 DynamicsGuidance { source: GuidanceError },
192 #[snafu(display("dynamical model issue due to Almanac: {action} {source}"))]
193 DynamicsAlmanacError {
194 action: &'static str,
195 #[snafu(source(from(AlmanacError, Box::new)))]
196 source: Box<AlmanacError>,
197 },
198 #[snafu(display("dynamical model issue due to planetary data: {action} {source}"))]
199 DynamicsPlanetaryError {
200 action: &'static str,
201 #[snafu(source(from(PlanetaryDataError, Box::new)))]
202 source: Box<PlanetaryDataError>,
203 },
204}