dess_core/
traits_and_macros.rs1use crate::imports::*;
2use bincode::{deserialize, serialize};
3use std::ffi::OsStr;
4use std::fs::File;
5use std::path::{Path, PathBuf};
6
7#[macro_export]
8macro_rules! time_it {
9 ($thing: expr) => {{
10 let t0 = Instant::now();
11 $thing;
12 let t_elapsed = Instant::now() - t0;
13 t_elapsed
14 }};
15}
16
17#[macro_export]
20macro_rules! zip {
21 ($x: expr) => ($x);
22 ($x: expr, $($y: expr), +) => (
23 $x.iter().zip(
24 zip!($($y), +))
25 )
26}
27
28#[macro_export]
31macro_rules! connect_states {
32 ($sys: ident, $(($s0: ident, $s1: ident, $c: ident)), +) => {
33 $(
34 $sys.$c.set_flow(&$sys.$s0, &$sys.$s1);
35 )+
36 };
37}
38
39#[macro_export]
41macro_rules! update_derivs {
42 ($sys: ident, $(($s0: ident, $s1: ident, $c: ident)), +) => {
43 $(
44 $sys.$s0.step_deriv(-$sys.$c.flow() / $sys.$s0.storage());
45 $sys.$s1.step_deriv($sys.$c.flow() / $sys.$s1.storage());
46 )+
47 };
48}
49
50#[macro_export]
55macro_rules! print_to_py {
56 ( $( $x:expr, $y:expr ),* ) => {
57 pyo3::Python::with_gil(|py| {
58 let locals = pyo3::types::PyDict::new(py);
59 $(
60 locals.set_item($x, $y).unwrap();
61 py.run(
62 &format!("print(f\"{}: {{{}:.3g}}\")", $x, $x),
63 None,
64 Some(locals),
65 )
66 .expect(&format!("printing `{}` failed", $x));
67 )*
68 });
69 };
70 ( $x:expr ) => {
71 pyo3::Python::with_gil(|py| {
73 py.run(
74 &format!("print({})", $x),
75 None,
76 None,
77 )
78 .expect(&format!("printing `{}` failed", $x));
79 });
80 }
81}
82
83pub trait HasState {
84 fn state(&self) -> f64;
86 fn set_state(&mut self, val: f64);
88 fn step_state_by_dt(&mut self, dt: &f64) {
91 self.set_state(self.state() + dt * self.deriv());
92 }
93 fn step_state(&mut self, val: f64) {
95 self.set_state(self.state() + val);
96 }
97 fn deriv(&self) -> f64;
99 fn set_deriv(&mut self, val: f64);
101 fn step_deriv(&mut self, val: f64) {
103 self.set_deriv(self.deriv() + val)
104 }
105 fn storage(&self) -> f64;
107}
108
109pub trait HasStates: BareClone {
110 fn states(&self) -> Vec<f64>;
112 fn set_states(&mut self, val: Vec<f64>);
114 fn step_states_by_dt(&mut self, dt: &f64);
117 fn step_states(&mut self, val: Vec<f64>);
120 fn derivs(&self) -> Vec<f64>;
122 fn set_derivs(&mut self, val: &[f64]);
124 fn step_derivs(&mut self, val: Vec<f64>);
126 fn storages(&self) -> Vec<f64>;
128}
129
130pub trait Flow {
131 fn set_flow(&mut self, p0: &dyn HasState, p1: &dyn HasState);
133 fn flow(&self) -> f64;
135}
136
137pub trait Diff {
138 fn diff(&self) -> Vec<f64>;
139}
140
141impl Diff for Vec<f64> {
142 fn diff(&self) -> Vec<f64> {
143 self.windows(2)
144 .map(|vs| {
145 let [x, y] = vs else {unreachable!()};
146 y - x
147 })
148 .collect()
149 }
150}
151
152pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> {
153 #[allow(clippy::wrong_self_convention)]
154 fn to_file(&self, filename: &str) -> Result<(), anyhow::Error> {
166 let file = PathBuf::from(filename);
167 let extension = Path::new(filename)
168 .extension()
169 .and_then(OsStr::to_str)
170 .unwrap_or("");
171 match extension {
172 "json" => {
173 serde_json::to_writer(&File::create(file)?, self)?;
174 Ok(())
175 }
176 "yaml" => {
177 serde_yaml::to_writer(&File::create(file)?, self)?;
178 Ok(())
179 }
180 _ => Err(anyhow!("Unsupported file extension {}", extension)),
181 }
182 }
183
184 fn from_file(filename: &str) -> Result<Self, anyhow::Error>
198 where
199 Self: std::marker::Sized,
200 for<'de> Self: Deserialize<'de>,
201 {
202 let extension = Path::new(filename)
203 .extension()
204 .and_then(OsStr::to_str)
205 .unwrap_or("");
206
207 let file = File::open(filename)?;
208 match extension {
209 "yaml" => Ok(serde_yaml::from_reader(file)?),
210 "json" => Ok(serde_json::from_reader(file)?),
211 _ => Err(anyhow!("Unsupported file extension {}", extension)),
212 }
213 }
214
215 fn to_json(&self) -> String {
217 serde_json::to_string(&self).unwrap()
218 }
219
220 fn from_json(json_str: &str) -> Result<Self, anyhow::Error> {
222 Ok(serde_json::from_str(json_str)?)
223 }
224
225 fn to_yaml(&self) -> String {
227 serde_yaml::to_string(&self).unwrap()
228 }
229
230 fn from_yaml(yaml_str: &str) -> Result<Self, anyhow::Error> {
232 Ok(serde_yaml::from_str(yaml_str)?)
233 }
234
235 fn to_bincode(&self) -> Vec<u8> {
237 serialize(&self).unwrap()
238 }
239
240 fn from_bincode(encoded: &[u8]) -> Result<Self, anyhow::Error> {
242 Ok(deserialize(encoded)?)
243 }
244}
245
246impl<T> SerdeAPI for T where T: Serialize + for<'a> Deserialize<'a> {}
247
248pub trait Linspace {
249 fn linspace(start: f64, stop: f64, n_elements: usize) -> Vec<f64> {
250 let n_steps = n_elements - 1;
251 let step_size = (stop - start) / n_steps as f64;
252 let v_norm: Vec<f64> = (0..=n_steps)
253 .collect::<Vec<usize>>()
254 .iter()
255 .map(|x| *x as f64)
256 .collect();
257 let v = v_norm.iter().map(|x| (x * step_size) + start).collect();
258 v
259 }
260}
261
262impl Linspace for Vec<f64> {}
263
264pub trait BareClone {
265 fn bare_clone(&self) -> Self;
266}