use super::MeasurementType;
use hifitime::Epoch;
use indexmap::{IndexMap, IndexSet};
use log::debug;
use nalgebra::{DefaultAllocator, DimName, OVector, allocator::Allocator};
use std::fmt;
#[cfg(feature = "python")]
use pyo3::prelude::*;
#[cfg_attr(
feature = "python",
pyclass(from_py_object),
pyo3(module = "nyx_space.od")
)]
#[derive(Clone, Debug)]
pub struct Measurement {
pub tracker: String,
pub epoch: Epoch,
pub data: IndexMap<MeasurementType, f64>,
pub rejected: bool,
}
#[cfg_attr(feature = "python", pymethods)]
impl Measurement {
pub fn correct(&mut self, msr_type: MeasurementType, correction: f64) {
if let Some(cur_value) = self.data.get_mut(&msr_type) {
let new_value = *cur_value + correction;
debug!("corrected {msr_type:?} from {cur_value} to {new_value}");
*cur_value = new_value;
}
}
pub fn push(&mut self, msr_type: MeasurementType, msr_value: f64) {
self.data.insert(msr_type, msr_value);
}
}
impl Measurement {
pub fn new(tracker: String, epoch: Epoch) -> Self {
Self {
tracker,
epoch,
data: IndexMap::new(),
rejected: false,
}
}
pub fn with(mut self, msr_type: MeasurementType, msr_value: f64) -> Self {
self.push(msr_type, msr_value);
self
}
pub fn observation<S: DimName>(&self, types: &IndexSet<MeasurementType>) -> OVector<f64, S>
where
DefaultAllocator: Allocator<S>,
{
let mut obs = OVector::zeros();
for (i, t) in types.iter().enumerate() {
if let Some(msr_value) = self.data.get(t) {
obs[i] = *msr_value;
}
}
obs
}
pub fn availability(&self, types: &IndexSet<MeasurementType>) -> Vec<bool> {
let mut rtn = vec![false; types.len()];
for (i, t) in types.iter().enumerate() {
if self.data.contains_key(t) {
rtn[i] = true;
}
}
rtn
}
}
impl fmt::Display for Measurement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let msrs = self
.data
.iter()
.map(|(msr_type, msr_value)| format!("{msr_type:?} = {msr_value} {}", msr_type.unit()))
.collect::<Vec<String>>()
.join(", ");
write!(f, "{} measured {} on {}", self.tracker, msrs, self.epoch)
}
}
impl PartialEq for Measurement {
fn eq(&self, other: &Self) -> bool {
self.tracker == other.tracker
&& self.epoch == other.epoch
&& self.data.iter().all(|(key, &value)| {
if let Some(&other_value) = other.data.get(key) {
(value - other_value).abs() < 1e-10
} else {
false
}
})
}
}