use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct XasGroup {
pub label: String,
pub filename: Option<PathBuf>,
pub energy: Vec<f64>,
pub mu: Vec<f64>,
pub i0: Option<Vec<f64>>,
pub it: Option<Vec<f64>>,
pub iflu: Option<Vec<f64>>,
pub iref: Option<Vec<f64>>,
pub e0: Option<f64>,
pub edge_step: Option<f64>,
pub pre_edge: Option<Vec<f64>>,
pub post_edge: Option<Vec<f64>>,
pub norm: Option<Vec<f64>>,
pub flat: Option<Vec<f64>>,
pub dmude: Option<Vec<f64>>,
pub bkg: Option<Vec<f64>>,
pub delta_bkg: Option<Vec<f64>>,
pub k: Option<Vec<f64>>,
pub chi: Option<Vec<f64>>,
pub delta_chi: Option<Vec<f64>>,
pub r: Option<Vec<f64>>,
pub chir_mag: Option<Vec<f64>>,
pub chir_re: Option<Vec<f64>>,
pub chir_im: Option<Vec<f64>>,
}
impl XasGroup {
pub fn from_mu(label: impl Into<String>, energy: Vec<f64>, mu: Vec<f64>) -> Self {
Self {
label: label.into(),
energy,
mu,
..Default::default()
}
}
pub fn from_chi(label: impl Into<String>, k: Vec<f64>, chi: Vec<f64>) -> Self {
Self {
label: label.into(),
k: Some(k),
chi: Some(chi),
..Default::default()
}
}
pub fn len(&self) -> usize {
self.energy.len()
}
pub fn clear_derived(&mut self) {
self.e0 = None;
self.edge_step = None;
self.pre_edge = None;
self.post_edge = None;
self.norm = None;
self.flat = None;
self.dmude = None;
self.bkg = None;
self.delta_bkg = None;
self.k = None;
self.chi = None;
self.delta_chi = None;
self.r = None;
self.chir_mag = None;
self.chir_re = None;
self.chir_im = None;
}
pub fn is_empty(&self) -> bool {
self.energy.is_empty()
}
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Folders {
pub data_dir: Option<PathBuf>,
pub work_dir: Option<PathBuf>,
pub feff_dir: Option<PathBuf>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct Session {
pub groups: Vec<XasGroup>,
pub current: Option<usize>,
pub folders: Folders,
}
impl Session {
pub fn new() -> Self {
Self::default()
}
pub fn add_group(&mut self, group: XasGroup) -> usize {
self.groups.push(group);
let idx = self.groups.len() - 1;
self.current = Some(idx);
idx
}
pub fn current_group(&self) -> Option<&XasGroup> {
self.current.and_then(|i| self.groups.get(i))
}
pub fn current_group_mut(&mut self) -> Option<&mut XasGroup> {
match self.current {
Some(i) => self.groups.get_mut(i),
None => None,
}
}
pub fn to_json(&self) -> Result<String, serde_json::Error> {
serde_json::to_string_pretty(self)
}
pub fn from_json(s: &str) -> Result<Self, serde_json::Error> {
serde_json::from_str(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn add_group_sets_current() {
let mut s = Session::new();
assert!(s.current_group().is_none());
let i = s.add_group(XasGroup::from_mu("a", vec![1.0, 2.0], vec![0.1, 0.2]));
assert_eq!(i, 0);
assert_eq!(s.current, Some(0));
assert_eq!(s.current_group().unwrap().label, "a");
let j = s.add_group(XasGroup::from_mu("b", vec![3.0], vec![0.3]));
assert_eq!(j, 1);
assert_eq!(s.current_group().unwrap().label, "b");
}
#[test]
fn group_len_and_empty() {
let g = XasGroup::from_mu("x", vec![1.0, 2.0, 3.0], vec![0.1, 0.2, 0.3]);
assert_eq!(g.len(), 3);
assert!(!g.is_empty());
assert!(XasGroup::default().is_empty());
}
#[test]
fn session_json_roundtrip() {
let mut s = Session::new();
let mut g = XasGroup::from_mu("cu", vec![8900.0, 8901.0], vec![0.5, 1.5]);
g.e0 = Some(8979.0);
g.edge_step = Some(1.0);
s.add_group(g);
s.folders.data_dir = Some(PathBuf::from("/tmp/data"));
let json = s.to_json().expect("serialize");
let back = Session::from_json(&json).expect("deserialize");
assert_eq!(back.groups.len(), 1);
assert_eq!(back.current, Some(0));
assert_eq!(back.groups[0].label, "cu");
assert_eq!(back.groups[0].e0, Some(8979.0));
assert_eq!(back.folders.data_dir, Some(PathBuf::from("/tmp/data")));
}
}