From adc3d85343c90c85f9af79afc2118f694c82b3bb Mon Sep 17 00:00:00 2001 From: Helge Eichhorn Date: Tue, 10 Dec 2024 19:52:28 +0100 Subject: [PATCH] WIP --- crates/lox-orbits/Cargo.toml | 2 +- crates/lox-orbits/src/analysis.rs | 41 +---- crates/lox-orbits/src/elements.rs | 4 +- crates/lox-orbits/src/frames.rs | 76 ++++---- .../src/propagators/semi_analytical.rs | 77 ++++++--- crates/lox-orbits/src/python.rs | 162 ++++-------------- crates/lox-orbits/src/states.rs | 46 +---- crates/lox-orbits/src/trajectories.rs | 37 +--- crates/lox-space/benches/observables.rs | 26 +-- 9 files changed, 143 insertions(+), 328 deletions(-) diff --git a/crates/lox-orbits/Cargo.toml b/crates/lox-orbits/Cargo.toml index 30b82ee6..12b65e0c 100644 --- a/crates/lox-orbits/Cargo.toml +++ b/crates/lox-orbits/Cargo.toml @@ -29,4 +29,4 @@ pyo3 = { workspace = true, features = ["auto-initialize"] } rstest.workspace = true [features] -python = ["dep:pyo3", "dep:numpy", "lox-bodies/python", "lox-time/python"] +python = ["dep:pyo3", "dep:numpy", "lox-bodies/python", "lox-ephem/python", "lox-time/python"] diff --git a/crates/lox-orbits/src/analysis.rs b/crates/lox-orbits/src/analysis.rs index eab3c736..4fee6ea1 100644 --- a/crates/lox-orbits/src/analysis.rs +++ b/crates/lox-orbits/src/analysis.rs @@ -19,7 +19,7 @@ use lox_time::TimeLike; use thiserror::Error; use crate::events::{find_windows, Window}; -use crate::frames::{BodyFixed, FrameTransformationProvider, Icrf, Topocentric, TryToFrame}; +use crate::frames::{BodyFixed, FrameTransformationProvider, Icrf, TryToFrame}; use crate::ground::GroundLocation; use crate::trajectories::Trajectory; @@ -65,34 +65,6 @@ pub fn elevation< T: TimeLike + TryToScale + Clone, O: Origin + Spheroid + RotationalElements + Clone, P: FrameTransformationProvider, ->( - time: T, - frame: &Topocentric, - gs: &Trajectory, - sc: &Trajectory, - provider: &P, -) -> Radians { - let body_fixed = BodyFixed(gs.origin()); - let gs = gs.interpolate_at(time.clone()).position(); - let sc = sc.interpolate_at(time.clone()).position(); - let r = sc - gs; - let Ok(tdb) = time.try_to_scale(Tdb, provider) else { - // FIXME - eprintln!("Failed to convert time to TDB"); - return f64::NAN; - }; - let seconds = tdb.seconds_since_j2000(); - let rot = body_fixed.rotation(seconds); - let r_body = rot.rotate_position(r); - let rot = frame.rotation_from_body_fixed(); - let r_sez = rot * r_body; - (r_sez.z / r.length()).asin() -} - -pub fn elevation2< - T: TimeLike + TryToScale + Clone, - O: Origin + Spheroid + RotationalElements + Clone, - P: FrameTransformationProvider, >( time: T, gs: &GroundLocation, @@ -130,7 +102,7 @@ pub fn visibility< let root_finder = Brent::default(); find_windows( |t| { - elevation2( + elevation( start.clone() + TimeDelta::from_decimal_seconds(t).unwrap(), gs, mask, @@ -164,7 +136,6 @@ mod tests { fn test_elevation() { let gs = ground_station_trajectory(); let sc = spacecraft_trajectory(); - let frame = frame(); let expected: Vec = include_str!("../../../data/elevation.csv") .lines() .map(|line| line.parse::().unwrap().to_radians()) @@ -172,7 +143,7 @@ mod tests { let actual: Vec = gs .times() .iter() - .map(|t| elevation(*t, &frame, &gs, &sc, &NoOpFrameTransformationProvider)) + .map(|t| elevation(*t, &gs, &sc, &NoOpFrameTransformationProvider)) .collect(); for (actual, expected) in actual.iter().zip(expected.iter()) { assert_close!(actual, expected, 1e-1); @@ -237,12 +208,6 @@ mod tests { GroundLocation::new(longitude, latitude, 0.0, Earth) } - fn frame() -> Topocentric { - let longitude = -4.3676f64.to_radians(); - let latitude = 40.4527f64.to_radians(); - Topocentric::from_coords(longitude, latitude, 0.0, Earth) - } - fn contacts() -> Vec>> { let mut windows = vec![]; let mut reader = diff --git a/crates/lox-orbits/src/elements.rs b/crates/lox-orbits/src/elements.rs index c348f8c9..c6ecc065 100644 --- a/crates/lox-orbits/src/elements.rs +++ b/crates/lox-orbits/src/elements.rs @@ -11,7 +11,7 @@ use std::f64::consts::TAU; use float_eq::float_eq; use glam::{DMat3, DVec3}; -use lox_bodies::{Origin, PointMass}; +use lox_bodies::{DynOrigin, Origin, PointMass}; use lox_time::deltas::TimeDelta; use lox_time::TimeLike; @@ -34,6 +34,8 @@ pub struct Keplerian { true_anomaly: f64, } +pub type DynKeplerian = Keplerian; + impl Keplerian where T: TimeLike, diff --git a/crates/lox-orbits/src/frames.rs b/crates/lox-orbits/src/frames.rs index 1cb1da9a..6425c63b 100644 --- a/crates/lox-orbits/src/frames.rs +++ b/crates/lox-orbits/src/frames.rs @@ -149,25 +149,25 @@ impl ReferenceFrame for BodyFixed { } } -#[derive(Clone, Debug)] -pub struct Topocentric(GroundLocation); - -impl Topocentric { - pub fn new(location: GroundLocation) -> Self { - Topocentric(location) - } - - pub fn from_coords(longitude: f64, latitude: f64, altitude: f64, body: B) -> Self { - let location = GroundLocation::new(longitude, latitude, altitude, body); - Topocentric(location) - } - - pub fn rotation_from_body_fixed(&self) -> DMat3 { - let r1 = DMat3::from_rotation_z(self.0.longitude()).transpose(); - let r2 = DMat3::from_rotation_y(FRAC_PI_2 - self.0.latitude()).transpose(); - r2 * r1 - } -} +// #[derive(Clone, Debug)] +// pub struct Topocentric(GroundLocation); + +// impl Topocentric { +// pub fn new(location: GroundLocation) -> Self { +// Topocentric(location) +// } +// +// pub fn from_coords(longitude: f64, latitude: f64, altitude: f64, body: B) -> Self { +// let location = GroundLocation::new(longitude, latitude, altitude, body); +// Topocentric(location) +// } +// +// pub fn rotation_from_body_fixed(&self) -> DMat3 { +// let r1 = DMat3::from_rotation_z(self.0.longitude()).transpose(); +// let r2 = DMat3::from_rotation_y(FRAC_PI_2 - self.0.latitude()).transpose(); +// r2 * r1 +// } +// } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum DynFrame { @@ -264,25 +264,25 @@ mod tests { use lox_math::is_close::IsClose; use rstest::rstest; - #[test] - fn test_topocentric() { - let topo = Topocentric::from_coords(8.0, 50.0, 0.0, Earth); - let r = topo.rotation_from_body_fixed(); - let x_axis = DVec3::new( - 0.038175550084451906, - -0.9893582466233818, - -0.14040258976976597, - ); - let y_axis = DVec3::new( - -0.25958272521858694, - -0.14550003380861354, - 0.9546970980000851, - ); - let z_axis = DVec3::new(-0.9649660284921128, 0.0, -0.2623748537039304); - assert_close!(r.x_axis, x_axis); - assert_close!(r.y_axis, y_axis); - assert_close!(r.z_axis, z_axis); - } + // #[test] + // fn test_topocentric() { + // let topo = Topocentric::from_coords(8.0, 50.0, 0.0, Earth); + // let r = topo.rotation_from_body_fixed(); + // let x_axis = DVec3::new( + // 0.038175550084451906, + // -0.9893582466233818, + // -0.14040258976976597, + // ); + // let y_axis = DVec3::new( + // -0.25958272521858694, + // -0.14550003380861354, + // 0.9546970980000851, + // ); + // let z_axis = DVec3::new(-0.9649660284921128, 0.0, -0.2623748537039304); + // assert_close!(r.x_axis, x_axis); + // assert_close!(r.y_axis, y_axis); + // assert_close!(r.z_axis, z_axis); + // } #[rstest] #[case("IAU_EARTH", Some(DynFrame::BodyFixed(DynOrigin::Earth)))] diff --git a/crates/lox-orbits/src/propagators/semi_analytical.rs b/crates/lox-orbits/src/propagators/semi_analytical.rs index aeb02d27..ad633bcd 100644 --- a/crates/lox-orbits/src/propagators/semi_analytical.rs +++ b/crates/lox-orbits/src/propagators/semi_analytical.rs @@ -8,12 +8,12 @@ use thiserror::Error; -use lox_bodies::PointMass; +use lox_bodies::{DynOrigin, MaybePointMass, Origin, PointMass}; use lox_time::TimeLike; -use crate::frames::{CoordinateSystem, Icrf}; +use crate::frames::{CoordinateSystem, DynFrame, Icrf, ReferenceFrame}; use crate::propagators::{stumpff, Propagator}; -use crate::states::State; +use crate::states::{DynState, State}; use crate::trajectories::TrajectoryError; #[derive(Debug, Error, Eq, PartialEq)] @@ -25,31 +25,33 @@ pub enum ValladoError { } #[derive(Debug, Copy, Clone, PartialEq)] -pub struct Vallado { - initial_state: State, +pub struct Vallado { + initial_state: State, max_iter: i32, } -impl CoordinateSystem for Vallado +impl CoordinateSystem for Vallado where T: TimeLike, - O: PointMass, + O: Origin, + R: ReferenceFrame + Clone, { - fn reference_frame(&self) -> Icrf { - Icrf + fn reference_frame(&self) -> R { + self.initial_state.reference_frame() } } -impl Vallado +impl Vallado where T: TimeLike, - O: PointMass, + O: MaybePointMass + Clone, + R: ReferenceFrame, { - pub fn new(initial_state: State) -> Self { - Self { - initial_state, - max_iter: 300, - } + fn gravitational_parameter(&self) -> f64 { + self.initial_state + .origin() + .maybe_gravitational_parameter() + .expect("gravitational parameter should be available") } pub fn with_max_iter(&mut self, max_iter: i32) -> &mut Self { @@ -65,17 +67,52 @@ where } } -impl Propagator for Vallado +impl Vallado +where + T: TimeLike, + O: PointMass, +{ + pub fn new(initial_state: State) -> Self { + Self { + initial_state, + max_iter: 300, + } + } +} + +impl Vallado +where + T: TimeLike, +{ + // TODO: Use better error type + pub fn with_dynamic(initial_state: DynState) -> Result { + if initial_state + .origin() + .maybe_gravitational_parameter() + .is_none() + || initial_state.reference_frame() != DynFrame::Icrf + { + return Err("invalid frame or origin"); + } + Ok(Self { + initial_state, + max_iter: 300, + }) + } +} + +impl Propagator for Vallado where T: TimeLike + Clone, - O: PointMass + Clone, + O: MaybePointMass + Clone, + R: ReferenceFrame + Clone, { type Error = ValladoError; - fn propagate(&self, time: T) -> Result, Self::Error> { + fn propagate(&self, time: T) -> Result, Self::Error> { let frame = self.reference_frame(); let origin = self.origin(); - let mu = origin.gravitational_parameter(); + let mu = self.gravitational_parameter(); let t0 = self.initial_state.time(); let dt = (time.clone() - t0).to_decimal_seconds(); let sqrt_mu = mu.sqrt(); diff --git a/crates/lox-orbits/src/python.rs b/crates/lox-orbits/src/python.rs index dd7257a0..a6ac54b1 100644 --- a/crates/lox-orbits/src/python.rs +++ b/crates/lox-orbits/src/python.rs @@ -33,14 +33,13 @@ use crate::analysis::{ElevationMask, ElevationMaskError}; use crate::elements::{Keplerian, ToKeplerian}; use crate::events::{Event, FindEventError, Window}; use crate::frames::{ - BodyFixed, CoordinateSystem, DynFrame, Icrf, ReferenceFrame, Topocentric, TryToFrame, - UnknownFrameError, + BodyFixed, CoordinateSystem, DynFrame, Icrf, ReferenceFrame, TryToFrame, UnknownFrameError, }; use crate::ground::{GroundLocation, GroundPropagator, GroundPropagatorError, Observables}; use crate::propagators::semi_analytical::{Vallado, ValladoError}; use crate::propagators::sgp4::{Sgp4, Sgp4Error}; use crate::propagators::Propagator; -use crate::states::ToCartesian; +use crate::states::{DynState, ToCartesian}; use crate::trajectories::TrajectoryTransformationError; use crate::{ frames::FrameTransformationProvider, @@ -239,7 +238,7 @@ impl PyState { "only inertial frames are supported for the LVLH rotation matrix", )); } - let rot = self.0.with_frame(Icrf).rotation_lvlh(); + let rot = self.0.rotation_lvlh(); let rot: Vec> = rot.to_cols_array_2d().iter().map(|v| v.to_vec()).collect(); Ok(PyArray2::from_vec2_bound(py, &rot)?) } @@ -258,7 +257,6 @@ impl PyState { } Ok(PyGroundLocation( self.0 - .with_origin_and_frame(Earth, Icrf) .try_to_frame(BodyFixed(Earth), &PyNoOpOffsetProvider)? .to_ground_location() .map_err(|err| PyValueError::new_err(err.to_string()))? @@ -340,7 +338,7 @@ impl PyKeplerian { } fn to_cartesian(&self) -> PyResult { - Ok(PyState(self.0.to_cartesian().with_frame(PyFrame::Icrf))) + Ok(PyState(self.0.to_cartesian())) } fn orbital_period(&self) -> PyTimeDelta { @@ -363,7 +361,7 @@ impl PyTrajectory { #[new] fn new(states: &Bound<'_, PyList>) -> PyResult { let states: Vec = states.extract()?; - let states: Vec> = states.into_iter().map(|s| s.0).collect(); + let states: Vec> = states.into_iter().map(|s| s.0).collect(); Ok(PyTrajectory(Trajectory::new(&states)?)) } @@ -373,41 +371,31 @@ impl PyTrajectory { _cls: &Bound<'_, PyType>, start_time: PyTime, array: &Bound<'_, PyArray2>, - origin: Option<&Bound<'_, PyAny>>, + origin: Option, frame: Option, ) -> PyResult { - let origin: PyBody = if let Some(origin) = origin { - PyBody::try_from(origin)? - } else { - PyBody::Planet(PyPlanet::new("Earth").unwrap()) - }; - let frame = frame.unwrap_or(PyFrame::Icrf); + let origin = origin.unwrap_or_default(); + let frame = frame.unwrap_or_default(); let array = array.to_owned_array(); if array.ncols() != 7 { return Err(PyValueError::new_err("invalid shape")); } - let mut states: Vec> = Vec::with_capacity(array.nrows()); + let mut states: Vec> = Vec::with_capacity(array.nrows()); for row in array.rows() { let time = PyTime(start_time.0 + TimeDelta::from_decimal_seconds(row[0]).unwrap()); let position = DVec3::new(row[1], row[2], row[3]); let velocity = DVec3::new(row[4], row[5], row[6]); - states.push(State::new( - time, - position, - velocity, - origin.clone(), - frame.clone(), - )); + states.push(State::new(time, position, velocity, origin.0, frame.0)); } Ok(PyTrajectory(Trajectory::new(&states)?)) } - fn origin(&self) -> PyObject { - self.0.origin().into() + fn origin(&self) -> PyOrigin { + PyOrigin(self.0.origin()) } fn reference_frame(&self) -> PyFrame { - self.0.reference_frame() + PyFrame(self.0.reference_frame()) } fn to_numpy<'py>(&self, py: Python<'py>) -> PyResult>> { @@ -464,23 +452,16 @@ impl PyTrajectory { frame: PyFrame, provider: Option<&Bound<'_, PyUt1Provider>>, ) -> PyResult { - let mut states: Vec> = - Vec::with_capacity(self.0.states().len()); + let mut states: Vec> = Vec::with_capacity(self.0.states().len()); for s in self.0.states() { states.push(PyState(s).to_frame(frame.clone(), provider)?.0); } Ok(PyTrajectory(Trajectory::new(&states)?)) } - fn to_origin(&self, target: &Bound<'_, PyAny>, ephemeris: &Bound<'_, PySpk>) -> PyResult { - let target = PyBody::try_from(target)?; + fn to_origin(&self, target: PyOrigin, ephemeris: &Bound<'_, PySpk>) -> PyResult { let spk = &ephemeris.borrow().0; - let s1 = self - .0 - .clone() - .with_frame(Icrf) - .to_origin(target, spk)? - .with_frame(PyFrame::Icrf); + let s1 = self.0.clone().to_origin(target, spk)?; Ok(Self(s1)) } } @@ -537,7 +518,7 @@ impl PyWindow { } #[pyclass(name = "Vallado", module = "lox_space", frozen)] -pub struct PyVallado(pub Vallado); +pub struct PyVallado(pub Vallado); impl From for PyErr { fn from(err: ValladoError) -> Self { @@ -551,12 +532,9 @@ impl PyVallado { #[new] #[pyo3(signature =(initial_state, max_iter=None))] fn new(initial_state: PyState, max_iter: Option) -> PyResult { - if initial_state.0.reference_frame() != PyFrame::Icrf { - return Err(PyValueError::new_err( - "only inertial frames are supported for the Vallado propagator", - )); - } - let mut vallado = Vallado::new(initial_state.0.with_frame(Icrf)); + let mut vallado = Vallado::with_dynamic(initial_state.0).map_err(|_| { + PyValueError::new_err("only inertial frames are supported for the Vallado propagator") + })?; if let Some(max_iter) = max_iter { vallado.with_max_iter(max_iter); } @@ -569,18 +547,10 @@ impl PyVallado { steps: &Bound<'py, PyAny>, ) -> PyResult> { if let Ok(time) = steps.extract::() { - return Ok(Bound::new( - py, - PyState(self.0.propagate(time)?.with_frame(PyFrame::Icrf)), - )? - .into_any()); + return Ok(Bound::new(py, PyState(self.0.propagate(time)?))?.into_any()); } if let Ok(steps) = steps.extract::>() { - return Ok(Bound::new( - py, - PyTrajectory(self.0.propagate_all(steps)?.with_frame(PyFrame::Icrf)), - )? - .into_any()); + return Ok(Bound::new(py, PyTrajectory(self.0.propagate_all(steps)?))?.into_any()); } Err(PyValueError::new_err("invalid time delta(s)")) } @@ -588,13 +558,13 @@ impl PyVallado { #[pyclass(name = "GroundLocation", module = "lox_space", frozen)] #[derive(Clone)] -pub struct PyGroundLocation(pub GroundLocation); +pub struct PyGroundLocation(pub GroundLocation); #[pymethods] impl PyGroundLocation { #[new] - fn new(planet: PyPlanet, longitude: f64, latitude: f64, altitude: f64) -> Self { - PyGroundLocation(GroundLocation::new(longitude, latitude, altitude, planet)) + fn new(origin: PyOrigin, longitude: f64, latitude: f64, altitude: f64) -> Self { + PyGroundLocation(GroundLocation::new(longitude, latitude, altitude, origin.0)) } #[pyo3(signature = (state, provider=None))] @@ -658,27 +628,10 @@ impl PyGroundPropagator { steps: &Bound<'py, PyAny>, ) -> PyResult> { if let Ok(time) = steps.extract::() { - return Ok(Bound::new( - py, - PyState( - self.0 - .propagate(time)? - .with_origin_and_frame(PyBody::Planet(self.0.origin()), PyFrame::Icrf), - ), - )? - .into_any()); + return Ok(Bound::new(py, PyState(self.0.propagate(time)?))?.into_any()); } if let Ok(steps) = steps.extract::>() { - return Ok(Bound::new( - py, - PyTrajectory( - self.0 - .propagate_all(steps)? - .with_frame(PyFrame::Icrf) - .with_origin_and_frame(PyBody::Planet(self.0.origin()), PyFrame::Icrf), - ), - )? - .into_any()); + return Ok(Bound::new(py, PyTrajectory(self.0.propagate_all(steps)?))?.into_any()); } Err(PyValueError::new_err("invalid time delta(s)")) } @@ -754,15 +707,8 @@ impl PySgp4 { }; steps.push(time); } - let trajectory = self - .0 - .propagate_all(steps)? - .with_frame(PyFrame::Icrf) - .with_origin_and_frame( - PyBody::Planet(PyPlanet::new("Earth").unwrap()), - PyFrame::Icrf, - ); - let states: Vec> = trajectory + let trajectory = self.0.propagate_all(steps)?; + let states: Vec> = trajectory .states() .iter() .map(|s| { @@ -795,16 +741,11 @@ pub fn visibility( "ground station and spacecraft must have the same origin", )); } - let sc_origin = match sc.0.origin() { - PyBody::Planet(planet) => planet, - _ => return Err(PyValueError::new_err("invalid origin")), - }; let times: Vec = times.extract()?; let provider = provider.get(); let mask = &mask.borrow().0; - let sc = sc.0.with_origin_and_frame(sc_origin, Icrf); Ok( - crate::analysis::visibility(×, &gs.0, mask, &sc, provider) + crate::analysis::visibility(×, &gs.0, mask, &sc.0, provider) .into_iter() .map(PyWindow) .collect(), @@ -885,49 +826,6 @@ impl PyElevationMask { } } -#[pyclass(name = "Topocentric", module = "lox_space", frozen)] -pub struct PyTopocentric(pub Topocentric); - -#[pymethods] -impl PyTopocentric { - #[new] - fn new(location: PyGroundLocation) -> Self { - PyTopocentric(Topocentric::new(location.0)) - } -} - -#[pyfunction] -pub fn elevation( - time: PyTime, - frame: &Bound<'_, PyTopocentric>, - gs: &Bound<'_, PyTrajectory>, - sc: &Bound<'_, PyTrajectory>, - provider: &Bound<'_, PyUt1Provider>, -) -> f64 { - let gs = gs.get(); - let sc = sc.get(); - let frame = frame.get(); - // FIXME - if gs.0.reference_frame() != PyFrame::Icrf || sc.0.reference_frame() != PyFrame::Icrf { - return f64::NAN; - } - if gs.0.origin().name() != sc.0.origin().name() { - return f64::NAN; - } - let gs_origin = match gs.0.origin() { - PyBody::Planet(planet) => planet, - _ => return f64::NAN, - }; - let sc_origin = match sc.0.origin() { - PyBody::Planet(planet) => planet, - _ => return f64::NAN, - }; - let provider = provider.get(); - let gs = gs.0.with_origin_and_frame(gs_origin, Icrf); - let sc = sc.0.with_origin_and_frame(sc_origin, Icrf); - crate::analysis::elevation(time, &frame.0, &gs, &sc, provider) -} - #[pyclass(name = "Observables", module = "lox_space", frozen)] pub struct PyObservables(pub Observables); diff --git a/crates/lox-orbits/src/states.rs b/crates/lox-orbits/src/states.rs index 80910903..05a4eef4 100644 --- a/crates/lox-orbits/src/states.rs +++ b/crates/lox-orbits/src/states.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use std::f64::consts::{PI, TAU}; use std::ops::Sub; -use lox_bodies::{Origin, PointMass, RotationalElements, Spheroid}; +use lox_bodies::{DynOrigin, Origin, PointMass, RotationalElements, Spheroid}; use lox_ephem::{path_from_ids, Ephemeris}; use lox_math::glam::Azimuth; use lox_math::math::{mod_two_pi, normalize_two_pi}; @@ -20,7 +20,8 @@ use lox_time::{julian_dates::JulianDate, time_scales::Tdb, transformations::TryT use crate::anomalies::{eccentric_to_true, hyperbolic_to_true}; use crate::elements::{is_circular, is_equatorial, Keplerian, ToKeplerian}; use crate::frames::{ - BodyFixed, CoordinateSystem, FrameTransformationProvider, Icrf, ReferenceFrame, TryToFrame, + BodyFixed, CoordinateSystem, DynFrame, FrameTransformationProvider, Icrf, ReferenceFrame, + TryToFrame, }; use crate::ground::GroundLocation; @@ -37,6 +38,8 @@ pub struct State { velocity: DVec3, } +pub type DynState = State; + impl State where T: TimeLike, @@ -60,45 +63,6 @@ where self.origin.clone() } - pub fn with_frame(&self, frame: U) -> State - where - T: Clone, - O: Clone, - { - State::new( - self.time(), - self.position, - self.velocity, - self.origin(), - frame, - ) - } - - pub fn with_origin(&self, origin: U) -> State - where - T: Clone, - R: Clone, - { - State::new( - self.time(), - self.position, - self.velocity, - origin, - self.reference_frame(), - ) - } - - pub fn with_origin_and_frame( - &self, - origin: U, - frame: V, - ) -> State - where - T: Clone, - { - State::new(self.time(), self.position, self.velocity, origin, frame) - } - pub fn time(&self) -> T where T: Clone, diff --git a/crates/lox-orbits/src/trajectories.rs b/crates/lox-orbits/src/trajectories.rs index 3e641ee4..f341aaf0 100644 --- a/crates/lox-orbits/src/trajectories.rs +++ b/crates/lox-orbits/src/trajectories.rs @@ -6,7 +6,7 @@ use glam::DVec3; use lox_ephem::Ephemeris; use thiserror::Error; -use lox_bodies::{Origin, RotationalElements}; +use lox_bodies::{DynOrigin, Origin, RotationalElements}; use lox_math::roots::Brent; use lox_math::series::{Series, SeriesError}; use lox_time::time_scales::{Tai, Tdb}; @@ -16,7 +16,7 @@ use lox_time::utc::Utc; use lox_time::{deltas::TimeDelta, Time, TimeLike}; use crate::events::{find_events, find_windows, Event, Window}; -use crate::frames::{BodyFixed, FrameTransformationProvider, Icrf, TryToFrame}; +use crate::frames::{BodyFixed, DynFrame, FrameTransformationProvider, Icrf, TryToFrame}; use crate::{ frames::{CoordinateSystem, ReferenceFrame}, states::State, @@ -60,6 +60,8 @@ pub struct Trajectory { vz: Series>, } +pub type DynTrajectory = Trajectory; + impl Trajectory where T: TimeLike + Clone, @@ -104,37 +106,6 @@ where self.states.first().unwrap().origin() } - pub fn with_frame(self, frame: R1) -> Trajectory { - let states: Vec> = self - .states - .into_iter() - .map(|s| s.with_frame(frame.clone())) - .collect(); - Trajectory::new(&states).unwrap() - } - - pub fn with_origin(&self, origin: O1) -> Trajectory { - let states: Vec> = self - .states - .iter() - .map(|s| s.with_origin(origin.clone())) - .collect(); - Trajectory::new(&states).unwrap() - } - - pub fn with_origin_and_frame( - &self, - origin: O1, - frame: R1, - ) -> Trajectory { - let states: Vec> = self - .states - .iter() - .map(|s| s.with_origin_and_frame(origin.clone(), frame.clone())) - .collect(); - Trajectory::new(&states).unwrap() - } - pub fn start_time(&self) -> T { self.states[0].time() } diff --git a/crates/lox-space/benches/observables.rs b/crates/lox-space/benches/observables.rs index 8677220d..22a3623a 100644 --- a/crates/lox-space/benches/observables.rs +++ b/crates/lox-space/benches/observables.rs @@ -7,7 +7,7 @@ */ use lox_bodies::Earth; -use lox_orbits::analysis::{elevation, elevation2}; +use lox_orbits::analysis::elevation; use lox_orbits::frames::{Icrf, NoOpFrameTransformationProvider, Topocentric}; use lox_orbits::ground::GroundLocation; use lox_orbits::trajectories::Trajectory; @@ -19,22 +19,6 @@ fn main() { divan::main(); } -#[divan::bench] -fn elevation_interpolation(bencher: divan::Bencher) { - bencher - .with_inputs(|| { - ( - time!(Tai, 2022, 2, 1).unwrap(), - ground_station_trajectory(), - spacecraft_trajectory(), - frame(), - ) - }) - .bench_values(|(t, gs, sc, frame)| { - elevation(t, &frame, &gs, &sc, &NoOpFrameTransformationProvider) - }); -} - #[divan::bench] fn elevation_rotation(bencher: divan::Bencher) { bencher @@ -45,7 +29,7 @@ fn elevation_rotation(bencher: divan::Bencher) { spacecraft_trajectory(), ) }) - .bench_values(|(t, gs, sc)| elevation2(t, &gs, &sc, &NoOpFrameTransformationProvider)); + .bench_values(|(t, gs, sc)| elevation(t, &gs, &sc, &NoOpFrameTransformationProvider)); } fn ground_station_trajectory() -> Trajectory, Earth, Icrf> { @@ -65,9 +49,3 @@ fn spacecraft_trajectory() -> Trajectory, Earth, Icrf> { ) .unwrap() } - -fn frame() -> Topocentric { - let longitude = -4.3676f64.to_radians(); - let latitude = 40.4527f64.to_radians(); - Topocentric::from_coords(longitude, latitude, 0.0, Earth) -}