From 1522810f7c0f5770000a9e0a97d81ca2e65ac76d Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Thu, 3 Apr 2025 14:49:03 +0200 Subject: [PATCH 01/14] feat(taillies): support reading option taillies record --- Cargo.lock | 42 +++++++++++---- Cargo.toml | 2 +- core/Cargo.toml | 3 ++ core/src/api.rs | 24 ++++----- core/src/datamodel/_impl.rs | 91 ++++++++++++++++++--------------- core/src/datamodel/main_file.rs | 74 +++++++++++++++++++++------ core/src/datamodel/mod.rs | 4 +- core/src/impl_concat.rs | 7 ++- core/src/impl_unique.rs | 5 +- examples/example_rust.rs | 18 ++++--- examples/out.html | 2 +- examples/out.svg | 2 +- 12 files changed, 180 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c75ba1e..c2c54f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,10 +81,13 @@ dependencies = [ [[package]] name = "bcore" -version = "0.3.4" +version = "0.4.1" dependencies = [ + "csv", "hdf5", "ndarray 0.16.1", + "serde", + "serde_json", "thiserror 2.0.11", ] @@ -243,6 +246,27 @@ dependencies = [ "typenum", ] +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + [[package]] name = "darling" version = "0.20.10" @@ -378,7 +402,7 @@ dependencies = [ [[package]] name = "examples" -version = "0.3.4" +version = "0.4.1" dependencies = [ "bcore", "ndarray 0.16.1", @@ -1047,7 +1071,7 @@ dependencies = [ [[package]] name = "python_wrap" -version = "0.3.4" +version = "0.4.1" dependencies = [ "bcore", "numpy", @@ -1217,18 +1241,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.216" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", @@ -1237,9 +1261,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", diff --git a/Cargo.toml b/Cargo.toml index c7b6872..75fd6a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.3.4" +version = "0.4.1" edition = "2021" license = "MIT" repository = "https://github.com/Benncs/BioMC_PostProcess/" diff --git a/core/Cargo.toml b/core/Cargo.toml index 25632d7..540e0a0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -12,8 +12,11 @@ authors.workspace = true publish = true [dependencies] +csv = "1.3.1" hdf5 = "0.8.1" ndarray = "0.16.1" +serde = { version = "1.0.219", features = ["derive"] } +serde_json = "1.0.140" thiserror = "2.0.11" #hdf5-sys = { version = "0.8.1", features = ["static"] } diff --git a/core/src/api.rs b/core/src/api.rs index df2f396..fd33d17 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -1,8 +1,7 @@ -use crate::datamodel::Weight; +use crate::datamodel::{Tallies, Weight}; use crate::error::ApiError; use ndarray::{Array1, Array2, ArrayView3}; - /// `Phase` enum represents different states or phases of a substance. #[derive(Clone, PartialEq, Copy)] pub enum Phase { @@ -10,14 +9,13 @@ pub enum Phase { Gas, } -/// Type of estimator to retrieve data from MC Particle +/// Type of estimator to retrieve data from MC Particle #[derive(Copy, Clone)] pub enum Estimator { MonteCarlo, Weighted, } - /// A trait for postprocessing operations on simulation results. /// /// This trait defines various methods for analyzing and retrieving data from simulation results. @@ -30,6 +28,8 @@ pub trait PostProcessReader { fn weight(&self) -> &Weight; + fn tailles(&self) -> Option<&Tallies>; + /// Returns a 1D array view of the time data from the simulation results. /// /// # Returns @@ -173,15 +173,12 @@ pub trait PostProcessReader { fn get_population_mean(&self, key: &str, i_export: usize) -> Result; } - - pub trait ModelEstimator { fn mu_direct(&self) -> Result, ApiError>; fn estimate(&self, etype: Estimator, key: &str, i_export: usize) -> Result; fn estimate_time(&self, etype: Estimator, key: &str) -> Result, ApiError>; - } #[cfg(test)] @@ -194,8 +191,8 @@ mod tests { let rx = Array1::from(vec![2.0, 4.0, 6.0]); let weight = 2.0; - - let result = crate::process::estimate(Estimator::MonteCarlo, &Weight::Single(weight), &rx).unwrap(); + let result = + crate::process::estimate(Estimator::MonteCarlo, &Weight::Single(weight), &rx).unwrap(); let dim = rx.dim(); let weighted_estimator: f64 = (rx * weight).sum(); // (2.0*2.0 + 4.0*2.0 + 6.0*2.0) = 24.0 let normalization_factor = (0..dim).map(|_| weight).sum::(); // 2.0 * 3 = 6.0 @@ -208,7 +205,8 @@ mod tests { let rx = Array1::from(vec![2.0, 4.0, 6.0]); let weight = 2.0; - let result = crate::process::estimate(Estimator::Weighted, &Weight::Single(weight), &rx).unwrap(); + let result = + crate::process::estimate(Estimator::Weighted, &Weight::Single(weight), &rx).unwrap(); let weighted_estimator: f64 = (rx * weight).sum(); // (2.0*2.0 + 4.0*2.0 + 6.0*2.0) = 24.0 let expected_result = weighted_estimator; // Since it's weighted, it should return the weighted sum. @@ -220,7 +218,8 @@ mod tests { let rx = Array1::from(vec![2.0, 4.0, 6.0]); let weight = 0.0; - let result = crate::process::estimate(Estimator::MonteCarlo, &Weight::Single(weight), &rx).unwrap(); + let result = + crate::process::estimate(Estimator::MonteCarlo, &Weight::Single(weight), &rx).unwrap(); assert_eq!(result, 0.0); } @@ -228,7 +227,8 @@ mod tests { fn test_empty_array() { let rx = Array1::from(vec![]); let weight = 2.0; - let result = crate::process::estimate(Estimator::Weighted, &Weight::Single(weight), &rx).unwrap(); + let result = + crate::process::estimate(Estimator::Weighted, &Weight::Single(weight), &rx).unwrap(); // With an empty array, the result should be zero assert_eq!(result, 0.0); diff --git a/core/src/datamodel/_impl.rs b/core/src/datamodel/_impl.rs index dab9d92..9ba6e75 100644 --- a/core/src/datamodel/_impl.rs +++ b/core/src/datamodel/_impl.rs @@ -1,6 +1,6 @@ use crate::process::Histogram; -use super::main_file::{MainFInal, MainInitial, MainRecords, Misc}; +use super::main_file::{MainFInal, MainInitial, MainRecords, Misc, Tallies}; use super::{Dim, ResultGroup}; use hdf5::Group; use ndarray::{s, Array1, Array2, ArrayView1}; @@ -72,7 +72,7 @@ fn read_spatial_model_properties( // Access the "biological_model" group let group = file.group("biological_model")?; - //TODO: use group.len() instead of n_export + //TODO: use group.len() instead of n_export for i_e in 0..n_export { // Read the data for the current export index let tmp: Vec = match group.dataset(&format!("{}/spatial/{}", i_e, key)) { @@ -88,13 +88,13 @@ fn read_spatial_model_properties( if tmp_array.len() == slice_shape { cx.slice_mut(s![i_e, ..]) .zip_mut_with(&tmp_array, |a, b| *a += b); - } else { - eprintln!( - "Shape mismatch: cx[{}, ..].shape = {}, tmp.shape = {}", - i_e, - slice_shape, - tmp_array.len() - ); + } else { + eprintln!( + "Shape mismatch: cx[{}, ..].shape = {}, tmp.shape = {}", + i_e, + slice_shape, + tmp_array.len() + ); } } } @@ -115,10 +115,9 @@ pub fn read_model_properties( let group = file.group("biological_model")?; // Not all nodes have th=e same number of export so it happens that i_export is > // number_export for the current file - if (group.len() as usize)>=i_export{ + if (group.len() as usize) >= i_export { let dataset = group.dataset(&format!("{}/{}", i_export, key))?; total_size += dataset.size(); - } } @@ -130,14 +129,15 @@ pub fn read_model_properties( // Access the "biological_model" group let group = file.group("biological_model")?; - if (group.len() as usize)>=i_export{ + if (group.len() as usize) >= i_export { let dataset = group.dataset(&format!("{}/{}", i_export, key))?; // Read the dataset into a temporary array let temp_array: Vec = dataset.read_raw::()?; - let tmp_array = ArrayView1::from_shape(temp_array.len(), &temp_array).map_err(|_| { - hdf5::Error::Internal("Shape mismatch while creating ArrayView1".to_string()) - })?; + let tmp_array = + ArrayView1::from_shape(temp_array.len(), &temp_array).map_err(|_| { + hdf5::Error::Internal("Shape mismatch while creating ArrayView1".to_string()) + })?; // Copy the data into the result array result @@ -151,27 +151,28 @@ pub fn read_model_properties( Ok(result) } -pub fn get_n_export_real(files:&[String])->hdf5::Result -{ - if files.is_empty() - { +pub fn get_n_export_real(files: &[String]) -> hdf5::Result { + if files.is_empty() { panic!("FIXME: not enough files") } let file = hdf5::File::open_as(&files[0], hdf5::file::OpenMode::Read)?; let group = file.group("biological_model")?; let group_size = group.len() as usize; //We export n_export times properties but if there is no //particle we do not export. group_size <= n_export and for - Ok(group_size) + Ok(group_size) } - -pub fn make_histogram(files:&[String],i_export:usize,key:&str,hist:&mut Histogram)->hdf5::Result<()> -{ +pub fn make_histogram( + files: &[String], + i_export: usize, + key: &str, + hist: &mut Histogram, +) -> hdf5::Result<()> { for filename in files.iter() { // Open the HDF5 file in read mode let file = hdf5::File::open_as(filename, hdf5::file::OpenMode::Read)?; let group = file.group("biological_model")?; - if (group.len() as usize)>=i_export{ + if (group.len() as usize) >= i_export { let dataset = group.dataset(&format!("{}/{}", i_export, key))?; let temp_array: Vec = dataset.read_raw::()?; hist.add(temp_array); @@ -194,8 +195,8 @@ pub fn read_avg_model_properties( let group = file.group("biological_model")?; let group_size = group.len() as usize; //We export n_export times properties but if there is no //particle we do not export. group_size <= n_export and for - //all i > group_size , value is set to 0 - for i_e in 0..group_size{ + //all i > group_size , value is set to 0 + for i_e in 0..group_size { let dataset = group.dataset(&format!("{}/{}", i_e, key))?; let temp_array: Vec = dataset.read_raw::()?; result[i_e] += temp_array.iter().sum::(); @@ -252,12 +253,16 @@ impl ResultGroup for Group { _ => (None, None), }; - let mtr = match self.dataset("mtr") - { + let mtr = match self.dataset("mtr") { Ok(_mtr) => Some(_mtr.read_raw::()?), _ => None, }; + let tallies = match self.dataset("tallies") { + Ok(_t) => Some(Tallies(_t.read_raw::()?)), + _ => None, + }; + let shape = self.dataset("concentration_liquid")?.shape(); let dim = Dim(shape[1], shape[2]); let time = read_vec!(self, "time", f64); @@ -267,6 +272,7 @@ impl ResultGroup for Group { concentration_gas, volume_gas, mtr, + tallies, dim, time, }) @@ -275,20 +281,25 @@ impl ResultGroup for Group { impl ResultGroup for Group { fn read_g(&self) -> hdf5::Result { - let ds_events = self.group("events")?; - let mut events: HashMap = HashMap::new(); - ds_events - .iter_visit_default(&mut events, |group, name, _link_info, fields| { - if let Ok(dataset) = group.dataset(name) { - if let Ok(value) = dataset.read_scalar::() { - fields.insert(name.to_string(), value); - } - } - true - }) - .unwrap(); let number_particles = read_scalar!(self, "number_particles", u64); + let events = if let Ok(ds_events) = self.group("events") { + let mut events: HashMap = HashMap::new(); + ds_events + .iter_visit_default(&mut events, |group, name, _link_info, fields| { + if let Ok(dataset) = group.dataset(name) { + if let Ok(value) = dataset.read_scalar::() { + fields.insert(name.to_string(), value); + } + } + true + }) + .unwrap(); + Some(events) + } else { + None + }; + Ok(MainFInal { events, number_particles, diff --git a/core/src/datamodel/main_file.rs b/core/src/datamodel/main_file.rs index c06da2f..01187b3 100644 --- a/core/src/datamodel/main_file.rs +++ b/core/src/datamodel/main_file.rs @@ -3,18 +3,59 @@ //! Provides objects and methods to read the simulation's main file. //! The object hierarchy mimics the file's structure: - +use super::{Dim, ResultGroup, Weight}; +use csv::Writer; +use serde::{Deserialize, Serialize}; +use serde_json; use std::collections::HashMap; -use super::{Dim, ResultGroup,Weight}; - -///File's mics section +///File's mics section #[derive(Debug)] pub struct Misc { pub n_node_thread: u64, pub n_rank: u64, } -///Time dependent scalar records +#[derive(Debug, Serialize, Deserialize)] +pub struct Tallies(pub Vec); + +impl Tallies { + pub fn validate(&self) -> bool { + self.0.len() % 6 == 0 + } + + pub fn to_json(&self) -> serde_json::Result { + serde_json::to_string_pretty(&self.0) + } + + pub fn to_csv(&self) -> Result { + if !self.validate() { + return Err( + "Validation failed: The number of elements is not divisible by 6.".to_string(), + ); + } + + let headers = vec![ + "NewParticle", + "Death", + "Move", + "Exit", + "Overflow", + "ChangeWeight", + ]; + let mut wtr = Writer::from_writer(vec![]); + + wtr.write_record(&headers).map_err(|e| e.to_string())?; + + for row in self.0.chunks(6) { + wtr.serialize(row).map_err(|e| e.to_string())?; + } + let data = String::from_utf8(wtr.into_inner().map_err(|e| e.to_string())?) + .map_err(|e| e.to_string())?; + Ok(data) + } +} + +///Time dependent scalar records #[derive(Debug)] pub struct MainRecords { pub concentration_liquid: Vec, @@ -22,11 +63,12 @@ pub struct MainRecords { pub concentration_gas: Option>, pub volume_gas: Option>, pub mtr: Option>, + pub tallies: Option, pub dim: Dim, - pub time:Vec, + pub time: Vec, } -///Initial information +///Initial information #[derive(Debug)] pub struct MainInitial { pub delta_time: f64, @@ -39,21 +81,21 @@ pub struct MainInitial { pub t_per_flow_map: f64, } -///Final information +///Final information #[derive(Debug)] pub struct MainFInal { - pub events: HashMap, + pub events: Option>, pub number_particles: u64, } -///Object that stores data main file +///Object that stores data main file #[derive(Debug)] pub struct MainResult { pub records: MainRecords, pub initial: MainInitial, pub cfinal: MainFInal, pub misc: Misc, - pub weight: Weight + pub weight: Weight, } impl MainResult { @@ -65,14 +107,13 @@ impl MainResult { let m_ds = file.group("misc")?; let misc = ResultGroup::::read_g(&m_ds)?; - + let m_ds = file.group("records")?; let records = ResultGroup::::read_g(&m_ds)?; let m_ds = file.group("final_result")?; let cfinal = ResultGroup::::read_g(&m_ds)?; - let weight = Weight::Single(initial.initial_weight); //TODO switch between single and multi weight Ok(MainResult { @@ -80,12 +121,11 @@ impl MainResult { initial, cfinal, misc, - weight + weight, }) } - pub fn time(&self)->&[f64] - { + pub fn time(&self) -> &[f64] { &self.records.time } -} \ No newline at end of file +} diff --git a/core/src/datamodel/mod.rs b/core/src/datamodel/mod.rs index 2a3a50e..447cea5 100644 --- a/core/src/datamodel/mod.rs +++ b/core/src/datamodel/mod.rs @@ -5,7 +5,7 @@ pub use _impl::{ get_n_export_real, make_histogram, read_avg_model_properties, read_model_mass, read_model_properties, }; -pub use main_file::MainResult; +pub use main_file::{MainResult, Tallies}; use ndarray::{Array2, ArrayView2, ArrayView3}; use std::path::PathBuf; @@ -93,7 +93,7 @@ pub fn vec_to_array_view2(vec: &[f64], nr: usize, nc: usize) -> ArrayView2<'_, f ArrayView2::from_shape((nr, nc), vec).expect("Failed to create ArrayView2") } -pub fn vec_to_array_view3<'a>(vec: &'a [f64], dim: &'a Dim, nt: usize) -> ArrayView3<'a,f64> { +pub fn vec_to_array_view3<'a>(vec: &'a [f64], dim: &'a Dim, nt: usize) -> ArrayView3<'a, f64> { assert_eq!( vec.len(), nt * dim.0 * dim.1, diff --git a/core/src/impl_concat.rs b/core/src/impl_concat.rs index 8bfd0ad..30e57e3 100644 --- a/core/src/impl_concat.rs +++ b/core/src/impl_concat.rs @@ -1,6 +1,6 @@ use crate::api::PostProcessReader; -use crate::datamodel::Weight; -use crate::{error::ApiError, api::Phase, PostProcess}; +use crate::datamodel::{Tallies, Weight}; +use crate::{api::Phase, error::ApiError, PostProcess}; use ndarray::{Array1, Array2, ArrayView3, Axis}; #[derive(Debug)] @@ -196,4 +196,7 @@ impl PostProcessReader for ConcatPostPrcess { fn get_population_mean(&self, key: &str, i_export: usize) -> Result { todo!() } + fn tailles(&self) -> Option<&Tallies> { + todo!() + } } diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index 3789414..d9cf392 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -1,7 +1,7 @@ use crate::api::{ModelEstimator, PostProcessReader}; use crate::datamodel::{ get_n_export_real, read_avg_model_properties, read_model_mass, read_model_properties, - vec_to_array_view2, vec_to_array_view3, Dim, Weight, + vec_to_array_view2, vec_to_array_view3, Dim, Tallies, Weight, }; use crate::datamodel::{make_histogram, Results}; use crate::process::{spatial_average_concentration, Histogram}; @@ -339,6 +339,9 @@ impl PostProcessReader for PostProcess { Err(e) => Err(ApiError::Io(e)), } } + fn tailles(&self) -> Option<&Tallies> { + self.results.main.records.tallies.as_ref() + } } impl ModelEstimator for PostProcess { diff --git a/examples/example_rust.rs b/examples/example_rust.rs index b11e531..e95c8c0 100644 --- a/examples/example_rust.rs +++ b/examples/example_rust.rs @@ -1,14 +1,12 @@ -use bcore::{PostProcess,PostProcessReader}; +use bcore::{PostProcess, PostProcessReader}; use ndarray::s; use plotly::ImageFormat; use plotly::{Layout, Plot, Scatter}; fn main() { if let Ok(obj) = PostProcess::new( - "cstr_0", - Some("/home-local/casale/Documents/thesis/simulations/ecoli_model_2024/out/steady_1/".to_string()), + "str_1", + Some("/home-local/casale/Documents/thesis/simulations/meta/out_str_nu_redis_2".to_string()), ) { - - let x = obj.get_biomass_concentration().unwrap(); let time: Vec = obj.time().into_iter().map(|t| t / 3600.).collect(); let xvec = x.slice(s![.., 0]).to_vec(); @@ -31,9 +29,13 @@ fn main() { plot.write_image("./examples/out.svg", ImageFormat::SVG, 800, 600, 1.0); plot.write_html("./examples/out.html"); - println!("{}",plot.to_inline_html(Some("div_plot_x"))); - } - else { + println!("{}", plot.to_inline_html(Some("div_plot_x"))); + + println!( + "{}", + obj.tailles().expect("REASON").to_csv().expect("REASE") + ); + } else { println!("Simulation not found"); } } diff --git a/examples/out.html b/examples/out.html index 711865b..e54b4c9 100644 --- a/examples/out.html +++ b/examples/out.html @@ -16,7 +16,7 @@ diff --git a/examples/out.svg b/examples/out.svg index 6b75874..c5b0d47 100644 --- a/examples/out.svg +++ b/examples/out.svg @@ -1 +1 @@ -02040608011.522.53Biomass Concentration Over TimeTime (h)Biomass Concentration (g/L) \ No newline at end of file +510152025302.052.12.152.2Biomass Concentration Over TimeTime (h)Biomass Concentration (g/L) \ No newline at end of file From 563670b208f1518be9ccc7d132935f82e882f827 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Thu, 3 Apr 2025 15:15:11 +0200 Subject: [PATCH 02/14] feat(tallies): conversion from tallies to Array2View and to Numpy --- core/src/api.rs | 5 ++-- core/src/datamodel/_impl.rs | 3 +- core/src/datamodel/main_file.rs | 44 ++--------------------------- core/src/datamodel/mod.rs | 3 +- core/src/datamodel/tallies.rs | 49 +++++++++++++++++++++++++++++++++ core/src/impl_concat.rs | 5 ++-- core/src/impl_unique.rs | 4 +-- examples/example_rust.rs | 2 +- python_wrap/src/lib.rs | 19 +++++++++++++ 9 files changed, 83 insertions(+), 51 deletions(-) create mode 100644 core/src/datamodel/tallies.rs diff --git a/core/src/api.rs b/core/src/api.rs index fd33d17..dff612d 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -1,4 +1,5 @@ -use crate::datamodel::{Tallies, Weight}; +use crate::datamodel::{Weight,tallies::Tallies}; + use crate::error::ApiError; use ndarray::{Array1, Array2, ArrayView3}; @@ -28,7 +29,7 @@ pub trait PostProcessReader { fn weight(&self) -> &Weight; - fn tailles(&self) -> Option<&Tallies>; + fn tallies(&self) -> Option<&Tallies>; /// Returns a 1D array view of the time data from the simulation results. /// diff --git a/core/src/datamodel/_impl.rs b/core/src/datamodel/_impl.rs index 9ba6e75..5b45264 100644 --- a/core/src/datamodel/_impl.rs +++ b/core/src/datamodel/_impl.rs @@ -1,6 +1,7 @@ use crate::process::Histogram; -use super::main_file::{MainFInal, MainInitial, MainRecords, Misc, Tallies}; +use super::main_file::{MainFInal, MainInitial, MainRecords, Misc}; +use super::tallies::Tallies; use super::{Dim, ResultGroup}; use hdf5::Group; use ndarray::{s, Array1, Array2, ArrayView1}; diff --git a/core/src/datamodel/main_file.rs b/core/src/datamodel/main_file.rs index 01187b3..57217ab 100644 --- a/core/src/datamodel/main_file.rs +++ b/core/src/datamodel/main_file.rs @@ -3,11 +3,9 @@ //! Provides objects and methods to read the simulation's main file. //! The object hierarchy mimics the file's structure: -use super::{Dim, ResultGroup, Weight}; -use csv::Writer; -use serde::{Deserialize, Serialize}; -use serde_json; +use super::{tallies::Tallies, Dim, ResultGroup, Weight}; use std::collections::HashMap; +use ndarray::{ArrayView2}; ///File's mics section #[derive(Debug)] pub struct Misc { @@ -15,45 +13,7 @@ pub struct Misc { pub n_rank: u64, } -#[derive(Debug, Serialize, Deserialize)] -pub struct Tallies(pub Vec); -impl Tallies { - pub fn validate(&self) -> bool { - self.0.len() % 6 == 0 - } - - pub fn to_json(&self) -> serde_json::Result { - serde_json::to_string_pretty(&self.0) - } - - pub fn to_csv(&self) -> Result { - if !self.validate() { - return Err( - "Validation failed: The number of elements is not divisible by 6.".to_string(), - ); - } - - let headers = vec![ - "NewParticle", - "Death", - "Move", - "Exit", - "Overflow", - "ChangeWeight", - ]; - let mut wtr = Writer::from_writer(vec![]); - - wtr.write_record(&headers).map_err(|e| e.to_string())?; - - for row in self.0.chunks(6) { - wtr.serialize(row).map_err(|e| e.to_string())?; - } - let data = String::from_utf8(wtr.into_inner().map_err(|e| e.to_string())?) - .map_err(|e| e.to_string())?; - Ok(data) - } -} ///Time dependent scalar records #[derive(Debug)] diff --git a/core/src/datamodel/mod.rs b/core/src/datamodel/mod.rs index 447cea5..739a861 100644 --- a/core/src/datamodel/mod.rs +++ b/core/src/datamodel/mod.rs @@ -1,11 +1,12 @@ mod _impl; mod main_file; +pub mod tallies; use crate::error::ApiError; pub use _impl::{ get_n_export_real, make_histogram, read_avg_model_properties, read_model_mass, read_model_properties, }; -pub use main_file::{MainResult, Tallies}; +pub use main_file::MainResult; use ndarray::{Array2, ArrayView2, ArrayView3}; use std::path::PathBuf; diff --git a/core/src/datamodel/tallies.rs b/core/src/datamodel/tallies.rs new file mode 100644 index 0000000..694595b --- /dev/null +++ b/core/src/datamodel/tallies.rs @@ -0,0 +1,49 @@ +use csv::Writer; +use ndarray::ArrayView2; +use serde::{Deserialize, Serialize}; +use serde_json; +use super::vec_to_array_view2; +#[derive(Debug, Serialize, Deserialize)] +pub struct Tallies(pub Vec); + +impl Tallies { + pub fn validate(&self) -> bool { + self.0.len() % 6 == 0 + } + + pub fn to_json(&self) -> serde_json::Result { + serde_json::to_string_pretty(&self.0) + } + + pub fn to_csv(&self) -> Result { + if !self.validate() { + return Err( + "Validation failed: The number of elements is not divisible by 6.".to_string(), + ); + } + + let headers = vec![ + "NewParticle", + "Death", + "Move", + "Exit", + "Overflow", + "ChangeWeight", + ]; + let mut wtr = Writer::from_writer(vec![]); + + wtr.write_record(&headers).map_err(|e| e.to_string())?; + + for row in self.0.chunks(6) { + wtr.serialize(row).map_err(|e| e.to_string())?; + } + let data = String::from_utf8(wtr.into_inner().map_err(|e| e.to_string())?) + .map_err(|e| e.to_string())?; + Ok(data) + } + + pub fn to_array(&self)->ArrayView2 + { + vec_to_array_view2(&self.0, self.0.len()/6, 6) + } +} \ No newline at end of file diff --git a/core/src/impl_concat.rs b/core/src/impl_concat.rs index 30e57e3..bf97748 100644 --- a/core/src/impl_concat.rs +++ b/core/src/impl_concat.rs @@ -1,5 +1,6 @@ use crate::api::PostProcessReader; -use crate::datamodel::{Tallies, Weight}; +use crate::datamodel::{Weight,tallies::Tallies}; + use crate::{api::Phase, error::ApiError, PostProcess}; use ndarray::{Array1, Array2, ArrayView3, Axis}; @@ -196,7 +197,7 @@ impl PostProcessReader for ConcatPostPrcess { fn get_population_mean(&self, key: &str, i_export: usize) -> Result { todo!() } - fn tailles(&self) -> Option<&Tallies> { + fn tallies(&self) -> Option<&Tallies> { todo!() } } diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index d9cf392..22f03d3 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -1,7 +1,7 @@ use crate::api::{ModelEstimator, PostProcessReader}; use crate::datamodel::{ get_n_export_real, read_avg_model_properties, read_model_mass, read_model_properties, - vec_to_array_view2, vec_to_array_view3, Dim, Tallies, Weight, + vec_to_array_view2, vec_to_array_view3, Dim, tallies::Tallies, Weight, }; use crate::datamodel::{make_histogram, Results}; use crate::process::{spatial_average_concentration, Histogram}; @@ -339,7 +339,7 @@ impl PostProcessReader for PostProcess { Err(e) => Err(ApiError::Io(e)), } } - fn tailles(&self) -> Option<&Tallies> { + fn tallies(&self) -> Option<&Tallies> { self.results.main.records.tallies.as_ref() } } diff --git a/examples/example_rust.rs b/examples/example_rust.rs index e95c8c0..b4ac290 100644 --- a/examples/example_rust.rs +++ b/examples/example_rust.rs @@ -33,7 +33,7 @@ fn main() { println!( "{}", - obj.tailles().expect("REASON").to_csv().expect("REASE") + obj.tallies().expect("REASON").to_csv().expect("REASE") ); } else { println!("Simulation not found"); diff --git a/python_wrap/src/lib.rs b/python_wrap/src/lib.rs index f0ef0d1..b9e6501 100644 --- a/python_wrap/src/lib.rs +++ b/python_wrap/src/lib.rs @@ -329,6 +329,25 @@ impl PythonPostProcess { Err(e) => Err(PyErr::new::(e.to_string())), } } + + pub fn get_csv_tallies(&self, py: Python<'_>)->PyResult + { + match self.inner.tallies() { + Some(e) => Ok(e.to_csv().unwrap()), + None=> Err(PyErr::new::("No data")), + } + } + + fn get_tallies(&self, py: Python<'_>) -> Py> { + match self.inner.tallies() { + Some(e) => + { + let v = e.to_array().to_owned(); + PyArray2::from_owned_array(py, v).unbind() + } + None => panic!("No data"), + } + } } #[pymodule] From 2ae406a82b1a26bcea03b5f4a75ac04f7933b269 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Fri, 2 May 2025 13:17:13 +0200 Subject: [PATCH 03/14] feat: add spatial property getter and probe read --- Cargo.lock | 6 ++--- Cargo.toml | 2 +- biomc_pp/rtd.py | 39 +++++++++++++++++++++++++++ core/src/api.rs | 5 ++++ core/src/datamodel/_impl.rs | 20 +++++++++++++- core/src/datamodel/main_file.rs | 9 ++++--- core/src/datamodel/mod.rs | 47 ++++++++++++++++++++++++++++++--- core/src/impl_concat.rs | 10 +++++++ core/src/impl_unique.rs | 31 +++++++++++++++++++++- examples/out_hist.html | 2 +- examples/out_hist.svg | 2 +- pyproject.toml | 2 +- python_wrap/src/lib.rs | 32 +++++++++++++++------- 13 files changed, 183 insertions(+), 24 deletions(-) create mode 100644 biomc_pp/rtd.py diff --git a/Cargo.lock b/Cargo.lock index c2c54f4..5a57654 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ dependencies = [ [[package]] name = "bcore" -version = "0.4.1" +version = "0.4.2" dependencies = [ "csv", "hdf5", @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "examples" -version = "0.4.1" +version = "0.4.2" dependencies = [ "bcore", "ndarray 0.16.1", @@ -1071,7 +1071,7 @@ dependencies = [ [[package]] name = "python_wrap" -version = "0.4.1" +version = "0.4.2" dependencies = [ "bcore", "numpy", diff --git a/Cargo.toml b/Cargo.toml index 75fd6a7..08b55f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.4.1" +version = "0.4.2" edition = "2021" license = "MIT" repository = "https://github.com/Benncs/BioMC_PostProcess/" diff --git a/biomc_pp/rtd.py b/biomc_pp/rtd.py new file mode 100644 index 0000000..1750f47 --- /dev/null +++ b/biomc_pp/rtd.py @@ -0,0 +1,39 @@ +import biomc_pp +import numpy as np +import matplotlib.pyplot as plt + +def get_rtd_from_scalar(pp,time,step_concentration): + + c = pp.get_spatial_average_concentration(0,biomc_pp.Phase.Liquid) + c0 = c[0] + delta_c = c - c0 + step_concentration = 5 + + # Cumulative probability + f_rtd = delta_c / step_concentration + # By defintion F(t)=integral 0 to t (E(t)) + e_rtd = np.diff(f_rtd) / np.diff(time) + + return f_rtd,e_rtd + +def get_rtd_particle(pp): + probes = pp.get_probes()/3600 + return np.histogram(probes, bins=100,density=True) + +def plot_rtd(pp,time,step_concentration): + + f_rtd,e_rtd = get_rtd_from_scalar(pp,time,step_concentration) + plt.figure() + plt.plot(time[1:],e_rtd,'--',color='red',label='Scalar') + c,e = get_rtd_particle(pp) + plt.bar( + e[:-1], + c, + width=np.diff(e), + edgecolor="black", + alpha=0.7, + color="blue", + label="Particles" + ) + return f_rtd,e_rtd + diff --git a/core/src/api.rs b/core/src/api.rs index dff612d..6cbe99e 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -66,6 +66,8 @@ pub trait PostProcessReader { /// * `Array1` - A 1D array containing the spatial average concentrations over time. fn get_spatial_average_concentration(&self, species: usize, phase: Phase) -> Array1; + fn get_spatial_average_property(&self, key:&str) -> Result, ApiError>; + fn get_spatial_average_biomass_concentration(&self) -> Result, ApiError>; fn get_concentrations(&self, phase: Phase) -> ArrayView3; @@ -96,6 +98,9 @@ pub trait PostProcessReader { /// or an error message if the calculation fails. fn get_biomass_concentration(&self) -> Result, ApiError>; + fn get_probes(&self) -> Result, ApiError>; + + /// Calculates the total growth in number. /// /// # Returns diff --git a/core/src/datamodel/_impl.rs b/core/src/datamodel/_impl.rs index 5b45264..25f1217 100644 --- a/core/src/datamodel/_impl.rs +++ b/core/src/datamodel/_impl.rs @@ -1,3 +1,4 @@ +use crate::error::ApiError; use crate::process::Histogram; use super::main_file::{MainFInal, MainInitial, MainRecords, Misc}; @@ -61,7 +62,7 @@ pub fn read_number_particle(filename: &str) -> hdf5::Result> { Ok(v) } -fn read_spatial_model_properties( +pub fn read_spatial_model_properties( key: &str, files: &[String], cx: &mut Array2, @@ -102,6 +103,23 @@ fn read_spatial_model_properties( Ok(()) } +pub fn get_probe_size(files: &[String])-> Result +{ + let mut probe_size = 0; + for filename in files.iter() { + let file = hdf5::File::open_as(filename, hdf5::file::OpenMode::Read)?; + if let Ok(dataset) = file.dataset("probes") + { + probe_size += dataset.size(); + } + else { + return Err(ApiError::Default("No Probes in dataset".to_string())); + } + + } + Ok(probe_size) +} + pub fn read_model_properties( key: &str, files: &[String], diff --git a/core/src/datamodel/main_file.rs b/core/src/datamodel/main_file.rs index 57217ab..8714582 100644 --- a/core/src/datamodel/main_file.rs +++ b/core/src/datamodel/main_file.rs @@ -53,7 +53,7 @@ pub struct MainFInal { pub struct MainResult { pub records: MainRecords, pub initial: MainInitial, - pub cfinal: MainFInal, + pub cfinal: Option, //TODO Add runtime parameter to throw error or not when missing pub misc: Misc, pub weight: Weight, } @@ -71,8 +71,11 @@ impl MainResult { let m_ds = file.group("records")?; let records = ResultGroup::::read_g(&m_ds)?; - let m_ds = file.group("final_result")?; - let cfinal = ResultGroup::::read_g(&m_ds)?; + let mut cfinal = None; + if let Ok(m_ds) = file.group("final_result") + { + cfinal= Some(ResultGroup::::read_g(&m_ds)?); + } let weight = Weight::Single(initial.initial_weight); //TODO switch between single and multi weight diff --git a/core/src/datamodel/mod.rs b/core/src/datamodel/mod.rs index 739a861..8e892e4 100644 --- a/core/src/datamodel/mod.rs +++ b/core/src/datamodel/mod.rs @@ -2,12 +2,13 @@ mod _impl; mod main_file; pub mod tallies; use crate::error::ApiError; +use _impl::get_probe_size; pub use _impl::{ get_n_export_real, make_histogram, read_avg_model_properties, read_model_mass, - read_model_properties, + read_model_properties, read_spatial_model_properties, }; pub use main_file::MainResult; -use ndarray::{Array2, ArrayView2, ArrayView3}; +use ndarray::{s, Array1, Array2, ArrayView1, ArrayView2, ArrayView3}; use std::path::PathBuf; trait ResultGroup { @@ -81,7 +82,7 @@ impl Results { // .collect(); } } - todo!() + vec![] //Let say is normal behaviour to return empty vector if there is no properties instead } pub fn get_files(&self) -> &[String] { @@ -89,6 +90,46 @@ impl Results { } } +pub fn f_get_probes(files: &[String]) -> Result, ApiError> { + let total_size = get_probe_size(files)?; + let mut probe = Array1::zeros(total_size); + let mut offset = 0; + + for filename in files.iter() { + let file = hdf5::File::open(filename)?; + // if let Ok(dataset) = file.dataset("probes") { + // let temp_array: Vec = match dataset.read_raw::() { + // Ok(data) => data, + // Err(_) => return None, + // }; + + // let tmp_array = match ArrayView1::from_shape(temp_array.len(), &temp_array) { + // Ok(view) => view, + // Err(_) => return None, + // }; + + // probe + // .slice_mut(s![offset..offset + temp_array.len()]) + // .assign(&tmp_array); + // offset += temp_array.len(); + // } else { + // return None; + // } + let dataset = file.dataset("probes")?; + let temp_array: Vec = dataset.read_raw::()?; + let tmp_array = match ArrayView1::from_shape(temp_array.len(), &temp_array) { + Ok(view) => view, + Err(_) => return Err(ApiError::ShapeError), + }; + probe + .slice_mut(s![offset..offset + temp_array.len()]) + .assign(&tmp_array); + offset += temp_array.len(); + } + + Ok(probe) +} + pub fn vec_to_array_view2(vec: &[f64], nr: usize, nc: usize) -> ArrayView2<'_, f64> { assert_eq!(vec.len(), nr * nc, "Vector size must match dimensions."); ArrayView2::from_shape((nr, nc), vec).expect("Failed to create ArrayView2") diff --git a/core/src/impl_concat.rs b/core/src/impl_concat.rs index bf97748..a0e8fa7 100644 --- a/core/src/impl_concat.rs +++ b/core/src/impl_concat.rs @@ -47,6 +47,11 @@ impl PostProcessReader for ConcatPostPrcess { todo!() } + fn get_spatial_average_property(&self, key:&str) -> Result, ApiError> + { + todo!() + } + fn get_concentrations(&self, phase: Phase) -> ArrayView3 { todo!() } @@ -64,6 +69,11 @@ impl PostProcessReader for ConcatPostPrcess { Ok(concatenated) } + fn get_probes(&self) -> Result, ApiError> + { + todo!(); + } + fn get_property_names(&self) -> Vec { self.dataset[0].get_property_names() //Names SHOULD be the same } diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index 22f03d3..9edeca3 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -3,7 +3,7 @@ use crate::datamodel::{ get_n_export_real, read_avg_model_properties, read_model_mass, read_model_properties, vec_to_array_view2, vec_to_array_view3, Dim, tallies::Tallies, Weight, }; -use crate::datamodel::{make_histogram, Results}; +use crate::datamodel::{f_get_probes, make_histogram, read_spatial_model_properties, Results}; use crate::process::{spatial_average_concentration, Histogram}; use crate::{api::Estimator, api::Phase, error::ApiError}; use ndarray::{s, Array1, Array2, ArrayView3, Axis}; @@ -193,6 +193,35 @@ impl PostProcessReader for PostProcess { } } + fn get_spatial_average_property(&self, key:&str) -> Result, ApiError> + { + let nt: usize = self.results.main.records.time.len(); // Number of time steps + let num_dimensions = self.results.main.records.dim.0; // Dimensionality + + // Initialize the biomass matrix + let mut biomass_matrix = Array2::zeros((nt, num_dimensions)); + + if !self.results.property_name.iter().any(|x| x == key) { + return Err(ApiError::KeyError(key.to_string())); + } + + // Attempt to read model mass + if let Err(err) = read_spatial_model_properties(key,self.results.get_files(), &mut biomass_matrix, nt) { + return Err(ApiError::Io(err)); + } + + + // Calculate biomass concentration + biomass_matrix /= self.get_number_particle(); + + Ok(biomass_matrix) + } + + fn get_probes(&self) -> Result, ApiError> + { + f_get_probes(&self.results.files) + } + /// Calculates the biomass concentration over time for the simulation. /// /// # Returns diff --git a/examples/out_hist.html b/examples/out_hist.html index 8c49c3b..595474a 100644 --- a/examples/out_hist.html +++ b/examples/out_hist.html @@ -16,7 +16,7 @@ diff --git a/examples/out_hist.svg b/examples/out_hist.svg index cf5c69d..05f62b3 100644 --- a/examples/out_hist.svg +++ b/examples/out_hist.svg @@ -1 +1 @@ -010M20M30M40M50M60M70M80M05k10k15k20k25kFrequency (nu_eff)Frequency (nu_meta)Final \nu_{eff}Bin Midpoints (seconds)Counts \ No newline at end of file +0.020.040.060.080.10.120.140.16010k20k30k40k50k60k70k80kFrequency (nu_eff)Frequency (nu_meta)Final \nu_{eff}Bin Midpoints (seconds)Counts \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index de872f9..b6ce66f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,7 +13,7 @@ classifiers = [ dynamic = ["version"] dependencies = [ "numpy>=2.2.0", - "matplotlib" + "matplotlib>=3.10" ] [project.optional-dependencies] diff --git a/python_wrap/src/lib.rs b/python_wrap/src/lib.rs index b9e6501..2dd7fa8 100644 --- a/python_wrap/src/lib.rs +++ b/python_wrap/src/lib.rs @@ -122,11 +122,18 @@ impl PythonPostProcess { #[new] #[pyo3(signature = (folder, root=None))] fn new(folder: &str, root: Option) -> PyResult { - if let Ok(pp) = PostProcess::new(folder, root) { - return Ok(Self { inner: pp }); - } + // if let Ok(pp) = PostProcess::new(folder, root) { + // return Ok(Self { inner: pp }); + // } - Err(PyValueError::new_err("Error creating object")) + + match PostProcess::new(folder, root) + { + Ok(pp) => {Ok(Self { inner: pp })}, + Err(err)=>{ + println!("{:?}",err); + Err(PyValueError::new_err("Error creating object"))} + } } fn get_property_names(&self) -> PyResult> { @@ -230,9 +237,12 @@ impl PythonPostProcess { panic!("") } - fn get_spatial_property(&self, name: &str) -> PyResult { + fn get_spatial_property(&self, py: Python<'_>,name: &str) -> Py>{ // TODO - Python::with_gil(|py| Ok(PyList::empty(py).to_object(py))) + match self.inner.get_spatial_average_property(name) { + Ok(e) => PyArray2::from_owned_array(py, e).unbind(), + Err(e) => panic!("{}", e), + } } fn get_biomass_concentration(&self, py: Python<'_>) -> Py> { @@ -254,9 +264,13 @@ impl PythonPostProcess { PyArray2::from_owned_array(py, e).unbind() } - fn get_rtd(&self, flow: f64, step: f64, is_str: Option) -> PyResult { - // todo - Python::with_gil(|py| Ok(py.None())) + fn get_probes(&self, py: Python<'_>) -> Py> { + match self.inner.get_probes() { + Ok(e) => PyArray1::from_owned_array(py, e).unbind(), + Err(e) => panic!("{}", e), + } + + } fn get_properties(&self, py: Python<'_>, key: &str, i_export: usize) -> Py> { From 7903ffa1a5bb97a2ba5af102eec11da2b01d5bf2 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Fri, 2 May 2025 13:48:43 +0200 Subject: [PATCH 04/14] doc: improve docstring --- core/src/api.rs | 14 +++++++++++++- core/src/datamodel/mod.rs | 18 ------------------ core/src/impl_unique.rs | 3 ++- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/core/src/api.rs b/core/src/api.rs index 6cbe99e..f441bdd 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -27,8 +27,16 @@ pub trait PostProcessReader { /// * `&[f64]` - A slice containing the time data. fn time(&self) -> &[f64]; + /// Returns a weight chosen for simulation + /// + /// # Returns + /// * `Weight object: Can contain either float (unique weight) or vector of weight (non implemented yet) fn weight(&self) -> &Weight; + // Returns tallies if exported during simulation + /// + /// # Returns + /// * `Option<&Tallies>: Some if tallies exported fn tallies(&self) -> Option<&Tallies>; /// Returns a 1D array view of the time data from the simulation results. @@ -53,7 +61,11 @@ pub trait PostProcessReader { /// # Returns /// * `usize` - The total number of export events. fn n_export(&self) -> usize; - + + /// Returns model's property names + /// + /// # Returns + /// * `Vec: Names, empty if no exported names fn get_property_names(&self) -> Vec; /// Computes the spatial average concentration for a specific species and phase. diff --git a/core/src/datamodel/mod.rs b/core/src/datamodel/mod.rs index 8e892e4..925fe90 100644 --- a/core/src/datamodel/mod.rs +++ b/core/src/datamodel/mod.rs @@ -97,24 +97,6 @@ pub fn f_get_probes(files: &[String]) -> Result, ApiError> { for filename in files.iter() { let file = hdf5::File::open(filename)?; - // if let Ok(dataset) = file.dataset("probes") { - // let temp_array: Vec = match dataset.read_raw::() { - // Ok(data) => data, - // Err(_) => return None, - // }; - - // let tmp_array = match ArrayView1::from_shape(temp_array.len(), &temp_array) { - // Ok(view) => view, - // Err(_) => return None, - // }; - - // probe - // .slice_mut(s![offset..offset + temp_array.len()]) - // .assign(&tmp_array); - // offset += temp_array.len(); - // } else { - // return None; - // } let dataset = file.dataset("probes")?; let temp_array: Vec = dataset.read_raw::()?; let tmp_array = match ArrayView1::from_shape(temp_array.len(), &temp_array) { diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index 9edeca3..e7873e7 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -169,7 +169,7 @@ impl PostProcessReader for PostProcess { fn get_time_average_concentration( &self, species: usize, - position: usize, + position: usize, phase: Phase, ) -> Result, ApiError> { let r = &self.results.main.records; @@ -193,6 +193,7 @@ impl PostProcessReader for PostProcess { } } + //Actually compute spatial average property cannot be use to follow distribution fn get_spatial_average_property(&self, key:&str) -> Result, ApiError> { let nt: usize = self.results.main.records.time.len(); // Number of time steps From 60bbd09a033d685d930e27a1bf8ff9b735de6aa3 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Fri, 2 May 2025 13:52:37 +0200 Subject: [PATCH 05/14] Use ApiError to error propagation (to improve) --- core/src/datamodel/_impl.rs | 4 ++-- core/src/impl_unique.rs | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/core/src/datamodel/_impl.rs b/core/src/datamodel/_impl.rs index 25f1217..a00aa00 100644 --- a/core/src/datamodel/_impl.rs +++ b/core/src/datamodel/_impl.rs @@ -67,7 +67,7 @@ pub fn read_spatial_model_properties( files: &[String], cx: &mut Array2, n_export: usize, -) -> hdf5::Result<()> { +) -> Result<(), ApiError> { for filename in files.iter() { // Open the HDF5 file in read mode let file = hdf5::File::open_as(filename, hdf5::file::OpenMode::Read)?; @@ -230,7 +230,7 @@ pub fn read_model_mass( files: &[String], cx: &mut Array2, n_export: usize, -) -> hdf5::Result<()> { +) -> Result<(), ApiError> { read_spatial_model_properties("mass", files, cx, n_export) } diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index e7873e7..341c325 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -206,10 +206,8 @@ impl PostProcessReader for PostProcess { return Err(ApiError::KeyError(key.to_string())); } - // Attempt to read model mass - if let Err(err) = read_spatial_model_properties(key,self.results.get_files(), &mut biomass_matrix, nt) { - return Err(ApiError::Io(err)); - } + read_spatial_model_properties(key,self.results.get_files(), &mut biomass_matrix, nt) ?; + // Calculate biomass concentration @@ -239,9 +237,7 @@ impl PostProcessReader for PostProcess { } // Attempt to read model mass - if let Err(err) = read_model_mass(self.results.get_files(), &mut biomass_matrix, nt) { - return Err(ApiError::Io(err)); - } + read_model_mass(self.results.get_files(), &mut biomass_matrix, nt)?; // Convert volume to an array view let volume = From 819f899c7de6c4963d708127e6e45cad1fa4d133 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 7 May 2025 13:43:05 +0200 Subject: [PATCH 06/14] ci: test pyo3 version --- .github/workflows/CI.yml | 2 +- Cargo.lock | 29 +-- pyproject.toml | 2 +- python_wrap/Cargo.toml | 4 +- uv.lock | 434 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 450 insertions(+), 21 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 79edc5f..fcf44c4 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -40,7 +40,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: - python-version: 3.x + python-version: 3.12 - name: Install system dependencies run: | sudo apt-get update diff --git a/Cargo.lock b/Cargo.lock index 5a57654..998dc60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -843,9 +843,9 @@ dependencies = [ [[package]] name = "numpy" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94caae805f998a07d33af06e6a3891e38556051b8045c615470a71590e13e78" +checksum = "a7cfbf3f0feededcaa4d289fe3079b03659e85c5b5a177f4ba6fb01ab4fb3e39" dependencies = [ "libc", "ndarray 0.16.1", @@ -853,6 +853,7 @@ dependencies = [ "num-integer", "num-traits", "pyo3", + "pyo3-build-config", "rustc-hash", ] @@ -1008,9 +1009,9 @@ dependencies = [ [[package]] name = "pyo3" -version = "0.23.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e484fd2c8b4cb67ab05a318f1fd6fa8f199fcc30819f08f07d200809dba26c15" +checksum = "e5203598f366b11a02b13aa20cab591229ff0a89fd121a308a5df751d5fc9219" dependencies = [ "cfg-if", "indoc", @@ -1026,9 +1027,9 @@ dependencies = [ [[package]] name = "pyo3-build-config" -version = "0.23.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e0469a84f208e20044b98965e1561028180219e35352a2afaf2b942beff3b" +checksum = "99636d423fa2ca130fa5acde3059308006d46f98caac629418e53f7ebb1e9999" dependencies = [ "once_cell", "target-lexicon", @@ -1036,9 +1037,9 @@ dependencies = [ [[package]] name = "pyo3-ffi" -version = "0.23.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb1547a7f9966f6f1a0f0227564a9945fe36b90da5a93b3933fc3dc03fae372d" +checksum = "78f9cf92ba9c409279bc3305b5409d90db2d2c22392d443a87df3a1adad59e33" dependencies = [ "libc", "pyo3-build-config", @@ -1046,9 +1047,9 @@ dependencies = [ [[package]] name = "pyo3-macros" -version = "0.23.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb6da8ec6fa5cedd1626c886fc8749bdcbb09424a86461eb8cdf096b7c33257" +checksum = "0b999cb1a6ce21f9a6b147dcf1be9ffedf02e0043aec74dc390f3007047cecd9" dependencies = [ "proc-macro2", "pyo3-macros-backend", @@ -1058,9 +1059,9 @@ dependencies = [ [[package]] name = "pyo3-macros-backend" -version = "0.23.3" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38a385202ff5a92791168b1136afae5059d3ac118457bb7bc304c197c2d33e7d" +checksum = "822ece1c7e1012745607d5cf0bcb2874769f0f7cb34c4cde03b9358eb9ef911a" dependencies = [ "heck", "proc-macro2", @@ -1377,9 +1378,9 @@ dependencies = [ [[package]] name = "target-lexicon" -version = "0.12.16" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a" [[package]] name = "thiserror" diff --git a/pyproject.toml b/pyproject.toml index b6ce66f..add9152 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,7 +18,7 @@ dependencies = [ [project.optional-dependencies] vtk = [ - 'cmtool>=1.0.0', +# 'cmtool>=1.0.0', 'vtk==9.3.0', ] diff --git a/python_wrap/Cargo.toml b/python_wrap/Cargo.toml index 611f8f3..f8692bd 100644 --- a/python_wrap/Cargo.toml +++ b/python_wrap/Cargo.toml @@ -16,8 +16,8 @@ bindings = "pyo3" [dependencies] bcore = { path = "../core" } -numpy = "0.23.0" -pyo3 = { version = "0.23.1", features = ["extension-module"] } +numpy = "0.24.0" +pyo3 = { version = "0.24.2", features = ["extension-module"] } [lib] diff --git a/uv.lock b/uv.lock index ed0fc07..42fd743 100644 --- a/uv.lock +++ b/uv.lock @@ -1,16 +1,282 @@ version = 1 -requires-python = ">=3.12" +requires-python = ">=3.10" [[package]] name = "biomc-pp" -version = "0.1.0" +version = "0.4.2" source = { editable = "." } dependencies = [ + { name = "matplotlib" }, { name = "numpy" }, ] +[package.optional-dependencies] +vtk = [ + { name = "vtk" }, +] + [package.metadata] -requires-dist = [{ name = "numpy", specifier = ">=2.2.0" }] +requires-dist = [ + { name = "matplotlib", specifier = ">=3.10" }, + { name = "numpy", specifier = ">=2.2.0" }, + { name = "vtk", marker = "extra == 'vtk'", specifier = "==9.3.0" }, +] + +[[package]] +name = "contourpy" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/a3/da4153ec8fe25d263aa48c1a4cbde7f49b59af86f0b6f7862788c60da737/contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934", size = 268551 }, + { url = "https://files.pythonhosted.org/packages/2f/6c/330de89ae1087eb622bfca0177d32a7ece50c3ef07b28002de4757d9d875/contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989", size = 253399 }, + { url = "https://files.pythonhosted.org/packages/c1/bd/20c6726b1b7f81a8bee5271bed5c165f0a8e1f572578a9d27e2ccb763cb2/contourpy-1.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9be002b31c558d1ddf1b9b415b162c603405414bacd6932d031c5b5a8b757f0d", size = 312061 }, + { url = "https://files.pythonhosted.org/packages/22/fc/a9665c88f8a2473f823cf1ec601de9e5375050f1958cbb356cdf06ef1ab6/contourpy-1.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8d2e74acbcba3bfdb6d9d8384cdc4f9260cae86ed9beee8bd5f54fee49a430b9", size = 351956 }, + { url = "https://files.pythonhosted.org/packages/25/eb/9f0a0238f305ad8fb7ef42481020d6e20cf15e46be99a1fcf939546a177e/contourpy-1.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e259bced5549ac64410162adc973c5e2fb77f04df4a439d00b478e57a0e65512", size = 320872 }, + { url = "https://files.pythonhosted.org/packages/32/5c/1ee32d1c7956923202f00cf8d2a14a62ed7517bdc0ee1e55301227fc273c/contourpy-1.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad687a04bc802cbe8b9c399c07162a3c35e227e2daccf1668eb1f278cb698631", size = 325027 }, + { url = "https://files.pythonhosted.org/packages/83/bf/9baed89785ba743ef329c2b07fd0611d12bfecbedbdd3eeecf929d8d3b52/contourpy-1.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cdd22595308f53ef2f891040ab2b93d79192513ffccbd7fe19be7aa773a5e09f", size = 1306641 }, + { url = "https://files.pythonhosted.org/packages/d4/cc/74e5e83d1e35de2d28bd97033426b450bc4fd96e092a1f7a63dc7369b55d/contourpy-1.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b4f54d6a2defe9f257327b0f243612dd051cc43825587520b1bf74a31e2f6ef2", size = 1374075 }, + { url = "https://files.pythonhosted.org/packages/0c/42/17f3b798fd5e033b46a16f8d9fcb39f1aba051307f5ebf441bad1ecf78f8/contourpy-1.3.2-cp310-cp310-win32.whl", hash = "sha256:f939a054192ddc596e031e50bb13b657ce318cf13d264f095ce9db7dc6ae81c0", size = 177534 }, + { url = "https://files.pythonhosted.org/packages/54/ec/5162b8582f2c994721018d0c9ece9dc6ff769d298a8ac6b6a652c307e7df/contourpy-1.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:c440093bbc8fc21c637c03bafcbef95ccd963bc6e0514ad887932c18ca2a759a", size = 221188 }, + { url = "https://files.pythonhosted.org/packages/b3/b9/ede788a0b56fc5b071639d06c33cb893f68b1178938f3425debebe2dab78/contourpy-1.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a37a2fb93d4df3fc4c0e363ea4d16f83195fc09c891bc8ce072b9d084853445", size = 269636 }, + { url = "https://files.pythonhosted.org/packages/e6/75/3469f011d64b8bbfa04f709bfc23e1dd71be54d05b1b083be9f5b22750d1/contourpy-1.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b7cd50c38f500bbcc9b6a46643a40e0913673f869315d8e70de0438817cb7773", size = 254636 }, + { url = "https://files.pythonhosted.org/packages/8d/2f/95adb8dae08ce0ebca4fd8e7ad653159565d9739128b2d5977806656fcd2/contourpy-1.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6658ccc7251a4433eebd89ed2672c2ed96fba367fd25ca9512aa92a4b46c4f1", size = 313053 }, + { url = "https://files.pythonhosted.org/packages/c3/a6/8ccf97a50f31adfa36917707fe39c9a0cbc24b3bbb58185577f119736cc9/contourpy-1.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70771a461aaeb335df14deb6c97439973d253ae70660ca085eec25241137ef43", size = 352985 }, + { url = "https://files.pythonhosted.org/packages/1d/b6/7925ab9b77386143f39d9c3243fdd101621b4532eb126743201160ffa7e6/contourpy-1.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65a887a6e8c4cd0897507d814b14c54a8c2e2aa4ac9f7686292f9769fcf9a6ab", size = 323750 }, + { url = "https://files.pythonhosted.org/packages/c2/f3/20c5d1ef4f4748e52d60771b8560cf00b69d5c6368b5c2e9311bcfa2a08b/contourpy-1.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3859783aefa2b8355697f16642695a5b9792e7a46ab86da1118a4a23a51a33d7", size = 326246 }, + { url = "https://files.pythonhosted.org/packages/8c/e5/9dae809e7e0b2d9d70c52b3d24cba134dd3dad979eb3e5e71f5df22ed1f5/contourpy-1.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:eab0f6db315fa4d70f1d8ab514e527f0366ec021ff853d7ed6a2d33605cf4b83", size = 1308728 }, + { url = "https://files.pythonhosted.org/packages/e2/4a/0058ba34aeea35c0b442ae61a4f4d4ca84d6df8f91309bc2d43bb8dd248f/contourpy-1.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d91a3ccc7fea94ca0acab82ceb77f396d50a1f67412efe4c526f5d20264e6ecd", size = 1375762 }, + { url = "https://files.pythonhosted.org/packages/09/33/7174bdfc8b7767ef2c08ed81244762d93d5c579336fc0b51ca57b33d1b80/contourpy-1.3.2-cp311-cp311-win32.whl", hash = "sha256:1c48188778d4d2f3d48e4643fb15d8608b1d01e4b4d6b0548d9b336c28fc9b6f", size = 178196 }, + { url = "https://files.pythonhosted.org/packages/5e/fe/4029038b4e1c4485cef18e480b0e2cd2d755448bb071eb9977caac80b77b/contourpy-1.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:5ebac872ba09cb8f2131c46b8739a7ff71de28a24c869bcad554477eb089a878", size = 222017 }, + { url = "https://files.pythonhosted.org/packages/34/f7/44785876384eff370c251d58fd65f6ad7f39adce4a093c934d4a67a7c6b6/contourpy-1.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4caf2bcd2969402bf77edc4cb6034c7dd7c0803213b3523f111eb7460a51b8d2", size = 271580 }, + { url = "https://files.pythonhosted.org/packages/93/3b/0004767622a9826ea3d95f0e9d98cd8729015768075d61f9fea8eeca42a8/contourpy-1.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:82199cb78276249796419fe36b7386bd8d2cc3f28b3bc19fe2454fe2e26c4c15", size = 255530 }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7bd49e1f4fa805772d9fd130e0d375554ebc771ed7172f48dfcd4ca61549/contourpy-1.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:106fab697af11456fcba3e352ad50effe493a90f893fca6c2ca5c033820cea92", size = 307688 }, + { url = "https://files.pythonhosted.org/packages/fc/97/e1d5dbbfa170725ef78357a9a0edc996b09ae4af170927ba8ce977e60a5f/contourpy-1.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d14f12932a8d620e307f715857107b1d1845cc44fdb5da2bc8e850f5ceba9f87", size = 347331 }, + { url = "https://files.pythonhosted.org/packages/6f/66/e69e6e904f5ecf6901be3dd16e7e54d41b6ec6ae3405a535286d4418ffb4/contourpy-1.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:532fd26e715560721bb0d5fc7610fce279b3699b018600ab999d1be895b09415", size = 318963 }, + { url = "https://files.pythonhosted.org/packages/a8/32/b8a1c8965e4f72482ff2d1ac2cd670ce0b542f203c8e1d34e7c3e6925da7/contourpy-1.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26b383144cf2d2c29f01a1e8170f50dacf0eac02d64139dcd709a8ac4eb3cfe", size = 323681 }, + { url = "https://files.pythonhosted.org/packages/30/c6/12a7e6811d08757c7162a541ca4c5c6a34c0f4e98ef2b338791093518e40/contourpy-1.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c49f73e61f1f774650a55d221803b101d966ca0c5a2d6d5e4320ec3997489441", size = 1308674 }, + { url = "https://files.pythonhosted.org/packages/2a/8a/bebe5a3f68b484d3a2b8ffaf84704b3e343ef1addea528132ef148e22b3b/contourpy-1.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3d80b2c0300583228ac98d0a927a1ba6a2ba6b8a742463c564f1d419ee5b211e", size = 1380480 }, + { url = "https://files.pythonhosted.org/packages/34/db/fcd325f19b5978fb509a7d55e06d99f5f856294c1991097534360b307cf1/contourpy-1.3.2-cp312-cp312-win32.whl", hash = "sha256:90df94c89a91b7362e1142cbee7568f86514412ab8a2c0d0fca72d7e91b62912", size = 178489 }, + { url = "https://files.pythonhosted.org/packages/01/c8/fadd0b92ffa7b5eb5949bf340a63a4a496a6930a6c37a7ba0f12acb076d6/contourpy-1.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c942a01d9163e2e5cfb05cb66110121b8d07ad438a17f9e766317bcb62abf73", size = 223042 }, + { url = "https://files.pythonhosted.org/packages/2e/61/5673f7e364b31e4e7ef6f61a4b5121c5f170f941895912f773d95270f3a2/contourpy-1.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:de39db2604ae755316cb5967728f4bea92685884b1e767b7c24e983ef5f771cb", size = 271630 }, + { url = "https://files.pythonhosted.org/packages/ff/66/a40badddd1223822c95798c55292844b7e871e50f6bfd9f158cb25e0bd39/contourpy-1.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3f9e896f447c5c8618f1edb2bafa9a4030f22a575ec418ad70611450720b5b08", size = 255670 }, + { url = "https://files.pythonhosted.org/packages/1e/c7/cf9fdee8200805c9bc3b148f49cb9482a4e3ea2719e772602a425c9b09f8/contourpy-1.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71e2bd4a1c4188f5c2b8d274da78faab884b59df20df63c34f74aa1813c4427c", size = 306694 }, + { url = "https://files.pythonhosted.org/packages/dd/e7/ccb9bec80e1ba121efbffad7f38021021cda5be87532ec16fd96533bb2e0/contourpy-1.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de425af81b6cea33101ae95ece1f696af39446db9682a0b56daaa48cfc29f38f", size = 345986 }, + { url = "https://files.pythonhosted.org/packages/dc/49/ca13bb2da90391fa4219fdb23b078d6065ada886658ac7818e5441448b78/contourpy-1.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:977e98a0e0480d3fe292246417239d2d45435904afd6d7332d8455981c408b85", size = 318060 }, + { url = "https://files.pythonhosted.org/packages/c8/65/5245ce8c548a8422236c13ffcdcdada6a2a812c361e9e0c70548bb40b661/contourpy-1.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:434f0adf84911c924519d2b08fc10491dd282b20bdd3fa8f60fd816ea0b48841", size = 322747 }, + { url = "https://files.pythonhosted.org/packages/72/30/669b8eb48e0a01c660ead3752a25b44fdb2e5ebc13a55782f639170772f9/contourpy-1.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c66c4906cdbc50e9cba65978823e6e00b45682eb09adbb78c9775b74eb222422", size = 1308895 }, + { url = "https://files.pythonhosted.org/packages/05/5a/b569f4250decee6e8d54498be7bdf29021a4c256e77fe8138c8319ef8eb3/contourpy-1.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8b7fc0cd78ba2f4695fd0a6ad81a19e7e3ab825c31b577f384aa9d7817dc3bef", size = 1379098 }, + { url = "https://files.pythonhosted.org/packages/19/ba/b227c3886d120e60e41b28740ac3617b2f2b971b9f601c835661194579f1/contourpy-1.3.2-cp313-cp313-win32.whl", hash = "sha256:15ce6ab60957ca74cff444fe66d9045c1fd3e92c8936894ebd1f3eef2fff075f", size = 178535 }, + { url = "https://files.pythonhosted.org/packages/12/6e/2fed56cd47ca739b43e892707ae9a13790a486a3173be063681ca67d2262/contourpy-1.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e1578f7eafce927b168752ed7e22646dad6cd9bca673c60bff55889fa236ebf9", size = 223096 }, + { url = "https://files.pythonhosted.org/packages/54/4c/e76fe2a03014a7c767d79ea35c86a747e9325537a8b7627e0e5b3ba266b4/contourpy-1.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0475b1f6604896bc7c53bb070e355e9321e1bc0d381735421a2d2068ec56531f", size = 285090 }, + { url = "https://files.pythonhosted.org/packages/7b/e2/5aba47debd55d668e00baf9651b721e7733975dc9fc27264a62b0dd26eb8/contourpy-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c85bb486e9be652314bb5b9e2e3b0d1b2e643d5eec4992c0fbe8ac71775da739", size = 268643 }, + { url = "https://files.pythonhosted.org/packages/a1/37/cd45f1f051fe6230f751cc5cdd2728bb3a203f5619510ef11e732109593c/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:745b57db7758f3ffc05a10254edd3182a2a83402a89c00957a8e8a22f5582823", size = 310443 }, + { url = "https://files.pythonhosted.org/packages/8b/a2/36ea6140c306c9ff6dd38e3bcec80b3b018474ef4d17eb68ceecd26675f4/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:970e9173dbd7eba9b4e01aab19215a48ee5dd3f43cef736eebde064a171f89a5", size = 349865 }, + { url = "https://files.pythonhosted.org/packages/95/b7/2fc76bc539693180488f7b6cc518da7acbbb9e3b931fd9280504128bf956/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c6c4639a9c22230276b7bffb6a850dfc8258a2521305e1faefe804d006b2e532", size = 321162 }, + { url = "https://files.pythonhosted.org/packages/f4/10/76d4f778458b0aa83f96e59d65ece72a060bacb20cfbee46cf6cd5ceba41/contourpy-1.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc829960f34ba36aad4302e78eabf3ef16a3a100863f0d4eeddf30e8a485a03b", size = 327355 }, + { url = "https://files.pythonhosted.org/packages/43/a3/10cf483ea683f9f8ab096c24bad3cce20e0d1dd9a4baa0e2093c1c962d9d/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d32530b534e986374fc19eaa77fcb87e8a99e5431499949b828312bdcd20ac52", size = 1307935 }, + { url = "https://files.pythonhosted.org/packages/78/73/69dd9a024444489e22d86108e7b913f3528f56cfc312b5c5727a44188471/contourpy-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e298e7e70cf4eb179cc1077be1c725b5fd131ebc81181bf0c03525c8abc297fd", size = 1372168 }, + { url = "https://files.pythonhosted.org/packages/0f/1b/96d586ccf1b1a9d2004dd519b25fbf104a11589abfd05484ff12199cca21/contourpy-1.3.2-cp313-cp313t-win32.whl", hash = "sha256:d0e589ae0d55204991450bb5c23f571c64fe43adaa53f93fc902a84c96f52fe1", size = 189550 }, + { url = "https://files.pythonhosted.org/packages/b0/e6/6000d0094e8a5e32ad62591c8609e269febb6e4db83a1c75ff8868b42731/contourpy-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:78e9253c3de756b3f6a5174d024c4835acd59eb3f8e2ca13e775dbffe1558f69", size = 238214 }, + { url = "https://files.pythonhosted.org/packages/33/05/b26e3c6ecc05f349ee0013f0bb850a761016d89cec528a98193a48c34033/contourpy-1.3.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:fd93cc7f3139b6dd7aab2f26a90dde0aa9fc264dbf70f6740d498a70b860b82c", size = 265681 }, + { url = "https://files.pythonhosted.org/packages/2b/25/ac07d6ad12affa7d1ffed11b77417d0a6308170f44ff20fa1d5aa6333f03/contourpy-1.3.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:107ba8a6a7eec58bb475329e6d3b95deba9440667c4d62b9b6063942b61d7f16", size = 315101 }, + { url = "https://files.pythonhosted.org/packages/8f/4d/5bb3192bbe9d3f27e3061a6a8e7733c9120e203cb8515767d30973f71030/contourpy-1.3.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ded1706ed0c1049224531b81128efbd5084598f18d8a2d9efae833edbd2b40ad", size = 220599 }, + { url = "https://files.pythonhosted.org/packages/ff/c0/91f1215d0d9f9f343e4773ba6c9b89e8c0cc7a64a6263f21139da639d848/contourpy-1.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:5f5964cdad279256c084b69c3f412b7801e15356b16efa9d78aa974041903da0", size = 266807 }, + { url = "https://files.pythonhosted.org/packages/d4/79/6be7e90c955c0487e7712660d6cead01fa17bff98e0ea275737cc2bc8e71/contourpy-1.3.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49b65a95d642d4efa8f64ba12558fcb83407e58a2dfba9d796d77b63ccfcaff5", size = 318729 }, + { url = "https://files.pythonhosted.org/packages/87/68/7f46fb537958e87427d98a4074bcde4b67a70b04900cfc5ce29bc2f556c1/contourpy-1.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:8c5acb8dddb0752bf252e01a3035b21443158910ac16a3b0d20e7fed7d534ce5", size = 221791 }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321 }, +] + +[[package]] +name = "fonttools" +version = "4.57.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/2d/a9a0b6e3a0cf6bd502e64fc16d894269011930cabfc89aee20d1635b1441/fonttools-4.57.0.tar.gz", hash = "sha256:727ece10e065be2f9dd239d15dd5d60a66e17eac11aea47d447f9f03fdbc42de", size = 3492448 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/17/3ddfd1881878b3f856065130bb603f5922e81ae8a4eb53bce0ea78f765a8/fonttools-4.57.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:babe8d1eb059a53e560e7bf29f8e8f4accc8b6cfb9b5fd10e485bde77e71ef41", size = 2756260 }, + { url = "https://files.pythonhosted.org/packages/26/2b/6957890c52c030b0bf9e0add53e5badab4682c6ff024fac9a332bb2ae063/fonttools-4.57.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:81aa97669cd726349eb7bd43ca540cf418b279ee3caba5e2e295fb4e8f841c02", size = 2284691 }, + { url = "https://files.pythonhosted.org/packages/cc/8e/c043b4081774e5eb06a834cedfdb7d432b4935bc8c4acf27207bdc34dfc4/fonttools-4.57.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0e9618630edd1910ad4f07f60d77c184b2f572c8ee43305ea3265675cbbfe7e", size = 4566077 }, + { url = "https://files.pythonhosted.org/packages/59/bc/e16ae5d9eee6c70830ce11d1e0b23d6018ddfeb28025fda092cae7889c8b/fonttools-4.57.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34687a5d21f1d688d7d8d416cb4c5b9c87fca8a1797ec0d74b9fdebfa55c09ab", size = 4608729 }, + { url = "https://files.pythonhosted.org/packages/25/13/e557bf10bb38e4e4c436d3a9627aadf691bc7392ae460910447fda5fad2b/fonttools-4.57.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:69ab81b66ebaa8d430ba56c7a5f9abe0183afefd3a2d6e483060343398b13fb1", size = 4759646 }, + { url = "https://files.pythonhosted.org/packages/bc/c9/5e2952214d4a8e31026bf80beb18187199b7001e60e99a6ce19773249124/fonttools-4.57.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d639397de852f2ccfb3134b152c741406752640a266d9c1365b0f23d7b88077f", size = 4941652 }, + { url = "https://files.pythonhosted.org/packages/df/04/e80242b3d9ec91a1f785d949edc277a13ecfdcfae744de4b170df9ed77d8/fonttools-4.57.0-cp310-cp310-win32.whl", hash = "sha256:cc066cb98b912f525ae901a24cd381a656f024f76203bc85f78fcc9e66ae5aec", size = 2159432 }, + { url = "https://files.pythonhosted.org/packages/33/ba/e858cdca275daf16e03c0362aa43734ea71104c3b356b2100b98543dba1b/fonttools-4.57.0-cp310-cp310-win_amd64.whl", hash = "sha256:7a64edd3ff6a7f711a15bd70b4458611fb240176ec11ad8845ccbab4fe6745db", size = 2203869 }, + { url = "https://files.pythonhosted.org/packages/81/1f/e67c99aa3c6d3d2f93d956627e62a57ae0d35dc42f26611ea2a91053f6d6/fonttools-4.57.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3871349303bdec958360eedb619169a779956503ffb4543bb3e6211e09b647c4", size = 2757392 }, + { url = "https://files.pythonhosted.org/packages/aa/f1/f75770d0ddc67db504850898d96d75adde238c35313409bfcd8db4e4a5fe/fonttools-4.57.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c59375e85126b15a90fcba3443eaac58f3073ba091f02410eaa286da9ad80ed8", size = 2285609 }, + { url = "https://files.pythonhosted.org/packages/f5/d3/bc34e4953cb204bae0c50b527307dce559b810e624a733351a654cfc318e/fonttools-4.57.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:967b65232e104f4b0f6370a62eb33089e00024f2ce143aecbf9755649421c683", size = 4873292 }, + { url = "https://files.pythonhosted.org/packages/41/b8/d5933559303a4ab18c799105f4c91ee0318cc95db4a2a09e300116625e7a/fonttools-4.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39acf68abdfc74e19de7485f8f7396fa4d2418efea239b7061d6ed6a2510c746", size = 4902503 }, + { url = "https://files.pythonhosted.org/packages/32/13/acb36bfaa316f481153ce78de1fa3926a8bad42162caa3b049e1afe2408b/fonttools-4.57.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9d077f909f2343daf4495ba22bb0e23b62886e8ec7c109ee8234bdbd678cf344", size = 5077351 }, + { url = "https://files.pythonhosted.org/packages/b5/23/6d383a2ca83b7516d73975d8cca9d81a01acdcaa5e4db8579e4f3de78518/fonttools-4.57.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:46370ac47a1e91895d40e9ad48effbe8e9d9db1a4b80888095bc00e7beaa042f", size = 5275067 }, + { url = "https://files.pythonhosted.org/packages/bc/ca/31b8919c6da0198d5d522f1d26c980201378c087bdd733a359a1e7485769/fonttools-4.57.0-cp311-cp311-win32.whl", hash = "sha256:ca2aed95855506b7ae94e8f1f6217b7673c929e4f4f1217bcaa236253055cb36", size = 2158263 }, + { url = "https://files.pythonhosted.org/packages/13/4c/de2612ea2216eb45cfc8eb91a8501615dd87716feaf5f8fb65cbca576289/fonttools-4.57.0-cp311-cp311-win_amd64.whl", hash = "sha256:17168a4670bbe3775f3f3f72d23ee786bd965395381dfbb70111e25e81505b9d", size = 2204968 }, + { url = "https://files.pythonhosted.org/packages/cb/98/d4bc42d43392982eecaaca117d79845734d675219680cd43070bb001bc1f/fonttools-4.57.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:889e45e976c74abc7256d3064aa7c1295aa283c6bb19810b9f8b604dfe5c7f31", size = 2751824 }, + { url = "https://files.pythonhosted.org/packages/1a/62/7168030eeca3742fecf45f31e63b5ef48969fa230a672216b805f1d61548/fonttools-4.57.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0425c2e052a5f1516c94e5855dbda706ae5a768631e9fcc34e57d074d1b65b92", size = 2283072 }, + { url = "https://files.pythonhosted.org/packages/5d/82/121a26d9646f0986ddb35fbbaf58ef791c25b59ecb63ffea2aab0099044f/fonttools-4.57.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44c26a311be2ac130f40a96769264809d3b0cb297518669db437d1cc82974888", size = 4788020 }, + { url = "https://files.pythonhosted.org/packages/5b/26/e0f2fb662e022d565bbe280a3cfe6dafdaabf58889ff86fdef2d31ff1dde/fonttools-4.57.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c41ba992df5b8d680b89fd84c6a1f2aca2b9f1ae8a67400c8930cd4ea115f6", size = 4859096 }, + { url = "https://files.pythonhosted.org/packages/9e/44/9075e323347b1891cdece4b3f10a3b84a8f4c42a7684077429d9ce842056/fonttools-4.57.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ea1e9e43ca56b0c12440a7c689b1350066595bebcaa83baad05b8b2675129d98", size = 4964356 }, + { url = "https://files.pythonhosted.org/packages/48/28/caa8df32743462fb966be6de6a79d7f30393859636d7732e82efa09fbbb4/fonttools-4.57.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:84fd56c78d431606332a0627c16e2a63d243d0d8b05521257d77c6529abe14d8", size = 5226546 }, + { url = "https://files.pythonhosted.org/packages/f6/46/95ab0f0d2e33c5b1a4fc1c0efe5e286ba9359602c0a9907adb1faca44175/fonttools-4.57.0-cp312-cp312-win32.whl", hash = "sha256:f4376819c1c778d59e0a31db5dc6ede854e9edf28bbfa5b756604727f7f800ac", size = 2146776 }, + { url = "https://files.pythonhosted.org/packages/06/5d/1be5424bb305880e1113631f49a55ea7c7da3a5fe02608ca7c16a03a21da/fonttools-4.57.0-cp312-cp312-win_amd64.whl", hash = "sha256:57e30241524879ea10cdf79c737037221f77cc126a8cdc8ff2c94d4a522504b9", size = 2193956 }, + { url = "https://files.pythonhosted.org/packages/e9/2f/11439f3af51e4bb75ac9598c29f8601aa501902dcedf034bdc41f47dd799/fonttools-4.57.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:408ce299696012d503b714778d89aa476f032414ae57e57b42e4b92363e0b8ef", size = 2739175 }, + { url = "https://files.pythonhosted.org/packages/25/52/677b55a4c0972dc3820c8dba20a29c358197a78229daa2ea219fdb19e5d5/fonttools-4.57.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bbceffc80aa02d9e8b99f2a7491ed8c4a783b2fc4020119dc405ca14fb5c758c", size = 2276583 }, + { url = "https://files.pythonhosted.org/packages/64/79/184555f8fa77b827b9460a4acdbbc0b5952bb6915332b84c615c3a236826/fonttools-4.57.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f022601f3ee9e1f6658ed6d184ce27fa5216cee5b82d279e0f0bde5deebece72", size = 4766437 }, + { url = "https://files.pythonhosted.org/packages/f8/ad/c25116352f456c0d1287545a7aa24e98987b6d99c5b0456c4bd14321f20f/fonttools-4.57.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dea5893b58d4637ffa925536462ba626f8a1b9ffbe2f5c272cdf2c6ebadb817", size = 4838431 }, + { url = "https://files.pythonhosted.org/packages/53/ae/398b2a833897297797a44f519c9af911c2136eb7aa27d3f1352c6d1129fa/fonttools-4.57.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dff02c5c8423a657c550b48231d0a48d7e2b2e131088e55983cfe74ccc2c7cc9", size = 4951011 }, + { url = "https://files.pythonhosted.org/packages/b7/5d/7cb31c4bc9ffb9a2bbe8b08f8f53bad94aeb158efad75da645b40b62cb73/fonttools-4.57.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:767604f244dc17c68d3e2dbf98e038d11a18abc078f2d0f84b6c24571d9c0b13", size = 5205679 }, + { url = "https://files.pythonhosted.org/packages/4c/e4/6934513ec2c4d3d69ca1bc3bd34d5c69dafcbf68c15388dd3bb062daf345/fonttools-4.57.0-cp313-cp313-win32.whl", hash = "sha256:8e2e12d0d862f43d51e5afb8b9751c77e6bec7d2dc00aad80641364e9df5b199", size = 2144833 }, + { url = "https://files.pythonhosted.org/packages/c4/0d/2177b7fdd23d017bcfb702fd41e47d4573766b9114da2fddbac20dcc4957/fonttools-4.57.0-cp313-cp313-win_amd64.whl", hash = "sha256:f1d6bc9c23356908db712d282acb3eebd4ae5ec6d8b696aa40342b1d84f8e9e3", size = 2190799 }, + { url = "https://files.pythonhosted.org/packages/90/27/45f8957c3132917f91aaa56b700bcfc2396be1253f685bd5c68529b6f610/fonttools-4.57.0-py3-none-any.whl", hash = "sha256:3122c604a675513c68bd24c6a8f9091f1c2376d18e8f5fe5a101746c81b3e98f", size = 1093605 }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/59/7c91426a8ac292e1cdd53a63b6d9439abd573c875c3f92c146767dd33faf/kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e", size = 97538 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/5f/4d8e9e852d98ecd26cdf8eaf7ed8bc33174033bba5e07001b289f07308fd/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88c6f252f6816a73b1f8c904f7bbe02fd67c09a69f7cb8a0eecdbf5ce78e63db", size = 124623 }, + { url = "https://files.pythonhosted.org/packages/1d/70/7f5af2a18a76fe92ea14675f8bd88ce53ee79e37900fa5f1a1d8e0b42998/kiwisolver-1.4.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c72941acb7b67138f35b879bbe85be0f6c6a70cab78fe3ef6db9c024d9223e5b", size = 66720 }, + { url = "https://files.pythonhosted.org/packages/c6/13/e15f804a142353aefd089fadc8f1d985561a15358c97aca27b0979cb0785/kiwisolver-1.4.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce2cf1e5688edcb727fdf7cd1bbd0b6416758996826a8be1d958f91880d0809d", size = 65413 }, + { url = "https://files.pythonhosted.org/packages/ce/6d/67d36c4d2054e83fb875c6b59d0809d5c530de8148846b1370475eeeece9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c8bf637892dc6e6aad2bc6d4d69d08764166e5e3f69d469e55427b6ac001b19d", size = 1650826 }, + { url = "https://files.pythonhosted.org/packages/de/c6/7b9bb8044e150d4d1558423a1568e4f227193662a02231064e3824f37e0a/kiwisolver-1.4.8-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:034d2c891f76bd3edbdb3ea11140d8510dca675443da7304205a2eaa45d8334c", size = 1628231 }, + { url = "https://files.pythonhosted.org/packages/b6/38/ad10d437563063eaaedbe2c3540a71101fc7fb07a7e71f855e93ea4de605/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d47b28d1dfe0793d5e96bce90835e17edf9a499b53969b03c6c47ea5985844c3", size = 1408938 }, + { url = "https://files.pythonhosted.org/packages/52/ce/c0106b3bd7f9e665c5f5bc1e07cc95b5dabd4e08e3dad42dbe2faad467e7/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb158fe28ca0c29f2260cca8c43005329ad58452c36f0edf298204de32a9a3ed", size = 1422799 }, + { url = "https://files.pythonhosted.org/packages/d0/87/efb704b1d75dc9758087ba374c0f23d3254505edaedd09cf9d247f7878b9/kiwisolver-1.4.8-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5536185fce131780ebd809f8e623bf4030ce1b161353166c49a3c74c287897f", size = 1354362 }, + { url = "https://files.pythonhosted.org/packages/eb/b3/fd760dc214ec9a8f208b99e42e8f0130ff4b384eca8b29dd0efc62052176/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:369b75d40abedc1da2c1f4de13f3482cb99e3237b38726710f4a793432b1c5ff", size = 2222695 }, + { url = "https://files.pythonhosted.org/packages/a2/09/a27fb36cca3fc01700687cc45dae7a6a5f8eeb5f657b9f710f788748e10d/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:641f2ddf9358c80faa22e22eb4c9f54bd3f0e442e038728f500e3b978d00aa7d", size = 2370802 }, + { url = "https://files.pythonhosted.org/packages/3d/c3/ba0a0346db35fe4dc1f2f2cf8b99362fbb922d7562e5f911f7ce7a7b60fa/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d561d2d8883e0819445cfe58d7ddd673e4015c3c57261d7bdcd3710d0d14005c", size = 2334646 }, + { url = "https://files.pythonhosted.org/packages/41/52/942cf69e562f5ed253ac67d5c92a693745f0bed3c81f49fc0cbebe4d6b00/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1732e065704b47c9afca7ffa272f845300a4eb959276bf6970dc07265e73b605", size = 2467260 }, + { url = "https://files.pythonhosted.org/packages/32/26/2d9668f30d8a494b0411d4d7d4ea1345ba12deb6a75274d58dd6ea01e951/kiwisolver-1.4.8-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcb1ebc3547619c3b58a39e2448af089ea2ef44b37988caf432447374941574e", size = 2288633 }, + { url = "https://files.pythonhosted.org/packages/98/99/0dd05071654aa44fe5d5e350729961e7bb535372935a45ac89a8924316e6/kiwisolver-1.4.8-cp310-cp310-win_amd64.whl", hash = "sha256:89c107041f7b27844179ea9c85d6da275aa55ecf28413e87624d033cf1f6b751", size = 71885 }, + { url = "https://files.pythonhosted.org/packages/6c/fc/822e532262a97442989335394d441cd1d0448c2e46d26d3e04efca84df22/kiwisolver-1.4.8-cp310-cp310-win_arm64.whl", hash = "sha256:b5773efa2be9eb9fcf5415ea3ab70fc785d598729fd6057bea38d539ead28271", size = 65175 }, + { url = "https://files.pythonhosted.org/packages/da/ed/c913ee28936c371418cb167b128066ffb20bbf37771eecc2c97edf8a6e4c/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a4d3601908c560bdf880f07d94f31d734afd1bb71e96585cace0e38ef44c6d84", size = 124635 }, + { url = "https://files.pythonhosted.org/packages/4c/45/4a7f896f7467aaf5f56ef093d1f329346f3b594e77c6a3c327b2d415f521/kiwisolver-1.4.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:856b269c4d28a5c0d5e6c1955ec36ebfd1651ac00e1ce0afa3e28da95293b561", size = 66717 }, + { url = "https://files.pythonhosted.org/packages/5f/b4/c12b3ac0852a3a68f94598d4c8d569f55361beef6159dce4e7b624160da2/kiwisolver-1.4.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c2b9a96e0f326205af81a15718a9073328df1173a2619a68553decb7097fd5d7", size = 65413 }, + { url = "https://files.pythonhosted.org/packages/a9/98/1df4089b1ed23d83d410adfdc5947245c753bddfbe06541c4aae330e9e70/kiwisolver-1.4.8-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5020c83e8553f770cb3b5fc13faac40f17e0b205bd237aebd21d53d733adb03", size = 1343994 }, + { url = "https://files.pythonhosted.org/packages/8d/bf/b4b169b050c8421a7c53ea1ea74e4ef9c335ee9013216c558a047f162d20/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dace81d28c787956bfbfbbfd72fdcef014f37d9b48830829e488fdb32b49d954", size = 1434804 }, + { url = "https://files.pythonhosted.org/packages/66/5a/e13bd341fbcf73325ea60fdc8af752addf75c5079867af2e04cc41f34434/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11e1022b524bd48ae56c9b4f9296bce77e15a2e42a502cceba602f804b32bb79", size = 1450690 }, + { url = "https://files.pythonhosted.org/packages/9b/4f/5955dcb376ba4a830384cc6fab7d7547bd6759fe75a09564910e9e3bb8ea/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b9b4d2892fefc886f30301cdd80debd8bb01ecdf165a449eb6e78f79f0fabd6", size = 1376839 }, + { url = "https://files.pythonhosted.org/packages/3a/97/5edbed69a9d0caa2e4aa616ae7df8127e10f6586940aa683a496c2c280b9/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a96c0e790ee875d65e340ab383700e2b4891677b7fcd30a699146f9384a2bb0", size = 1435109 }, + { url = "https://files.pythonhosted.org/packages/13/fc/e756382cb64e556af6c1809a1bbb22c141bbc2445049f2da06b420fe52bf/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:23454ff084b07ac54ca8be535f4174170c1094a4cff78fbae4f73a4bcc0d4dab", size = 2245269 }, + { url = "https://files.pythonhosted.org/packages/76/15/e59e45829d7f41c776d138245cabae6515cb4eb44b418f6d4109c478b481/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:87b287251ad6488e95b4f0b4a79a6d04d3ea35fde6340eb38fbd1ca9cd35bbbc", size = 2393468 }, + { url = "https://files.pythonhosted.org/packages/e9/39/483558c2a913ab8384d6e4b66a932406f87c95a6080112433da5ed668559/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b21dbe165081142b1232a240fc6383fd32cdd877ca6cc89eab93e5f5883e1c25", size = 2355394 }, + { url = "https://files.pythonhosted.org/packages/01/aa/efad1fbca6570a161d29224f14b082960c7e08268a133fe5dc0f6906820e/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:768cade2c2df13db52475bd28d3a3fac8c9eff04b0e9e2fda0f3760f20b3f7fc", size = 2490901 }, + { url = "https://files.pythonhosted.org/packages/c9/4f/15988966ba46bcd5ab9d0c8296914436720dd67fca689ae1a75b4ec1c72f/kiwisolver-1.4.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d47cfb2650f0e103d4bf68b0b5804c68da97272c84bb12850d877a95c056bd67", size = 2312306 }, + { url = "https://files.pythonhosted.org/packages/2d/27/bdf1c769c83f74d98cbc34483a972f221440703054894a37d174fba8aa68/kiwisolver-1.4.8-cp311-cp311-win_amd64.whl", hash = "sha256:ed33ca2002a779a2e20eeb06aea7721b6e47f2d4b8a8ece979d8ba9e2a167e34", size = 71966 }, + { url = "https://files.pythonhosted.org/packages/4a/c9/9642ea855604aeb2968a8e145fc662edf61db7632ad2e4fb92424be6b6c0/kiwisolver-1.4.8-cp311-cp311-win_arm64.whl", hash = "sha256:16523b40aab60426ffdebe33ac374457cf62863e330a90a0383639ce14bf44b2", size = 65311 }, + { url = "https://files.pythonhosted.org/packages/fc/aa/cea685c4ab647f349c3bc92d2daf7ae34c8e8cf405a6dcd3a497f58a2ac3/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d6af5e8815fd02997cb6ad9bbed0ee1e60014438ee1a5c2444c96f87b8843502", size = 124152 }, + { url = "https://files.pythonhosted.org/packages/c5/0b/8db6d2e2452d60d5ebc4ce4b204feeb16176a851fd42462f66ade6808084/kiwisolver-1.4.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bade438f86e21d91e0cf5dd7c0ed00cda0f77c8c1616bd83f9fc157fa6760d31", size = 66555 }, + { url = "https://files.pythonhosted.org/packages/60/26/d6a0db6785dd35d3ba5bf2b2df0aedc5af089962c6eb2cbf67a15b81369e/kiwisolver-1.4.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b83dc6769ddbc57613280118fb4ce3cd08899cc3369f7d0e0fab518a7cf37fdb", size = 65067 }, + { url = "https://files.pythonhosted.org/packages/c9/ed/1d97f7e3561e09757a196231edccc1bcf59d55ddccefa2afc9c615abd8e0/kiwisolver-1.4.8-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:111793b232842991be367ed828076b03d96202c19221b5ebab421ce8bcad016f", size = 1378443 }, + { url = "https://files.pythonhosted.org/packages/29/61/39d30b99954e6b46f760e6289c12fede2ab96a254c443639052d1b573fbc/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:257af1622860e51b1a9d0ce387bf5c2c4f36a90594cb9514f55b074bcc787cfc", size = 1472728 }, + { url = "https://files.pythonhosted.org/packages/0c/3e/804163b932f7603ef256e4a715e5843a9600802bb23a68b4e08c8c0ff61d/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b5637c3f316cab1ec1c9a12b8c5f4750a4c4b71af9157645bf32830e39c03a", size = 1478388 }, + { url = "https://files.pythonhosted.org/packages/8a/9e/60eaa75169a154700be74f875a4d9961b11ba048bef315fbe89cb6999056/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:782bb86f245ec18009890e7cb8d13a5ef54dcf2ebe18ed65f795e635a96a1c6a", size = 1413849 }, + { url = "https://files.pythonhosted.org/packages/bc/b3/9458adb9472e61a998c8c4d95cfdfec91c73c53a375b30b1428310f923e4/kiwisolver-1.4.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc978a80a0db3a66d25767b03688f1147a69e6237175c0f4ffffaaedf744055a", size = 1475533 }, + { url = "https://files.pythonhosted.org/packages/e4/7a/0a42d9571e35798de80aef4bb43a9b672aa7f8e58643d7bd1950398ffb0a/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:36dbbfd34838500a31f52c9786990d00150860e46cd5041386f217101350f0d3", size = 2268898 }, + { url = "https://files.pythonhosted.org/packages/d9/07/1255dc8d80271400126ed8db35a1795b1a2c098ac3a72645075d06fe5c5d/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:eaa973f1e05131de5ff3569bbba7f5fd07ea0595d3870ed4a526d486fe57fa1b", size = 2425605 }, + { url = "https://files.pythonhosted.org/packages/84/df/5a3b4cf13780ef6f6942df67b138b03b7e79e9f1f08f57c49957d5867f6e/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a66f60f8d0c87ab7f59b6fb80e642ebb29fec354a4dfad687ca4092ae69d04f4", size = 2375801 }, + { url = "https://files.pythonhosted.org/packages/8f/10/2348d068e8b0f635c8c86892788dac7a6b5c0cb12356620ab575775aad89/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858416b7fb777a53f0c59ca08190ce24e9abbd3cffa18886a5781b8e3e26f65d", size = 2520077 }, + { url = "https://files.pythonhosted.org/packages/32/d8/014b89fee5d4dce157d814303b0fce4d31385a2af4c41fed194b173b81ac/kiwisolver-1.4.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:085940635c62697391baafaaeabdf3dd7a6c3643577dde337f4d66eba021b2b8", size = 2338410 }, + { url = "https://files.pythonhosted.org/packages/bd/72/dfff0cc97f2a0776e1c9eb5bef1ddfd45f46246c6533b0191887a427bca5/kiwisolver-1.4.8-cp312-cp312-win_amd64.whl", hash = "sha256:01c3d31902c7db5fb6182832713d3b4122ad9317c2c5877d0539227d96bb2e50", size = 71853 }, + { url = "https://files.pythonhosted.org/packages/dc/85/220d13d914485c0948a00f0b9eb419efaf6da81b7d72e88ce2391f7aed8d/kiwisolver-1.4.8-cp312-cp312-win_arm64.whl", hash = "sha256:a3c44cb68861de93f0c4a8175fbaa691f0aa22550c331fefef02b618a9dcb476", size = 65424 }, + { url = "https://files.pythonhosted.org/packages/79/b3/e62464a652f4f8cd9006e13d07abad844a47df1e6537f73ddfbf1bc997ec/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:1c8ceb754339793c24aee1c9fb2485b5b1f5bb1c2c214ff13368431e51fc9a09", size = 124156 }, + { url = "https://files.pythonhosted.org/packages/8d/2d/f13d06998b546a2ad4f48607a146e045bbe48030774de29f90bdc573df15/kiwisolver-1.4.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:54a62808ac74b5e55a04a408cda6156f986cefbcf0ada13572696b507cc92fa1", size = 66555 }, + { url = "https://files.pythonhosted.org/packages/59/e3/b8bd14b0a54998a9fd1e8da591c60998dc003618cb19a3f94cb233ec1511/kiwisolver-1.4.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:68269e60ee4929893aad82666821aaacbd455284124817af45c11e50a4b42e3c", size = 65071 }, + { url = "https://files.pythonhosted.org/packages/f0/1c/6c86f6d85ffe4d0ce04228d976f00674f1df5dc893bf2dd4f1928748f187/kiwisolver-1.4.8-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:34d142fba9c464bc3bbfeff15c96eab0e7310343d6aefb62a79d51421fcc5f1b", size = 1378053 }, + { url = "https://files.pythonhosted.org/packages/4e/b9/1c6e9f6dcb103ac5cf87cb695845f5fa71379021500153566d8a8a9fc291/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3ddc373e0eef45b59197de815b1b28ef89ae3955e7722cc9710fb91cd77b7f47", size = 1472278 }, + { url = "https://files.pythonhosted.org/packages/ee/81/aca1eb176de671f8bda479b11acdc42c132b61a2ac861c883907dde6debb/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77e6f57a20b9bd4e1e2cedda4d0b986ebd0216236f0106e55c28aea3d3d69b16", size = 1478139 }, + { url = "https://files.pythonhosted.org/packages/49/f4/e081522473671c97b2687d380e9e4c26f748a86363ce5af48b4a28e48d06/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08e77738ed7538f036cd1170cbed942ef749137b1311fa2bbe2a7fda2f6bf3cc", size = 1413517 }, + { url = "https://files.pythonhosted.org/packages/8f/e9/6a7d025d8da8c4931522922cd706105aa32b3291d1add8c5427cdcd66e63/kiwisolver-1.4.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5ce1e481a74b44dd5e92ff03ea0cb371ae7a0268318e202be06c8f04f4f1246", size = 1474952 }, + { url = "https://files.pythonhosted.org/packages/82/13/13fa685ae167bee5d94b415991c4fc7bb0a1b6ebea6e753a87044b209678/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fc2ace710ba7c1dfd1a3b42530b62b9ceed115f19a1656adefce7b1782a37794", size = 2269132 }, + { url = "https://files.pythonhosted.org/packages/ef/92/bb7c9395489b99a6cb41d502d3686bac692586db2045adc19e45ee64ed23/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3452046c37c7692bd52b0e752b87954ef86ee2224e624ef7ce6cb21e8c41cc1b", size = 2425997 }, + { url = "https://files.pythonhosted.org/packages/ed/12/87f0e9271e2b63d35d0d8524954145837dd1a6c15b62a2d8c1ebe0f182b4/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7e9a60b50fe8b2ec6f448fe8d81b07e40141bfced7f896309df271a0b92f80f3", size = 2376060 }, + { url = "https://files.pythonhosted.org/packages/02/6e/c8af39288edbce8bf0fa35dee427b082758a4b71e9c91ef18fa667782138/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:918139571133f366e8362fa4a297aeba86c7816b7ecf0bc79168080e2bd79957", size = 2520471 }, + { url = "https://files.pythonhosted.org/packages/13/78/df381bc7b26e535c91469f77f16adcd073beb3e2dd25042efd064af82323/kiwisolver-1.4.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e063ef9f89885a1d68dd8b2e18f5ead48653176d10a0e324e3b0030e3a69adeb", size = 2338793 }, + { url = "https://files.pythonhosted.org/packages/d0/dc/c1abe38c37c071d0fc71c9a474fd0b9ede05d42f5a458d584619cfd2371a/kiwisolver-1.4.8-cp313-cp313-win_amd64.whl", hash = "sha256:a17b7c4f5b2c51bb68ed379defd608a03954a1845dfed7cc0117f1cc8a9b7fd2", size = 71855 }, + { url = "https://files.pythonhosted.org/packages/a0/b6/21529d595b126ac298fdd90b705d87d4c5693de60023e0efcb4f387ed99e/kiwisolver-1.4.8-cp313-cp313-win_arm64.whl", hash = "sha256:3cd3bc628b25f74aedc6d374d5babf0166a92ff1317f46267f12d2ed54bc1d30", size = 65430 }, + { url = "https://files.pythonhosted.org/packages/34/bd/b89380b7298e3af9b39f49334e3e2a4af0e04819789f04b43d560516c0c8/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:370fd2df41660ed4e26b8c9d6bbcad668fbe2560462cba151a721d49e5b6628c", size = 126294 }, + { url = "https://files.pythonhosted.org/packages/83/41/5857dc72e5e4148eaac5aa76e0703e594e4465f8ab7ec0fc60e3a9bb8fea/kiwisolver-1.4.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:84a2f830d42707de1d191b9490ac186bf7997a9495d4e9072210a1296345f7dc", size = 67736 }, + { url = "https://files.pythonhosted.org/packages/e1/d1/be059b8db56ac270489fb0b3297fd1e53d195ba76e9bbb30e5401fa6b759/kiwisolver-1.4.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a3ad337add5148cf51ce0b55642dc551c0b9d6248458a757f98796ca7348712", size = 66194 }, + { url = "https://files.pythonhosted.org/packages/e1/83/4b73975f149819eb7dcf9299ed467eba068ecb16439a98990dcb12e63fdd/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7506488470f41169b86d8c9aeff587293f530a23a23a49d6bc64dab66bedc71e", size = 1465942 }, + { url = "https://files.pythonhosted.org/packages/c7/2c/30a5cdde5102958e602c07466bce058b9d7cb48734aa7a4327261ac8e002/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f0121b07b356a22fb0414cec4666bbe36fd6d0d759db3d37228f496ed67c880", size = 1595341 }, + { url = "https://files.pythonhosted.org/packages/ff/9b/1e71db1c000385aa069704f5990574b8244cce854ecd83119c19e83c9586/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6d6bd87df62c27d4185de7c511c6248040afae67028a8a22012b010bc7ad062", size = 1598455 }, + { url = "https://files.pythonhosted.org/packages/85/92/c8fec52ddf06231b31cbb779af77e99b8253cd96bd135250b9498144c78b/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:291331973c64bb9cce50bbe871fb2e675c4331dab4f31abe89f175ad7679a4d7", size = 1522138 }, + { url = "https://files.pythonhosted.org/packages/0b/51/9eb7e2cd07a15d8bdd976f6190c0164f92ce1904e5c0c79198c4972926b7/kiwisolver-1.4.8-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:893f5525bb92d3d735878ec00f781b2de998333659507d29ea4466208df37bed", size = 1582857 }, + { url = "https://files.pythonhosted.org/packages/0f/95/c5a00387a5405e68ba32cc64af65ce881a39b98d73cc394b24143bebc5b8/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b47a465040146981dc9db8647981b8cb96366fbc8d452b031e4f8fdffec3f26d", size = 2293129 }, + { url = "https://files.pythonhosted.org/packages/44/83/eeb7af7d706b8347548313fa3a3a15931f404533cc54fe01f39e830dd231/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:99cea8b9dd34ff80c521aef46a1dddb0dcc0283cf18bde6d756f1e6f31772165", size = 2421538 }, + { url = "https://files.pythonhosted.org/packages/05/f9/27e94c1b3eb29e6933b6986ffc5fa1177d2cd1f0c8efc5f02c91c9ac61de/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:151dffc4865e5fe6dafce5480fab84f950d14566c480c08a53c663a0020504b6", size = 2390661 }, + { url = "https://files.pythonhosted.org/packages/d9/d4/3c9735faa36ac591a4afcc2980d2691000506050b7a7e80bcfe44048daa7/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:577facaa411c10421314598b50413aa1ebcf5126f704f1e5d72d7e4e9f020d90", size = 2546710 }, + { url = "https://files.pythonhosted.org/packages/4c/fa/be89a49c640930180657482a74970cdcf6f7072c8d2471e1babe17a222dc/kiwisolver-1.4.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:be4816dc51c8a471749d664161b434912eee82f2ea66bd7628bd14583a833e85", size = 2349213 }, + { url = "https://files.pythonhosted.org/packages/1f/f9/ae81c47a43e33b93b0a9819cac6723257f5da2a5a60daf46aa5c7226ea85/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e7a019419b7b510f0f7c9dceff8c5eae2392037eae483a7f9162625233802b0a", size = 60403 }, + { url = "https://files.pythonhosted.org/packages/58/ca/f92b5cb6f4ce0c1ebfcfe3e2e42b96917e16f7090e45b21102941924f18f/kiwisolver-1.4.8-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:286b18e86682fd2217a48fc6be6b0f20c1d0ed10958d8dc53453ad58d7be0bf8", size = 58657 }, + { url = "https://files.pythonhosted.org/packages/80/28/ae0240f732f0484d3a4dc885d055653c47144bdf59b670aae0ec3c65a7c8/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4191ee8dfd0be1c3666ccbac178c5a05d5f8d689bbe3fc92f3c4abec817f8fe0", size = 84948 }, + { url = "https://files.pythonhosted.org/packages/5d/eb/78d50346c51db22c7203c1611f9b513075f35c4e0e4877c5dde378d66043/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cd2785b9391f2873ad46088ed7599a6a71e762e1ea33e87514b1a441ed1da1c", size = 81186 }, + { url = "https://files.pythonhosted.org/packages/43/f8/7259f18c77adca88d5f64f9a522792e178b2691f3748817a8750c2d216ef/kiwisolver-1.4.8-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c07b29089b7ba090b6f1a669f1411f27221c3662b3a1b7010e67b59bb5a6f10b", size = 80279 }, + { url = "https://files.pythonhosted.org/packages/3a/1d/50ad811d1c5dae091e4cf046beba925bcae0a610e79ae4c538f996f63ed5/kiwisolver-1.4.8-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:65ea09a5a3faadd59c2ce96dc7bf0f364986a315949dc6374f04396b0d60e09b", size = 71762 }, +] + +[[package]] +name = "matplotlib" +version = "3.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/08/b89867ecea2e305f408fbb417139a8dd941ecf7b23a2e02157c36da546f0/matplotlib-3.10.1.tar.gz", hash = "sha256:e8d2d0e3881b129268585bf4765ad3ee73a4591d77b9a18c214ac7e3a79fb2ba", size = 36743335 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/b1/f70e27cf1cd76ce2a5e1aa5579d05afe3236052c6d9b9a96325bc823a17e/matplotlib-3.10.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ff2ae14910be903f4a24afdbb6d7d3a6c44da210fc7d42790b87aeac92238a16", size = 8163654 }, + { url = "https://files.pythonhosted.org/packages/26/af/5ec3d4636106718bb62503a03297125d4514f98fe818461bd9e6b9d116e4/matplotlib-3.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0721a3fd3d5756ed593220a8b86808a36c5031fce489adb5b31ee6dbb47dd5b2", size = 8037943 }, + { url = "https://files.pythonhosted.org/packages/a1/3d/07f9003a71b698b848c9925d05979ffa94a75cd25d1a587202f0bb58aa81/matplotlib-3.10.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0673b4b8f131890eb3a1ad058d6e065fb3c6e71f160089b65f8515373394698", size = 8449510 }, + { url = "https://files.pythonhosted.org/packages/12/87/9472d4513ff83b7cd864311821793ab72234fa201ab77310ec1b585d27e2/matplotlib-3.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8e875b95ac59a7908978fe307ecdbdd9a26af7fa0f33f474a27fcf8c99f64a19", size = 8586585 }, + { url = "https://files.pythonhosted.org/packages/31/9e/fe74d237d2963adae8608faeb21f778cf246dbbf4746cef87cffbc82c4b6/matplotlib-3.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2589659ea30726284c6c91037216f64a506a9822f8e50592d48ac16a2f29e044", size = 9397911 }, + { url = "https://files.pythonhosted.org/packages/b6/1b/025d3e59e8a4281ab463162ad7d072575354a1916aba81b6a11507dfc524/matplotlib-3.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a97ff127f295817bc34517255c9db6e71de8eddaab7f837b7d341dee9f2f587f", size = 8052998 }, + { url = "https://files.pythonhosted.org/packages/a5/14/a1b840075be247bb1834b22c1e1d558740b0f618fe3a823740181ca557a1/matplotlib-3.10.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:057206ff2d6ab82ff3e94ebd94463d084760ca682ed5f150817b859372ec4401", size = 8174669 }, + { url = "https://files.pythonhosted.org/packages/0a/e4/300b08e3e08f9c98b0d5635f42edabf2f7a1d634e64cb0318a71a44ff720/matplotlib-3.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a144867dd6bf8ba8cb5fc81a158b645037e11b3e5cf8a50bd5f9917cb863adfe", size = 8047996 }, + { url = "https://files.pythonhosted.org/packages/75/f9/8d99ff5a2498a5f1ccf919fb46fb945109623c6108216f10f96428f388bc/matplotlib-3.10.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56c5d9fcd9879aa8040f196a235e2dcbdf7dd03ab5b07c0696f80bc6cf04bedd", size = 8461612 }, + { url = "https://files.pythonhosted.org/packages/40/b8/53fa08a5eaf78d3a7213fd6da1feec4bae14a81d9805e567013811ff0e85/matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f69dc9713e4ad2fb21a1c30e37bd445d496524257dfda40ff4a8efb3604ab5c", size = 8602258 }, + { url = "https://files.pythonhosted.org/packages/40/87/4397d2ce808467af86684a622dd112664553e81752ea8bf61bdd89d24a41/matplotlib-3.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c59af3e8aca75d7744b68e8e78a669e91ccbcf1ac35d0102a7b1b46883f1dd7", size = 9408896 }, + { url = "https://files.pythonhosted.org/packages/d7/68/0d03098b3feb786cbd494df0aac15b571effda7f7cbdec267e8a8d398c16/matplotlib-3.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:11b65088c6f3dae784bc72e8d039a2580186285f87448babb9ddb2ad0082993a", size = 8061281 }, + { url = "https://files.pythonhosted.org/packages/7c/1d/5e0dc3b59c034e43de16f94deb68f4ad8a96b3ea00f4b37c160b7474928e/matplotlib-3.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:66e907a06e68cb6cfd652c193311d61a12b54f56809cafbed9736ce5ad92f107", size = 8175488 }, + { url = "https://files.pythonhosted.org/packages/7a/81/dae7e14042e74da658c3336ab9799128e09a1ee03964f2d89630b5d12106/matplotlib-3.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e9b4bb156abb8fa5e5b2b460196f7db7264fc6d62678c03457979e7d5254b7be", size = 8046264 }, + { url = "https://files.pythonhosted.org/packages/21/c4/22516775dcde10fc9c9571d155f90710761b028fc44f660508106c363c97/matplotlib-3.10.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1985ad3d97f51307a2cbfc801a930f120def19ba22864182dacef55277102ba6", size = 8452048 }, + { url = "https://files.pythonhosted.org/packages/63/23/c0615001f67ce7c96b3051d856baedc0c818a2ed84570b9bf9bde200f85d/matplotlib-3.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c96f2c2f825d1257e437a1482c5a2cf4fee15db4261bd6fc0750f81ba2b4ba3d", size = 8597111 }, + { url = "https://files.pythonhosted.org/packages/ca/c0/a07939a82aed77770514348f4568177d7dadab9787ebc618a616fe3d665e/matplotlib-3.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:35e87384ee9e488d8dd5a2dd7baf471178d38b90618d8ea147aced4ab59c9bea", size = 9402771 }, + { url = "https://files.pythonhosted.org/packages/a6/b6/a9405484fb40746fdc6ae4502b16a9d6e53282ba5baaf9ebe2da579f68c4/matplotlib-3.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfd414bce89cc78a7e1d25202e979b3f1af799e416010a20ab2b5ebb3a02425c", size = 8063742 }, + { url = "https://files.pythonhosted.org/packages/60/73/6770ff5e5523d00f3bc584acb6031e29ee5c8adc2336b16cd1d003675fe0/matplotlib-3.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42eee41e1b60fd83ee3292ed83a97a5f2a8239b10c26715d8a6172226988d7b", size = 8176112 }, + { url = "https://files.pythonhosted.org/packages/08/97/b0ca5da0ed54a3f6599c3ab568bdda65269bc27c21a2c97868c1625e4554/matplotlib-3.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f0647b17b667ae745c13721602b540f7aadb2a32c5b96e924cd4fea5dcb90f1", size = 8046931 }, + { url = "https://files.pythonhosted.org/packages/df/9a/1acbdc3b165d4ce2dcd2b1a6d4ffb46a7220ceee960c922c3d50d8514067/matplotlib-3.10.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa3854b5f9473564ef40a41bc922be978fab217776e9ae1545c9b3a5cf2092a3", size = 8453422 }, + { url = "https://files.pythonhosted.org/packages/51/d0/2bc4368abf766203e548dc7ab57cf7e9c621f1a3c72b516cc7715347b179/matplotlib-3.10.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e496c01441be4c7d5f96d4e40f7fca06e20dcb40e44c8daa2e740e1757ad9e6", size = 8596819 }, + { url = "https://files.pythonhosted.org/packages/ab/1b/8b350f8a1746c37ab69dda7d7528d1fc696efb06db6ade9727b7887be16d/matplotlib-3.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5d45d3f5245be5b469843450617dcad9af75ca50568acf59997bed9311131a0b", size = 9402782 }, + { url = "https://files.pythonhosted.org/packages/89/06/f570373d24d93503988ba8d04f213a372fa1ce48381c5eb15da985728498/matplotlib-3.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:8e8e25b1209161d20dfe93037c8a7f7ca796ec9aa326e6e4588d8c4a5dd1e473", size = 8063812 }, + { url = "https://files.pythonhosted.org/packages/fc/e0/8c811a925b5a7ad75135f0e5af46408b78af88bbb02a1df775100ef9bfef/matplotlib-3.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:19b06241ad89c3ae9469e07d77efa87041eac65d78df4fcf9cac318028009b01", size = 8214021 }, + { url = "https://files.pythonhosted.org/packages/4a/34/319ec2139f68ba26da9d00fce2ff9f27679fb799a6c8e7358539801fd629/matplotlib-3.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:01e63101ebb3014e6e9f80d9cf9ee361a8599ddca2c3e166c563628b39305dbb", size = 8090782 }, + { url = "https://files.pythonhosted.org/packages/77/ea/9812124ab9a99df5b2eec1110e9b2edc0b8f77039abf4c56e0a376e84a29/matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f06bad951eea6422ac4e8bdebcf3a70c59ea0a03338c5d2b109f57b64eb3972", size = 8478901 }, + { url = "https://files.pythonhosted.org/packages/c9/db/b05bf463689134789b06dea85828f8ebe506fa1e37593f723b65b86c9582/matplotlib-3.10.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfb036f34873b46978f55e240cff7a239f6c4409eac62d8145bad3fc6ba5a3", size = 8613864 }, + { url = "https://files.pythonhosted.org/packages/c2/04/41ccec4409f3023a7576df3b5c025f1a8c8b81fbfe922ecfd837ac36e081/matplotlib-3.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dc6ab14a7ab3b4d813b88ba957fc05c79493a037f54e246162033591e770de6f", size = 9409487 }, + { url = "https://files.pythonhosted.org/packages/ac/c2/0d5aae823bdcc42cc99327ecdd4d28585e15ccd5218c453b7bcd827f3421/matplotlib-3.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bc411ebd5889a78dabbc457b3fa153203e22248bfa6eedc6797be5df0164dbf9", size = 8134832 }, + { url = "https://files.pythonhosted.org/packages/c8/f6/10adb696d8cbeed2ab4c2e26ecf1c80dd3847bbf3891f4a0c362e0e08a5a/matplotlib-3.10.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:648406f1899f9a818cef8c0231b44dcfc4ff36f167101c3fd1c9151f24220fdc", size = 8158685 }, + { url = "https://files.pythonhosted.org/packages/3f/84/0603d917406072763e7f9bb37747d3d74d7ecd4b943a8c947cc3ae1cf7af/matplotlib-3.10.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:02582304e352f40520727984a5a18f37e8187861f954fea9be7ef06569cf85b4", size = 8035491 }, + { url = "https://files.pythonhosted.org/packages/fd/7d/6a8b31dd07ed856b3eae001c9129670ef75c4698fa1c2a6ac9f00a4a7054/matplotlib-3.10.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3809916157ba871bcdd33d3493acd7fe3037db5daa917ca6e77975a94cef779", size = 8590087 }, +] [[package]] name = "numpy" @@ -18,6 +284,26 @@ version = "2.2.1" source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f2/a5/fdbf6a7871703df6160b5cf3dd774074b086d278172285c52c2758b76305/numpy-2.2.1.tar.gz", hash = "sha256:45681fd7128c8ad1c379f0ca0776a8b0c6583d2f69889ddac01559dfe4390918", size = 20227662 } wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/c4/5588367dc9f91e1a813beb77de46ea8cab13f778e1b3a0e661ab031aba44/numpy-2.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5edb4e4caf751c1518e6a26a83501fda79bff41cc59dac48d70e6d65d4ec4440", size = 21213214 }, + { url = "https://files.pythonhosted.org/packages/d8/8b/32dd9f08419023a4cf856c5ad0b4eba9b830da85eafdef841a104c4fc05a/numpy-2.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:aa3017c40d513ccac9621a2364f939d39e550c542eb2a894b4c8da92b38896ab", size = 14352248 }, + { url = "https://files.pythonhosted.org/packages/84/2d/0e895d02940ba6e12389f0ab5cac5afcf8dc2dc0ade4e8cad33288a721bd/numpy-2.2.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:61048b4a49b1c93fe13426e04e04fdf5a03f456616f6e98c7576144677598675", size = 5391007 }, + { url = "https://files.pythonhosted.org/packages/11/b9/7f1e64a0d46d9c2af6d17966f641fb12d5b8ea3003f31b2308f3e3b9a6aa/numpy-2.2.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:7671dc19c7019103ca44e8d94917eba8534c76133523ca8406822efdd19c9308", size = 6926174 }, + { url = "https://files.pythonhosted.org/packages/2e/8c/043fa4418bc9364e364ab7aba8ff6ef5f6b9171ade22de8fbcf0e2fa4165/numpy-2.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4250888bcb96617e00bfa28ac24850a83c9f3a16db471eca2ee1f1714df0f957", size = 14330914 }, + { url = "https://files.pythonhosted.org/packages/f7/b6/d8110985501ca8912dfc1c3bbef99d66e62d487f72e46b2337494df77364/numpy-2.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7746f235c47abc72b102d3bce9977714c2444bdfaea7888d241b4c4bb6a78bf", size = 16379607 }, + { url = "https://files.pythonhosted.org/packages/e2/57/bdca9fb8bdaa810c3a4ff2eb3231379b77f618a7c0d24be9f7070db50775/numpy-2.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:059e6a747ae84fce488c3ee397cee7e5f905fd1bda5fb18c66bc41807ff119b2", size = 15541760 }, + { url = "https://files.pythonhosted.org/packages/97/55/3b9147b3cbc3b6b1abc2a411dec5337a46c873deca0dd0bf5bef9d0579cc/numpy-2.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f62aa6ee4eb43b024b0e5a01cf65a0bb078ef8c395e8713c6e8a12a697144528", size = 18168476 }, + { url = "https://files.pythonhosted.org/packages/00/e7/7c2cde16c9b87a8e14fdd262ca7849c4681cf48c8a774505f7e6f5e3b643/numpy-2.2.1-cp310-cp310-win32.whl", hash = "sha256:48fd472630715e1c1c89bf1feab55c29098cb403cc184b4859f9c86d4fcb6a95", size = 6570985 }, + { url = "https://files.pythonhosted.org/packages/a1/a8/554b0e99fc4ac11ec481254781a10da180d0559c2ebf2c324232317349ee/numpy-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:b541032178a718c165a49638d28272b771053f628382d5e9d1c93df23ff58dbf", size = 12913384 }, + { url = "https://files.pythonhosted.org/packages/59/14/645887347124e101d983e1daf95b48dc3e136bf8525cb4257bf9eab1b768/numpy-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40f9e544c1c56ba8f1cf7686a8c9b5bb249e665d40d626a23899ba6d5d9e1484", size = 21217379 }, + { url = "https://files.pythonhosted.org/packages/9f/fd/2279000cf29f58ccfd3778cbf4670dfe3f7ce772df5e198c5abe9e88b7d7/numpy-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9b57eaa3b0cd8db52049ed0330747b0364e899e8a606a624813452b8203d5f7", size = 14388520 }, + { url = "https://files.pythonhosted.org/packages/58/b0/034eb5d5ba12d66ab658ff3455a31f20add0b78df8203c6a7451bd1bee21/numpy-2.2.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bc8a37ad5b22c08e2dbd27df2b3ef7e5c0864235805b1e718a235bcb200cf1cb", size = 5389286 }, + { url = "https://files.pythonhosted.org/packages/5d/69/6f3cccde92e82e7835fdb475c2bf439761cbf8a1daa7c07338e1e132dfec/numpy-2.2.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:9036d6365d13b6cbe8f27a0eaf73ddcc070cae584e5ff94bb45e3e9d729feab5", size = 6930345 }, + { url = "https://files.pythonhosted.org/packages/d1/72/1cd38e91ab563e67f584293fcc6aca855c9ae46dba42e6b5ff4600022899/numpy-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51faf345324db860b515d3f364eaa93d0e0551a88d6218a7d61286554d190d73", size = 14335748 }, + { url = "https://files.pythonhosted.org/packages/f2/d4/f999444e86986f3533e7151c272bd8186c55dda554284def18557e013a2a/numpy-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38efc1e56b73cc9b182fe55e56e63b044dd26a72128fd2fbd502f75555d92591", size = 16391057 }, + { url = "https://files.pythonhosted.org/packages/99/7b/85cef6a3ae1b19542b7afd97d0b296526b6ef9e3c43ea0c4d9c4404fb2d0/numpy-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:31b89fa67a8042e96715c68e071a1200c4e172f93b0fbe01a14c0ff3ff820fc8", size = 15556943 }, + { url = "https://files.pythonhosted.org/packages/69/7e/b83cc884c3508e91af78760f6b17ab46ad649831b1fa35acb3eb26d9e6d2/numpy-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4c86e2a209199ead7ee0af65e1d9992d1dce7e1f63c4b9a616500f93820658d0", size = 18180785 }, + { url = "https://files.pythonhosted.org/packages/b2/9f/eb4a9a38867de059dcd4b6e18d47c3867fbd3795d4c9557bb49278f94087/numpy-2.2.1-cp311-cp311-win32.whl", hash = "sha256:b34d87e8a3090ea626003f87f9392b3929a7bbf4104a05b6667348b6bd4bf1cd", size = 6568983 }, + { url = "https://files.pythonhosted.org/packages/6d/1e/be3b9f3073da2f8c7fa361fcdc231b548266b0781029fdbaf75eeab997fd/numpy-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:360137f8fb1b753c5cde3ac388597ad680eccbbbb3865ab65efea062c4a1fd16", size = 12917260 }, { url = "https://files.pythonhosted.org/packages/62/12/b928871c570d4a87ab13d2cc19f8817f17e340d5481621930e76b80ffb7d/numpy-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:694f9e921a0c8f252980e85bce61ebbd07ed2b7d4fa72d0e4246f2f8aa6642ab", size = 20909861 }, { url = "https://files.pythonhosted.org/packages/3d/c3/59df91ae1d8ad7c5e03efd63fd785dec62d96b0fe56d1f9ab600b55009af/numpy-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3683a8d166f2692664262fd4900f207791d005fb088d7fdb973cc8d663626faa", size = 14095776 }, { url = "https://files.pythonhosted.org/packages/af/4e/8ed5868efc8e601fb69419644a280e9c482b75691466b73bfaab7d86922c/numpy-2.2.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:780077d95eafc2ccc3ced969db22377b3864e5b9a0ea5eb347cc93b3ea900315", size = 5126239 }, @@ -48,4 +334,146 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/ff/94a4ce67ea909f41cf7ea712aebbe832dc67decad22944a1020bb398a5ee/numpy-2.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:26c9c4382b19fcfbbed3238a14abf7ff223890ea1936b8890f058e7ba35e8d71", size = 17852844 }, { url = "https://files.pythonhosted.org/packages/46/72/8a5dbce4020dfc595592333ef2fbb0a187d084ca243b67766d29d03e0096/numpy-2.2.1-cp313-cp313t-win32.whl", hash = "sha256:93cf4e045bae74c90ca833cba583c14b62cb4ba2cba0abd2b141ab52548247e2", size = 6326007 }, { url = "https://files.pythonhosted.org/packages/7b/9c/4fce9cf39dde2562584e4cfd351a0140240f82c0e3569ce25a250f47037d/numpy-2.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:bff7d8ec20f5f42607599f9994770fa65d76edca264a87b5e4ea5629bce12268", size = 12693107 }, + { url = "https://files.pythonhosted.org/packages/f1/65/d36a76b811ffe0a4515e290cb05cb0e22171b1b0f0db6bee9141cf023545/numpy-2.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7ba9cc93a91d86365a5d270dee221fdc04fb68d7478e6bf6af650de78a8339e3", size = 21044672 }, + { url = "https://files.pythonhosted.org/packages/aa/3f/b644199f165063154df486d95198d814578f13dd4d8c1651e075bf1cb8af/numpy-2.2.1-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:3d03883435a19794e41f147612a77a8f56d4e52822337844fff3d4040a142964", size = 6789873 }, + { url = "https://files.pythonhosted.org/packages/d7/df/2adb0bb98a3cbe8a6c3c6d1019aede1f1d8b83927ced228a46cc56c7a206/numpy-2.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4511d9e6071452b944207c8ce46ad2f897307910b402ea5fa975da32e0102800", size = 16194933 }, + { url = "https://files.pythonhosted.org/packages/13/3e/1959d5219a9e6d200638d924cedda6a606392f7186a4ed56478252e70d55/numpy-2.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5c5cc0cbabe9452038ed984d05ac87910f89370b9242371bd9079cb4af61811e", size = 12820057 }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, +] + +[[package]] +name = "pillow" +version = "11.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/cb/bb5c01fcd2a69335b86c22142b2bccfc3464087efb7fd382eee5ffc7fdf7/pillow-11.2.1.tar.gz", hash = "sha256:a64dd61998416367b7ef979b73d3a85853ba9bec4c2925f74e588879a58716b6", size = 47026707 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/8b/b158ad57ed44d3cc54db8d68ad7c0a58b8fc0e4c7a3f995f9d62d5b464a1/pillow-11.2.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:d57a75d53922fc20c165016a20d9c44f73305e67c351bbc60d1adaf662e74047", size = 3198442 }, + { url = "https://files.pythonhosted.org/packages/b1/f8/bb5d956142f86c2d6cc36704943fa761f2d2e4c48b7436fd0a85c20f1713/pillow-11.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:127bf6ac4a5b58b3d32fc8289656f77f80567d65660bc46f72c0d77e6600cc95", size = 3030553 }, + { url = "https://files.pythonhosted.org/packages/22/7f/0e413bb3e2aa797b9ca2c5c38cb2e2e45d88654e5b12da91ad446964cfae/pillow-11.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4ba4be812c7a40280629e55ae0b14a0aafa150dd6451297562e1764808bbe61", size = 4405503 }, + { url = "https://files.pythonhosted.org/packages/f3/b4/cc647f4d13f3eb837d3065824aa58b9bcf10821f029dc79955ee43f793bd/pillow-11.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8bd62331e5032bc396a93609982a9ab6b411c05078a52f5fe3cc59234a3abd1", size = 4490648 }, + { url = "https://files.pythonhosted.org/packages/c2/6f/240b772a3b35cdd7384166461567aa6713799b4e78d180c555bd284844ea/pillow-11.2.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:562d11134c97a62fe3af29581f083033179f7ff435f78392565a1ad2d1c2c45c", size = 4508937 }, + { url = "https://files.pythonhosted.org/packages/f3/5e/7ca9c815ade5fdca18853db86d812f2f188212792780208bdb37a0a6aef4/pillow-11.2.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:c97209e85b5be259994eb5b69ff50c5d20cca0f458ef9abd835e262d9d88b39d", size = 4599802 }, + { url = "https://files.pythonhosted.org/packages/02/81/c3d9d38ce0c4878a77245d4cf2c46d45a4ad0f93000227910a46caff52f3/pillow-11.2.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0c3e6d0f59171dfa2e25d7116217543310908dfa2770aa64b8f87605f8cacc97", size = 4576717 }, + { url = "https://files.pythonhosted.org/packages/42/49/52b719b89ac7da3185b8d29c94d0e6aec8140059e3d8adcaa46da3751180/pillow-11.2.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cc1c3bc53befb6096b84165956e886b1729634a799e9d6329a0c512ab651e579", size = 4654874 }, + { url = "https://files.pythonhosted.org/packages/5b/0b/ede75063ba6023798267023dc0d0401f13695d228194d2242d5a7ba2f964/pillow-11.2.1-cp310-cp310-win32.whl", hash = "sha256:312c77b7f07ab2139924d2639860e084ec2a13e72af54d4f08ac843a5fc9c79d", size = 2331717 }, + { url = "https://files.pythonhosted.org/packages/ed/3c/9831da3edea527c2ed9a09f31a2c04e77cd705847f13b69ca60269eec370/pillow-11.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9bc7ae48b8057a611e5fe9f853baa88093b9a76303937449397899385da06fad", size = 2676204 }, + { url = "https://files.pythonhosted.org/packages/01/97/1f66ff8a1503d8cbfc5bae4dc99d54c6ec1e22ad2b946241365320caabc2/pillow-11.2.1-cp310-cp310-win_arm64.whl", hash = "sha256:2728567e249cdd939f6cc3d1f049595c66e4187f3c34078cbc0a7d21c47482d2", size = 2414767 }, + { url = "https://files.pythonhosted.org/packages/68/08/3fbf4b98924c73037a8e8b4c2c774784805e0fb4ebca6c5bb60795c40125/pillow-11.2.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35ca289f712ccfc699508c4658a1d14652e8033e9b69839edf83cbdd0ba39e70", size = 3198450 }, + { url = "https://files.pythonhosted.org/packages/84/92/6505b1af3d2849d5e714fc75ba9e69b7255c05ee42383a35a4d58f576b16/pillow-11.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0409af9f829f87a2dfb7e259f78f317a5351f2045158be321fd135973fff7bf", size = 3030550 }, + { url = "https://files.pythonhosted.org/packages/3c/8c/ac2f99d2a70ff966bc7eb13dacacfaab57c0549b2ffb351b6537c7840b12/pillow-11.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e5c5edee874dce4f653dbe59db7c73a600119fbea8d31f53423586ee2aafd7", size = 4415018 }, + { url = "https://files.pythonhosted.org/packages/1f/e3/0a58b5d838687f40891fff9cbaf8669f90c96b64dc8f91f87894413856c6/pillow-11.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b93a07e76d13bff9444f1a029e0af2964e654bfc2e2c2d46bfd080df5ad5f3d8", size = 4498006 }, + { url = "https://files.pythonhosted.org/packages/21/f5/6ba14718135f08fbfa33308efe027dd02b781d3f1d5c471444a395933aac/pillow-11.2.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:e6def7eed9e7fa90fde255afaf08060dc4b343bbe524a8f69bdd2a2f0018f600", size = 4517773 }, + { url = "https://files.pythonhosted.org/packages/20/f2/805ad600fc59ebe4f1ba6129cd3a75fb0da126975c8579b8f57abeb61e80/pillow-11.2.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8f4f3724c068be008c08257207210c138d5f3731af6c155a81c2b09a9eb3a788", size = 4607069 }, + { url = "https://files.pythonhosted.org/packages/71/6b/4ef8a288b4bb2e0180cba13ca0a519fa27aa982875882392b65131401099/pillow-11.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a0a6709b47019dff32e678bc12c63008311b82b9327613f534e496dacaefb71e", size = 4583460 }, + { url = "https://files.pythonhosted.org/packages/62/ae/f29c705a09cbc9e2a456590816e5c234382ae5d32584f451c3eb41a62062/pillow-11.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f6b0c664ccb879109ee3ca702a9272d877f4fcd21e5eb63c26422fd6e415365e", size = 4661304 }, + { url = "https://files.pythonhosted.org/packages/6e/1a/c8217b6f2f73794a5e219fbad087701f412337ae6dbb956db37d69a9bc43/pillow-11.2.1-cp311-cp311-win32.whl", hash = "sha256:cc5d875d56e49f112b6def6813c4e3d3036d269c008bf8aef72cd08d20ca6df6", size = 2331809 }, + { url = "https://files.pythonhosted.org/packages/e2/72/25a8f40170dc262e86e90f37cb72cb3de5e307f75bf4b02535a61afcd519/pillow-11.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f5c7eda47bf8e3c8a283762cab94e496ba977a420868cb819159980b6709193", size = 2676338 }, + { url = "https://files.pythonhosted.org/packages/06/9e/76825e39efee61efea258b479391ca77d64dbd9e5804e4ad0fa453b4ba55/pillow-11.2.1-cp311-cp311-win_arm64.whl", hash = "sha256:4d375eb838755f2528ac8cbc926c3e31cc49ca4ad0cf79cff48b20e30634a4a7", size = 2414918 }, + { url = "https://files.pythonhosted.org/packages/c7/40/052610b15a1b8961f52537cc8326ca6a881408bc2bdad0d852edeb6ed33b/pillow-11.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:78afba22027b4accef10dbd5eed84425930ba41b3ea0a86fa8d20baaf19d807f", size = 3190185 }, + { url = "https://files.pythonhosted.org/packages/e5/7e/b86dbd35a5f938632093dc40d1682874c33dcfe832558fc80ca56bfcb774/pillow-11.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78092232a4ab376a35d68c4e6d5e00dfd73454bd12b230420025fbe178ee3b0b", size = 3030306 }, + { url = "https://files.pythonhosted.org/packages/a4/5c/467a161f9ed53e5eab51a42923c33051bf8d1a2af4626ac04f5166e58e0c/pillow-11.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25a5f306095c6780c52e6bbb6109624b95c5b18e40aab1c3041da3e9e0cd3e2d", size = 4416121 }, + { url = "https://files.pythonhosted.org/packages/62/73/972b7742e38ae0e2ac76ab137ca6005dcf877480da0d9d61d93b613065b4/pillow-11.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c7b29dbd4281923a2bfe562acb734cee96bbb129e96e6972d315ed9f232bef4", size = 4501707 }, + { url = "https://files.pythonhosted.org/packages/e4/3a/427e4cb0b9e177efbc1a84798ed20498c4f233abde003c06d2650a6d60cb/pillow-11.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3e645b020f3209a0181a418bffe7b4a93171eef6c4ef6cc20980b30bebf17b7d", size = 4522921 }, + { url = "https://files.pythonhosted.org/packages/fe/7c/d8b1330458e4d2f3f45d9508796d7caf0c0d3764c00c823d10f6f1a3b76d/pillow-11.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2dbea1012ccb784a65349f57bbc93730b96e85b42e9bf7b01ef40443db720b4", size = 4612523 }, + { url = "https://files.pythonhosted.org/packages/b3/2f/65738384e0b1acf451de5a573d8153fe84103772d139e1e0bdf1596be2ea/pillow-11.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:da3104c57bbd72948d75f6a9389e6727d2ab6333c3617f0a89d72d4940aa0443", size = 4587836 }, + { url = "https://files.pythonhosted.org/packages/6a/c5/e795c9f2ddf3debb2dedd0df889f2fe4b053308bb59a3cc02a0cd144d641/pillow-11.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:598174aef4589af795f66f9caab87ba4ff860ce08cd5bb447c6fc553ffee603c", size = 4669390 }, + { url = "https://files.pythonhosted.org/packages/96/ae/ca0099a3995976a9fce2f423166f7bff9b12244afdc7520f6ed38911539a/pillow-11.2.1-cp312-cp312-win32.whl", hash = "sha256:1d535df14716e7f8776b9e7fee118576d65572b4aad3ed639be9e4fa88a1cad3", size = 2332309 }, + { url = "https://files.pythonhosted.org/packages/7c/18/24bff2ad716257fc03da964c5e8f05d9790a779a8895d6566e493ccf0189/pillow-11.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:14e33b28bf17c7a38eede290f77db7c664e4eb01f7869e37fa98a5aa95978941", size = 2676768 }, + { url = "https://files.pythonhosted.org/packages/da/bb/e8d656c9543276517ee40184aaa39dcb41e683bca121022f9323ae11b39d/pillow-11.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:21e1470ac9e5739ff880c211fc3af01e3ae505859392bf65458c224d0bf283eb", size = 2415087 }, + { url = "https://files.pythonhosted.org/packages/36/9c/447528ee3776e7ab8897fe33697a7ff3f0475bb490c5ac1456a03dc57956/pillow-11.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fdec757fea0b793056419bca3e9932eb2b0ceec90ef4813ea4c1e072c389eb28", size = 3190098 }, + { url = "https://files.pythonhosted.org/packages/b5/09/29d5cd052f7566a63e5b506fac9c60526e9ecc553825551333e1e18a4858/pillow-11.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0e130705d568e2f43a17bcbe74d90958e8a16263868a12c3e0d9c8162690830", size = 3030166 }, + { url = "https://files.pythonhosted.org/packages/71/5d/446ee132ad35e7600652133f9c2840b4799bbd8e4adba881284860da0a36/pillow-11.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bdb5e09068332578214cadd9c05e3d64d99e0e87591be22a324bdbc18925be0", size = 4408674 }, + { url = "https://files.pythonhosted.org/packages/69/5f/cbe509c0ddf91cc3a03bbacf40e5c2339c4912d16458fcb797bb47bcb269/pillow-11.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d189ba1bebfbc0c0e529159631ec72bb9e9bc041f01ec6d3233d6d82eb823bc1", size = 4496005 }, + { url = "https://files.pythonhosted.org/packages/f9/b3/dd4338d8fb8a5f312021f2977fb8198a1184893f9b00b02b75d565c33b51/pillow-11.2.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:191955c55d8a712fab8934a42bfefbf99dd0b5875078240943f913bb66d46d9f", size = 4518707 }, + { url = "https://files.pythonhosted.org/packages/13/eb/2552ecebc0b887f539111c2cd241f538b8ff5891b8903dfe672e997529be/pillow-11.2.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:ad275964d52e2243430472fc5d2c2334b4fc3ff9c16cb0a19254e25efa03a155", size = 4610008 }, + { url = "https://files.pythonhosted.org/packages/72/d1/924ce51bea494cb6e7959522d69d7b1c7e74f6821d84c63c3dc430cbbf3b/pillow-11.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:750f96efe0597382660d8b53e90dd1dd44568a8edb51cb7f9d5d918b80d4de14", size = 4585420 }, + { url = "https://files.pythonhosted.org/packages/43/ab/8f81312d255d713b99ca37479a4cb4b0f48195e530cdc1611990eb8fd04b/pillow-11.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fe15238d3798788d00716637b3d4e7bb6bde18b26e5d08335a96e88564a36b6b", size = 4667655 }, + { url = "https://files.pythonhosted.org/packages/94/86/8f2e9d2dc3d308dfd137a07fe1cc478df0a23d42a6c4093b087e738e4827/pillow-11.2.1-cp313-cp313-win32.whl", hash = "sha256:3fe735ced9a607fee4f481423a9c36701a39719252a9bb251679635f99d0f7d2", size = 2332329 }, + { url = "https://files.pythonhosted.org/packages/6d/ec/1179083b8d6067a613e4d595359b5fdea65d0a3b7ad623fee906e1b3c4d2/pillow-11.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:74ee3d7ecb3f3c05459ba95eed5efa28d6092d751ce9bf20e3e253a4e497e691", size = 2676388 }, + { url = "https://files.pythonhosted.org/packages/23/f1/2fc1e1e294de897df39fa8622d829b8828ddad938b0eaea256d65b84dd72/pillow-11.2.1-cp313-cp313-win_arm64.whl", hash = "sha256:5119225c622403afb4b44bad4c1ca6c1f98eed79db8d3bc6e4e160fc6339d66c", size = 2414950 }, + { url = "https://files.pythonhosted.org/packages/c4/3e/c328c48b3f0ead7bab765a84b4977acb29f101d10e4ef57a5e3400447c03/pillow-11.2.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:8ce2e8411c7aaef53e6bb29fe98f28cd4fbd9a1d9be2eeea434331aac0536b22", size = 3192759 }, + { url = "https://files.pythonhosted.org/packages/18/0e/1c68532d833fc8b9f404d3a642991441d9058eccd5606eab31617f29b6d4/pillow-11.2.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:9ee66787e095127116d91dea2143db65c7bb1e232f617aa5957c0d9d2a3f23a7", size = 3033284 }, + { url = "https://files.pythonhosted.org/packages/b7/cb/6faf3fb1e7705fd2db74e070f3bf6f88693601b0ed8e81049a8266de4754/pillow-11.2.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9622e3b6c1d8b551b6e6f21873bdcc55762b4b2126633014cea1803368a9aa16", size = 4445826 }, + { url = "https://files.pythonhosted.org/packages/07/94/8be03d50b70ca47fb434a358919d6a8d6580f282bbb7af7e4aa40103461d/pillow-11.2.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63b5dff3a68f371ea06025a1a6966c9a1e1ee452fc8020c2cd0ea41b83e9037b", size = 4527329 }, + { url = "https://files.pythonhosted.org/packages/fd/a4/bfe78777076dc405e3bd2080bc32da5ab3945b5a25dc5d8acaa9de64a162/pillow-11.2.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:31df6e2d3d8fc99f993fd253e97fae451a8db2e7207acf97859732273e108406", size = 4549049 }, + { url = "https://files.pythonhosted.org/packages/65/4d/eaf9068dc687c24979e977ce5677e253624bd8b616b286f543f0c1b91662/pillow-11.2.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:062b7a42d672c45a70fa1f8b43d1d38ff76b63421cbbe7f88146b39e8a558d91", size = 4635408 }, + { url = "https://files.pythonhosted.org/packages/1d/26/0fd443365d9c63bc79feb219f97d935cd4b93af28353cba78d8e77b61719/pillow-11.2.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4eb92eca2711ef8be42fd3f67533765d9fd043b8c80db204f16c8ea62ee1a751", size = 4614863 }, + { url = "https://files.pythonhosted.org/packages/49/65/dca4d2506be482c2c6641cacdba5c602bc76d8ceb618fd37de855653a419/pillow-11.2.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:f91ebf30830a48c825590aede79376cb40f110b387c17ee9bd59932c961044f9", size = 4692938 }, + { url = "https://files.pythonhosted.org/packages/b3/92/1ca0c3f09233bd7decf8f7105a1c4e3162fb9142128c74adad0fb361b7eb/pillow-11.2.1-cp313-cp313t-win32.whl", hash = "sha256:e0b55f27f584ed623221cfe995c912c61606be8513bfa0e07d2c674b4516d9dd", size = 2335774 }, + { url = "https://files.pythonhosted.org/packages/a5/ac/77525347cb43b83ae905ffe257bbe2cc6fd23acb9796639a1f56aa59d191/pillow-11.2.1-cp313-cp313t-win_amd64.whl", hash = "sha256:36d6b82164c39ce5482f649b437382c0fb2395eabc1e2b1702a6deb8ad647d6e", size = 2681895 }, + { url = "https://files.pythonhosted.org/packages/67/32/32dc030cfa91ca0fc52baebbba2e009bb001122a1daa8b6a79ad830b38d3/pillow-11.2.1-cp313-cp313t-win_arm64.whl", hash = "sha256:225c832a13326e34f212d2072982bb1adb210e0cc0b153e688743018c94a2681", size = 2417234 }, + { url = "https://files.pythonhosted.org/packages/33/49/c8c21e4255b4f4a2c0c68ac18125d7f5460b109acc6dfdef1a24f9b960ef/pillow-11.2.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9b7b0d4fd2635f54ad82785d56bc0d94f147096493a79985d0ab57aedd563156", size = 3181727 }, + { url = "https://files.pythonhosted.org/packages/6d/f1/f7255c0838f8c1ef6d55b625cfb286835c17e8136ce4351c5577d02c443b/pillow-11.2.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:aa442755e31c64037aa7c1cb186e0b369f8416c567381852c63444dd666fb772", size = 2999833 }, + { url = "https://files.pythonhosted.org/packages/e2/57/9968114457bd131063da98d87790d080366218f64fa2943b65ac6739abb3/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d3348c95b766f54b76116d53d4cb171b52992a1027e7ca50c81b43b9d9e363", size = 3437472 }, + { url = "https://files.pythonhosted.org/packages/b2/1b/e35d8a158e21372ecc48aac9c453518cfe23907bb82f950d6e1c72811eb0/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85d27ea4c889342f7e35f6d56e7e1cb345632ad592e8c51b693d7b7556043ce0", size = 3459976 }, + { url = "https://files.pythonhosted.org/packages/26/da/2c11d03b765efff0ccc473f1c4186dc2770110464f2177efaed9cf6fae01/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:bf2c33d6791c598142f00c9c4c7d47f6476731c31081331664eb26d6ab583e01", size = 3527133 }, + { url = "https://files.pythonhosted.org/packages/79/1a/4e85bd7cadf78412c2a3069249a09c32ef3323650fd3005c97cca7aa21df/pillow-11.2.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e616e7154c37669fc1dfc14584f11e284e05d1c650e1c0f972f281c4ccc53193", size = 3571555 }, + { url = "https://files.pythonhosted.org/packages/69/03/239939915216de1e95e0ce2334bf17a7870ae185eb390fab6d706aadbfc0/pillow-11.2.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:39ad2e0f424394e3aebc40168845fee52df1394a4673a6ee512d840d14ab3013", size = 2674713 }, + { url = "https://files.pythonhosted.org/packages/a4/ad/2613c04633c7257d9481ab21d6b5364b59fc5d75faafd7cb8693523945a3/pillow-11.2.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:80f1df8dbe9572b4b7abdfa17eb5d78dd620b1d55d9e25f834efdbee872d3aed", size = 3181734 }, + { url = "https://files.pythonhosted.org/packages/a4/fd/dcdda4471ed667de57bb5405bb42d751e6cfdd4011a12c248b455c778e03/pillow-11.2.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ea926cfbc3957090becbcbbb65ad177161a2ff2ad578b5a6ec9bb1e1cd78753c", size = 2999841 }, + { url = "https://files.pythonhosted.org/packages/ac/89/8a2536e95e77432833f0db6fd72a8d310c8e4272a04461fb833eb021bf94/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:738db0e0941ca0376804d4de6a782c005245264edaa253ffce24e5a15cbdc7bd", size = 3437470 }, + { url = "https://files.pythonhosted.org/packages/9d/8f/abd47b73c60712f88e9eda32baced7bfc3e9bd6a7619bb64b93acff28c3e/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db98ab6565c69082ec9b0d4e40dd9f6181dab0dd236d26f7a50b8b9bfbd5076", size = 3460013 }, + { url = "https://files.pythonhosted.org/packages/f6/20/5c0a0aa83b213b7a07ec01e71a3d6ea2cf4ad1d2c686cc0168173b6089e7/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:036e53f4170e270ddb8797d4c590e6dd14d28e15c7da375c18978045f7e6c37b", size = 3527165 }, + { url = "https://files.pythonhosted.org/packages/58/0e/2abab98a72202d91146abc839e10c14f7cf36166f12838ea0c4db3ca6ecb/pillow-11.2.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:14f73f7c291279bd65fda51ee87affd7c1e097709f7fdd0188957a16c264601f", size = 3571586 }, + { url = "https://files.pythonhosted.org/packages/21/2c/5e05f58658cf49b6667762cca03d6e7d85cededde2caf2ab37b81f80e574/pillow-11.2.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:208653868d5c9ecc2b327f9b9ef34e0e42a4cdd172c2988fd81d62d2bc9bc044", size = 2674751 }, +] + +[[package]] +name = "pyparsing" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120 }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 }, +] + +[[package]] +name = "vtk" +version = "9.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/bb/2308cfd512ebb6b97173105fc27faa71b948136b331bd7d341349eb7e468/vtk-9.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7d3492cb6c52b23dc0c6e664938b8119254a77b5e3099106e2567ed0b6473162", size = 76476756 }, + { url = "https://files.pythonhosted.org/packages/13/36/3b4bb5d9073d682ccf31d5bb6d06c3275bcfc379ed2fc1d730c28a6ba303/vtk-9.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3f4e86bff7a4cd71bd6205bd18cf4b6ab70956ecf9cbd73e77a95b2210d98ef", size = 70111274 }, + { url = "https://files.pythonhosted.org/packages/c4/66/23118087ce6bb1914ce367638b6113d827f2257b76ca506a06e288c0e13b/vtk-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a827fb5f05ab78b2cbad81f5d3a3d7065fa995cc907cecdfa7a7b76374130ef3", size = 91995386 }, + { url = "https://files.pythonhosted.org/packages/d8/ac/248a646b83fea3b910ac3cb08f0ce6ab2cb118de3e673bd266bc5f472a0c/vtk-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:2aae778297817335ddd6698b4c124c109d8ac476512691fe19446614ae43ba56", size = 52422442 }, + { url = "https://files.pythonhosted.org/packages/7a/86/bcd5dc64141d90604bc5a9efcb6f0a2a11983e6c001a2d9d9e0bbb4fedcf/vtk-9.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:a3cd59108b21f55b873a63878a0decec0a707bd960b59d5e15b37d1ad873590f", size = 76476999 }, + { url = "https://files.pythonhosted.org/packages/c2/45/ffb4e2fc07c12f772cfddeb095f0a9a72bad7097c7ab0f08a292fc474be1/vtk-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6d2bdd2c60f0fa5d1926c11b72d96dc23caf9ff41781bae76e48edd09fb8aa03", size = 70111238 }, + { url = "https://files.pythonhosted.org/packages/00/cf/e827806a34efe69ce286ba842605535c40b45ea338f8315dd0e0986e89a9/vtk-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a02bf6067cae7abfd7f6b1330c69555b715be8ec71a3c8d6471af45a96e8e56", size = 91995090 }, + { url = "https://files.pythonhosted.org/packages/0a/a5/c5e380300715cab30166d5ec9bba2ccabbf41452d3b09e2d7c1bfcfc11d5/vtk-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:ff0eedcde5821c023623f70951f2499e9d59e709e288b67a2e2334abafacc322", size = 52420923 }, + { url = "https://files.pythonhosted.org/packages/13/f1/f36b1978f1bee2323303207043a1c4b99387cfd2d9a8b7b6b79f0262d8a4/vtk-9.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:94678fa0476e113500f3b99e9692b92b83a5b058caace7bac3b5f780b12b36ed", size = 76620745 }, + { url = "https://files.pythonhosted.org/packages/39/8d/d705ad84092cee806769084dca1cd143d296903854caaeb9164bbb0f595a/vtk-9.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:371b96afca3ed41a0bf1cd80a42f4b906ca2f470a13df32f39b22a9169d996d7", size = 70146262 }, + { url = "https://files.pythonhosted.org/packages/97/a6/91b79b1a4f90bcbd104613bc44a3038f6b63140554de211c71b8304d98a0/vtk-9.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cfa8d73acbab386b9d6ef8a1a01149fd096a21a23547f10bf0cf98d88300724", size = 92039877 }, + { url = "https://files.pythonhosted.org/packages/de/ca/0ba875f1924fc6b662c5c87a16d45604d3cc79fd1161bf8540b3096af941/vtk-9.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:75d27b73270a42923ebefd87a8522f7717618c36825b8058c4d3aa8e64d6145d", size = 52426002 }, ] From 8a9124aaee69e621f32a0b5c74acbad14c0368b5 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 7 May 2025 13:50:30 +0200 Subject: [PATCH 07/14] feat: add variance calculation --- core/src/api.rs | 9 +++- core/src/impl_concat.rs | 12 +++++- core/src/impl_unique.rs | 73 ++++++++++++++++++++++++++------ core/src/process/mod.rs | 12 +++++- python_wrap/src/lib.rs | 93 ++++++++++++++++++++++++----------------- 5 files changed, 143 insertions(+), 56 deletions(-) diff --git a/core/src/api.rs b/core/src/api.rs index f441bdd..5b439da 100644 --- a/core/src/api.rs +++ b/core/src/api.rs @@ -1,7 +1,7 @@ use crate::datamodel::{Weight,tallies::Tallies}; use crate::error::ApiError; -use ndarray::{Array1, Array2, ArrayView3}; +use ndarray::{Array1, Array2, ArrayView2, ArrayView3}; /// `Phase` enum represents different states or phases of a substance. #[derive(Clone, PartialEq, Copy)] @@ -27,6 +27,8 @@ pub trait PostProcessReader { /// * `&[f64]` - A slice containing the time data. fn time(&self) -> &[f64]; + fn v_liquid(&self) -> ArrayView2<'_, f64>; + /// Returns a weight chosen for simulation /// /// # Returns @@ -86,6 +88,11 @@ pub trait PostProcessReader { fn get_spatial_average_mtr(&self, species: usize) -> Result, ApiError>; + fn get_variance_concentration(&self,species:usize,phase:Phase)-> Result, ApiError>; + + + + /// Computes the time average concentration for a specific species, position, and phase. /// /// # Arguments diff --git a/core/src/impl_concat.rs b/core/src/impl_concat.rs index a0e8fa7..1680ccd 100644 --- a/core/src/impl_concat.rs +++ b/core/src/impl_concat.rs @@ -2,7 +2,7 @@ use crate::api::PostProcessReader; use crate::datamodel::{Weight,tallies::Tallies}; use crate::{api::Phase, error::ApiError, PostProcess}; -use ndarray::{Array1, Array2, ArrayView3, Axis}; +use ndarray::{Array1, Array2, ArrayView2, ArrayView3, Axis}; #[derive(Debug)] pub struct ConcatPostPrcess { @@ -47,6 +47,11 @@ impl PostProcessReader for ConcatPostPrcess { todo!() } + fn v_liquid(&self) -> ArrayView2<'_, f64> + { + todo!() + } + fn get_spatial_average_property(&self, key:&str) -> Result, ApiError> { todo!() @@ -56,6 +61,11 @@ impl PostProcessReader for ConcatPostPrcess { todo!() } + fn get_variance_concentration(&self,species:usize,phase:Phase)-> Result, ApiError> + { + todo!() + } + fn get_spatial_average_biomass_concentration(&self) -> Result, ApiError> { let mut concatenated = Array1::::default(0); for postprocess in &self.dataset { diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index 341c325..4071019 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -1,12 +1,14 @@ use crate::api::{ModelEstimator, PostProcessReader}; +use crate::datamodel::{f_get_probes, make_histogram, read_spatial_model_properties, Results}; use crate::datamodel::{ get_n_export_real, read_avg_model_properties, read_model_mass, read_model_properties, - vec_to_array_view2, vec_to_array_view3, Dim, tallies::Tallies, Weight, + tallies::Tallies, vec_to_array_view2, vec_to_array_view3, Dim, Weight, +}; +use crate::process::{ + normalize_concentration, spatial_average_concentration, variance_concentration, Histogram, }; -use crate::datamodel::{f_get_probes, make_histogram, read_spatial_model_properties, Results}; -use crate::process::{spatial_average_concentration, Histogram}; use crate::{api::Estimator, api::Phase, error::ApiError}; -use ndarray::{s, Array1, Array2, ArrayView3, Axis}; +use ndarray::{s, Array1, Array2, ArrayView1, ArrayView2, ArrayView3, Axis}; /// The `PostProcess` struct handles post-processing of simulation results. /// @@ -67,6 +69,55 @@ impl PostProcessReader for PostProcess { // let mtr = vec_to_array_view3(self.results., &dim, nt); } + fn v_liquid(&self) -> ArrayView2<'_, f64> { + let nt = self.results.main.records.time.len(); + let dim = &self.results.main.records.dim; + vec_to_array_view2(&self.results.main.records.volume_liquid, nt, dim.0) + } + + fn get_variance_concentration( + &self, + species: usize, + phase: Phase, + ) -> Result, ApiError> { + // Helper + fn process_phase( + concentration: &Vec, + volume: &Vec, + nt: usize, + dim: &Dim, + species: usize, + ) -> Array1 { + let c: ndarray::ArrayBase, ndarray::Dim<[usize; 3]>> = + vec_to_array_view3(concentration, dim, nt); + let vol = vec_to_array_view2(volume, nt, dim.0); + let c_slice = &c.slice(s![.., .., species]); + let normalized_c = variance_concentration(&c_slice, &vol); + normalized_c + } + + let records = &self.results.main.records; + let nt = records.time.len(); + let dim = &records.dim; + + match phase { + Phase::Gas => { + if let (Some(c), Some(v)) = (&records.concentration_gas, &records.volume_gas) { + return Ok(process_phase(c, v, nt, dim, species)); + } + + panic!("Gas is not present"); + } + Phase::Liquid => Ok(process_phase( + &records.concentration_liquid, + &records.volume_liquid, + nt, + dim, + species, + )), + } + } + /// Returns an `ArrayView1` representing the time data from the simulation results. /// /// # Returns @@ -169,7 +220,7 @@ impl PostProcessReader for PostProcess { fn get_time_average_concentration( &self, species: usize, - position: usize, + position: usize, phase: Phase, ) -> Result, ApiError> { let r = &self.results.main.records; @@ -193,9 +244,8 @@ impl PostProcessReader for PostProcess { } } - //Actually compute spatial average property cannot be use to follow distribution - fn get_spatial_average_property(&self, key:&str) -> Result, ApiError> - { + //Actually compute spatial average property cannot be use to follow distribution + fn get_spatial_average_property(&self, key: &str) -> Result, ApiError> { let nt: usize = self.results.main.records.time.len(); // Number of time steps let num_dimensions = self.results.main.records.dim.0; // Dimensionality @@ -206,9 +256,7 @@ impl PostProcessReader for PostProcess { return Err(ApiError::KeyError(key.to_string())); } - read_spatial_model_properties(key,self.results.get_files(), &mut biomass_matrix, nt) ?; - - + read_spatial_model_properties(key, self.results.get_files(), &mut biomass_matrix, nt)?; // Calculate biomass concentration biomass_matrix /= self.get_number_particle(); @@ -216,8 +264,7 @@ impl PostProcessReader for PostProcess { Ok(biomass_matrix) } - fn get_probes(&self) -> Result, ApiError> - { + fn get_probes(&self) -> Result, ApiError> { f_get_probes(&self.results.files) } diff --git a/core/src/process/mod.rs b/core/src/process/mod.rs index c65bbfe..b63b231 100644 --- a/core/src/process/mod.rs +++ b/core/src/process/mod.rs @@ -21,11 +21,19 @@ pub fn normalize_concentration( } pub fn variance_concentration( - mean_concentration: &ArrayView1, concentration_record: &ArrayView2, full_volume: &ArrayView2, ) -> Array1 { - let mean_concentration = spatial_average_concentration(concentration_record, full_volume); + let mean_concentration = spatial_average_concentration(concentration_record, full_volume).insert_axis(Axis(1)); + ((concentration_record - mean_concentration).powi(2) * full_volume).sum_axis(Axis(1)) +} + + +pub fn variance_concentration_from_mean( + concentration_record: &ArrayView2, + mean_concentration: &ArrayView1, + full_volume: &ArrayView2, +) -> Array1 { ((concentration_record - mean_concentration).pow2() * full_volume).sum_axis(Axis(1)) } diff --git a/python_wrap/src/lib.rs b/python_wrap/src/lib.rs index 2dd7fa8..1360c84 100644 --- a/python_wrap/src/lib.rs +++ b/python_wrap/src/lib.rs @@ -1,11 +1,11 @@ use bcore::api::ModelEstimator; +use bcore::Weight; use bcore::{PostProcess, PostProcessReader}; use numpy::PyArray2; use numpy::{PyArray1, PyArray3}; use pyo3::exceptions::{PyRuntimeError, PyValueError}; use pyo3::prelude::*; use pyo3::types::PyList; -use bcore::Weight; /// A struct that wraps the `PostProcess` type for Python bindings. /// /// The `PythonPostProcess` struct is designed to provide a Python interface for the @@ -59,7 +59,6 @@ impl From for Phase { } } - /// An enum representing different phases . /// # Example /// ```python @@ -91,7 +90,6 @@ impl From for Estimator { } } - #[pymethods] impl PythonPostProcess { /// Creates a new instance of `PythonPostProcess`. @@ -126,13 +124,12 @@ impl PythonPostProcess { // return Ok(Self { inner: pp }); // } - - match PostProcess::new(folder, root) - { - Ok(pp) => {Ok(Self { inner: pp })}, - Err(err)=>{ - println!("{:?}",err); - Err(PyValueError::new_err("Error creating object"))} + match PostProcess::new(folder, root) { + Ok(pp) => Ok(Self { inner: pp }), + Err(err) => { + println!("{:?}", err); + Err(PyValueError::new_err("Error creating object")) + } } } @@ -140,6 +137,13 @@ impl PythonPostProcess { Ok(self.inner.get_property_names()) } + #[getter] + fn v_liquid(&self, py: Python<'_>)-> Py> + { + let e = self.inner.v_liquid().to_owned(); + PyArray2::from_owned_array(py, e).unbind() + } + /// Gets the time data /// /// This function provides access to the time data stored within the `PostProcess` object. @@ -185,14 +189,11 @@ impl PythonPostProcess { } #[getter] - fn weight(&self,py: Python<'_>) -> Py> { - match self.inner.weight() - { - Weight::Single(sw)=>{PyArray1::from_vec(py, vec![*sw]).unbind()}, - Weight::Multiple(mw)=>{PyArray1::from_vec(py, mw.clone()).unbind()} + fn weight(&self, py: Python<'_>) -> Py> { + match self.inner.weight() { + Weight::Single(sw) => PyArray1::from_vec(py, vec![*sw]).unbind(), + Weight::Multiple(mw) => PyArray1::from_vec(py, mw.clone()).unbind(), } - - } fn get_spatial_average_concentration( @@ -208,6 +209,19 @@ impl PythonPostProcess { PyArray1::from_owned_array(py, e).unbind() } + fn get_variance_concentration( + &self, + py: Python<'_>, + species: usize, + phase: Phase, + ) -> Py> { + if let Ok(e) = self.inner.get_variance_concentration(species, phase.into()) { + PyArray1::from_owned_array(py, e).unbind() + } else { + panic!("get_variance_concentration") + } + } + fn get_spatial_average_mtr(&self, py: Python<'_>, species: usize) -> Py> { match self.inner.get_spatial_average_mtr(species) { Ok(e) => PyArray1::from_owned_array(py, e).unbind(), @@ -228,16 +242,16 @@ impl PythonPostProcess { position: usize, phase: Phase, ) -> Py> { - if let Ok(e) = - self.inner - .get_time_average_concentration(species, position, phase.into()) + if let Ok(e) = self + .inner + .get_time_average_concentration(species, position, phase.into()) { return PyArray1::from_owned_array(py, e).unbind(); } panic!("") } - fn get_spatial_property(&self, py: Python<'_>,name: &str) -> Py>{ + fn get_spatial_property(&self, py: Python<'_>, name: &str) -> Py> { // TODO match self.inner.get_spatial_average_property(name) { Ok(e) => PyArray2::from_owned_array(py, e).unbind(), @@ -269,8 +283,6 @@ impl PythonPostProcess { Ok(e) => PyArray1::from_owned_array(py, e).unbind(), Err(e) => panic!("{}", e), } - - } fn get_properties(&self, py: Python<'_>, key: &str, i_export: usize) -> Py> { @@ -320,42 +332,45 @@ impl PythonPostProcess { } } - pub fn estimate(&self, etype: Estimator, key: &str, i_export: usize) -> PyResult - { - match self.inner.estimate(etype.into(),key,i_export) { + pub fn estimate(&self, etype: Estimator, key: &str, i_export: usize) -> PyResult { + match self.inner.estimate(etype.into(), key, i_export) { Ok(e) => Ok(e), Err(e) => Err(PyErr::new::(e.to_string())), } } - - fn get_spatial_average_biomass_concentration(&self,py: Python<'_>) -> PyResult>> - { + + fn get_spatial_average_biomass_concentration( + &self, + py: Python<'_>, + ) -> PyResult>> { match self.inner.get_spatial_average_biomass_concentration() { Ok(e) => Ok(PyArray1::from_owned_array(py, e).unbind()), Err(e) => Err(PyErr::new::(e.to_string())), } } - pub fn estimate_time(&self, py: Python<'_>,etype: Estimator, key: &str) -> PyResult>> - { - match self.inner.estimate_time(etype.into(),key) { + pub fn estimate_time( + &self, + py: Python<'_>, + etype: Estimator, + key: &str, + ) -> PyResult>> { + match self.inner.estimate_time(etype.into(), key) { Ok(e) => Ok(PyArray1::from_owned_array(py, e).unbind()), Err(e) => Err(PyErr::new::(e.to_string())), } } - pub fn get_csv_tallies(&self, py: Python<'_>)->PyResult - { + pub fn get_csv_tallies(&self, py: Python<'_>) -> PyResult { match self.inner.tallies() { Some(e) => Ok(e.to_csv().unwrap()), - None=> Err(PyErr::new::("No data")), + None => Err(PyErr::new::("No data")), } } fn get_tallies(&self, py: Python<'_>) -> Py> { match self.inner.tallies() { - Some(e) => - { + Some(e) => { let v = e.to_array().to_owned(); PyArray2::from_owned_array(py, v).unbind() } @@ -366,10 +381,10 @@ impl PythonPostProcess { #[pymodule] mod biomc_pp { - #[pymodule_export] - use super::Phase; #[pymodule_export] use super::Estimator; #[pymodule_export] + use super::Phase; + #[pymodule_export] use super::PythonPostProcess; } From 1649f993a1a7e545b227f2b386d4b3c053fc7087 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 16:44:19 +0200 Subject: [PATCH 08/14] ci: add doc --- .github/workflows/pages.yml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/pages.yml diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..97c633d --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,30 @@ +name: Deploy Documentation + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Generate Documentation + run: cargo doc --no-deps --document-private-items + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./target/doc From b19ee335276454638beceae0c33e708d2cfd71b6 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 16:48:46 +0200 Subject: [PATCH 09/14] ci: remove dep from doc --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 97c633d..9a0887e 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -21,7 +21,7 @@ jobs: override: true - name: Generate Documentation - run: cargo doc --no-deps --document-private-items + run: cargo doc --workspace --no-deps --document-private-items - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 From 65623238124371e858a627aebc4fe45b0cfc9317 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 16:50:26 +0200 Subject: [PATCH 10/14] ci: remove dep from doc --- .github/workflows/pages.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 9a0887e..7dd203e 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -13,6 +13,11 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y cmake libhdf5-dev + - name: Install Rust uses: actions-rs/toolchain@v1 with: From 2a266780def1049a9289fabdbd6d9c41e7cdb7e8 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 16:53:03 +0200 Subject: [PATCH 11/14] ci: fix --- .github/workflows/pages.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 7dd203e..c00e10d 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -28,8 +28,10 @@ jobs: - name: Generate Documentation run: cargo doc --workspace --no-deps --document-private-items - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + - name: Deploy Docs + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages publish_dir: ./target/doc + force_orphan: true From c919544d14a9b24ad7544369af320e70afde9a37 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 16:57:37 +0200 Subject: [PATCH 12/14] ci: fix --- .github/workflows/pages.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index c00e10d..581a14a 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,5 +1,6 @@ name: Deploy Documentation - +permissions: + contents: write on: push: branches: [ main ] From 8ff16d3fa8ac1ec987404d874b53fe55febb6c9e Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 17:11:13 +0200 Subject: [PATCH 13/14] chore: clippy --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- README.md | 1 + core/src/datamodel/main_file.rs | 1 - core/src/datamodel/mod.rs | 4 ++-- core/src/impl_unique.rs | 8 ++++---- examples/example_histogram.rs | 3 +-- examples/example_rust.rs | 2 +- python_wrap/src/lib.rs | 1 - 9 files changed, 13 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 998dc60..b8d4d3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ dependencies = [ [[package]] name = "bcore" -version = "0.4.2" +version = "0.4.4" dependencies = [ "csv", "hdf5", @@ -402,7 +402,7 @@ dependencies = [ [[package]] name = "examples" -version = "0.4.2" +version = "0.4.4" dependencies = [ "bcore", "ndarray 0.16.1", @@ -1072,7 +1072,7 @@ dependencies = [ [[package]] name = "python_wrap" -version = "0.4.2" +version = "0.4.4" dependencies = [ "bcore", "numpy", diff --git a/Cargo.toml b/Cargo.toml index 08b55f6..e2cde31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "2" [workspace.package] -version = "0.4.2" +version = "0.4.4" edition = "2021" license = "MIT" repository = "https://github.com/Benncs/BioMC_PostProcess/" diff --git a/README.md b/README.md index a985b6b..85de5f8 100644 --- a/README.md +++ b/README.md @@ -35,3 +35,4 @@ It also includes **PyO3 bindings** to provide a high-level Python API for end us ### LICENSE +This code is under [MIT](./LICENSE) license \ No newline at end of file diff --git a/core/src/datamodel/main_file.rs b/core/src/datamodel/main_file.rs index 8714582..9e05f24 100644 --- a/core/src/datamodel/main_file.rs +++ b/core/src/datamodel/main_file.rs @@ -5,7 +5,6 @@ use super::{tallies::Tallies, Dim, ResultGroup, Weight}; use std::collections::HashMap; -use ndarray::{ArrayView2}; ///File's mics section #[derive(Debug)] pub struct Misc { diff --git a/core/src/datamodel/mod.rs b/core/src/datamodel/mod.rs index 925fe90..3237db2 100644 --- a/core/src/datamodel/mod.rs +++ b/core/src/datamodel/mod.rs @@ -165,7 +165,7 @@ mod tests { #[test] fn test_vec_to_array_view3() { let vec = vec![1.0; 6]; // 2 * 3 dimensions - let dim = &Dim { 0: 2, 1: 3 }; + let dim = &Dim(2, 3); let nt = 1; let vec_copy = vec.clone(); let array_view = vec_to_array_view3(&vec, dim, nt); @@ -179,7 +179,7 @@ mod tests { #[should_panic] fn test_vec_to_array_view3_size_mismatch() { let vec = vec![1.0, 2.0, 3.0]; - let dim = &Dim { 0: 2, 1: 3 }; + let dim = &Dim(2, 3); let nt = 1; let _ = vec_to_array_view3(&vec, dim, nt); diff --git a/core/src/impl_unique.rs b/core/src/impl_unique.rs index 4071019..411a51a 100644 --- a/core/src/impl_unique.rs +++ b/core/src/impl_unique.rs @@ -5,10 +5,10 @@ use crate::datamodel::{ tallies::Tallies, vec_to_array_view2, vec_to_array_view3, Dim, Weight, }; use crate::process::{ - normalize_concentration, spatial_average_concentration, variance_concentration, Histogram, + spatial_average_concentration, variance_concentration, Histogram, }; use crate::{api::Estimator, api::Phase, error::ApiError}; -use ndarray::{s, Array1, Array2, ArrayView1, ArrayView2, ArrayView3, Axis}; +use ndarray::{s, Array1, Array2, ArrayView2, ArrayView3, Axis}; /// The `PostProcess` struct handles post-processing of simulation results. /// @@ -92,8 +92,8 @@ impl PostProcessReader for PostProcess { vec_to_array_view3(concentration, dim, nt); let vol = vec_to_array_view2(volume, nt, dim.0); let c_slice = &c.slice(s![.., .., species]); - let normalized_c = variance_concentration(&c_slice, &vol); - normalized_c + + variance_concentration(c_slice, &vol) } let records = &self.results.main.records; diff --git a/examples/example_histogram.rs b/examples/example_histogram.rs index a22d03c..618f212 100644 --- a/examples/example_histogram.rs +++ b/examples/example_histogram.rs @@ -1,6 +1,5 @@ use bcore::{PostProcess,PostProcessReader}; -use plotly::layout::{Shape, ShapeLine, ShapeType}; -use plotly::{ImageFormat, Scatter}; +use plotly::ImageFormat; use plotly::{Bar, Layout, Plot}; fn main() { diff --git a/examples/example_rust.rs b/examples/example_rust.rs index b4ac290..a99dbdd 100644 --- a/examples/example_rust.rs +++ b/examples/example_rust.rs @@ -8,7 +8,7 @@ fn main() { Some("/home-local/casale/Documents/thesis/simulations/meta/out_str_nu_redis_2".to_string()), ) { let x = obj.get_biomass_concentration().unwrap(); - let time: Vec = obj.time().into_iter().map(|t| t / 3600.).collect(); + let time: Vec = obj.time().iter().map(|t| t / 3600.).collect(); let xvec = x.slice(s![.., 0]).to_vec(); let mut plot = Plot::new(); diff --git a/python_wrap/src/lib.rs b/python_wrap/src/lib.rs index 1360c84..c498e2b 100644 --- a/python_wrap/src/lib.rs +++ b/python_wrap/src/lib.rs @@ -5,7 +5,6 @@ use numpy::PyArray2; use numpy::{PyArray1, PyArray3}; use pyo3::exceptions::{PyRuntimeError, PyValueError}; use pyo3::prelude::*; -use pyo3::types::PyList; /// A struct that wraps the `PostProcess` type for Python bindings. /// /// The `PythonPostProcess` struct is designed to provide a Python interface for the From f7bb956515ee2e0e6506360f0d9beeb614ca1656 Mon Sep 17 00:00:00 2001 From: Casale Benjamin Date: Wed, 21 May 2025 17:15:48 +0200 Subject: [PATCH 14/14] chore: readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 85de5f8..c4cffdf 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Project Overview -The **BioMC Postprocessor API** is a Rust module designed to facilitate interaction with post-processing simulation results via the BiomC API. +The **BioMC Postprocessor API** is a Rust API designed to interact with and perform post-processing on simulation results obtained with the [BioMC code](https://github.com/Benncs/BioCMA-MCST). It also includes **PyO3 bindings** to provide a high-level Python API for end users.