nyx_space/md/events/
mod.rs1pub mod details;
20use log::warn;
21pub mod evaluators;
22pub mod search;
23use super::StateParameter;
24use crate::errors::EventError;
25use crate::linalg::allocator::Allocator;
26use crate::linalg::DefaultAllocator;
27use crate::time::{Duration, Unit};
28use crate::State;
29use anise::prelude::{Almanac, Frame};
30use anise::structure::planetocentric::ellipsoid::Ellipsoid;
31use serde::{Deserialize, Serialize};
32
33use std::default::Default;
34use std::fmt;
35use std::sync::Arc;
36
37pub trait EventEvaluator<S: State>: fmt::Display + Send + Sync
39where
40 DefaultAllocator: Allocator<S::Size> + Allocator<S::Size, S::Size> + Allocator<S::VecLength>,
41{
42 fn eval_crossing(
44 &self,
45 prev_state: &S,
46 next_state: &S,
47 almanac: Arc<Almanac>,
48 ) -> Result<bool, EventError> {
49 let prev = self.eval(prev_state, almanac.clone())?;
50 let next = self.eval(next_state, almanac)?;
51
52 Ok(prev * next < 0.0)
53 }
54
55 fn eval(&self, state: &S, almanac: Arc<Almanac>) -> Result<f64, EventError>;
57 fn eval_string(&self, state: &S, almanac: Arc<Almanac>) -> Result<String, EventError>;
59 fn epoch_precision(&self) -> Duration;
60 fn value_precision(&self) -> f64;
61}
62
63#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
65pub struct Event {
66 pub parameter: StateParameter,
68 pub desired_value: f64,
70 pub epoch_precision: Duration,
72 pub value_precision: f64,
74 pub obs_frame: Option<Frame>,
76}
77
78impl fmt::Display for Event {
79 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
80 write!(f, "{:?}", self.parameter)?;
81 if self.parameter != StateParameter::Apoapsis && self.parameter != StateParameter::Periapsis
82 {
83 if self.desired_value.abs() > 1e3 {
84 write!(
85 f,
86 " = {:e} {} (± {:e} {})",
87 self.desired_value,
88 self.parameter.unit(),
89 self.value_precision,
90 self.parameter.unit()
91 )?;
92 } else {
93 write!(
94 f,
95 " = {} {} (± {} {})",
96 self.desired_value,
97 self.parameter.unit(),
98 self.value_precision,
99 self.parameter.unit()
100 )?;
101 }
102 }
103 if let Some(frame) = self.obs_frame {
104 write!(f, "in frame {frame}")?;
105 }
106 fmt::Result::Ok(())
107 }
108}
109
110impl Event {
111 pub fn new(parameter: StateParameter, desired_value: f64) -> Self {
116 Self::within_tolerance(
117 parameter,
118 desired_value,
119 parameter.default_event_precision(),
120 )
121 }
122
123 pub fn within_tolerance(
125 parameter: StateParameter,
126 desired_value: f64,
127 value_precision: f64,
128 ) -> Self {
129 Self::specific(parameter, desired_value, value_precision, Unit::Millisecond)
130 }
131
132 pub fn specific(
134 parameter: StateParameter,
135 desired_value: f64,
136 value_precision: f64,
137 unit_precision: Unit,
138 ) -> Self {
139 Self {
140 parameter,
141 desired_value,
142 epoch_precision: 1 * unit_precision,
143 value_precision,
144 obs_frame: None,
145 }
146 }
147
148 pub fn periapsis() -> Self {
150 Self::new(StateParameter::Periapsis, 0.0)
151 }
152
153 pub fn apoapsis() -> Self {
155 Self::new(StateParameter::Apoapsis, 180.0)
156 }
157
158 pub fn mean_surface(body: &Ellipsoid) -> Self {
161 Self::new(StateParameter::Rmag, body.mean_equatorial_radius_km())
162 }
163
164 pub fn in_frame(parameter: StateParameter, desired_value: f64, target_frame: Frame) -> Self {
166 warn!("Searching for an event in another frame is slow: you should instead convert the trajectory into that other frame");
167 Self {
168 parameter,
169 desired_value,
170 epoch_precision: Unit::Millisecond * 1,
171 value_precision: 1e-3,
172 obs_frame: Some(target_frame),
173 }
174 }
175}
176
177impl Default for Event {
178 fn default() -> Self {
179 Self {
180 parameter: StateParameter::Periapsis,
181 desired_value: 0.0,
182 value_precision: 1e-3,
183 epoch_precision: Unit::Second * 1,
184 obs_frame: None,
185 }
186 }
187}