use super::StateParameter;
use crate::{Spacecraft, State, errors::StateError};
use serde::{Deserialize, Serialize};
use serde_dhall::StaticType;
use std::fmt;
#[derive(Copy, Clone, Debug, Serialize, Deserialize, StaticType)]
pub struct Objective {
pub parameter: StateParameter,
pub desired_value: f64,
pub tolerance: f64,
pub multiplicative_factor: f64,
pub additive_factor: f64,
}
impl Objective {
pub fn new(parameter: StateParameter, desired_value: f64) -> Self {
Self::within_tolerance(
parameter,
desired_value,
parameter.default_event_precision(),
)
}
pub fn within_tolerance(parameter: StateParameter, desired_value: f64, tolerance: f64) -> Self {
Self {
parameter,
desired_value,
tolerance,
multiplicative_factor: 1.0,
additive_factor: 0.0,
}
}
pub fn assess(&self, achieved: &Spacecraft) -> Result<(bool, f64), StateError> {
Ok(self.assess_value(achieved.value(self.parameter)?))
}
pub fn assess_value(&self, achieved: f64) -> (bool, f64) {
let param_err =
self.multiplicative_factor * (self.desired_value - achieved) + self.additive_factor;
(param_err.abs() <= self.tolerance, param_err)
}
}
impl fmt::Display for Objective {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
write!(f, "\t{self:x}")
}
}
impl fmt::LowerHex for Objective {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let max_obj_tol = self.tolerance.log10().abs().ceil() as usize;
write!(
f,
"{:?} → {:.prec$} {}",
self.parameter,
self.desired_value,
self.parameter.unit(),
prec = max_obj_tol,
)?;
if self.tolerance.abs() < 1e-1 {
write!(f, " (± {:.1e})", self.tolerance)
} else {
write!(f, " (± {:.2})", self.tolerance)
}
}
}