bcore/datamodel/
mod.rs

1mod _impl;
2mod main_file;
3pub mod tallies;
4use crate::error::ApiError;
5use _impl::get_probe_size;
6pub use _impl::{
7    get_n_export_real, make_histogram, read_avg_model_properties, read_model_mass,
8    read_model_properties, read_spatial_model_properties,
9};
10pub use main_file::MainResult;
11use ndarray::{s, Array1, Array2, ArrayView1, ArrayView2, ArrayView3};
12use std::path::PathBuf;
13
14trait ResultGroup<T> {
15    fn read_g(&self) -> hdf5::Result<T>;
16}
17
18#[derive(Debug)]
19pub struct Dim(pub usize, pub usize);
20
21#[derive(Debug)]
22pub enum Weight {
23    Single(f64),        // Represents a single f64 value
24    Multiple(Vec<f64>), // Represents a vector of f64 values
25}
26
27#[derive(Debug)]
28pub struct Results {
29    pub main: MainResult,
30    pub files: Vec<String>,
31    pub total_particle_repetition: Array2<f64>,
32    pub property_name: Vec<String>,
33}
34
35impl Results {
36    pub fn new(fp: &str, root: &str, folder: &str) -> Result<Self, ApiError> {
37        match MainResult::read(fp) {
38            Ok(main) => {
39                let files: Vec<String> = (0..main.misc.n_rank)
40                    .map(|i| format!("{}/{}/{}_partial_{}.h5", root, folder, folder, i))
41                    .collect();
42
43                let nt = main.records.time.len();
44                let shape = (nt, main.records.dim.0);
45                let mut total_particle_repetition: Array2<f64> = Array2::zeros(shape);
46                for i_f in &files {
47                    let n_p = _impl::read_number_particle(i_f)?;
48                    total_particle_repetition =
49                        total_particle_repetition + Array2::from_shape_vec(shape, n_p).unwrap();
50                }
51                let property_name = Self::get_property_name(&files);
52                Ok(Results {
53                    main,
54                    files,
55                    total_particle_repetition,
56                    property_name,
57                })
58            }
59            Err(hdf5_error) => Err(ApiError::Io(hdf5_error)),
60        }
61    }
62
63    fn get_property_name(files: &[String]) -> Vec<String> {
64        if let Ok(file) = hdf5::File::open(files[0].clone()) {
65            if let Ok(group) = file.group("biological_model/0") {
66                let dataset_names: Vec<String> = group
67                    .datasets()
68                    .unwrap()
69                    .into_iter()
70                    .map(|d| {
71                        PathBuf::from(d.name())
72                            .file_name()
73                            .and_then(|name| name.to_str())
74                            .unwrap_or("")
75                            .to_string()
76                    }) // Extract the names of each dataset
77                    .collect();
78                return dataset_names;
79
80                // .attr_names().unwrap()
81                // .into_iter().map(|g| g)  // Extract the names of each group
82                // .collect();
83            }
84        }
85        vec![] //Let say is normal behaviour to return empty vector if there is no properties instead
86    }
87
88    pub fn get_files(&self) -> &[String] {
89        &self.files
90    }
91}
92
93pub fn f_get_probes(files: &[String]) -> Result<Array1<f64>, ApiError> {
94    let total_size = get_probe_size(files)?;
95    let mut probe = Array1::zeros(total_size);
96    let mut offset = 0;
97
98    for filename in files.iter() {
99        let file = hdf5::File::open(filename)?;
100        let dataset = file.dataset("probes")?;
101        let temp_array: Vec<f64> = dataset.read_raw::<f64>()?;
102        let tmp_array = match ArrayView1::from_shape(temp_array.len(), &temp_array) {
103            Ok(view) => view,
104            Err(_) => return Err(ApiError::ShapeError),
105        };
106        probe
107            .slice_mut(s![offset..offset + temp_array.len()])
108            .assign(&tmp_array);
109        offset += temp_array.len();
110    }
111
112    Ok(probe)
113}
114
115pub fn vec_to_array_view2(vec: &[f64], nr: usize, nc: usize) -> ArrayView2<'_, f64> {
116    assert_eq!(vec.len(), nr * nc, "Vector size must match dimensions.");
117    ArrayView2::from_shape((nr, nc), vec).expect("Failed to create ArrayView2")
118}
119
120pub fn vec_to_array_view3<'a>(vec: &'a [f64], dim: &'a Dim, nt: usize) -> ArrayView3<'a, f64> {
121    assert_eq!(
122        vec.len(),
123        nt * dim.0 * dim.1,
124        "Vector size must match dimensions."
125    );
126    ArrayView3::from_shape((nt, dim.0, dim.1), vec).expect("Failed to create ArrayView2")
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132    use ndarray::{array, Array3};
133
134    #[test]
135    fn test_vec_to_array_view2_valid() {
136        let vec = vec![1.0, 2.0, 3.0, 4.0]; // 2x2 matrix
137        let nr = 2;
138        let nc = 2;
139
140        let view = vec_to_array_view2(&vec, nr, nc);
141
142        assert_eq!(view.shape(), &[2, 2]);
143        assert_eq!(view, array![[1.0, 2.0], [3.0, 4.0]]);
144    }
145
146    #[test]
147    #[should_panic(expected = "Vector size must match dimensions.")]
148    fn test_vec_to_array_view2_invalid_size() {
149        let vec = vec![1.0, 2.0, 3.0]; // Incorrect size, should be 2x2
150        let nr = 2;
151        let nc = 2;
152
153        vec_to_array_view2(&vec, nr, nc);
154    }
155
156    #[test]
157    #[should_panic]
158    fn test_vec_to_array_view2_empty_vector() {
159        let vec: Vec<f64> = vec![];
160        let nr = 2;
161        let nc = 2;
162
163        vec_to_array_view2(&vec, nr, nc);
164    }
165    #[test]
166    fn test_vec_to_array_view3() {
167        let vec = vec![1.0; 6]; // 2 * 3 dimensions
168        let dim = &Dim(2, 3);
169        let nt = 1;
170        let vec_copy = vec.clone();
171        let array_view = vec_to_array_view3(&vec, dim, nt);
172
173        let expected_array = Array3::from_shape_vec((nt, dim.0, dim.1), vec_copy)
174            .expect("Failed to create expected Array3");
175        assert_eq!(array_view, expected_array.view());
176    }
177
178    #[test]
179    #[should_panic]
180    fn test_vec_to_array_view3_size_mismatch() {
181        let vec = vec![1.0, 2.0, 3.0];
182        let dim = &Dim(2, 3);
183        let nt = 1;
184
185        let _ = vec_to_array_view3(&vec, dim, nt);
186    }
187
188    #[test]
189    #[should_panic]
190    fn test_vec_to_array_view3_invalid_size() {
191        let vec = vec![1.0, 2.0, 3.0]; // Incorrect size, should be 1x2x3
192        let dim = Dim(1, 2);
193        let nt = 1;
194
195        vec_to_array_view3(&vec, &dim, nt);
196    }
197
198    #[test]
199    #[should_panic]
200    fn test_vec_to_array_view3_empty_vector() {
201        let vec: Vec<f64> = vec![];
202        let dim = Dim(1, 2);
203        let nt = 1;
204
205        vec_to_array_view3(&vec, &dim, nt);
206    }
207}