Skip to main content

nyx_space/od/ground_station/
python.rs

1use super::super::msr::MeasurementType;
2use super::super::noise::StochasticNoise;
3use super::GroundStation;
4use anise::astro::Location;
5use hifitime::Duration;
6use indexmap::{IndexMap, IndexSet};
7use pyo3::prelude::*;
8use std::collections::HashMap;
9
10#[cfg(feature = "python")]
11#[pymethods]
12impl GroundStation {
13    #[new]
14    #[pyo3(signature = (name, location, stochastic_noises, integration_time=None, light_time_correction=false, timestamp_noise_s=None))]
15    fn py_new(
16        name: String,
17        location: Location,
18        stochastic_noises: HashMap<MeasurementType, StochasticNoise>,
19        integration_time: Option<Duration>,
20        light_time_correction: Option<bool>,
21        timestamp_noise_s: Option<StochasticNoise>,
22    ) -> Self {
23        Self {
24            name,
25            location,
26            measurement_types: IndexSet::from_iter(
27                stochastic_noises
28                    .keys()
29                    .copied()
30                    .collect::<Vec<MeasurementType>>(),
31            ),
32            integration_time,
33            light_time_correction: light_time_correction.unwrap_or(false),
34            timestamp_noise_s,
35            stochastic_noises: Some(stochastic_noises.into_iter().collect()),
36        }
37    }
38
39    #[classmethod]
40    #[pyo3(name = "from_yaml")]
41    fn py_from_yaml(_cls: &Bound<'_, pyo3::types::PyType>, yaml_str: &str) -> PyResult<Self> {
42        serde_yml::from_str(yaml_str)
43            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
44    }
45
46    #[pyo3(name = "to_yaml")]
47    fn py_to_yaml(&self) -> PyResult<String> {
48        serde_yml::to_string(self)
49            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
50    }
51
52    #[classmethod]
53    #[pyo3(name = "load_many_yaml")]
54    fn py_load_many_yaml(_cls: &Bound<'_, pyo3::types::PyType>, path: &str) -> PyResult<Vec<Self>> {
55        use crate::io::ConfigRepr;
56        Self::load_many(path).map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
57    }
58
59    #[classmethod]
60    #[pyo3(name = "loads_many_yaml")]
61    fn py_loads_many_yaml(
62        _cls: &Bound<'_, pyo3::types::PyType>,
63        yaml_str: &str,
64    ) -> PyResult<Vec<Self>> {
65        use crate::io::ConfigRepr;
66        Self::loads_many(yaml_str)
67            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
68    }
69
70    #[classmethod]
71    #[pyo3(name = "dump_many_yaml")]
72    fn py_dump_many_yaml(
73        _cls: &Bound<'_, pyo3::types::PyType>,
74        stations: Vec<Self>,
75        path: &str,
76    ) -> PyResult<()> {
77        let s = serde_yml::to_string(&stations)
78            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))?;
79        std::fs::write(path, s).map_err(|e| pyo3::exceptions::PyIOError::new_err(e.to_string()))
80    }
81
82    #[classmethod]
83    #[pyo3(name = "dumps_many_yaml")]
84    fn py_dumps_many_yaml(
85        _cls: &Bound<'_, pyo3::types::PyType>,
86        stations: Vec<Self>,
87    ) -> PyResult<String> {
88        serde_yml::to_string(&stations)
89            .map_err(|e| pyo3::exceptions::PyValueError::new_err(e.to_string()))
90    }
91
92    #[getter]
93    pub fn get_name(&self) -> String {
94        self.name.clone()
95    }
96
97    #[setter]
98    pub fn set_name(&mut self, name: String) {
99        self.name = name;
100    }
101
102    #[getter]
103    pub fn get_location(&self) -> Location {
104        self.location.clone()
105    }
106
107    #[setter]
108    pub fn set_location(&mut self, location: Location) {
109        self.location = location;
110    }
111
112    #[getter]
113    pub fn get_integration_time(&self) -> Option<Duration> {
114        self.integration_time
115    }
116
117    #[setter]
118    pub fn set_integration_time(&mut self, integration_time: Option<Duration>) {
119        self.integration_time = integration_time;
120    }
121
122    #[getter]
123    pub fn get_light_time_correction(&self) -> bool {
124        self.light_time_correction
125    }
126
127    #[setter]
128    pub fn set_light_time_correction(&mut self, light_time_correction: bool) {
129        self.light_time_correction = light_time_correction;
130    }
131
132    #[getter]
133    pub fn get_timestamp_noise_s(&self) -> Option<StochasticNoise> {
134        self.timestamp_noise_s
135    }
136
137    #[setter]
138    pub fn set_timestamp_noise_s(&mut self, noise: Option<StochasticNoise>) {
139        self.timestamp_noise_s = noise;
140    }
141
142    #[getter]
143    pub fn get_measurement_types(&self) -> Vec<MeasurementType> {
144        self.measurement_types.iter().cloned().collect()
145    }
146
147    #[setter]
148    pub fn set_measurement_types(&mut self, types: Vec<MeasurementType>) {
149        self.measurement_types = types.into_iter().collect();
150    }
151
152    pub fn add_measurement_type(&mut self, msr_type: MeasurementType, noise: StochasticNoise) {
153        self.measurement_types.insert(msr_type);
154        self.stochastic_noises
155            .get_or_insert_with(IndexMap::new)
156            .insert(msr_type, noise);
157    }
158
159    pub fn remove_measurement_type(&mut self, msr_type: &MeasurementType) -> bool {
160        // (Note: Requires IndexSet to be used with the `shift_remove` method to maintain order,
161        // fallback to `.remove()` if order preservation upon deletion is not strictly required)
162        self.measurement_types.shift_remove(msr_type)
163    }
164
165    pub fn clear_measurement_types(&mut self) {
166        self.measurement_types.clear();
167    }
168
169    #[getter]
170    pub fn get_stochastic_noises(&self) -> Option<Vec<(MeasurementType, StochasticNoise)>> {
171        self.stochastic_noises
172            .as_ref()
173            .map(|map| map.iter().map(|(k, v)| (*k, *v)).collect())
174    }
175
176    pub fn get_stochastic_noise(&self, m_type: &MeasurementType) -> Option<StochasticNoise> {
177        self.stochastic_noises
178            .as_ref()
179            .and_then(|map| map.get(m_type).cloned())
180    }
181
182    pub fn set_stochastic_noise(&mut self, m_type: MeasurementType, noise: StochasticNoise) {
183        self.stochastic_noises
184            .get_or_insert_with(indexmap::IndexMap::new)
185            .insert(m_type, noise);
186    }
187
188    pub fn remove_stochastic_noise(&mut self, m_type: &MeasurementType) -> Option<StochasticNoise> {
189        self.stochastic_noises
190            .as_mut()
191            .and_then(|map| map.shift_remove(m_type))
192    }
193
194    pub fn clear_stochastic_noises(&mut self) {
195        self.stochastic_noises = None;
196    }
197
198    fn __str__(&self) -> String {
199        format!("{self}")
200    }
201
202    fn __repr__(&self) -> String {
203        format!("{self:?} @ {self:p}")
204    }
205
206    fn __eq__(&self, other: &Self) -> bool {
207        self == other
208    }
209}