nyx_space/md/opti/multipleshooting/
ctrlnodes.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 anise::prelude::Frame;
20
21use crate::md::prelude::{Objective, StateParameter};
22use crate::time::Epoch;
23use crate::NyxError;
24use serde_derive::{Deserialize, Serialize};
25use std::convert::Into;
26use std::str::FromStr;
27
28use super::multishoot::MultishootNode;
29
30#[derive(Serialize, Deserialize, Clone, Debug)]
31pub struct NodesSerde {
32    pub nodes: Vec<NodeSerde>,
33}
34
35impl NodesSerde {
36    pub fn to_node_vec(&self) -> Result<Vec<Node>, NyxError> {
37        let mut rtn = Vec::with_capacity(self.nodes.len());
38        for n in &self.nodes {
39            rtn.push(n.to_node()?)
40        }
41        Ok(rtn)
42    }
43}
44
45#[derive(Serialize, Deserialize, Clone, Debug)]
46pub struct NodeSerde {
47    pub x: f64,
48    pub y: f64,
49    pub z: f64,
50    pub vmag: Option<f64>,
51    pub epoch: String,
52    pub frame: Frame,
53}
54
55impl NodeSerde {
56    pub fn to_node(&self) -> Result<Node, NyxError> {
57        let epoch = Epoch::from_str(&self.epoch).unwrap();
58
59        Ok(Node {
60            x: self.x,
61            y: self.y,
62            z: self.z,
63            vmag: self.vmag.unwrap_or(0.0),
64            frame: self.frame,
65            epoch,
66        })
67    }
68}
69
70#[derive(Copy, Clone, Debug)]
71pub struct Node {
72    pub x: f64,
73    pub y: f64,
74    pub z: f64,
75    pub vmag: f64,
76    pub epoch: Epoch,
77    pub frame: Frame,
78}
79
80impl Node {
81    pub fn rmag(&self) -> f64 {
82        (self.x.powi(2) + self.y.powi(2) + self.z.powi(2)).sqrt()
83    }
84}
85
86impl MultishootNode<3> for Node {
87    fn epoch(&self) -> Epoch {
88        self.epoch
89    }
90
91    fn update_component(&mut self, component: usize, add_val: f64) {
92        match component {
93            0 => self.x += add_val,
94            1 => self.y += add_val,
95            2 => self.z += add_val,
96            3 => self.vmag += add_val,
97            _ => unreachable!(),
98        }
99    }
100}
101
102#[allow(clippy::from_over_into)]
103impl Into<[Objective; 3]> for Node {
104    fn into(self) -> [Objective; 3] {
105        [
106            Objective::new(StateParameter::X, self.x),
107            Objective::new(StateParameter::Y, self.y),
108            Objective::new(StateParameter::Z, self.z),
109        ]
110    }
111}
112
113impl MultishootNode<4> for Node {
114    fn epoch(&self) -> Epoch {
115        self.epoch
116    }
117
118    fn update_component(&mut self, component: usize, add_val: f64) {
119        match component {
120            0 => self.x += add_val,
121            1 => self.y += add_val,
122            2 => self.z += add_val,
123            3 => self.vmag += add_val,
124            _ => unreachable!(),
125        }
126    }
127}
128
129#[allow(clippy::from_over_into)]
130impl Into<[Objective; 4]> for Node {
131    fn into(self) -> [Objective; 4] {
132        [
133            Objective::new(StateParameter::X, self.x),
134            Objective::new(StateParameter::Y, self.y),
135            Objective::new(StateParameter::Z, self.z),
136            Objective::new(StateParameter::Vmag, self.vmag),
137        ]
138    }
139}
140
141#[allow(clippy::from_over_into)]
142impl Into<NodeSerde> for Node {
143    fn into(self) -> NodeSerde {
144        NodeSerde {
145            x: self.x,
146            y: self.y,
147            z: self.z,
148            vmag: Some(self.vmag),
149            frame: self.frame,
150            epoch: self.epoch.to_string(),
151        }
152    }
153}
154
155#[allow(clippy::from_over_into)]
156impl Into<NodeSerde> for &Node {
157    fn into(self) -> NodeSerde {
158        NodeSerde {
159            x: self.x,
160            y: self.y,
161            z: self.z,
162            vmag: Some(self.vmag),
163            frame: self.frame,
164            epoch: self.epoch.to_string(),
165        }
166    }
167}
168
169#[test]
170fn test_nodeserde() {
171    use toml;
172
173    let str_nodes = r#"[[nodes]]
174x = -394.37164017582654
175y = -80.02184491079583
176z = -1702.1160791417442
177vmag = 0.0
178epoch = "2023-11-25T14:11:46.789000034 UTC"
179
180[nodes.frame]
181ephemeris_id = 301
182orientation_id = 1
183
184[[nodes]]
185x = -381.68254116206856
186y = -48.21573534985666
187z = -1705.829637126235
188vmag = 0.0
189epoch = "2023-11-25T14:12:06.789000034 UTC"
190
191[nodes.frame]
192ephemeris_id = 301
193orientation_id = 1
194
195[[nodes]]
196x = -368.8474537620047
197y = -16.401929604226403
198z = -1708.8692139449731
199vmag = 0.0
200epoch = "2023-11-25T14:12:26.789000034 UTC"
201
202[nodes.frame]
203ephemeris_id = 301
204orientation_id = 1
205"#;
206
207    let toml_nodes: NodesSerde = toml::from_str(str_nodes).unwrap();
208
209    let nodes = toml_nodes.to_node_vec().unwrap();
210
211    dbg!(&nodes);
212
213    let v = NodesSerde {
214        nodes: nodes.iter().map(|n| n.into()).collect::<Vec<NodeSerde>>(),
215    };
216    let toml_ser = toml::to_string(&v).unwrap();
217
218    println!("GOT\n{}\n\nWANTED:{}", toml_ser, str_nodes);
219
220    assert_eq!(toml_ser, str_nodes);
221}