bcore/api.rs
1use crate::datamodel::{Weight,tallies::Tallies};
2
3use crate::error::ApiError;
4use ndarray::{Array1, Array2, ArrayView2, ArrayView3};
5
6/// `Phase` enum represents different states or phases of a substance.
7#[derive(Clone, PartialEq, Copy)]
8pub enum Phase {
9 Liquid,
10 Gas,
11}
12
13/// Type of estimator to retrieve data from MC Particle
14#[derive(Copy, Clone)]
15pub enum Estimator {
16 MonteCarlo,
17 Weighted,
18}
19
20/// A trait for postprocessing operations on simulation results.
21///
22/// This trait defines various methods for analyzing and retrieving data from simulation results.
23pub trait PostProcessReader {
24 /// Returns a reference to the time data from the simulation results.
25 ///
26 /// # Returns
27 /// * `&[f64]` - A slice containing the time data.
28 fn time(&self) -> &[f64];
29
30 fn v_liquid(&self) -> ArrayView2<'_, f64>;
31
32 /// Returns a weight chosen for simulation
33 ///
34 /// # Returns
35 /// * `Weight object: Can contain either float (unique weight) or vector of weight (non implemented yet)
36 fn weight(&self) -> &Weight;
37
38 // Returns tallies if exported during simulation
39 ///
40 /// # Returns
41 /// * `Option<&Tallies>: Some if tallies exported
42 fn tallies(&self) -> Option<&Tallies>;
43
44 /// Returns a 1D array view of the time data from the simulation results.
45 ///
46 /// # Returns
47 /// * `ArrayView1<f64>` - A 1D array view containing the time data.
48 fn time_array(&self) -> Array1<f64>;
49
50 /// Retrieves the maximum number of biological export events.
51 ///
52 /// This method determines the maximum number of export events specifically related
53 /// to biological data dumps.
54 ///
55 /// # Returns
56 /// * `usize` - The number of biological export events, or `0` if no events are found.
57 fn get_max_n_export_bio(&self) -> usize;
58
59 /// Retrieves the total number of export events from the simulation results.
60 ///
61 /// This count includes all types of export actions.
62 ///
63 /// # Returns
64 /// * `usize` - The total number of export events.
65 fn n_export(&self) -> usize;
66
67 /// Returns model's property names
68 ///
69 /// # Returns
70 /// * `Vec<String>: Names, empty if no exported names
71 fn get_property_names(&self) -> Vec<String>;
72
73 /// Computes the spatial average concentration for a specific species and phase.
74 ///
75 /// # Arguments
76 /// * `species` - The index of the species for which to calculate the average.
77 /// * `phase` - The phase (e.g., liquid or gas) to consider.
78 ///
79 /// # Returns
80 /// * `Array1<f64>` - A 1D array containing the spatial average concentrations over time.
81 fn get_spatial_average_concentration(&self, species: usize, phase: Phase) -> Array1<f64>;
82
83 fn get_spatial_average_property(&self, key:&str) -> Result<Array2<f64>, ApiError>;
84
85 fn get_spatial_average_biomass_concentration(&self) -> Result<Array1<f64>, ApiError>;
86
87 fn get_concentrations(&self, phase: Phase) -> ArrayView3<f64>;
88
89 fn get_spatial_average_mtr(&self, species: usize) -> Result<Array1<f64>, ApiError>;
90
91 fn get_variance_concentration(&self,species:usize,phase:Phase)-> Result<Array1<f64>, ApiError>;
92
93
94
95
96 /// Computes the time average concentration for a specific species, position, and phase.
97 ///
98 /// # Arguments
99 /// * `species` - The index of the species for which to calculate the average.
100 /// * `position` - The position in the simulation domain to consider.
101 /// * `phase` - The phase (e.g., liquid or gas) to consider.
102 ///
103 /// # Returns
104 /// * `Result<Array1<f64>, String>` - A 1D array containing the time average concentrations,
105 /// or an error message if the calculation fails.
106 fn get_time_average_concentration(
107 &self,
108 species: usize,
109 position: usize,
110 phase: Phase,
111 ) -> Result<Array1<f64>, ApiError>;
112
113 /// Calculates the biomass concentration over time.
114 ///
115 /// # Returns
116 /// * `Result<Array2<f64>, String>` - A 2D array containing biomass concentrations over time,
117 /// or an error message if the calculation fails.
118 fn get_biomass_concentration(&self) -> Result<Array2<f64>, ApiError>;
119
120 fn get_probes(&self) -> Result<Array1<f64>, ApiError>;
121
122
123 /// Calculates the total growth in number.
124 ///
125 /// # Returns
126 /// * `Array1<f64>` - A 1D array containing the summed growth numbers over time.
127 fn get_growth_in_number(&self) -> Array1<f64>;
128
129 /// Retrieves a reference to the 2D array of particle numbers.
130 ///
131 /// # Returns
132 /// * `&Array2<f64>` - A reference to the 2D array of particle numbers.
133 fn get_number_particle(&self) -> &Array2<f64>;
134
135 /// Fetches specific properties of the model at a given export index.
136 ///
137 /// # Arguments
138 /// * `key` - The key identifying the property to retrieve.
139 /// * `i_export` - The export index for which to retrieve the property.
140 ///
141 /// # Returns
142 /// * `Result<Array1<f64>, String>` - A 1D array of property values,
143 /// or an error message if the retrieval fails.
144 fn get_properties(&self, key: &str, i_export: usize) -> Result<Array1<f64>, ApiError>;
145
146 /// Calculates the time-averaged population mean for a specific property key.
147 ///
148 /// # Arguments
149 /// * `key` - The key identifying the property to average.
150 ///
151 /// # Returns
152 /// * `Result<Array1<f64>, String>` - A 1D array of mean values over time,
153 /// or an error message if the calculation fails.
154 fn get_time_population_mean(&self, key: &str) -> Result<Array1<f64>, ApiError>;
155
156 /// Retrieves histogram data for a specific property key at a given export index.
157 ///
158 /// # Arguments
159 /// * `n_bins` - The number of bins to use in the histogram.
160 /// * `i_export` - The export index for which to retrieve the histogram.
161 /// * `key` - The key identifying the property to calculate the histogram for.
162 ///
163 /// # Returns
164 /// * `Result<(Array1<f64>, Array1<f64>), String>` - The histogram bins and counts,
165 /// or an error message if the calculation fails.
166 fn get_histogram_array(
167 &self,
168 n_bins: usize,
169 i_export: usize,
170 key: &str,
171 ) -> Result<(Array1<f64>, Array1<f64>), ApiError>;
172
173 /// Retrieves histogram data for a specific property key at a given export index.
174 ///
175 /// # Arguments
176 /// * `n_bins` - The number of bins to use in the histogram.
177 /// * `i_export` - The export index for which to retrieve the histogram.
178 /// * `key` - The key identifying the property to calculate the histogram for.
179 ///
180 /// # Returns
181 /// * `Result<(Vec<f64>, Vec<f64>), String>` - The histogram bins and counts as vectors,
182 /// or an error message if the calculation fails.
183 fn get_histogram(
184 &self,
185 n_bins: usize,
186 i_export: usize,
187 key: &str,
188 ) -> Result<(Vec<f64>, Vec<f64>), ApiError>;
189
190 /// Retrieves the population mean for a specific property key at a given export index.
191 ///
192 /// # Arguments
193 /// * `key` - The key identifying the property to calculate the mean for.
194 /// * `i_export` - The export index for which to calculate the mean.
195 ///
196 /// # Returns
197 /// * `Result<f64, String>` - The population mean, or an error message if the calculation fails.
198 fn get_population_mean(&self, key: &str, i_export: usize) -> Result<f64, ApiError>;
199}
200
201pub trait ModelEstimator {
202 fn mu_direct(&self) -> Result<Array1<f64>, ApiError>;
203
204 fn estimate(&self, etype: Estimator, key: &str, i_export: usize) -> Result<f64, ApiError>;
205
206 fn estimate_time(&self, etype: Estimator, key: &str) -> Result<Array1<f64>, ApiError>;
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212 use ndarray::Array1;
213
214 #[test]
215 fn test_monte_carlo_estimate() {
216 let rx = Array1::from(vec![2.0, 4.0, 6.0]);
217 let weight = 2.0;
218
219 let result =
220 crate::process::estimate(Estimator::MonteCarlo, &Weight::Single(weight), &rx).unwrap();
221 let dim = rx.dim();
222 let weighted_estimator: f64 = (rx * weight).sum(); // (2.0*2.0 + 4.0*2.0 + 6.0*2.0) = 24.0
223 let normalization_factor = (0..dim).map(|_| weight).sum::<f64>(); // 2.0 * 3 = 6.0
224 let expected_result = weighted_estimator / normalization_factor; // 24.0 / 6.0 = 4.0
225 assert_eq!(result, expected_result);
226 }
227
228 #[test]
229 fn test_weighted_estimate() {
230 let rx = Array1::from(vec![2.0, 4.0, 6.0]);
231 let weight = 2.0;
232
233 let result =
234 crate::process::estimate(Estimator::Weighted, &Weight::Single(weight), &rx).unwrap();
235
236 let weighted_estimator: f64 = (rx * weight).sum(); // (2.0*2.0 + 4.0*2.0 + 6.0*2.0) = 24.0
237 let expected_result = weighted_estimator; // Since it's weighted, it should return the weighted sum.
238 assert_eq!(result, expected_result);
239 }
240
241 #[test]
242 fn test_zero_weight() {
243 let rx = Array1::from(vec![2.0, 4.0, 6.0]);
244 let weight = 0.0;
245
246 let result =
247 crate::process::estimate(Estimator::MonteCarlo, &Weight::Single(weight), &rx).unwrap();
248 assert_eq!(result, 0.0);
249 }
250
251 #[test]
252 fn test_empty_array() {
253 let rx = Array1::from(vec![]);
254 let weight = 2.0;
255 let result =
256 crate::process::estimate(Estimator::Weighted, &Weight::Single(weight), &rx).unwrap();
257
258 // With an empty array, the result should be zero
259 assert_eq!(result, 0.0);
260 }
261}