Skip to content

Commit 1499fb9

Browse files
Add equality checks in Python
1 parent 3a7390f commit 1499fb9

File tree

7 files changed

+68
-12
lines changed

7 files changed

+68
-12
lines changed

anise-py/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
use ::anise::almanac::metaload::{MetaAlmanac, MetaFile};
1212
use ::anise::almanac::Almanac;
13-
use ::anise::analysis::event::{Event, EventArc, EventDetails};
13+
use ::anise::analysis::event::{Event, EventArc, EventDetails, EventEdge};
1414
use ::anise::analysis::prelude::OrbitalElement;
1515
use ::anise::analysis::python::{
1616
PyFrameSpec, PyOrthogonalFrame, PyScalarExpr, PyStateSpec, PyVectorExpr,
@@ -67,6 +67,7 @@ fn analysis(_py: Python, sm: &Bound<PyModule>) -> PyResult<()> {
6767
sm.add_class::<Plane>()?;
6868
sm.add_class::<Event>()?;
6969
sm.add_class::<EventDetails>()?;
70+
sm.add_class::<EventEdge>()?;
7071
sm.add_class::<EventArc>()?;
7172
sm.add_class::<ReportScalars>()?;
7273
Ok(())

anise-py/tests/test_analysis.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from anise.time import Epoch, TimeSeries, Unit
44
from anise.constants import Frames
55
from anise.astro import Frame
6+
from pathlib import Path
67

78

89
def test_analysis_gen_report():
@@ -173,6 +174,7 @@ def test_analysis_event():
173174
"""
174175
Tests event finding for apoapsis, periapsis, eclipses, and other criteria.
175176
"""
177+
data_path = Path(__file__).parent.joinpath("..", "..", "data")
176178
almanac = (
177179
Almanac(str(data_path.joinpath("de440s.bsp")))
178180
.load(str(data_path.joinpath("pck08.pca")))
@@ -241,19 +243,23 @@ def test_analysis_event():
241243
]
242244
assert all((dt - period).abs() < Unit.Minute * 5 for dt in dts_peri)
243245

246+
tick = Epoch.system_now()
244247
# Find sunset/sunrise arcs
245248
sunset_arcs = almanac.report_event_arcs(
246249
lro_state_spec, sunset_nadir, start_epoch, end_epoch
247250
)
248-
assert sunset_arcs[1].rise.edge == analysis.EventEdge.Rising()
249-
assert sunset_arcs[1].fall.edge == analysis.EventEdge.Falling()
251+
print(f"{len(sunset_arcs)} sunset arcs found in {Epoch.system_now().timedelta(tick)}")
252+
assert sunset_arcs[1].rise.edge == analysis.EventEdge.Rising
253+
assert sunset_arcs[1].fall.edge == analysis.EventEdge.Falling
250254
assert len(sunset_arcs) == 309
251255

252256
# Find eclipse arcs in a short time span
257+
tick = Epoch.system_now()
253258
eclipse_arcs = almanac.report_event_arcs(
254259
lro_state_spec, eclipse, start_epoch, start_epoch + Unit.Hour * 3
255260
)
256261
assert len(eclipse_arcs) == 2
262+
print("Eclipse arcs found in ", Epoch.system_now().timedelta(tick))
257263

258264
# Validate the eclipse periods
259265
for arc in eclipse_arcs:

anise/src/analysis/elements.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::prelude::Orbit;
2222
/// Orbital element defines all of the supported orbital elements in ANISE, which are all built from a State.
2323
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
2424
#[cfg_attr(feature = "python", pyclass)]
25+
#[cfg_attr(feature = "python", pyo3(module = "anise.analysis"))]
2526
#[derive(Copy, Clone, Debug, PartialEq, Deserialize, Serialize)]
2627
pub enum OrbitalElement {
2728
/// Argument of Latitude (deg)
@@ -274,4 +275,10 @@ impl OrbitalElement {
274275
self.evaluate(orbit)
275276
.map_err(|e| PyException::new_err(e.to_string()))
276277
}
278+
fn __eq__(&self, other: &Self) -> bool {
279+
self == other
280+
}
281+
fn __ne__(&self, other: &Self) -> bool {
282+
self != other
283+
}
277284
}

anise/src/analysis/event.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use pyo3::types::PyType;
3737
/// :type value_precision: float
3838
/// :type ab_corr: Aberration, optional
3939
#[cfg_attr(feature = "python", pyclass)]
40+
#[cfg_attr(feature = "python", pyo3(module = "anise.analysis"))]
4041
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
4142
pub struct Event {
4243
/// The state parameter
@@ -283,6 +284,13 @@ impl Event {
283284
fn __repr__(&self) -> String {
284285
format!("{self}@{self:p}")
285286
}
287+
288+
fn __eq__(&self, other: &Self) -> bool {
289+
self == other
290+
}
291+
fn __ne__(&self, other: &Self) -> bool {
292+
self != other
293+
}
286294
}
287295

288296
impl fmt::Display for Event {
@@ -304,6 +312,7 @@ impl fmt::Display for Event {
304312
/// `EventEdge` is used to describe the nature of a trajectory event, particularly in terms of its temporal dynamics relative to a specified condition or threshold. This enum helps in distinguishing whether the event is occurring at a rising edge, a falling edge, or if the edge is unclear due to insufficient data or ambiguous conditions.
305313
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
306314
#[cfg_attr(feature = "python", pyclass)]
315+
#[cfg_attr(feature = "python", pyo3(module = "anise.analysis"))]
307316
pub enum EventEdge {
308317
/// Represents a rising edge of the event. This indicates that the event is transitioning from a lower to a higher evaluation of the event. For example, in the context of elevation, a rising edge would indicate an increase in elevation from a lower angle.
309318
Rising,
@@ -317,6 +326,17 @@ pub enum EventEdge {
317326
Unclear,
318327
}
319328

329+
#[cfg(feature = "python")]
330+
#[cfg_attr(feature = "python", pymethods)]
331+
impl EventEdge {
332+
fn __eq__(&self, other: &Self) -> bool {
333+
self == other
334+
}
335+
fn __ne__(&self, other: &Self) -> bool {
336+
self != other
337+
}
338+
}
339+
320340
/// Represents the details of an event occurring along a trajectory.
321341
///
322342
/// `EventDetails` encapsulates the state at which a particular event occurs in a trajectory, along with additional information about the nature of the event. This struct is particularly useful for understanding the dynamics of the event, such as whether it represents a rising or falling edge, or if the edge is unclear.
@@ -325,7 +345,7 @@ pub enum EventEdge {
325345
/// S: Interpolatable - A type that represents the state of the trajectory. This type must implement the `Interpolatable` trait, ensuring that it can be interpolated and manipulated according to the trajectory's requirements.
326346
#[derive(Clone, PartialEq)]
327347
#[cfg_attr(feature = "python", pyclass)]
328-
#[cfg_attr(feature = "python", pyo3(get_all))]
348+
#[cfg_attr(feature = "python", pyo3(module = "anise.analysis", get_all))]
329349
pub struct EventDetails {
330350
/// The state of the trajectory at the found event.
331351
/// :rtype: Orbit
@@ -444,6 +464,12 @@ impl EventDetails {
444464
fn __repr__(&self) -> String {
445465
format!("{self}@{self:p}")
446466
}
467+
fn __eq__(&self, other: &Self) -> bool {
468+
self == other
469+
}
470+
fn __ne__(&self, other: &Self) -> bool {
471+
self != other
472+
}
447473
}
448474

449475
impl fmt::Display for EventDetails {
@@ -473,7 +499,7 @@ impl fmt::Debug for EventDetails {
473499
}
474500

475501
#[cfg_attr(feature = "python", pyclass)]
476-
#[cfg_attr(feature = "python", pyo3(get_all))]
502+
#[cfg_attr(feature = "python", pyo3(module = "anise.analysis", get_all))]
477503
#[derive(Clone, PartialEq)]
478504
pub struct EventArc {
479505
/// rise event of this arc

anise/src/analysis/python.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ impl Almanac {
112112
})
113113
}
114114

115-
/// Find all event arcs, i.e. the start and stop time of when a given event occurs.
116-
///
117-
/// **Performance:** for robustness, this function calls the memory and computationally intensive [report_events_slow] function.
115+
/// Find all event arcs, i.e. the start and stop time of when a given event occurs. This function
116+
/// calls the memory and computationally intensive [report_events_slow] function.
118117
#[pyo3(name = "report_event_arcs")]
119118
fn py_report_event_arcs(
120119
&self,
@@ -535,6 +534,23 @@ impl PyStateSpec {
535534
spec.to_s_expr()
536535
.map_err(|e| PyException::new_err(e.to_string()))
537536
}
537+
/// Evaluate the orbital element enum variant for the provided orbit
538+
#[pyo3(name = "evaluate", signature=(epoch, almanac))]
539+
fn py_evaluate(&self, epoch: Epoch, almanac: &Almanac) -> Result<Orbit, PyErr> {
540+
let spec = StateSpec::from(self.clone());
541+
spec.evaluate(epoch, almanac)
542+
.map_err(|e| PyException::new_err(e.to_string()))
543+
}
544+
fn __eq__(&self, other: &Self) -> bool {
545+
let me = StateSpec::from(self.clone());
546+
let other = StateSpec::from(other.clone());
547+
me == other
548+
}
549+
fn __ne__(&self, other: &Self) -> bool {
550+
let me = StateSpec::from(self.clone());
551+
let other = StateSpec::from(other.clone());
552+
me != other
553+
}
538554
}
539555

540556
/// FrameSpec allows defining a frame that can be computed from another set of loaded frames, which include a center.

anise/src/analysis/report.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use super::python::{PyScalarExpr, PyStateSpec};
3030
// :type state_spec: StateSpec
3131
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
3232
#[cfg_attr(feature = "python", pyclass)]
33+
#[cfg_attr(feature = "python", pyo3(module = "anise.analysis"))]
3334
pub struct ReportScalars {
3435
pub scalars: Vec<(ScalarExpr, Option<String>)>,
3536
pub state_spec: StateSpec,

anise/src/analysis/search.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,8 @@ impl Almanac {
355355
Ok(events)
356356
}
357357

358-
/// Find all event arcs, i.e. the start and stop time of when a given event occurs.
359-
///
360-
/// **Performance:** for robustness, this function calls the memory and computationally intensive [report_events_slow] function.
358+
/// Find all event arcs, i.e. the start and stop time of when a given event occurs. This function
359+
/// calls the memory and computationally intensive [report_events_slow] function.
361360
pub fn report_event_arcs(
362361
&self,
363362
state_spec: &StateSpec,
@@ -430,7 +429,7 @@ impl Almanac {
430429
if event_value >= 0.0 {
431430
// We're in an arc.
432431
if let Some(next_value) = crossing.next_value {
433-
if next_value < 0.0 {
432+
if next_value < 0.0 && rise.is_some() {
434433
// At the next immediate step, the event ends, so this marks the end of the arc.
435434
arcs.push(EventArc {
436435
rise: rise.clone().unwrap(),

0 commit comments

Comments
 (0)