Skip to content

Commit

Permalink
Merge pull request #216 from nyx-space/212-expose-configrepr-capabili…
Browse files Browse the repository at this point in the history
…ties-in-nyx-python-api

Support pickling of a number of important structures to Python
  • Loading branch information
ChristopherRabotin authored Aug 21, 2023
2 parents 857c7e5 + 91c2f35 commit c000659
Show file tree
Hide file tree
Showing 27 changed files with 873 additions and 136 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
set -e
ls -lh dist
pip install nyx_space --find-links dist --force-reinstall -v --no-cache-dir
pip install pytest numpy pandas plotly pyarrow scipy
pip install pytest numpy pandas plotly pyarrow scipy pyyaml
pytest
- name: Upload python tests HTMLs
Expand Down Expand Up @@ -82,7 +82,7 @@ jobs:
set -e
ls -lh dist
pip install --find-links dist --force-reinstall nyx_space
pip install pytest numpy pandas plotly pyarrow
pip install pytest numpy pandas plotly pyarrow pyyaml
pytest
macos:
Expand Down Expand Up @@ -115,7 +115,7 @@ jobs:
set -e
ls -lh dist
pip install --find-links dist --force-reinstall nyx_space
pip install pytest numpy pandas plotly pyarrow
pip install pytest numpy pandas plotly pyarrow pyyaml
pytest
sdist:
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ node_modules/
*.svg
*.data
*.folded
*.venv
*.venv*
dist/
*.parquet
*.profraw
Expand Down
46 changes: 33 additions & 13 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,21 @@ keywords = ["space", "mission", "design", "orbit", "estimation"]
categories = ["science", "simulation", "aerospace", "science::robotics"]
readme = "README.md"
license = "AGPL-3.0-or-later"
exclude = ["tests/GMAT_scripts/*", "examples", "data/*.gz", "data/*.png", "data/od_plots/", "rustfmt.toml", "de438s.xb", "Pipfile*", ".vscode/launch.json", "*.kst", "docs/*", "*.bsp", "data/tests/*"]
exclude = [
"tests/GMAT_scripts/*",
"examples",
"data/*.gz",
"data/*.png",
"data/od_plots/",
"rustfmt.toml",
"de438s.xb",
"Pipfile*",
".vscode/launch.json",
"*.kst",
"docs/*",
"*.bsp",
"data/tests/*",
]

[badges]
maintenance = { status = "actively-developed" }
Expand All @@ -21,8 +35,10 @@ gitlab = { repository = "nyx-space/nyx", branch = "master" }
[dependencies]
nalgebra = "=0.32"
log = "0.4"
hifitime = { version = "3.8.2", features = ["std"] }
flate2 = { version = "1.0", features = ["rust_backend"], default-features = false }
hifitime = { version = "3.8.3", features = ["std"] }
flate2 = { version = "1.0", features = [
"rust_backend",
], default-features = false }
serde = "1.0"
serde_derive = "1.0"
csv = "1"
Expand All @@ -40,25 +56,29 @@ rayon = "1.6"
lazy_static = "1.4.0"
approx = "0.5"
rand_pcg = "0.3"
pyo3 = {version = "0.18.0", optional = true, features = ["extension-module"]}
pyo3-log = {version = "0.8.2", optional = true}
numpy = {version = "0.18", optional = true}
indicatif = {version = "0.17", features = ["rayon"]}
pyo3 = { version = "0.19.0", optional = true, features = ["extension-module"] }
pyo3-log = { version = "0.8.2", optional = true }
numpy = { version = "0.19", optional = true }
indicatif = { version = "0.17", features = ["rayon"] }
rstats = "1.2.50"
thiserror = "1.0"
parquet = {version = "45.0.0", default-features = false, features = ["arrow", "brotli"]}
parquet = { version = "45.0.0", default-features = false, features = [
"arrow",
"brotli",
] }
arrow = "45.0.0"
shadow-rs = {version = "0.23.0", default-features = false}
shadow-rs = { version = "0.23.0", default-features = false }
serde_yaml = "0.9.21"
whoami = "1.3.0"
either = {version = "1.8.1", features = ["serde"]}
either = { version = "1.8.1", features = ["serde"] }
num = "0.4.0"
enum-iterator = "1.4.0"
getrandom = {version = "0.2", features = ["js"]}
getrandom = { version = "0.2", features = ["js"] }
typed-builder = "0.15.0"
pythonize = { version = "0.19", optional = true }

[dev-dependencies]
polars = {version = "0.32.1", features = ["parquet"]}
polars = { version = "0.32.1", features = ["parquet"] }
rstest = "0.18.1"
pretty_env_logger = "0.5"

Expand All @@ -67,7 +87,7 @@ shadow-rs = "0.23.0"

[features]
default = []
python = ["pyo3", "pyo3-log", "hifitime/python", "numpy"]
python = ["pyo3", "pyo3-log", "hifitime/python", "numpy", "pythonize"]

[lib]
crate-type = ["cdylib", "rlib"]
Expand Down
8 changes: 4 additions & 4 deletions python/nyx_space/plots/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@
# Color blindness friendly colors, from https://jfly.uni-koeln.de/color/#pallet
# And from https://davidmathlogic.com/colorblind/#%23E1BE6A-%2340B0A6-%237bcb12-%233d9087
colors = {
"orange": (230, 159, 0), # #e69f00
"sky_blue": (86, 180, 233), # #56b4e9
"purple": (204, 121, 167), # #cc79a7
"green": (0, 158, 115), # #009e73
"yellow": (240, 228, 66), # #f0e442
"blue": (0, 114, 178), # #0072b2
"red_ish": (213, 94, 0), # #d55e00
"purple": (204, 121, 167), # #cc79a7
"orange": (230, 159, 0), # #e69f00
"blue": (0, 114, 178), # #0072b2
"yellow": (240, 228, 66), # #f0e442
"yellow2": (255, 194, 10), # #ffc20a
"blue2": (12, 123, 220), # #0c7bdc
"bright_green": (26, 255, 26), # #1aff1a
Expand Down
16 changes: 13 additions & 3 deletions src/cosmic/orbit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ use crate::io::ConfigError;
#[cfg(feature = "python")]
use crate::python::cosmic::Frame as PyFrame;
#[cfg(feature = "python")]
use pyo3::class::basic::CompareOp;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use pyo3::types::PyType;
Expand Down Expand Up @@ -1321,7 +1323,11 @@ impl Orbit {
.to_degrees(),
)
} else if self.ecc() > 1.0 {
info!("computing the hyperbolic anomaly");
info!(
"computing the hyperbolic anomaly (ecc = {:.6} @ {})",
self.ecc(),
self.epoch
);
// From GMAT's TrueToHyperbolicAnomaly
((self.ta_deg().to_radians().sin() * (self.ecc().powi(2) - 1.0)).sqrt()
/ (1.0 + self.ecc() * self.ta_deg().to_radians().cos()))
Expand Down Expand Up @@ -1591,8 +1597,12 @@ impl Orbit {
}

#[cfg(feature = "python")]
fn __eq__(&self, other: &Self) -> bool {
self == other
fn __richcmp__(&self, other: &Self, op: CompareOp) -> Result<bool, NyxError> {
match op {
CompareOp::Eq => Ok(self == other),
CompareOp::Ne => Ok(self != other),
_ => Err(NyxError::CustomError(format!("{op:?} not available"))),
}
}

/// Creates a new Orbit in the provided frame at the provided Epoch given the position and velocity components.
Expand Down
3 changes: 3 additions & 0 deletions src/cosmic/spacecraft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ impl From<GuidanceMode> for f64 {
/// Optionally, the spacecraft state can also store the state transition matrix from the start of the propagation until the current time (i.e. trajectory STM, not step-size STM).
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "nyx_space.cosmic"))]
#[cfg_attr(
feature = "python",
pyo3(
Expand Down Expand Up @@ -127,6 +128,7 @@ impl Default for Spacecraft {

#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(text_signature = "(area_m2, cr=1.8)"))]
#[cfg_attr(feature = "python", pyo3(module = "nyx_space.cosmic"))]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
/// The Solar Radiation Pressure configuration for a spacecraft
pub struct SrpConfig {
Expand Down Expand Up @@ -157,6 +159,7 @@ impl Default for SrpConfig {

#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(text_signature = "(area_m2, cd=2.2)"))]
#[cfg_attr(feature = "python", pyo3(module = "nyx_space.cosmic"))]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq)]
/// The drag configuration for a spacecraft
pub struct DragConfig {
Expand Down
24 changes: 24 additions & 0 deletions src/dynamics/spacecraft.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,14 @@ use crate::cosmic::Cosm;
#[cfg(feature = "python")]
use crate::io::ConfigRepr;
#[cfg(feature = "python")]
use pyo3::class::basic::CompareOp;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg(feature = "python")]
use pyo3::types::PyType;
#[cfg(feature = "python")]
use pythonize::depythonize;
#[cfg(feature = "python")]
use std::collections::HashMap;

const NORM_ERR: f64 = 1e-4;
Expand All @@ -50,6 +54,7 @@ const NORM_ERR: f64 = 1e-4;
/// Note: if the spacecraft runs out of fuel, the propagation segment will return an error.
#[derive(Clone)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "nyx_space.mission_design"))]
pub struct SpacecraftDynamics {
pub orbital_dyn: OrbitalDynamics,
pub force_models: Vec<Arc<dyn ForceModel>>,
Expand Down Expand Up @@ -212,6 +217,25 @@ impl SpacecraftDynamics {
fn __repr__(&self) -> String {
format!("{self}")
}

#[cfg(feature = "python")]
fn __richcmp__(&self, other: &Self, op: CompareOp) -> Result<bool, NyxError> {
match op {
CompareOp::Eq => Ok(self.__repr__() == other.__repr__()),
CompareOp::Ne => Ok(self.__repr__() != other.__repr__()),
_ => Err(NyxError::CustomError(format!("{op:?} not available"))),
}
}

#[cfg(feature = "python")]
#[classmethod]
/// Loads the SpacecraftDynamics from its YAML representation
fn loads(_cls: &PyType, state: &PyAny) -> Result<Self, ConfigError> {
<Self as Configurable>::from_config(
depythonize(state).map_err(|e| ConfigError::InvalidConfig(e.to_string()))?,
Cosm::de438(),
)
}
}

impl fmt::Display for SpacecraftDynamics {
Expand Down
2 changes: 1 addition & 1 deletion src/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ pub trait ConfigRepr: Debug + Sized + Serialize + DeserializeOwned {
serde_yaml::from_reader(reader).map_err(ConfigError::ParseError)
}

// Builds a sequence of "Selves" from the provided string of a yaml
/// Builds a sequence of "Selves" from the provided string of a yaml
fn loads_many(data: &str) -> Result<Vec<Self>, ConfigError> {
debug!("Loading YAML:\n{data}");
serde_yaml::from_str(data).map_err(ConfigError::ParseError)
Expand Down
11 changes: 9 additions & 2 deletions src/io/trajectory_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ use crate::Spacecraft;
#[cfg(feature = "python")]
use log::warn;
#[cfg(feature = "python")]
use pyo3::class::basic::CompareOp;
#[cfg(feature = "python")]
use pyo3::prelude::*;

use crate::cosmic::Cosm;
Expand Down Expand Up @@ -345,7 +347,12 @@ impl TrajectoryLoader {
Ok((self.path.clone(),))
}

fn __eq__(&self, other: &Self) -> bool {
self == other
#[cfg(feature = "python")]
fn __richcmp__(&self, other: &Self, op: CompareOp) -> Result<bool, NyxError> {
match op {
CompareOp::Eq => Ok(self == other),
CompareOp::Ne => Ok(self != other),
_ => Err(NyxError::CustomError(format!("{op:?} not available"))),
}
}
}
7 changes: 6 additions & 1 deletion src/md/trajectory/traj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,12 @@ where
}
}

info!("Serialized {} states", states.len());
info!(
"Serialized {} states from {} to {}",
states.len(),
states.first().unwrap().epoch(),
states.last().unwrap().epoch()
);

// Add all of the evaluated events
if let Some(events) = events {
Expand Down
1 change: 1 addition & 0 deletions src/od/ground_station.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use pyo3::prelude::*;
/// GroundStation defines a two-way ranging and doppler station.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[cfg_attr(feature = "python", pyclass)]
#[cfg_attr(feature = "python", pyo3(module = "nyx_space.orbit_determination"))]
pub struct GroundStation {
pub name: String,
/// in degrees
Expand Down
Loading

0 comments on commit c000659

Please sign in to comment.