use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use nalgebra as na;
use nalgebra::{DMatrix, DVector, SVector, Vector3, Vector6};
use numpy::{
IntoPyArray, Ix1, Ix2, PyArray, PyArrayMethods, PyReadonlyArray1, PyReadonlyArray2,
PyReadonlyArray3, PyUntypedArrayMethods, ToPyArray, ndarray,
};
use pyo3::create_exception;
use pyo3::panic::PanicException;
use pyo3::prelude::*;
use pyo3::pyclass::CompareOp;
use pyo3::types::{
PyDateAccess, PyDateTime, PyDict, PyFloat, PyList, PyString, PyTimeAccess, PyTuple, PyType,
};
use pyo3::{IntoPyObjectExt, PyRefMut, exceptions, wrap_pyfunction};
use rayon::prelude::*;
use crate::math::interpolation::CovarianceInterpolationConfig;
use crate::traits::*;
use crate::utils::{
BraheError as RustBraheError, format_time_string, get_brahe_cache_dir,
get_brahe_cache_dir_with_subdir, get_celestrak_cache_dir, get_eop_cache_dir, get_max_threads,
set_max_threads, set_num_threads,
};
use crate::*;
create_exception!(brahe._brahe, BraheError, pyo3::exceptions::PyException);
impl From<RustBraheError> for pyo3::PyErr {
fn from(error: RustBraheError) -> pyo3::PyErr {
BraheError::new_err(error.to_string())
}
}
macro_rules! matrix_to_numpy {
($py:expr,$mat:expr,$r:expr,$c:expr,$typ:ty) => {{
let flat_vec: Vec<$typ> = (0..$r)
.flat_map(|i| (0..$c).map(move |j| $mat[(i, j)]))
.collect();
flat_vec.into_pyarray($py).reshape([$r, $c]).unwrap()
}};
}
macro_rules! vector_to_numpy {
($py:expr,$vec:expr,$l:expr,$typ:ty) => {{
let flat_vec: Vec<$typ> = (0..$l).map(|i| $vec[i]).collect();
flat_vec.into_pyarray($py)
}};
}
macro_rules! numpy_to_vector3 {
($arr:expr) => {{
let vec = $arr.to_vec().map_err(|_| {
pyo3::exceptions::PyValueError::new_err("Failed to convert numpy array to vector")
})?;
if vec.len() != 3 {
return Err(pyo3::exceptions::PyValueError::new_err(format!(
"Expected array of length 3, got {}",
vec.len()
)));
}
nalgebra::Vector3::new(vec[0], vec[1], vec[2])
}};
}
macro_rules! numpy_to_vector6 {
($arr:expr) => {{
let vec = $arr.to_vec().map_err(|_| {
pyo3::exceptions::PyValueError::new_err("Failed to convert numpy array to vector")
})?;
if vec.len() != 6 {
return Err(pyo3::exceptions::PyValueError::new_err(format!(
"Expected array of length 6, got {}",
vec.len()
)));
}
nalgebra::Vector6::new(vec[0], vec[1], vec[2], vec[3], vec[4], vec[5])
}};
}
macro_rules! numpy_to_smatrix3 {
($arr:expr) => {{
let shape = $arr.shape();
if shape[0] != 3 || shape[1] != 3 {
return Err(pyo3::exceptions::PyValueError::new_err(format!(
"Expected 3x3 matrix, got {}x{}",
shape[0], shape[1]
)));
}
let mat_vec = $arr.to_vec().map_err(|_| {
pyo3::exceptions::PyValueError::new_err("Failed to convert numpy array to matrix")
})?;
nalgebra::SMatrix::<f64, 3, 3>::from_row_slice(&mat_vec)
}};
}
fn pyany_to_f64_array1(arr: &Bound<'_, PyAny>, expected_len: Option<usize>) -> PyResult<Vec<f64>> {
if let Ok(vec) = arr.extract::<Vec<f64>>() {
if let Some(len) = expected_len
&& vec.len() != len
{
return Err(exceptions::PyValueError::new_err(format!(
"Expected array or list of length {}, got {}",
len,
vec.len()
)));
}
return Ok(vec);
}
let py = arr.py();
let np = py
.import("numpy")
.map_err(|_| exceptions::PyImportError::new_err("Failed to import numpy"))?;
let float64_dtype = np
.getattr("float64")
.map_err(|_| exceptions::PyAttributeError::new_err("Failed to get numpy.float64"))?;
let arr_f64 = arr
.call_method1("astype", (float64_dtype,))
.map_err(|_| exceptions::PyTypeError::new_err("Expected a numpy array or Python list"))?;
let pyarray = arr_f64
.cast::<PyArray<f64, Ix1>>()
.map_err(|_| exceptions::PyTypeError::new_err("Expected a 1-D numpy array or list"))?;
let vec = pyarray
.to_vec()
.map_err(|_| exceptions::PyValueError::new_err("Failed to convert array to vector"))?;
if let Some(len) = expected_len
&& vec.len() != len
{
return Err(exceptions::PyValueError::new_err(format!(
"Expected array or list of length {}, got {}",
len,
vec.len()
)));
}
Ok(vec)
}
fn pyany_to_f64_array2(
arr: &Bound<'_, PyAny>,
expected_shape: Option<(usize, usize)>,
) -> PyResult<Vec<Vec<f64>>> {
if let Ok(mat_vec) = arr.extract::<Vec<Vec<f64>>>() {
if let Some((exp_rows, exp_cols)) = expected_shape {
if mat_vec.len() != exp_rows {
return Err(exceptions::PyValueError::new_err(format!(
"Expected matrix or list with {} rows, got {}",
exp_rows,
mat_vec.len()
)));
}
for (i, row) in mat_vec.iter().enumerate() {
if row.len() != exp_cols {
return Err(exceptions::PyValueError::new_err(format!(
"Expected {} columns in row {}, got {}",
exp_cols,
i,
row.len()
)));
}
}
}
return Ok(mat_vec);
}
let py = arr.py();
let np = py
.import("numpy")
.map_err(|_| exceptions::PyImportError::new_err("Failed to import numpy"))?;
let float64_dtype = np
.getattr("float64")
.map_err(|_| exceptions::PyAttributeError::new_err("Failed to get numpy.float64"))?;
let arr_f64 = arr.call_method1("astype", (float64_dtype,)).map_err(|_| {
exceptions::PyTypeError::new_err("Expected a 2D numpy array or nested Python list")
})?;
let pyarray = arr_f64.cast::<PyArray<f64, Ix2>>().map_err(|_| {
exceptions::PyTypeError::new_err("Expected a 2-D numpy array or nested list")
})?;
let shape = pyarray.shape();
if shape.len() != 2 {
return Err(exceptions::PyValueError::new_err(format!(
"Expected 2-D array, got {}-D",
shape.len()
)));
}
let rows = shape[0];
let cols = shape[1];
if let Some((exp_rows, exp_cols)) = expected_shape
&& (rows != exp_rows || cols != exp_cols)
{
return Err(exceptions::PyValueError::new_err(format!(
"Expected array or list of shape ({}, {}), got ({}, {})",
exp_rows, exp_cols, rows, cols
)));
}
let flat_vec = pyarray
.to_vec()
.map_err(|_| exceptions::PyValueError::new_err("Failed to convert array to vector"))?;
let mut result = Vec::with_capacity(rows);
for i in 0..rows {
let row = flat_vec[i * cols..(i + 1) * cols].to_vec();
result.push(row);
}
Ok(result)
}
fn pyany_to_svector<const N: usize>(arr: &Bound<'_, PyAny>) -> PyResult<na::SVector<f64, N>> {
if let Ok(vec) = arr.extract::<Vec<f64>>() {
if vec.len() != N {
return Err(exceptions::PyValueError::new_err(format!(
"Expected array or list of length {}, got {}",
N,
vec.len()
)));
}
return Ok(na::SVector::<f64, N>::from_vec(vec));
}
let py = arr.py();
let np = py
.import("numpy")
.map_err(|_| exceptions::PyImportError::new_err("Failed to import numpy"))?;
let float64_dtype = np
.getattr("float64")
.map_err(|_| exceptions::PyAttributeError::new_err("Failed to get numpy.float64"))?;
let arr_f64 = arr
.call_method1("astype", (float64_dtype,))
.map_err(|_| exceptions::PyTypeError::new_err("Expected a numpy array or Python list"))?;
let pyarray = arr_f64
.cast::<PyArray<f64, Ix1>>()
.map_err(|_| exceptions::PyTypeError::new_err("Expected a 1-D numpy array or list"))?;
let vec = pyarray
.to_vec()
.map_err(|_| exceptions::PyValueError::new_err("Failed to convert array to vector"))?;
if vec.len() != N {
return Err(exceptions::PyValueError::new_err(format!(
"Expected array or list of length {}, got {}",
N,
vec.len()
)));
}
Ok(na::SVector::<f64, N>::from_vec(vec))
}
#[allow(dead_code)]
fn pyany_to_smatrix<const R: usize, const C: usize>(
arr: &Bound<'_, PyAny>,
) -> PyResult<na::SMatrix<f64, R, C>> {
if let Ok(mat_vec) = arr.extract::<Vec<Vec<f64>>>() {
if mat_vec.len() != R {
return Err(exceptions::PyValueError::new_err(format!(
"Expected matrix or list with {} rows, got {}",
R,
mat_vec.len()
)));
}
for (i, row) in mat_vec.iter().enumerate() {
if row.len() != C {
return Err(exceptions::PyValueError::new_err(format!(
"Expected {} columns in row {}, got {}",
C,
i,
row.len()
)));
}
}
let flat: Vec<f64> = (0..C)
.flat_map(|col| mat_vec.iter().map(move |row| row[col]))
.collect();
return Ok(na::SMatrix::<f64, R, C>::from_vec(flat));
}
let py = arr.py();
let np = py
.import("numpy")
.map_err(|_| exceptions::PyImportError::new_err("Failed to import numpy"))?;
let float64_dtype = np
.getattr("float64")
.map_err(|_| exceptions::PyAttributeError::new_err("Failed to get numpy.float64"))?;
let arr_f64 = arr.call_method1("astype", (float64_dtype,)).map_err(|_| {
exceptions::PyTypeError::new_err("Expected a 2D numpy array or nested Python list")
})?;
let pyarray = arr_f64.cast::<PyArray<f64, Ix2>>().map_err(|_| {
exceptions::PyTypeError::new_err("Expected a 2-D numpy array or nested list")
})?;
let shape = pyarray.shape();
if shape.len() != 2 {
return Err(exceptions::PyValueError::new_err(format!(
"Expected 2-D array, got {}-D",
shape.len()
)));
}
let rows = shape[0];
let cols = shape[1];
if rows != R || cols != C {
return Err(exceptions::PyValueError::new_err(format!(
"Expected array or list of shape ({}, {}), got ({}, {})",
R, C, rows, cols
)));
}
let flat_vec = pyarray
.to_vec()
.map_err(|_| exceptions::PyValueError::new_err("Failed to convert array to vector"))?;
let mut mat_vec = Vec::with_capacity(R);
for i in 0..R {
let row = flat_vec[i * C..(i + 1) * C].to_vec();
mat_vec.push(row);
}
let flat: Vec<f64> = (0..C)
.flat_map(|col| mat_vec.iter().map(move |row| row[col]))
.collect();
Ok(na::SMatrix::<f64, R, C>::from_vec(flat))
}
#[pyclass(module = "brahe._brahe", from_py_object)]
#[pyo3(name = "AngleFormat")]
#[derive(Clone)]
pub struct PyAngleFormat {
pub(crate) value: constants::AngleFormat,
}
#[pymethods]
impl PyAngleFormat {
#[classattr]
#[allow(non_snake_case)]
fn RADIANS() -> Self {
PyAngleFormat {
value: constants::AngleFormat::Radians,
}
}
#[classattr]
#[allow(non_snake_case)]
fn DEGREES() -> Self {
PyAngleFormat {
value: constants::AngleFormat::Degrees,
}
}
fn __str__(&self) -> String {
format!("{:?}", self.value)
}
fn __repr__(&self) -> String {
format!("AngleFormat.{:?}", self.value)
}
fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
match op {
CompareOp::Eq => Ok(self.value == other.value),
CompareOp::Ne => Ok(self.value != other.value),
_ => Err(exceptions::PyNotImplementedError::new_err(
"Comparison not supported",
)),
}
}
}
include!("datasets.rs");
include!("py_gcat.rs");
include!("eop.rs");
include!("space_weather.rs");
include!("time.rs");
include!("frames.rs");
include!("coordinates.rs");
include!("orbits.rs");
include!("orbit_dynamics.rs"); include!("integrators.rs"); include!("events.rs"); include!("propagators.rs");
include!("attitude.rs");
include!("trajectories.rs");
include!("access.rs");
include!("relative_motion.rs");
include!("math.rs");
include!("utils.rs");
include!("earth_models.rs");
include!("spacetrack.rs");
include!("celestrak.rs");
include!("ccsds.rs");
include!("estimation.rs");
#[cfg(feature = "python")] #[pymodule(name = "_brahe")] pub fn _brahe(py: Python<'_>, module: &Bound<'_, PyModule>) -> PyResult<()> {
module.add("PanicException", py.get_type::<PanicException>())?;
module.add("BraheError", py.get_type::<BraheError>())?;
module.add("__version__", env!("CARGO_PKG_VERSION"))?;
module.add("DEG2RAD", constants::DEG2RAD)?;
module.add("RAD2DEG", constants::RAD2DEG)?;
module.add("AS2RAD", constants::AS2RAD)?;
module.add("RAD2AS", constants::RAD2AS)?;
module.add("MJD_ZERO", constants::MJD_ZERO)?;
module.add("MJD_J2000", constants::MJD_J2000)?;
module.add("JD_J2000", constants::JD_J2000)?;
module.add("GPS_TAI", constants::GPS_TAI)?;
module.add("TAI_GPS", constants::TAI_GPS)?;
module.add("TT_TAI", constants::TT_TAI)?;
module.add("TAI_TT", constants::TAI_TT)?;
module.add("GPS_TT", constants::GPS_TT)?;
module.add("TT_GPS", constants::TT_GPS)?;
module.add("GPS_ZERO", constants::GPS_ZERO)?;
module.add("BDT_TAI", constants::BDT_TAI)?;
module.add("TAI_BDT", constants::TAI_BDT)?;
module.add("GST_TAI", constants::GST_TAI)?;
module.add("TAI_GST", constants::TAI_GST)?;
module.add("BDT_ZERO", constants::BDT_ZERO)?;
module.add("GST_ZERO", constants::GST_ZERO)?;
module.add("UNIX_EPOCH_JD", constants::UNIX_EPOCH_JD)?;
module.add("UNIX_EPOCH_MJD", constants::UNIX_EPOCH_MJD)?;
module.add("C_LIGHT", constants::C_LIGHT)?;
module.add("AU", constants::AU)?;
module.add("R_EARTH", constants::R_EARTH)?;
module.add("WGS84_A", constants::WGS84_A)?;
module.add("WGS84_F", constants::WGS84_F)?;
module.add("GM_EARTH", constants::GM_EARTH)?;
module.add("ECC_EARTH", constants::ECC_EARTH)?;
module.add("J2_EARTH", constants::J2_EARTH)?;
module.add("OMEGA_EARTH", constants::OMEGA_EARTH)?;
module.add("GM_SUN", constants::GM_SUN)?;
module.add("R_SUN", constants::R_SUN)?;
module.add("P_SUN", constants::P_SUN)?;
module.add("R_MOON", constants::R_MOON)?;
module.add("GM_MOON", constants::GM_MOON)?;
module.add("GM_MERCURY", constants::GM_MERCURY)?;
module.add("GM_VENUS", constants::GM_VENUS)?;
module.add("GM_MARS", constants::GM_MARS)?;
module.add("GM_JUPITER", constants::GM_JUPITER)?;
module.add("GM_SATURN", constants::GM_SATURN)?;
module.add("GM_URANUS", constants::GM_URANUS)?;
module.add("GM_NEPTUNE", constants::GM_NEPTUNE)?;
module.add("GM_PLUTO", constants::GM_PLUTO)?;
module.add_function(wrap_pyfunction!(py_download_c04_eop_file, module)?)?;
module.add_function(wrap_pyfunction!(py_download_standard_eop_file, module)?)?;
module.add_class::<PyStaticEOPProvider>()?;
module.add_class::<PyFileEOPProvider>()?;
module.add_class::<PyCachingEOPProvider>()?;
module.add_function(wrap_pyfunction!(py_set_global_eop_provider, module)?)?;
module.add_function(wrap_pyfunction!(
py_set_global_eop_provider_from_static_provider,
module
)?)?;
module.add_function(wrap_pyfunction!(
py_set_global_eop_provider_from_file_provider,
module
)?)?;
module.add_function(wrap_pyfunction!(
py_set_global_eop_provider_from_caching_provider,
module
)?)?;
module.add_function(wrap_pyfunction!(py_get_global_ut1_utc, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_pm, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_dxdy, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_lod, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_initialization, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_len, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_type, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_extrapolation, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_interpolation, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_mjd_min, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_mjd_max, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_mjd_last_lod, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_eop_mjd_last_dxdy, module)?)?;
module.add_function(wrap_pyfunction!(py_initialize_eop, module)?)?;
module.add_class::<PyStaticSpaceWeatherProvider>()?;
module.add_class::<PyFileSpaceWeatherProvider>()?;
module.add_class::<PyCachingSpaceWeatherProvider>()?;
module.add_function(wrap_pyfunction!(
py_set_global_space_weather_provider,
module
)?)?;
module.add_function(wrap_pyfunction!(py_get_global_kp, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_kp_all, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_kp_daily, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_ap, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_ap_all, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_ap_daily, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_f107_observed, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_f107_adjusted, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_f107_obs_avg81, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_f107_adj_avg81, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sunspot_number, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_kp, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_ap, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_daily_kp, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_daily_ap, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_f107, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_kpap_epochs, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_last_daily_epochs, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sw_initialization, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sw_len, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sw_type, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sw_extrapolation, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sw_mjd_min, module)?)?;
module.add_function(wrap_pyfunction!(py_get_global_sw_mjd_max, module)?)?;
module.add_function(wrap_pyfunction!(
py_get_global_sw_mjd_last_observed,
module
)?)?;
module.add_function(wrap_pyfunction!(
py_get_global_sw_mjd_last_daily_predicted,
module
)?)?;
module.add_function(wrap_pyfunction!(
py_get_global_sw_mjd_last_monthly_predicted,
module
)?)?;
module.add_function(wrap_pyfunction!(py_initialize_sw, module)?)?;
module.add_class::<PyTimeSystem>()?;
module.add_class::<PyEpoch>()?;
module.add_class::<PyTimeRange>()?;
module.add_function(wrap_pyfunction!(py_mjd_to_datetime, module)?)?;
module.add_function(wrap_pyfunction!(py_datetime_to_mjd, module)?)?;
module.add_function(wrap_pyfunction!(py_jd_to_datetime, module)?)?;
module.add_function(wrap_pyfunction!(py_datetime_to_jd, module)?)?;
module.add_function(wrap_pyfunction!(py_time_system_offset_for_mjd, module)?)?;
module.add_function(wrap_pyfunction!(py_time_system_offset_for_jd, module)?)?;
module.add_function(wrap_pyfunction!(
py_time_system_offset_for_datetime,
module
)?)?;
module.add(
"GPS",
PyTimeSystem {
ts: time::TimeSystem::GPS,
},
)?;
module.add(
"TAI",
PyTimeSystem {
ts: time::TimeSystem::TAI,
},
)?;
module.add(
"TT",
PyTimeSystem {
ts: time::TimeSystem::TT,
},
)?;
module.add(
"UTC",
PyTimeSystem {
ts: time::TimeSystem::UTC,
},
)?;
module.add(
"UT1",
PyTimeSystem {
ts: time::TimeSystem::UT1,
},
)?;
module.add(
"TDB",
PyTimeSystem {
ts: time::TimeSystem::TDB,
},
)?;
module.add(
"TCG",
PyTimeSystem {
ts: time::TimeSystem::TCG,
},
)?;
module.add(
"TCB",
PyTimeSystem {
ts: time::TimeSystem::TCB,
},
)?;
module.add(
"BDT",
PyTimeSystem {
ts: time::TimeSystem::BDT,
},
)?;
module.add(
"GST",
PyTimeSystem {
ts: time::TimeSystem::GST,
},
)?;
module.add_function(wrap_pyfunction!(py_bias_precession_nutation, module)?)?;
module.add_function(wrap_pyfunction!(py_earth_rotation, module)?)?;
module.add_function(wrap_pyfunction!(py_polar_motion, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_gcrf_to_itrf, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_itrf_to_gcrf, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_eci_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_ecef_to_eci, module)?)?;
module.add_function(wrap_pyfunction!(py_position_gcrf_to_itrf, module)?)?;
module.add_function(wrap_pyfunction!(py_position_itrf_to_gcrf, module)?)?;
module.add_function(wrap_pyfunction!(py_position_eci_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_position_ecef_to_eci, module)?)?;
module.add_function(wrap_pyfunction!(py_state_gcrf_to_itrf, module)?)?;
module.add_function(wrap_pyfunction!(py_state_itrf_to_gcrf, module)?)?;
module.add_function(wrap_pyfunction!(py_state_eci_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_state_ecef_to_eci, module)?)?;
module.add_function(wrap_pyfunction!(py_bias_eme2000, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_gcrf_to_eme2000, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_eme2000_to_gcrf, module)?)?;
module.add_function(wrap_pyfunction!(py_position_gcrf_to_eme2000, module)?)?;
module.add_function(wrap_pyfunction!(py_position_eme2000_to_gcrf, module)?)?;
module.add_function(wrap_pyfunction!(py_state_gcrf_to_eme2000, module)?)?;
module.add_function(wrap_pyfunction!(py_state_eme2000_to_gcrf, module)?)?;
module.add_class::<PyEllipsoidalConversionType>()?;
module.add_function(wrap_pyfunction!(py_state_koe_to_eci, module)?)?;
module.add_function(wrap_pyfunction!(py_state_eci_to_koe, module)?)?;
module.add_function(wrap_pyfunction!(py_position_geocentric_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_position_ecef_to_geocentric, module)?)?;
module.add_function(wrap_pyfunction!(py_position_geodetic_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_position_ecef_to_geodetic, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_ellipsoid_to_enz, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_enz_to_ellipsoid, module)?)?;
module.add_function(wrap_pyfunction!(py_relative_position_ecef_to_enz, module)?)?;
module.add_function(wrap_pyfunction!(py_relative_position_enz_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_ellipsoid_to_sez, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_sez_to_ellipsoid, module)?)?;
module.add_function(wrap_pyfunction!(py_relative_position_ecef_to_sez, module)?)?;
module.add_function(wrap_pyfunction!(py_relative_position_sez_to_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_position_enz_to_azel, module)?)?;
module.add_function(wrap_pyfunction!(py_position_sez_to_azel, module)?)?;
module.add_function(wrap_pyfunction!(py_orbital_period, module)?)?;
module.add_function(wrap_pyfunction!(py_orbital_period_general, module)?)?;
module.add_function(wrap_pyfunction!(py_orbital_period_from_state, module)?)?;
module.add_function(wrap_pyfunction!(py_mean_motion, module)?)?;
module.add_function(wrap_pyfunction!(py_mean_motion_general, module)?)?;
module.add_function(wrap_pyfunction!(py_semimajor_axis, module)?)?;
module.add_function(wrap_pyfunction!(py_semimajor_axis_general, module)?)?;
module.add_function(wrap_pyfunction!(
py_semimajor_axis_from_orbital_period,
module
)?)?;
module.add_function(wrap_pyfunction!(
py_semimajor_axis_from_orbital_period_general,
module
)?)?;
module.add_function(wrap_pyfunction!(py_perigee_velocity, module)?)?;
module.add_function(wrap_pyfunction!(py_periapsis_velocity, module)?)?;
module.add_function(wrap_pyfunction!(py_periapsis_distance, module)?)?;
module.add_function(wrap_pyfunction!(py_apogee_velocity, module)?)?;
module.add_function(wrap_pyfunction!(py_apoapsis_velocity, module)?)?;
module.add_function(wrap_pyfunction!(py_apoapsis_distance, module)?)?;
module.add_function(wrap_pyfunction!(py_periapsis_altitude, module)?)?;
module.add_function(wrap_pyfunction!(py_perigee_altitude, module)?)?;
module.add_function(wrap_pyfunction!(py_apoapsis_altitude, module)?)?;
module.add_function(wrap_pyfunction!(py_apogee_altitude, module)?)?;
module.add_function(wrap_pyfunction!(py_sun_synchronous_inclination, module)?)?;
module.add_function(wrap_pyfunction!(py_geo_sma, module)?)?;
module.add_function(wrap_pyfunction!(py_anomaly_eccentric_to_mean, module)?)?;
module.add_function(wrap_pyfunction!(py_anomaly_mean_to_eccentric, module)?)?;
module.add_function(wrap_pyfunction!(py_anomaly_true_to_eccentric, module)?)?;
module.add_function(wrap_pyfunction!(py_anomaly_eccentric_to_true, module)?)?;
module.add_function(wrap_pyfunction!(py_anomaly_true_to_mean, module)?)?;
module.add_function(wrap_pyfunction!(py_anomaly_mean_to_true, module)?)?;
module.add_class::<PySGPPropagator>()?;
module.add_class::<PyKeplerianPropagator>()?;
module.add_class::<PyIntegrationMethod>()?;
module.add_class::<PyAtmosphericModel>()?;
module.add_class::<PyEclipseModel>()?;
module.add_class::<PyNumericalPropagationConfig>()?;
module.add_class::<PyVariationalConfig>()?;
module.add_class::<PyParameterSource>()?;
module.add_class::<PyGravityConfiguration>()?;
module.add_class::<PyDragConfiguration>()?;
module.add_class::<PySolarRadiationPressureConfiguration>()?;
module.add_class::<PyThirdBody>()?;
module.add_class::<PyThirdBodyConfiguration>()?;
module.add_class::<PyForceModelConfig>()?;
module.add_class::<PyNumericalOrbitPropagator>()?;
module.add_class::<PyNumericalPropagator>()?;
module.add_class::<PyTrajectoryMode>()?;
module.add_function(wrap_pyfunction!(py_par_propagate_to, module)?)?;
module.add_function(wrap_pyfunction!(py_validate_tle_lines, module)?)?;
module.add_function(wrap_pyfunction!(py_validate_tle_line, module)?)?;
module.add_function(wrap_pyfunction!(py_calculate_tle_line_checksum, module)?)?;
module.add_function(wrap_pyfunction!(py_parse_norad_id, module)?)?;
module.add_function(wrap_pyfunction!(py_norad_id_numeric_to_alpha5, module)?)?;
module.add_function(wrap_pyfunction!(py_norad_id_alpha5_to_numeric, module)?)?;
module.add_function(wrap_pyfunction!(py_keplerian_elements_from_tle, module)?)?;
module.add_function(wrap_pyfunction!(py_keplerian_elements_to_tle, module)?)?;
module.add_function(wrap_pyfunction!(py_create_tle_lines, module)?)?;
module.add_function(wrap_pyfunction!(py_epoch_from_tle, module)?)?;
module.add_function(wrap_pyfunction!(py_state_koe_osc_to_mean, module)?)?;
module.add_function(wrap_pyfunction!(py_state_koe_mean_to_osc, module)?)?;
module.add_class::<PyWalkerPattern>()?;
module.add_class::<PyWalkerConstellationGenerator>()?;
module.add_function(wrap_pyfunction!(py_rotation_rtn_to_eci, module)?)?;
module.add_function(wrap_pyfunction!(py_rotation_eci_to_rtn, module)?)?;
module.add_function(wrap_pyfunction!(py_state_eci_to_rtn, module)?)?;
module.add_function(wrap_pyfunction!(py_state_rtn_to_eci, module)?)?;
module.add_function(wrap_pyfunction!(py_state_oe_to_roe, module)?)?;
module.add_function(wrap_pyfunction!(py_state_roe_to_oe, module)?)?;
module.add_function(wrap_pyfunction!(py_state_eci_to_roe, module)?)?;
module.add_function(wrap_pyfunction!(py_state_roe_to_eci, module)?)?;
module.add_class::<PyOrbitFrame>()?;
module.add_class::<PyOrbitRepresentation>()?;
module.add_class::<PyAngleFormat>()?;
module.add_class::<PyInterpolationMethod>()?;
module.add_class::<PyCovarianceInterpolationMethod>()?;
module.add_class::<PyOrbitalTrajectory>()?;
module.add_class::<PyTrajectory>()?;
module.add_class::<PyQuaternion>()?;
module.add_class::<PyEulerAxis>()?;
module.add_class::<PyEulerAngle>()?;
module.add_class::<PyEulerAngleOrder>()?;
module.add_class::<PyRotationMatrix>()?;
module.add_function(wrap_pyfunction!(py_groundstations_load, module)?)?;
module.add_function(wrap_pyfunction!(py_groundstations_load_from_file, module)?)?;
module.add_function(wrap_pyfunction!(py_groundstations_load_all, module)?)?;
module.add_function(wrap_pyfunction!(py_groundstations_list_providers, module)?)?;
module.add_function(wrap_pyfunction!(py_naif_download_de_kernel, module)?)?;
module.add_class::<PyGCATSatcatRecord>()?;
module.add_class::<PyGCATPsatcatRecord>()?;
module.add_class::<PyGCATSatcat>()?;
module.add_class::<PyGCATPsatcat>()?;
module.add_function(wrap_pyfunction!(py_gcat_get_satcat, module)?)?;
module.add_function(wrap_pyfunction!(py_gcat_get_psatcat, module)?)?;
module.add_class::<PyEphemerisSource>()?;
module.add_function(wrap_pyfunction!(py_sun_position, module)?)?;
module.add_function(wrap_pyfunction!(py_moon_position, module)?)?;
module.add_function(wrap_pyfunction!(py_sun_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_moon_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_mercury_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_venus_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_mars_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_jupiter_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_saturn_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_uranus_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_neptune_position_de, module)?)?;
module.add_function(wrap_pyfunction!(
py_solar_system_barycenter_position_de,
module
)?)?;
module.add_function(wrap_pyfunction!(py_ssb_position_de, module)?)?;
module.add_function(wrap_pyfunction!(py_initialize_ephemeris, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_sun, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_moon, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_sun_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_moon_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_mercury_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_venus_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_mars_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_jupiter_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_saturn_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_uranus_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_third_body_neptune_de, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_point_mass_gravity, module)?)?;
module.add_class::<PyGravityModelType>()?;
module.add_class::<PyGravityModelTideSystem>()?;
module.add_class::<PyGravityModelErrors>()?;
module.add_class::<PyGravityModelNormalization>()?;
module.add_class::<PyGravityModel>()?;
module.add_function(wrap_pyfunction!(
py_accel_gravity_spherical_harmonics,
module
)?)?;
module.add_function(wrap_pyfunction!(py_density_harris_priester, module)?)?;
module.add_function(wrap_pyfunction!(py_density_nrlmsise00, module)?)?;
module.add_function(wrap_pyfunction!(py_density_nrlmsise00_geod, module)?)?;
module.add_function(wrap_pyfunction!(py_igrf_geodetic_enz, module)?)?;
module.add_function(wrap_pyfunction!(py_igrf_geocentric_enz, module)?)?;
module.add_function(wrap_pyfunction!(py_igrf_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_wmmhr_geodetic_enz, module)?)?;
module.add_function(wrap_pyfunction!(py_wmmhr_geocentric_enz, module)?)?;
module.add_function(wrap_pyfunction!(py_wmmhr_ecef, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_drag, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_solar_radiation_pressure, module)?)?;
module.add_function(wrap_pyfunction!(py_eclipse_conical, module)?)?;
module.add_function(wrap_pyfunction!(py_eclipse_cylindrical, module)?)?;
module.add_function(wrap_pyfunction!(py_accel_relativity, module)?)?;
module.add_class::<PyLookDirection>()?;
module.add_class::<PyAscDsc>()?;
module.add_class::<PyElevationConstraint>()?;
module.add_class::<PyElevationMaskConstraint>()?;
module.add_class::<PyOffNadirConstraint>()?;
module.add_class::<PyLocalTimeConstraint>()?;
module.add_class::<PyLookDirectionConstraint>()?;
module.add_class::<PyAscDscConstraint>()?;
module.add_class::<PyConstraintAll>()?;
module.add_class::<PyConstraintAny>()?;
module.add_class::<PyConstraintNot>()?;
module.add_class::<PyPointLocation>()?;
module.add_class::<PyPolygonLocation>()?;
module.add_class::<PyPropertiesDict>()?;
module.add_class::<PyAccessWindow>()?;
module.add_class::<PyAccessProperties>()?;
module.add_class::<PyAccessPropertiesView>()?;
module.add_class::<PySubdivisionConfig>()?;
module.add_class::<PyAccessSearchConfig>()?;
module.add_class::<PyAdditionalPropertiesDict>()?;
module.add_class::<PySamplingConfig>()?;
module.add_class::<PyDopplerComputer>()?;
module.add_class::<PyRangeComputer>()?;
module.add_class::<PyRangeRateComputer>()?;
module.add_class::<PyAccessPropertyComputer>()?;
module.add_class::<PyAccessConstraintComputer>()?;
module.add_function(wrap_pyfunction!(py_location_accesses, module)?)?;
module.add_class::<PyOrbitGeometryTessellatorConfig>()?;
module.add_class::<PyOrbitGeometryTessellator>()?;
module.add_function(wrap_pyfunction!(py_tile_merge_orbit_geometry, module)?)?;
module.add_class::<PyEventDirection>()?;
module.add_class::<PyEdgeType>()?;
module.add_class::<PyEventAction>()?;
module.add_class::<PyEventType>()?;
module.add_class::<PyDetectedEvent>()?;
module.add_class::<PyEventQuery>()?;
module.add_class::<PyEventQueryIterator>()?;
module.add_class::<PyTimeEvent>()?;
module.add_class::<PyValueEvent>()?;
module.add_class::<PyBinaryEvent>()?;
module.add_class::<PyAltitudeEvent>()?;
module.add_class::<PySemiMajorAxisEvent>()?;
module.add_class::<PyEccentricityEvent>()?;
module.add_class::<PyInclinationEvent>()?;
module.add_class::<PyArgumentOfPerigeeEvent>()?;
module.add_class::<PyMeanAnomalyEvent>()?;
module.add_class::<PyEccentricAnomalyEvent>()?;
module.add_class::<PyTrueAnomalyEvent>()?;
module.add_class::<PyArgumentOfLatitudeEvent>()?;
module.add_class::<PyAscendingNodeEvent>()?;
module.add_class::<PyDescendingNodeEvent>()?;
module.add_class::<PySpeedEvent>()?;
module.add_class::<PyLongitudeEvent>()?;
module.add_class::<PyLatitudeEvent>()?;
module.add_class::<PyUmbraEvent>()?;
module.add_class::<PyPenumbraEvent>()?;
module.add_class::<PyEclipseEvent>()?;
module.add_class::<PySunlitEvent>()?;
module.add_class::<PyAOIEntryEvent>()?;
module.add_class::<PyAOIExitEvent>()?;
module.add_function(wrap_pyfunction!(py_get_brahe_cache_dir, module)?)?;
module.add_function(wrap_pyfunction!(
py_get_brahe_cache_dir_with_subdir,
module
)?)?;
module.add_function(wrap_pyfunction!(py_get_eop_cache_dir, module)?)?;
module.add_function(wrap_pyfunction!(py_get_celestrak_cache_dir, module)?)?;
module.add_function(wrap_pyfunction!(py_set_num_threads, module)?)?;
module.add_function(wrap_pyfunction!(py_set_max_threads, module)?)?;
module.add_function(wrap_pyfunction!(py_set_ludicrous_speed, module)?)?;
module.add_function(wrap_pyfunction!(py_get_max_threads, module)?)?;
module.add_function(wrap_pyfunction!(py_format_time_string, module)?)?;
module.add_class::<PyDifferenceMethod>()?;
module.add_class::<PyPerturbationStrategy>()?;
module.add_class::<PyDNumericalJacobian>()?;
module.add_class::<PyDAnalyticJacobian>()?;
module.add_class::<PyDNumericalSensitivity>()?;
module.add_class::<PyDAnalyticSensitivity>()?;
module.add_class::<PyIntegratorConfig>()?;
module.add_class::<PyAdaptiveStepDResult>()?;
module.add_class::<PyRK4DIntegrator>()?;
module.add_class::<PyRKF45DIntegrator>()?;
module.add_class::<PyDP54DIntegrator>()?;
module.add_class::<PyRKN1210DIntegrator>()?;
module.add_class::<PyRequestController>()?;
module.add_class::<PyRequestClass>()?;
module.add_class::<PySortOrder>()?;
module.add_class::<PyOutputFormat>()?;
module.add_class::<PyRateLimitConfig>()?;
module.add_class::<PySpaceTrackQuery>()?;
module.add_class::<PySpaceTrackClient>()?;
module.add_class::<PyGPRecord>()?;
module.add_class::<PySATCATRecord>()?;
module.add_class::<PyFileShareFileRecord>()?;
module.add_class::<PyFolderRecord>()?;
module.add_class::<PySPEphemerisFileRecord>()?;
module.add_function(wrap_pyfunction!(py_spacetrack_greater_than, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_less_than, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_not_equal, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_inclusive_range, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_like, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_startswith, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_now, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_now_offset, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_null_val, module)?)?;
module.add_function(wrap_pyfunction!(py_spacetrack_or_list, module)?)?;
module.add_class::<PyCelestrakQueryType>()?;
module.add_class::<PyCelestrakOutputFormat>()?;
module.add_class::<PySupGPSource>()?;
module.add_class::<PyCelestrakQuery>()?;
module.add_class::<PyCelestrakClient>()?;
module.add_class::<PyCelestrakSATCATRecord>()?;
module.add_class::<PyOEM>()?;
module.add_class::<PyOEMSegments>()?;
module.add_class::<PyOEMSegment>()?;
module.add_class::<PyOEMStates>()?;
module.add_class::<PyOEMStateVector>()?;
module.add_class::<PyOEMSegmentIterator>()?;
module.add_class::<PyOEMStateIterator>()?;
module.add_class::<PyOMM>()?;
module.add_class::<PyOPM>()?;
module.add_class::<PyOPMManeuver>()?;
module.add_class::<PyOPMManeuvers>()?;
module.add_class::<PyOPMManeuverIterator>()?;
module.add_class::<PyCDM>()?;
module.add_class::<PyCDMObject>()?;
module.add_class::<PyCDMStateVector>()?;
module.add_class::<PyCDMRTNCovariance>()?;
module.add_class::<PyProcessNoiseConfig>()?;
module.add_class::<PyEKFConfig>()?;
module.add_class::<PyObservation>()?;
module.add_class::<PyFilterRecord>()?;
module.add_class::<PyMeasurementModel>()?;
module.add_class::<PyInertialPositionMeasurementModel>()?;
module.add_class::<PyInertialVelocityMeasurementModel>()?;
module.add_class::<PyInertialStateMeasurementModel>()?;
module.add_class::<PyEcefPositionMeasurementModel>()?;
module.add_class::<PyEcefVelocityMeasurementModel>()?;
module.add_class::<PyEcefStateMeasurementModel>()?;
module.add_class::<PyExtendedKalmanFilter>()?;
module.add_class::<PyUKFConfig>()?;
module.add_class::<PyUnscentedKalmanFilter>()?;
module.add_class::<PyBLSSolverMethod>()?;
module.add_class::<PyConsiderParameterConfig>()?;
module.add_class::<PyBLSConfig>()?;
module.add_class::<PyBLSIterationRecord>()?;
module.add_class::<PyBLSObservationResidual>()?;
module.add_class::<PyBatchLeastSquares>()?;
module.add_function(wrap_pyfunction!(py_isotropic_covariance, module)?)?;
module.add_function(wrap_pyfunction!(py_diagonal_covariance, module)?)?;
Ok(())
}