nyx_space/md/objective.rs
1/*
2 Nyx, blazing fast astrodynamics
3 Copyright (C) 2018-onwards Christopher Rabotin <christopher.rabotin@gmail.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19use super::StateParameter;
20use crate::{errors::StateError, Spacecraft, State};
21use serde::{Deserialize, Serialize};
22use std::fmt;
23
24/// Defines a state parameter event finder
25#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
26pub struct Objective {
27 /// The state parameter to target
28 pub parameter: StateParameter,
29 /// The desired self.desired_value, must be in the same units as the state parameter
30 pub desired_value: f64,
31 /// The precision on the desired value
32 pub tolerance: f64,
33 /// A multiplicative factor this parameter's error in the targeting (defaults to 1.0)
34 pub multiplicative_factor: f64,
35 /// An additive factor to this parameters's error in the targeting (defaults to 0.0)
36 pub additive_factor: f64,
37}
38
39impl Objective {
40 /// Match a specific value for the parameter.
41 /// By default, the tolerance on the parameter is 0.1 times whatever unit is the default for that parameter.
42 /// For example, a radius event will seek the requested value at the decimeter level, and an angle event will seek it at the tenth of a degree.
43 pub fn new(parameter: StateParameter, desired_value: f64) -> Self {
44 Self::within_tolerance(
45 parameter,
46 desired_value,
47 parameter.default_event_precision(),
48 )
49 }
50
51 /// Match a specific value for the parameter to hit the specified value with the provided tolerance on the value
52 pub fn within_tolerance(parameter: StateParameter, desired_value: f64, tolerance: f64) -> Self {
53 Self {
54 parameter,
55 desired_value,
56 tolerance,
57 multiplicative_factor: 1.0,
58 additive_factor: 0.0,
59 }
60 }
61
62 /// Returns whether this objective has been achieved, and the associated parameter error.
63 pub fn assess(&self, achieved: &Spacecraft) -> Result<(bool, f64), StateError> {
64 Ok(self.assess_value(achieved.value(self.parameter)?))
65 }
66
67 /// Returns whether this objective has been achieved, and the associated parameter error.
68 /// Warning: the parameter `achieved` must be in the same unit as the objective.
69 pub fn assess_value(&self, achieved: f64) -> (bool, f64) {
70 let param_err =
71 self.multiplicative_factor * (self.desired_value - achieved) + self.additive_factor;
72
73 (param_err.abs() <= self.tolerance, param_err)
74 }
75}
76
77impl fmt::Display for Objective {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
79 write!(f, "\t{self:x}")
80 }
81}
82
83impl fmt::LowerHex for Objective {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
85 let max_obj_tol = self.tolerance.log10().abs().ceil() as usize;
86
87 write!(
88 f,
89 "{:?} → {:.prec$} {}",
90 self.parameter,
91 self.desired_value,
92 self.parameter.unit(),
93 prec = max_obj_tol,
94 )?;
95
96 if self.tolerance.abs() < 1e-1 {
97 write!(f, " (± {:.1e})", self.tolerance)
98 } else {
99 write!(f, " (± {:.2})", self.tolerance)
100 }
101 }
102}