Skip to content

Commit

Permalink
Merge pull request #367 from nyx-space/366-reduce-number-of-generics-…
Browse files Browse the repository at this point in the history
…for-propagator-options

Reduce number of generics for propagator options
  • Loading branch information
ChristopherRabotin authored Sep 30, 2024
2 parents 089b996 + a9444f5 commit acaad4f
Show file tree
Hide file tree
Showing 52 changed files with 1,015 additions and 876 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ typed-builder = "0.20.0"
pythonize = { version = "0.21", optional = true }
snafu = { version = "0.8.3", features = ["backtrace"] }
serde_dhall = "0.12"
toml = "0.8.14"


[dev-dependencies]
polars = { version = "0.43.1", features = ["parquet"] }
rstest = "0.22.0"
pretty_env_logger = "0.5"
toml = "0.8.14"

[build-dependencies]
shadow-rs = "0.35.0"
Expand Down
6 changes: 3 additions & 3 deletions examples/03_geo_analysis/raise.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use nyx::{
},
io::{gravity::HarmonicsMem, ExportCfg},
md::{prelude::Objective, StateParameter},
propagators::{PropOpts, Propagator, RSSCartesianStep},
propagators::{ErrorControl, IntegratorOptions, Propagator},
Spacecraft,
};
use std::{error::Error, sync::Arc};
Expand Down Expand Up @@ -117,9 +117,9 @@ fn main() -> Result<(), Box<dyn Error>> {
// We specify a minimum step in the propagator because the Ruggiero control would otherwise drive this step very low.
let (final_state, traj) = Propagator::rk89(
sc_dynamics.clone(),
PropOpts::builder()
IntegratorOptions::builder()
.min_step(10.0_f64.seconds())
.error_ctrl(RSSCartesianStep {})
.error_ctrl(ErrorControl::RSSCartesianStep)
.build(),
)
.with(sc, almanac.clone())
Expand Down
6 changes: 3 additions & 3 deletions examples/03_geo_analysis/stationkeeping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use nyx::{
io::{gravity::HarmonicsMem, ExportCfg},
mc::{MonteCarlo, MultivariateNormal, StateDispersion},
md::{prelude::Objective, StateParameter},
propagators::{PropOpts, Propagator, RSSCartesianStep},
propagators::{ErrorControl, IntegratorOptions, Propagator},
Spacecraft, State,
};
use std::{error::Error, sync::Arc};
Expand Down Expand Up @@ -103,9 +103,9 @@ fn main() -> Result<(), Box<dyn Error>> {
// Build the propagator setup.
let setup = Propagator::rk89(
sc_dynamics.clone(),
PropOpts::builder()
IntegratorOptions::builder()
.min_step(10.0_f64.seconds())
.error_ctrl(RSSCartesianStep {})
.error_ctrl(ErrorControl::RSSCartesianStep)
.build(),
);

Expand Down
6 changes: 6 additions & 0 deletions src/cosmic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ where
fn set_value(&mut self, param: StateParameter, _val: f64) -> Result<(), StateError> {
Err(StateError::Unavailable { param })
}

/// Returns a copy of the orbit
fn orbit(&self) -> Orbit;

/// Modifies this state's orbit
fn set_orbit(&mut self, _orbit: Orbit) {}
}

pub fn assert_orbit_eq_or_abs(left: &Orbit, right: &Orbit, epsilon: f64, msg: &str) {
Expand Down
8 changes: 8 additions & 0 deletions src/cosmic/spacecraft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,14 @@ impl State for Spacecraft {
fn unset_stm(&mut self) {
self.stm = None;
}

fn orbit(&self) -> Orbit {
self.orbit
}

fn set_orbit(&mut self, orbit: Orbit) {
self.orbit = orbit;
}
}

impl Add<OVector<f64, Const<6>>> for Spacecraft {
Expand Down
1 change: 1 addition & 0 deletions src/dynamics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ pub trait AccelModel: Send + Sync + fmt::Display {

/// Stores dynamical model errors
#[derive(Debug, PartialEq, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum DynamicsError {
/// Fuel exhausted at the provided spacecraft state
#[snafu(display("fuel exhausted at {sc}"))]
Expand Down
6 changes: 3 additions & 3 deletions src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,13 @@ impl ExportCfg {
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum ConfigError {
#[snafu(display("Failed to read configuration file: {source}"))]
#[snafu(display("failed to read configuration file: {source}"))]
ReadError { source: io::Error },

#[snafu(display("Failed to parse YAML configuration file: {source}"))]
#[snafu(display("failed to parse YAML configuration file: {source}"))]
ParseError { source: serde_yaml::Error },

#[snafu(display("Invalid configuration: {msg}"))]
#[snafu(display("of invalid configuration: {msg}"))]
InvalidConfig { msg: String },
}

Expand Down
26 changes: 13 additions & 13 deletions src/mc/montecarlo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::mc::results::{PropResult, Results, Run};
use crate::mc::DispersedState;
use crate::md::trajectory::Interpolatable;
use crate::md::EventEvaluator;
use crate::propagators::{ErrorCtrl, Propagator};
use crate::propagators::Propagator;
#[cfg(not(target_arch = "wasm32"))]
use crate::time::Unit;
use crate::time::{Duration, Epoch};
Expand Down Expand Up @@ -89,9 +89,9 @@ where

/// Generate states and propagate each independently until a specific event is found `trigger` times.
#[allow(clippy::needless_lifetimes)]
pub fn run_until_nth_event<'a, D, E, F>(
pub fn run_until_nth_event<D, F>(
self,
prop: Propagator<'a, D, E>,
prop: Propagator<D>,
almanac: Arc<Almanac>,
max_duration: Duration,
event: &F,
Expand All @@ -100,7 +100,7 @@ where
) -> Results<S, PropResult<S>>
where
D: Dynamics<StateType = S>,
E: ErrorCtrl,

F: EventEvaluator<S>,
DefaultAllocator: Allocator<<D::StateType as State>::Size>
+ Allocator<<D::StateType as State>::Size, <D::StateType as State>::Size>
Expand All @@ -113,9 +113,9 @@ where
/// Generate states and propagate each independently until a specific event is found `trigger` times.
#[must_use = "Monte Carlo result must be used"]
#[allow(clippy::needless_lifetimes)]
pub fn resume_run_until_nth_event<'a, D, E, F>(
pub fn resume_run_until_nth_event<D, F>(
&self,
prop: Propagator<'a, D, E>,
prop: Propagator<D>,
almanac: Arc<Almanac>,
skip: usize,
max_duration: Duration,
Expand All @@ -125,7 +125,7 @@ where
) -> Results<S, PropResult<S>>
where
D: Dynamics<StateType = S>,
E: ErrorCtrl,

F: EventEvaluator<S>,
DefaultAllocator: Allocator<<D::StateType as State>::Size>
+ Allocator<<D::StateType as State>::Size, <D::StateType as State>::Size>
Expand Down Expand Up @@ -188,16 +188,16 @@ where
/// Generate states and propagate each independently until a specific event is found `trigger` times.
#[must_use = "Monte Carlo result must be used"]
#[allow(clippy::needless_lifetimes)]
pub fn run_until_epoch<'a, D, E>(
pub fn run_until_epoch<D>(
self,
prop: Propagator<'a, D, E>,
prop: Propagator<D>,
almanac: Arc<Almanac>,
end_epoch: Epoch,
num_runs: usize,
) -> Results<S, PropResult<S>>
where
D: Dynamics<StateType = S>,
E: ErrorCtrl,

DefaultAllocator: Allocator<<D::StateType as State>::Size>
+ Allocator<<D::StateType as State>::Size, <D::StateType as State>::Size>
+ Allocator<<D::StateType as State>::VecLength>,
Expand All @@ -209,17 +209,17 @@ where
/// Resumes a Monte Carlo run by skipping the first `skip` items, generating states only after that, and propagate each independently until the specified epoch.
#[must_use = "Monte Carlo result must be used"]
#[allow(clippy::needless_lifetimes)]
pub fn resume_run_until_epoch<'a, D, E>(
pub fn resume_run_until_epoch<D>(
&self,
prop: Propagator<'a, D, E>,
prop: Propagator<D>,
almanac: Arc<Almanac>,
skip: usize,
end_epoch: Epoch,
num_runs: usize,
) -> Results<S, PropResult<S>>
where
D: Dynamics<StateType = S>,
E: ErrorCtrl,

DefaultAllocator: Allocator<<D::StateType as State>::Size>
+ Allocator<<D::StateType as State>::Size, <D::StateType as State>::Size>
+ Allocator<<D::StateType as State>::VecLength>,
Expand Down
6 changes: 3 additions & 3 deletions src/md/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use snafu::prelude::*;

pub mod prelude {
pub use super::{
optimizer::*,
targeter::*,
trajectory::{ExportCfg, Interpolatable, Traj},
Event, ScTraj, StateParameter,
};
Expand All @@ -36,7 +36,7 @@ pub mod prelude {
pub use crate::dynamics::{Dynamics, NyxError};
pub use crate::io::gravity::HarmonicsMem;
pub use crate::md::objective::Objective;
pub use crate::propagators::{PropOpts, Propagator};
pub use crate::propagators::{IntegratorOptions, Propagator};
pub use crate::time::{Duration, Epoch, TimeUnits, Unit};
pub use crate::Spacecraft;
pub use crate::{State, TimeTagged};
Expand All @@ -52,7 +52,7 @@ pub use events::{Event, EventEvaluator};

pub mod objective;
pub mod opti;
pub use opti::optimizer;
pub use opti::targeter;
pub type ScTraj = trajectory::Traj<Spacecraft>;
// pub type Ephemeris = trajectory::Traj<Orbit>;

Expand Down
8 changes: 4 additions & 4 deletions src/md/opti/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@
// pub mod convert_impulsive;
pub mod multipleshooting;
pub use multipleshooting::{ctrlnodes, multishoot};
/// Uses a Levenberg Marquardt minimizer to solve the damped least squares problem.
// #[cfg(feature = "broken-donotuse")]
// pub mod minimize_lm;
pub mod optimizer;
/// Uses a [Newton Raphson](https://en.wikipedia.org/wiki/Newton%27s_method_in_optimization) method where the Jacobian is computed via finite differencing.
pub mod raphson_finite_diff;
/// Uses a [Newton Raphson](https://en.wikipedia.org/wiki/Newton%27s_method_in_optimization) method where the Jacobian is computed via hyperdual numbers.
pub mod raphson_hyperdual;
pub mod solution;
pub mod target_variable;
/// Uses a Levenberg Marquardt minimizer to solve the damped least squares problem.
// #[cfg(feature = "broken-donotuse")]
// pub mod minimize_lm;
pub mod targeter;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum DiffMethod {
Expand Down
5 changes: 2 additions & 3 deletions src/md/opti/multipleshooting/altitude_heuristic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ use super::{
};
use crate::errors::TargetingError;
use crate::md::{prelude::*, PropSnafu};
use crate::propagators::error_ctrl::ErrorCtrl;
use crate::{Orbit, Spacecraft};

impl<'a, E: ErrorCtrl> MultipleShooting<'a, E, Node, 3, 3> {
impl<'a> MultipleShooting<'a, Node, 3, 3> {
/// Builds a multiple shooting structure assuming that the optimal trajectory is near a linear
/// heuristic in geodetic altitude and direction.
/// For example, if x0 has an altitude of 100 km and xf has an altitude
Expand All @@ -42,7 +41,7 @@ impl<'a, E: ErrorCtrl> MultipleShooting<'a, E, Node, 3, 3> {
node_count: usize,
angular_velocity_deg_s: f64,
body_frame: Frame,
prop: &'a Propagator<'a, SpacecraftDynamics, E>,
prop: &'a Propagator<SpacecraftDynamics>,
almanac: Arc<Almanac>,
) -> Result<Self, MultipleShootingError> {
if node_count < 3 {
Expand Down
5 changes: 2 additions & 3 deletions src/md/opti/multipleshooting/equidistant_heuristic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ use super::multishoot::MultipleShooting;
pub use super::CostFunction;
use crate::errors::TargetingError;
use crate::md::prelude::*;
use crate::propagators::error_ctrl::ErrorCtrl;
use crate::{Orbit, Spacecraft};

impl<'a, E: ErrorCtrl> MultipleShooting<'a, E, Node, 3, 3> {
impl<'a> MultipleShooting<'a, Node, 3, 3> {
/// Builds a multiple shooting structure assuming that the optimal trajectory is a straight line
/// between the start and end points. The position of the nodes will be update at each iteration
/// of the outer loop.
Expand All @@ -33,7 +32,7 @@ impl<'a, E: ErrorCtrl> MultipleShooting<'a, E, Node, 3, 3> {
x0: Spacecraft,
xf: Orbit,
node_count: usize,
prop: &'a Propagator<'a, SpacecraftDynamics, E>,
prop: &'a Propagator<SpacecraftDynamics>,
) -> Result<Self, TargetingError> {
if node_count < 3 {
error!("At least three nodes are needed for a multiple shooting optimization");
Expand Down
37 changes: 14 additions & 23 deletions src/md/opti/multipleshooting/multishoot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,8 @@ pub use super::CostFunction;
use super::{MultipleShootingError, TargetingSnafu};
use crate::linalg::{DMatrix, DVector, SVector};
use crate::md::opti::solution::TargeterSolution;
use crate::md::optimizer::Optimizer;
use crate::md::targeter::Targeter;
use crate::md::{prelude::*, TargetingError};
use crate::propagators::error_ctrl::ErrorCtrl;
use crate::pseudo_inverse;
use crate::{Orbit, Spacecraft};

Expand All @@ -39,15 +38,9 @@ pub trait MultishootNode<const O: usize>: Copy + Into<[Objective; O]> {
/// Source of implementation: "Low Thrust Optimization in Cislunar and Translunar space", 2018 Nathan Re (Parrish)
/// OT: size of the objectives for each node (e.g. 3 if the objectives are X, Y, Z).
/// VT: size of the variables for targeter node (e.g. 4 if the objectives are thrust direction (x,y,z) and thrust level).
pub struct MultipleShooting<
'a,
E: ErrorCtrl,
T: MultishootNode<OT>,
const VT: usize,
const OT: usize,
> {
pub struct MultipleShooting<'a, T: MultishootNode<OT>, const VT: usize, const OT: usize> {
/// The propagator setup (kind, stages, etc.)
pub prop: &'a Propagator<'a, SpacecraftDynamics, E>,
pub prop: &'a Propagator<SpacecraftDynamics>,
/// List of nodes of the optimal trajectory
pub targets: Vec<T>,
/// Starting point, must be a spacecraft equipped with a thruster
Expand All @@ -66,9 +59,7 @@ pub struct MultipleShooting<
pub all_dvs: Vec<SVector<f64, VT>>,
}

impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize>
MultipleShooting<'a, E, T, VT, OT>
{
impl<'a, T: MultishootNode<OT>, const VT: usize, const OT: usize> MultipleShooting<'a, T, VT, OT> {
/// Solve the multiple shooting problem by finding the arrangement of nodes to minimize the cost function.
pub fn solve(
&mut self,
Expand All @@ -90,7 +81,7 @@ impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize>
/* ***
** 1. Solve the delta-v differential corrector between each node
** *** */
let tgt = Optimizer {
let tgt = Targeter {
prop: self.prop,
objectives: self.targets[i].into(),
variables: self.variables,
Expand Down Expand Up @@ -134,7 +125,7 @@ impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize>
** Note that because the first initial_state is x0, the i-th "initial state"
** is the initial state to reach the i-th node.
** *** */
let inner_tgt_a = Optimizer::delta_v(self.prop, next_node);
let inner_tgt_a = Targeter::delta_v(self.prop, next_node);
let inner_sol_a = inner_tgt_a
.try_achieve_dual(
initial_states[i],
Expand All @@ -160,7 +151,7 @@ impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize>
/* ***
** 2.C. Rerun the targeter from the new state at the perturbed node to the next unpertubed node
** *** */
let inner_tgt_b = Optimizer::delta_v(self.prop, self.targets[i + 1].into());
let inner_tgt_b = Targeter::delta_v(self.prop, self.targets[i + 1].into());
let inner_sol_b = inner_tgt_b
.try_achieve_dual(
inner_sol_a.achieved_state,
Expand Down Expand Up @@ -250,7 +241,7 @@ impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize>

for (i, node) in self.targets.iter().enumerate() {
// Run the unpertubed targeter
let tgt = Optimizer::delta_v(self.prop, (*node).into());
let tgt = Targeter::delta_v(self.prop, (*node).into());
let sol = tgt
.try_achieve_dual(
initial_states[i],
Expand Down Expand Up @@ -287,8 +278,8 @@ impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize>
}
}

impl<'a, E: ErrorCtrl, T: MultishootNode<OT>, const VT: usize, const OT: usize> fmt::Display
for MultipleShooting<'a, E, T, VT, OT>
impl<'a, T: MultishootNode<OT>, const VT: usize, const OT: usize> fmt::Display
for MultipleShooting<'a, T, VT, OT>
{
#[allow(clippy::or_fun_call, clippy::clone_on_copy)]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Expand Down Expand Up @@ -357,15 +348,15 @@ impl<T: MultishootNode<O>, const O: usize> fmt::Display for MultipleShootingSolu
impl<T: MultishootNode<O>, const O: usize> MultipleShootingSolution<T, O> {
/// Allows building the trajectories between different nodes
/// This will rebuild the targeters and apply the solutions sequentially
pub fn build_trajectories<'a, E: ErrorCtrl>(
pub fn build_trajectories(
&self,
prop: &'a Propagator<'a, SpacecraftDynamics, E>,
prop: &Propagator<SpacecraftDynamics>,
almanac: Arc<Almanac>,
) -> Result<Vec<ScTraj>, MultipleShootingError> {
let mut trajz = Vec::with_capacity(self.nodes.len());

for (i, node) in self.nodes.iter().enumerate() {
let (_, traj) = Optimizer::delta_v(prop, (*node).into())
for (i, node) in self.nodes.iter().copied().enumerate() {
let (_, traj) = Targeter::delta_v(prop, node.into())
.apply_with_traj(&self.solutions[i], almanac.clone())
.context(TargetingSnafu { segment: i })?;
trajz.push(traj);
Expand Down
Loading

0 comments on commit acaad4f

Please sign in to comment.