bcore/
impl_concat.rs

1use crate::api::PostProcessReader;
2use crate::datamodel::{Weight,tallies::Tallies};
3
4use crate::{api::Phase, error::ApiError, PostProcess};
5use ndarray::{Array1, Array2, ArrayView2, ArrayView3, Axis};
6
7#[derive(Debug)]
8pub struct ConcatPostPrcess {
9    dataset: Vec<PostProcess>,
10}
11
12impl ConcatPostPrcess {
13    pub fn new(folder: &[&str], root: Option<String>) -> Result<Self, ApiError> {
14        if folder.len() > 1 {
15            let dataset: Vec<PostProcess> = folder
16                .iter()
17                .map(|f| PostProcess::new(f, root.clone()))
18                .collect::<Result<Vec<_>, _>>()?; // Collect into a Result and propagate errors
19            if dataset.is_empty() {
20                return Err(ApiError::Default("Need at least one file".to_string()));
21            }
22            Ok(Self { dataset })
23        } else {
24            Err(ApiError::Default("Need at least one file".to_string()))
25        }
26    }
27
28    /// Retrieves the last time value from each dataset in the collection.
29    ///
30    /// # Returns
31    /// * `Result<Vec<f64>, String>` - A vector of the last time values for each dataset or an error message if any dataset is empty.
32    pub fn get_time_end(&self) -> Result<Vec<f64>, String> {
33        self.dataset
34            .iter()
35            .map(|ds| {
36                ds.time()
37                    .last()
38                    .copied()
39                    .ok_or_else(|| "Dataset has no time values".to_string())
40            })
41            .collect()
42    }
43}
44
45impl PostProcessReader for ConcatPostPrcess {
46    fn time(&self) -> &[f64] {
47        todo!()
48    }
49
50    fn v_liquid(&self) -> ArrayView2<'_, f64>
51    {
52        todo!()
53    }
54
55    fn get_spatial_average_property(&self, key:&str) ->  Result<Array2<f64>, ApiError>
56    {
57        todo!()
58    }
59
60    fn get_concentrations(&self, phase: Phase) -> ArrayView3<f64> {
61        todo!()
62    }
63
64    fn get_variance_concentration(&self,species:usize,phase:Phase)-> Result<Array1<f64>, ApiError>
65    {
66        todo!()
67    }
68
69    fn get_spatial_average_biomass_concentration(&self) -> Result<Array1<f64>, ApiError> {
70        let mut concatenated = Array1::<f64>::default(0);
71        for postprocess in &self.dataset {
72            match postprocess.get_spatial_average_biomass_concentration() {
73                Ok(data) => concatenated.append(Axis(0), data.view()).unwrap(),
74                Err(e) => {
75                    return Err(e);
76                }
77            }
78        }
79        Ok(concatenated)
80    }
81
82    fn get_probes(&self) -> Result<Array1<f64>, ApiError>
83    {
84        todo!();
85    }
86
87    fn get_property_names(&self) -> Vec<String> {
88        self.dataset[0].get_property_names() //Names SHOULD be the same
89    }
90
91    /// Concatenates the time arrays from all datasets into a single array view.
92    ///
93    /// # Returns
94    /// * `ArrayView1<f64>` - A concatenated array view of time data.
95    fn time_array(&self) -> Array1<f64> {
96        let concatenated: Vec<f64> = self
97            .dataset
98            .iter()
99            .flat_map(|postprocess| postprocess.time_array().to_vec())
100            .collect();
101        Array1::from_vec(concatenated)
102    }
103
104    fn get_max_n_export_bio(&self) -> usize {
105        self.dataset
106            .iter()
107            .map(|postprocess| postprocess.get_max_n_export_bio())
108            .sum()
109    }
110
111    fn n_export(&self) -> usize {
112        self.dataset
113            .iter()
114            .map(|postprocess| postprocess.n_export())
115            .sum()
116    }
117
118    fn get_spatial_average_concentration(&self, species: usize, phase: Phase) -> Array1<f64> {
119        let mut concatenated = Array1::<f64>::default(0);
120        for postprocess in &self.dataset {
121            let data = postprocess.get_spatial_average_concentration(species, phase);
122            concatenated.append(Axis(0), data.view()).unwrap();
123        }
124        concatenated
125    }
126
127    fn get_time_average_concentration(
128        &self,
129        species: usize,
130        position: usize,
131        phase: Phase,
132    ) -> Result<Array1<f64>, ApiError> {
133        let mut concatenated = Array1::<f64>::default(0);
134        for postprocess in &self.dataset {
135            match postprocess.get_time_average_concentration(species, position, phase) {
136                Ok(data) => concatenated.append(Axis(0), data.view()).unwrap(),
137                Err(e) => return Err(e),
138            }
139        }
140        Ok(concatenated)
141    }
142
143    fn get_spatial_average_mtr(&self, species: usize) -> Result<Array1<f64>, ApiError> {
144        let mut concatenated = Array1::<f64>::default(0);
145        for postprocess in &self.dataset {
146            match postprocess.get_spatial_average_mtr(species) {
147                Ok(data) => {
148                    concatenated.append(Axis(0), data.view()).unwrap();
149                }
150                e => {
151                    return e;
152                }
153            };
154        }
155        Ok(concatenated)
156    }
157
158    fn get_biomass_concentration(&self) -> Result<Array2<f64>, ApiError> {
159        let mut concatenated = Array2::<f64>::default((0, 0));
160        let mut init = false;
161        for postprocess in &self.dataset {
162            match postprocess.get_biomass_concentration() {
163                Ok(data) => {
164                    if !init {
165                        concatenated = data;
166                        init = true;
167                    } else if let Err(err) = concatenated.append(Axis(0), data.view()) {
168                        return Err(ApiError::Default(err.to_string()));
169                    }
170                }
171
172                Err(e) => return Err(e),
173            }
174        }
175        Ok(concatenated)
176    }
177
178    fn get_growth_in_number(&self) -> Array1<f64> {
179        todo!()
180    }
181
182    fn weight(&self) -> &Weight {
183        //FIXME
184        self.dataset[0].weight()
185    }
186
187    fn get_number_particle(&self) -> &Array2<f64> {
188        todo!()
189    }
190
191    fn get_properties(&self, key: &str, i_export: usize) -> Result<Array1<f64>, ApiError> {
192        todo!()
193    }
194
195    fn get_time_population_mean(&self, key: &str) -> Result<Array1<f64>, ApiError> {
196        todo!()
197    }
198
199    fn get_histogram_array(
200        &self,
201        n_bins: usize,
202        i_export: usize,
203        key: &str,
204    ) -> Result<(Array1<f64>, Array1<f64>), ApiError> {
205        todo!()
206    }
207
208    fn get_histogram(
209        &self,
210        n_bins: usize,
211        i_export: usize,
212        key: &str,
213    ) -> Result<(Vec<f64>, Vec<f64>), ApiError> {
214        todo!()
215    }
216
217    fn get_population_mean(&self, key: &str, i_export: usize) -> Result<f64, ApiError> {
218        todo!()
219    }
220    fn tallies(&self) -> Option<&Tallies> {
221        todo!()
222    }
223}