From 758a660e16519846bc7f6a4014af5357f116ff6b Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Wed, 31 May 2023 13:52:39 -0600 Subject: [PATCH 01/27] dropped in a TODO for Asmaa --- rust/fastsim-core/src/simdrivelabel.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index b701a6c5..205c7a84 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -12,6 +12,8 @@ use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +// TODO: Asmaa, this struct (and maybe structs that are in its fields) need to +// be exposed to Python using the `add_pyo3_api` attribute-style procedural macro /// Label fuel economy values pub struct LabelFe { pub veh: vehicle::RustVehicle, From aa0a8860bf3a365e1acfbd2ce3a27e054db34ffe Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Mon, 12 Jun 2023 12:46:26 -0600 Subject: [PATCH 02/27] add _py version --- rust/fastsim-core/src/fastsim | 1 + rust/fastsim-core/src/vehicle.rs | 92 +++++++++++++++++++------------- 2 files changed, 57 insertions(+), 36 deletions(-) create mode 160000 rust/fastsim-core/src/fastsim diff --git a/rust/fastsim-core/src/fastsim b/rust/fastsim-core/src/fastsim new file mode 160000 index 00000000..26edd86c --- /dev/null +++ b/rust/fastsim-core/src/fastsim @@ -0,0 +1 @@ +Subproject commit 26edd86c100a03fc31586da2e93f5cfbd4fa4d63 diff --git a/rust/fastsim-core/src/vehicle.rs b/rust/fastsim-core/src/vehicle.rs index 14c16b8a..5fb3f55e 100644 --- a/rust/fastsim-core/src/vehicle.rs +++ b/rust/fastsim-core/src/vehicle.rs @@ -49,44 +49,64 @@ lazy_static! { self.mc_peak_eff() } - // TODO: refactor this to have a non-py and `_py` version - #[setter] - pub fn set_mc_peak_eff(&mut self, new_peak: f64) { - let mc_max_eff = ndarrmax(&self.mc_eff_array); - self.mc_eff_array *= new_peak / mc_max_eff; - let mc_max_full_eff = arrmax(&self.mc_full_eff_array); - self.mc_full_eff_array = self - .mc_full_eff_array - .iter() - .map(|e: &f64| -> f64 { e * (new_peak / mc_max_full_eff) }) - .collect(); - } - - #[getter] - pub fn get_max_fc_eff_kw(&self) -> f64 { - self.max_fc_eff_kw() - } + // TODO: refactor this to have a non-py and `_py` version + #[setter] + pub fn set_mc_peak_eff(&mut self, new_peak: f64) { + let mc_max_eff = ndarrmax(&self.mc_eff_array); + self.mc_eff_array *= new_peak / mc_max_eff; + let mc_max_full_eff = arrmax(&self.mc_full_eff_array); + self.mc_full_eff_array = self + .mc_full_eff_array + .iter() + .map(|e: &f64| -> f64 { e * (new_peak / mc_max_full_eff) }) + .collect(); + } - #[getter] - pub fn get_fc_peak_eff(&self) -> f64 { - self.fc_peak_eff() - } + #[getter] + pub fn get_max_fc_eff_kw(&self) -> f64 { + self.max_fc_eff_kw() + } + + #[pyo3(name = "set_mc_peak_eff")] + pub fn set_mc_peak_eff_py(&mut self, new_peak: f64) { + self.set_mc_peak_eff(new_peak); + } + + #[pyo3(name = "get_max_fc_eff_kw")] + pub fn get_max_fc_eff_kw_py(&self) -> f64 { + self.get_max_fc_eff_kw() + } + + #[getter] + pub fn get_fc_peak_eff(&self) -> f64 { + self.fc_peak_eff() + } - #[setter] - pub fn set_fc_peak_eff(&mut self, new_peak: f64) { - let old_fc_peak_eff = self.fc_peak_eff(); - let multiplier = new_peak / old_fc_peak_eff; - self.fc_eff_array = self - .fc_eff_array - .iter() - .map(|eff: &f64| -> f64 { eff * multiplier }) - .collect(); - let new_fc_peak_eff = self.fc_peak_eff(); - let eff_map_multiplier = new_peak / new_fc_peak_eff; - self.fc_eff_map = self - .fc_eff_map - .map(|eff| -> f64 { eff * eff_map_multiplier }); - } + #[setter] + pub fn set_fc_peak_eff(&mut self, new_peak: f64) { + let old_fc_peak_eff = self.fc_peak_eff(); + let multiplier = new_peak / old_fc_peak_eff; + self.fc_eff_array = self + .fc_eff_array + .iter() + .map(|eff: &f64| -> f64 { eff * multiplier }) + .collect(); + let new_fc_peak_eff = self.fc_peak_eff(); + let eff_map_multiplier = new_peak / new_fc_peak_eff; + self.fc_eff_map = self + .fc_eff_map + .map(|eff| -> f64 { eff * eff_map_multiplier }); + } + + #[pyo3(name = "get_fc_peak_eff")] + pub fn get_fc_peak_eff_py(&self) -> f64 { + self.get_fc_peak_eff() + } + + #[pyo3(name = "set_fc_peak_eff")] + pub fn set_fc_peak_eff_py(&mut self, new_peak: f64) { + self.set_fc_peak_eff(new_peak); + } #[pyo3(name = "set_derived")] pub fn set_derived_py(&mut self) { From 916c0c0400d6e298e2c99cb6e9f35a8edf09fd1a Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 13 Jun 2023 10:08:56 -0600 Subject: [PATCH 03/27] refactored to separate pyo3 getter and setter functions from core functions --- rust/fastsim-core/src/params.rs | 3 +- rust/fastsim-core/src/simdrivelabel.rs | 2 +- rust/fastsim-core/src/vehicle.rs | 106 +++++++++++-------------- 3 files changed, 51 insertions(+), 60 deletions(-) diff --git a/rust/fastsim-core/src/params.rs b/rust/fastsim-core/src/params.rs index 69c8d8fa..95e7194c 100644 --- a/rust/fastsim-core/src/params.rs +++ b/rust/fastsim-core/src/params.rs @@ -151,7 +151,8 @@ pub struct AdjCoef { impl Default for RustLongParams { fn default() -> Self { - let long_params_str: &str = include_str!("../../../python/fastsim/resources/longparams.json"); + let long_params_str: &str = + include_str!("../../../python/fastsim/resources/longparams.json"); let long_params: Self = from_str(long_params_str).unwrap(); return long_params; } diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 205c7a84..1c78d086 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -12,7 +12,7 @@ use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -// TODO: Asmaa, this struct (and maybe structs that are in its fields) need to +// TODO: Asmaa, this struct (and maybe structs that are in its fields) need to // be exposed to Python using the `add_pyo3_api` attribute-style procedural macro /// Label fuel economy values pub struct LabelFe { diff --git a/rust/fastsim-core/src/vehicle.rs b/rust/fastsim-core/src/vehicle.rs index 5fb3f55e..effd29bc 100644 --- a/rust/fastsim-core/src/vehicle.rs +++ b/rust/fastsim-core/src/vehicle.rs @@ -37,6 +37,8 @@ lazy_static! { #[add_pyo3_api( #[pyo3(name = "set_veh_mass")] pub fn set_veh_mass_py(&mut self) { + // TODO: not urgent, but I think it'd better for all instances + // of `set_veh_mass` to be `update_veh_mass` self.set_veh_mass() } @@ -49,64 +51,25 @@ lazy_static! { self.mc_peak_eff() } - // TODO: refactor this to have a non-py and `_py` version - #[setter] - pub fn set_mc_peak_eff(&mut self, new_peak: f64) { - let mc_max_eff = ndarrmax(&self.mc_eff_array); - self.mc_eff_array *= new_peak / mc_max_eff; - let mc_max_full_eff = arrmax(&self.mc_full_eff_array); - self.mc_full_eff_array = self - .mc_full_eff_array - .iter() - .map(|e: &f64| -> f64 { e * (new_peak / mc_max_full_eff) }) - .collect(); - } + #[setter("mc_peak_eff")] + pub fn set_mc_peak_eff_py(&mut self, new_peak: f64) { + self.set_mc_peak_eff(new_peak); + } + + #[getter] + pub fn get_max_fc_eff_kw(&self) -> f64 { + self.max_fc_eff_kw() + } - #[getter] - pub fn get_max_fc_eff_kw(&self) -> f64 { - self.max_fc_eff_kw() - } - - #[pyo3(name = "set_mc_peak_eff")] - pub fn set_mc_peak_eff_py(&mut self, new_peak: f64) { - self.set_mc_peak_eff(new_peak); - } - - #[pyo3(name = "get_max_fc_eff_kw")] - pub fn get_max_fc_eff_kw_py(&self) -> f64 { - self.get_max_fc_eff_kw() - } - - #[getter] - pub fn get_fc_peak_eff(&self) -> f64 { - self.fc_peak_eff() - } + #[setter("fc_peak_eff")] + pub fn set_fc_peak_eff_py(&mut self, new_peak: f64) { + self.set_fc_peak_eff(new_peak); + } - #[setter] - pub fn set_fc_peak_eff(&mut self, new_peak: f64) { - let old_fc_peak_eff = self.fc_peak_eff(); - let multiplier = new_peak / old_fc_peak_eff; - self.fc_eff_array = self - .fc_eff_array - .iter() - .map(|eff: &f64| -> f64 { eff * multiplier }) - .collect(); - let new_fc_peak_eff = self.fc_peak_eff(); - let eff_map_multiplier = new_peak / new_fc_peak_eff; - self.fc_eff_map = self - .fc_eff_map - .map(|eff| -> f64 { eff * eff_map_multiplier }); - } - - #[pyo3(name = "get_fc_peak_eff")] - pub fn get_fc_peak_eff_py(&self) -> f64 { - self.get_fc_peak_eff() - } - - #[pyo3(name = "set_fc_peak_eff")] - pub fn set_fc_peak_eff_py(&mut self, new_peak: f64) { - self.set_fc_peak_eff(new_peak); - } + #[getter] + pub fn get_fc_peak_eff(&self) -> f64 { + self.fc_peak_eff() + } #[pyo3(name = "set_derived")] pub fn set_derived_py(&mut self) { @@ -161,7 +124,7 @@ pub struct RustVehicle { #[serde(alias = "gliderKg")] #[validate(range(min = 0))] pub glider_kg: f64, - /// Vehicle center of mass height, $m$ + /// Vehicle center of mass height, $m$ /// **NOTE:** positive for FWD, negative for RWD, AWD, 4WD #[serde(alias = "vehCgM")] pub veh_cg_m: f64, @@ -211,7 +174,7 @@ pub struct RustVehicle { /// Fuel converter efficiency map #[serde(default)] pub fc_eff_map: Array1, - /// Fuel converter efficiency type, one of \[[SI](SI), [ATKINSON](ATKINSON), [DIESEL](DIESEL), [H2FC](H2FC), [HD_DIESEL](HD_DIESEL)\] + /// Fuel converter efficiency type, one of \[[SI](SI), [ATKINSON](ATKINSON), [DIESEL](DIESEL), [H2FC](H2FC), [HD_DIESEL](HD_DIESEL)\] /// Used for calculating [fc_eff_map](RustVehicle::fc_eff_map), and other calculations if H2FC #[serde(alias = "fcEffType")] #[validate(regex( @@ -588,6 +551,7 @@ impl RustVehicle { arrmax(&self.mc_full_eff_array) } + /// Returns _first_ FC output power at which peak efficiency occurs pub fn max_fc_eff_kw(&self) -> f64 { let fc_eff_arr_max_i = first_eq(&self.fc_eff_array, arrmax(&self.fc_eff_array)).unwrap_or(0); @@ -598,6 +562,32 @@ impl RustVehicle { arrmax(&self.fc_eff_array) } + pub fn set_mc_peak_eff(&mut self, new_peak: f64) { + let mc_max_eff = ndarrmax(&self.mc_eff_array); + self.mc_eff_array *= new_peak / mc_max_eff; + let mc_max_full_eff = arrmax(&self.mc_full_eff_array); + self.mc_full_eff_array = self + .mc_full_eff_array + .iter() + .map(|e: &f64| -> f64 { e * (new_peak / mc_max_full_eff) }) + .collect(); + } + + pub fn set_fc_peak_eff(&mut self, new_peak: f64) { + let old_fc_peak_eff = self.fc_peak_eff(); + let multiplier = new_peak / old_fc_peak_eff; + self.fc_eff_array = self + .fc_eff_array + .iter() + .map(|eff: &f64| -> f64 { eff * multiplier }) + .collect(); + let new_fc_peak_eff = self.fc_peak_eff(); + let eff_map_multiplier = new_peak / new_fc_peak_eff; + self.fc_eff_map = self + .fc_eff_map + .map(|eff| -> f64 { eff * eff_map_multiplier }); + } + /// Sets derived parameters: /// - `no_elec_sys` /// - `no_elec_aux` From 0971c9f363ef61e0445d4ab64bc87370d2734bd1 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 13 Jun 2023 11:24:40 -0600 Subject: [PATCH 04/27] renamed function to remove warning --- rust/fastsim-cli/src/bin/fastsim-cli.rs | 6 +++--- rust/fastsim-core/src/vehicle.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust/fastsim-cli/src/bin/fastsim-cli.rs b/rust/fastsim-cli/src/bin/fastsim-cli.rs index d15c95a9..34a3bfa5 100644 --- a/rust/fastsim-cli/src/bin/fastsim-cli.rs +++ b/rust/fastsim-cli/src/bin/fastsim-cli.rs @@ -246,9 +246,9 @@ pub fn main() { let (veh_string, pwr_out_perc, h2share) = json_rewrite(veh_string); hd_h2_diesel_ice_h2share = h2share; fc_pwr_out_perc = pwr_out_perc; - RustVehicle::from_str(&veh_string) + RustVehicle::from_json_str(&veh_string) } else { - RustVehicle::from_str(&veh_string) + RustVehicle::from_json_str(&veh_string) } } else if let Some(veh_file_path) = fastsim_api.veh_file { if is_adopt || is_adopt_hd { @@ -256,7 +256,7 @@ pub fn main() { let (vehstring, pwr_out_perc, h2share) = json_rewrite(vehstring); hd_h2_diesel_ice_h2share = h2share; fc_pwr_out_perc = pwr_out_perc; - RustVehicle::from_str(&vehstring) + RustVehicle::from_json_str(&vehstring) } else { RustVehicle::from_file(&veh_file_path) } diff --git a/rust/fastsim-core/src/vehicle.rs b/rust/fastsim-core/src/vehicle.rs index effd29bc..be20138d 100644 --- a/rust/fastsim-core/src/vehicle.rs +++ b/rust/fastsim-core/src/vehicle.rs @@ -917,7 +917,7 @@ impl RustVehicle { v } - pub fn from_str(filename: &str) -> Result { + pub fn from_json_str(filename: &str) -> Result { let mut veh_res: Result = Ok(serde_json::from_str(filename)?); veh_res.as_mut().unwrap().set_derived()?; veh_res @@ -1095,7 +1095,7 @@ mod tests { }) .collect(), modern_max: MODERN_MAX, - mc_eff_array: mc_eff_map.clone(), + mc_eff_array: mc_eff_map, mc_kw_in_array: [0.0; 101] .iter() .enumerate() From 0f92ee54348d63060a659938b3a41dceb6e76f57 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:34:39 -0600 Subject: [PATCH 05/27] modify with add pyo3 --- rust/fastsim-core/src/simdrivelabel.rs | 65 ++++++++++++++------------ 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index b5bb0c3a..205c7a84 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -147,7 +147,7 @@ pub fn get_label_fe( veh: &vehicle::RustVehicle, full_detail: Option, verbose: Option, -) -> anyhow::Result<(LabelFe, Option>)> { +) -> Result<(LabelFe, Option>), anyhow::Error> { // Generates label fuel economy (FE) values for a provided vehicle. // // Arguments: @@ -239,9 +239,11 @@ pub fn get_label_fe( for (k, val) in sd.iter_mut() { val.sim_drive(None, None)?; - let key = String::from(*k); + let key = String::from(k.clone()); let trace_miss_speed_mph = val.trace_miss_speed_mps * MPH_PER_MPS; - if (key == *"udds" || key == *"hwy") && trace_miss_speed_mph > max_trace_miss_in_mph { + if (key == String::from("udds") || key == String::from("hwy")) + && trace_miss_speed_mph > max_trace_miss_in_mph + { max_trace_miss_in_mph = trace_miss_speed_mph; } } @@ -326,9 +328,9 @@ pub fn get_label_fe( out.adj_comb_kwh_per_mi = 0.55 * out.adj_udds_kwh_per_mi + 0.45 * out.adj_hwy_kwh_per_mi; - out.adj_udds_kwh_per_mi *= CHG_EFF; - out.adj_hwy_kwh_per_mi *= CHG_EFF; - out.adj_comb_kwh_per_mi *= CHG_EFF; + out.adj_udds_kwh_per_mi = out.adj_udds_kwh_per_mi * CHG_EFF; + out.adj_hwy_kwh_per_mi = out.adj_hwy_kwh_per_mi * CHG_EFF; + out.adj_comb_kwh_per_mi = out.adj_comb_kwh_per_mi * CHG_EFF; // range for combined city/highway out.net_range_miles = veh.ess_max_kwh / out.adj_comb_ess_kwh_per_mi; @@ -403,14 +405,14 @@ pub fn get_label_fe( if full_detail.unwrap_or(false) && verbose.unwrap_or(false) { println!("{:#?}", out); - Ok((out, Some(sd))) + return Ok((out, Some(sd))); } else if full_detail.unwrap_or(false) { - Ok((out, Some(sd))) + return Ok((out, Some(sd))); } else if verbose.unwrap_or(false) { println!("{:#?}", out); - Ok((out, None)) + return Ok((out, None)); } else { - Ok((out, None)) + return Ok((out, None)); } } @@ -434,18 +436,17 @@ pub fn get_label_fe_phev( // props : RustPhysicalProperties // // Returns label fuel economy values for PHEV as a struct. - let mut phev_calcs = LabelFePHEV { - regen_soc_buffer: min( - ((0.5 * veh.veh_kg * ((60. * (1. / MPH_PER_MPS)).powi(2))) - * (1. / 3600.) - * (1. / 1000.) - * veh.max_regen - * veh.mc_peak_eff()) - / veh.ess_max_kwh, - (veh.max_soc - veh.min_soc) / 2.0, - ), - ..LabelFePHEV::default() - }; + let mut phev_calcs: LabelFePHEV = LabelFePHEV::default(); + + phev_calcs.regen_soc_buffer = min( + ((0.5 * veh.veh_kg * ((60. * (1. / MPH_PER_MPS)).powi(2))) + * (1. / 3600.) + * (1. / 1000.) + * veh.max_regen + * veh.mc_peak_eff()) + / veh.ess_max_kwh, + (veh.max_soc - veh.min_soc) / 2.0, + ); // charge sustaining behavior for (key, sd_val) in sd.iter_mut() { @@ -583,17 +584,18 @@ pub fn get_label_fe_phev( * (1.0 - sim_params.max_epa_adj), )); - for (c, lab_iter_kwh_per_mi) in phev_calc.lab_iter_kwh_per_mi.iter().enumerate() { - if *lab_iter_kwh_per_mi == 0.0 { + for c in 0..phev_calc.lab_iter_kwh_per_mi.len() { + if phev_calc.lab_iter_kwh_per_mi[c] == 0.0 { adj_iter_kwh_per_mi_vals[c] = 0.0; } else { adj_iter_kwh_per_mi_vals[c] = (1.0 / max( 1.0 / (adj_params.city_intercept + (adj_params.city_slope - / ((1.0 / lab_iter_kwh_per_mi) * props.kwh_per_gge))), + / ((1.0 / phev_calc.lab_iter_kwh_per_mi[c]) + * props.kwh_per_gge))), (1.0 - sim_params.max_epa_adj) - * ((1.0 / lab_iter_kwh_per_mi) * props.kwh_per_gge), + * ((1.0 / phev_calc.lab_iter_kwh_per_mi[c]) * props.kwh_per_gge), )) * props.kwh_per_gge; } } @@ -613,17 +615,18 @@ pub fn get_label_fe_phev( * (1.0 - sim_params.max_epa_adj), )); - for (c, lab_iter_kwh_per_mi) in phev_calc.lab_iter_kwh_per_mi.iter().enumerate() { - if *lab_iter_kwh_per_mi == 0.0 { + for c in 0..phev_calc.lab_iter_kwh_per_mi.len() { + if phev_calc.lab_iter_kwh_per_mi[c] == 0.0 { adj_iter_kwh_per_mi_vals[c] = 0.0; } else { adj_iter_kwh_per_mi_vals[c] = (1.0 / max( 1.0 / (adj_params.hwy_intercept + (adj_params.hwy_slope - / ((1.0 / lab_iter_kwh_per_mi) * props.kwh_per_gge))), + / ((1.0 / phev_calc.lab_iter_kwh_per_mi[c]) + * props.kwh_per_gge))), (1.0 - sim_params.max_epa_adj) - * ((1.0 / lab_iter_kwh_per_mi) * props.kwh_per_gge), + * ((1.0 / phev_calc.lab_iter_kwh_per_mi[c]) * props.kwh_per_gge), )) * props.kwh_per_gge; } } @@ -706,7 +709,7 @@ pub fn get_label_fe_phev( }; } - Ok(phev_calcs) + return Ok(phev_calcs); } #[cfg(test)] From 150ed85a7b885db12a86cc1574092f8557ae9511 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Tue, 20 Jun 2023 12:49:30 -0600 Subject: [PATCH 06/27] add pyo3 --- rust/fastsim-core/src/simdrivelabel4.rs | 148 ++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 rust/fastsim-core/src/simdrivelabel4.rs diff --git a/rust/fastsim-core/src/simdrivelabel4.rs b/rust/fastsim-core/src/simdrivelabel4.rs new file mode 100644 index 00000000..8c26e57f --- /dev/null +++ b/rust/fastsim-core/src/simdrivelabel4.rs @@ -0,0 +1,148 @@ +// Modify the existing code from 1-125 to add pyo3 + +//! Module containing classes and methods for calculating label fuel economy. + +use ndarray::Array; +use std::collections::HashMap; + +// crate local +use crate::cycle::RustCycle; +use crate::imports::*; +use crate::params::*; + +use crate::proc_macros::{add_pyo3_api, ApproxEq}; +#[cfg(feature = "pyo3")] +use crate::pyo3imports::*; + +use crate::simdrive::{RustSimDrive, RustSimDriveParams}; +use crate::vehicle; + + +#[pyclass] +#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +/// Label fuel economy values +pub struct LabelFe { + pub veh: vehicle::RustVehicle, + pub adj_params: AdjCoef, + pub lab_udds_mpgge: f64, + pub lab_hwy_mpgge: f64, + pub lab_comb_mpgge: f64, + pub lab_udds_kwh_per_mi: f64, + pub lab_hwy_kwh_per_mi: f64, + pub lab_comb_kwh_per_mi: f64, + pub adj_udds_mpgge: f64, + pub adj_hwy_mpgge: f64, + pub adj_comb_mpgge: f64, + pub adj_udds_kwh_per_mi: f64, + pub adj_hwy_kwh_per_mi: f64, + pub adj_comb_kwh_per_mi: f64, + pub adj_udds_ess_kwh_per_mi: f64, + pub adj_hwy_ess_kwh_per_mi: f64, + pub adj_comb_ess_kwh_per_mi: f64, + /// Range for combined city/highway + pub net_range_miles: f64, + /// Utility factor + pub uf: f64, + pub net_accel: f64, + pub res_found: String, + pub phev_calcs: Option, + pub adj_cs_comb_mpgge: Option, + pub adj_cd_comb_mpgge: Option, + pub net_phev_cd_miles: Option, + pub trace_miss_speed_mph: f64, +} + +#[pyclass] +#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +/// Label fuel economy values for a PHEV vehicle +pub struct LabelFePHEV { + pub regen_soc_buffer: f64, + pub udds: PHEVCycleCalc, + pub hwy: PHEVCycleCalc, +} + +#[pyclass] +#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +/// Label fuel economy calculations for a specific cycle of a PHEV vehicle +pub struct PHEVCycleCalc { + /// Charge depletion battery kW-hr + pub cd_ess_kwh: f64, + pub cd_ess_kwh_per_mi: f64, + /// Charge depletion fuel gallons + pub cd_fs_gal: f64, + pub cd_fs_kwh: f64, + pub cd_mpg: f64, + /// Number of cycles in charge depletion mode, up to transition + pub cd_cycs: f64, + pub cd_miles: f64, + pub cd_lab_mpg: f64, + pub cd_adj_mpg: f64, + /// Fraction of transition cycles spent in charge depletion + pub cd_frac_in_trans: f64, + /// SOC change during 1 cycle + pub trans_init_soc: f64, + /// charge depletion battery kW-hr + pub trans_ess_kwh: f64, + pub trans_ess_kwh_per_mi: f64, + pub trans_fs_gal: f64, + pub trans_fs_kwh: f64, + /// charge sustaining battery kW-hr + pub cs_ess_kwh: f64, + pub cs_ess_kwh_per_mi: f64, + /// charge sustaining fuel gallons + pub cs_fs_gal: f64, + pub cs_fs_kwh: f64, + pub cs_mpg: f64, + pub lab_mpgge: f64, + pub lab_kwh_per_mi: f64, + pub lab_uf: f64, + pub lab_uf_gpm: Array1, + pub lab_iter_uf: Array1, + pub lab_iter_uf_kwh_per_mi: Array1, + pub lab_iter_kwh_per_mi: Array1, + pub adj_iter_mpgge: Array1, + pub adj_iter_kwh_per_mi: Array1, + pub adj_iter_cd_miles: Array1, + pub adj_iter_uf: Array1, + pub adj_iter_uf_gpm: Vec, + pub adj_iter_uf_kwh_per_mi: Array1, + pub adj_cd_miles: f64, + pub adj_cd_mpgge: f64, + pub adj_cs_mpgge: f64, + pub adj_uf: f64, + pub adj_mpgge: f64, + pub adj_kwh_per_mi: f64, + pub adj_ess_kwh_per_mi: f64, + pub delta_soc: f64, + /// Total number of miles in charge depletion mode, assuming constant kWh_per_mi + pub total_cd_miles: f64, +} + + +#[cfg(feature = "pyo3")] +#[pymodule] +fn label_fuel_economy(_py: Python, m: &PyModule) -> PyResult<()> { + // Register the make_accel_trace_py function + #[pyfn(m, "make_accel_trace")] + fn make_accel_trace_py() -> PyResult { + let accel_cyc_secs = Array::range(0., 300., 0.1); + let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + accel_cyc_mps[0] = 0.0; + + let rust_cycle = RustCycle::new( + accel_cyc_secs.to_vec(), + accel_cyc_mps.to_vec(), + Array::zeros(accel_cyc_secs.len()).to_vec(), + Array::zeros(accel_cyc_secs.len()).to_vec(), + String::from("accel"), + ); + + Ok(rust_cycle) + } + + // Add the make_accel_trace_py function to the module + m.add_function(wrap_pyfunction!(make_accel_trace_py, m)?)?; + + // Return Ok(()) to indicate successful execution + Ok(()) +} From 519f9bc325ac93e8ed9186d9d257b64ce58bf28e Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Tue, 20 Jun 2023 13:50:09 -0600 Subject: [PATCH 07/27] add pyo3 --- rust/fastsim-core/src/vehicle.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rust/fastsim-core/src/vehicle.rs b/rust/fastsim-core/src/vehicle.rs index 2a6d9d69..53d5e510 100644 --- a/rust/fastsim-core/src/vehicle.rs +++ b/rust/fastsim-core/src/vehicle.rs @@ -917,9 +917,7 @@ impl RustVehicle { v } - pub fn from_json_str(filename: &str) -> Result { - let mut veh_res: Result = Ok(serde_json::from_str(filename)?); veh_res.as_mut().unwrap().set_derived()?; veh_res From 4aa3d9eb311f7eafb0ef3abd19f47c18ae5f590d Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:58:34 -0600 Subject: [PATCH 08/27] changes to add_pyo3_api --- rust/fastsim-core/src/simdrivelabel4.rs | 386 ++++++++++++++++++------ 1 file changed, 295 insertions(+), 91 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel4.rs b/rust/fastsim-core/src/simdrivelabel4.rs index 8c26e57f..d381bdaf 100644 --- a/rust/fastsim-core/src/simdrivelabel4.rs +++ b/rust/fastsim-core/src/simdrivelabel4.rs @@ -1,6 +1,4 @@ -// Modify the existing code from 1-125 to add pyo3 - -//! Module containing classes and methods for calculating label fuel economy. +// Modify the existing code from 1-56 to add pyo3 use ndarray::Array; use std::collections::HashMap; @@ -17,10 +15,8 @@ use crate::pyo3imports::*; use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; - -#[pyclass] #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -/// Label fuel economy values +#[add_pyo3_api] pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, @@ -39,9 +35,7 @@ pub struct LabelFe { pub adj_udds_ess_kwh_per_mi: f64, pub adj_hwy_ess_kwh_per_mi: f64, pub adj_comb_ess_kwh_per_mi: f64, - /// Range for combined city/highway pub net_range_miles: f64, - /// Utility factor pub uf: f64, pub net_accel: f64, pub res_found: String, @@ -52,8 +46,270 @@ pub struct LabelFe { pub trace_miss_speed_mph: f64, } -#[pyclass] +impl LabelFe { + #[getter] + pub fn get_veh(&self) -> &vehicle::RustVehicle { + &self.veh + } + + #[setter] + pub fn set_veh_py(&mut self, new_veh: vehicle::RustVehicle) { + self.veh = new_veh; + } + + #[getter] + pub fn get_adj_params(&self) -> &AdjCoef { + &self.adj_params + } + + #[setter] + pub fn set_adj_params_py(&mut self, new_params: AdjCoef) { + self.adj_params = new_params; + } + + #[getter] + pub fn get_lab_udds_mpgge(&self) -> f64 { + self.lab_udds_mpgge + } + + #[setter] + pub fn set_lab_udds_mpgge_py(&mut self, new_value: f64) { + self.lab_udds_mpgge = new_value; + } + + #[getter] + pub fn get_lab_hwy_mpgge(&self) -> f64 { + self.lab_hwy_mpgge + } + + #[setter] + pub fn set_lab_hwy_mpgge_py(&mut self, new_value: f64) { + self.lab_hwy_mpgge = new_value; + } + + #[getter] + pub fn get_lab_comb_mpgge(&self) -> f64 { + self.lab_comb_mpgge + } + + #[setter] + pub fn set_lab_comb_mpgge_py(&mut self, new_value: f64) { + self.lab_comb_mpgge = new_value; + } + + #[getter] + pub fn get_lab_udds_kwh_per_mi(&self) -> f64 { + self.lab_udds_kwh_per_mi + } + + #[setter] + pub fn set_lab_udds_kwh_per_mi_py(&mut self, new_value: f64) { + self.lab_udds_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_lab_hwy_kwh_per_mi(&self) -> f64 { + self.lab_hwy_kwh_per_mi + } + + #[setter] + pub fn set_lab_hwy_kwh_per_mi_py(&mut self, new_value: f64) { + self.lab_hwy_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_lab_comb_kwh_per_mi(&self) -> f64 { + self.lab_comb_kwh_per_mi + } + + #[setter] + pub fn set_lab_comb_kwh_per_mi_py(&mut self, new_value: f64) { + self.lab_comb_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_adj_udds_mpgge(&self) -> f64 { + self.adj_udds_mpgge + } + + #[setter] + pub fn set_adj_udds_mpgge_py(&mut self, new_value: f64) { + self.adj_udds_mpgge = new_value; + } + + #[getter] + pub fn get_adj_hwy_mpgge(&self) -> f64 { + self.adj_hwy_mpgge + } + + #[setter] + pub fn set_adj_hwy_mpgge_py(&mut self, new_value: f64) { + self.adj_hwy_mpgge = new_value; + } + + #[getter] + pub fn get_adj_comb_mpgge(&self) -> f64 { + self.adj_comb_mpgge + } + + #[setter] + pub fn set_adj_comb_mpgge_py(&mut self, new_value: f64) { + self.adj_comb_mpgge = new_value; + } + + #[getter] + pub fn get_adj_udds_kwh_per_mi(&self) -> f64 { + self.adj_udds_kwh_per_mi + } + + #[setter] + pub fn set_adj_udds_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_udds_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_adj_hwy_kwh_per_mi(&self) -> f64 { + self.adj_hwy_kwh_per_mi + } + + #[setter] + pub fn set_adj_hwy_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_hwy_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_adj_comb_kwh_per_mi(&self) -> f64 { + self.adj_comb_kwh_per_mi + } + + #[setter] + pub fn set_adj_comb_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_comb_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_adj_udds_ess_kwh_per_mi(&self) -> f64 { + self.adj_udds_ess_kwh_per_mi + } + + #[setter] + pub fn set_adj_udds_ess_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_udds_ess_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_adj_hwy_ess_kwh_per_mi(&self) -> f64 { + self.adj_hwy_ess_kwh_per_mi + } + + #[setter] + pub fn set_adj_hwy_ess_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_hwy_ess_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_adj_comb_ess_kwh_per_mi(&self) -> f64 { + self.adj_comb_ess_kwh_per_mi + } + + #[setter] + pub fn set_adj_comb_ess_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_comb_ess_kwh_per_mi = new_value; + } + + #[getter] + pub fn get_net_range_miles(&self) -> f64 { + self.net_range_miles + } + + #[setter] + pub fn set_net_range_miles_py(&mut self, new_value: f64) { + self.net_range_miles = new_value; + } + + #[getter] + pub fn get_uf(&self) -> f64 { + self.uf + } + + #[setter] + pub fn set_uf_py(&mut self, new_value: f64) { + self.uf = new_value; + } + + #[getter] + pub fn get_net_accel(&self) -> f64 { + self.net_accel + } + + #[setter] + pub fn set_net_accel_py(&mut self, new_value: f64) { + self.net_accel = new_value; + } + + #[getter] + pub fn get_res_found(&self) -> &str { + &self.res_found + } + + #[setter] + pub fn set_res_found_py(&mut self, new_value: String) { + self.res_found = new_value; + } + + #[getter] + pub fn get_phev_calcs(&self) -> Option<&LabelFePHEV> { + self.phev_calcs.as_ref() + } + + #[setter] + pub fn set_phev_calcs_py(&mut self, new_value: Option) { + self.phev_calcs = new_value; + } + + #[getter] + pub fn get_adj_cs_comb_mpgge(&self) -> Option { + self.adj_cs_comb_mpgge + } + + #[setter] + pub fn set_adj_cs_comb_mpgge_py(&mut self, new_value: Option) { + self.adj_cs_comb_mpgge = new_value; + } + + #[getter] + pub fn get_adj_cd_comb_mpgge(&self) -> Option { + self.adj_cd_comb_mpgge + } + + #[setter] + pub fn set_adj_cd_comb_mpgge_py(&mut self, new_value: Option) { + self.adj_cd_comb_mpgge = new_value; + } + + #[getter] + pub fn get_net_phev_cd_miles(&self) -> Option { + self.net_phev_cd_miles + } + + #[setter] + pub fn set_net_phev_cd_miles_py(&mut self, new_value: Option) { + self.net_phev_cd_miles = new_value; + } + + #[getter] + pub fn get_trace_miss_speed_mph(&self) -> f64 { + self.trace_miss_speed_mph + } + + #[setter] + pub fn set_trace_miss_speed_mph_py(&mut self, new_value: f64) { + self.trace_miss_speed_mph = new_value; + } +} + #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +#[add_pyo3_api] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { pub regen_soc_buffer: f64, @@ -61,88 +317,36 @@ pub struct LabelFePHEV { pub hwy: PHEVCycleCalc, } -#[pyclass] -#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -/// Label fuel economy calculations for a specific cycle of a PHEV vehicle -pub struct PHEVCycleCalc { - /// Charge depletion battery kW-hr - pub cd_ess_kwh: f64, - pub cd_ess_kwh_per_mi: f64, - /// Charge depletion fuel gallons - pub cd_fs_gal: f64, - pub cd_fs_kwh: f64, - pub cd_mpg: f64, - /// Number of cycles in charge depletion mode, up to transition - pub cd_cycs: f64, - pub cd_miles: f64, - pub cd_lab_mpg: f64, - pub cd_adj_mpg: f64, - /// Fraction of transition cycles spent in charge depletion - pub cd_frac_in_trans: f64, - /// SOC change during 1 cycle - pub trans_init_soc: f64, - /// charge depletion battery kW-hr - pub trans_ess_kwh: f64, - pub trans_ess_kwh_per_mi: f64, - pub trans_fs_gal: f64, - pub trans_fs_kwh: f64, - /// charge sustaining battery kW-hr - pub cs_ess_kwh: f64, - pub cs_ess_kwh_per_mi: f64, - /// charge sustaining fuel gallons - pub cs_fs_gal: f64, - pub cs_fs_kwh: f64, - pub cs_mpg: f64, - pub lab_mpgge: f64, - pub lab_kwh_per_mi: f64, - pub lab_uf: f64, - pub lab_uf_gpm: Array1, - pub lab_iter_uf: Array1, - pub lab_iter_uf_kwh_per_mi: Array1, - pub lab_iter_kwh_per_mi: Array1, - pub adj_iter_mpgge: Array1, - pub adj_iter_kwh_per_mi: Array1, - pub adj_iter_cd_miles: Array1, - pub adj_iter_uf: Array1, - pub adj_iter_uf_gpm: Vec, - pub adj_iter_uf_kwh_per_mi: Array1, - pub adj_cd_miles: f64, - pub adj_cd_mpgge: f64, - pub adj_cs_mpgge: f64, - pub adj_uf: f64, - pub adj_mpgge: f64, - pub adj_kwh_per_mi: f64, - pub adj_ess_kwh_per_mi: f64, - pub delta_soc: f64, - /// Total number of miles in charge depletion mode, assuming constant kWh_per_mi - pub total_cd_miles: f64, -} +#[pymethods] +impl LabelFePHEV { + #[getter] + pub fn get_regen_soc_buffer(&self) -> f64 { + self.regen_soc_buffer() + } + #[setter] + pub fn set_regen_soc_buffer_py(&mut self, new_value: f64) { + self.regen_soc_buffer = new_value; + } -#[cfg(feature = "pyo3")] -#[pymodule] -fn label_fuel_economy(_py: Python, m: &PyModule) -> PyResult<()> { - // Register the make_accel_trace_py function - #[pyfn(m, "make_accel_trace")] - fn make_accel_trace_py() -> PyResult { - let accel_cyc_secs = Array::range(0., 300., 0.1); - let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - accel_cyc_mps[0] = 0.0; - - let rust_cycle = RustCycle::new( - accel_cyc_secs.to_vec(), - accel_cyc_mps.to_vec(), - Array::zeros(accel_cyc_secs.len()).to_vec(), - Array::zeros(accel_cyc_secs.len()).to_vec(), - String::from("accel"), - ); - - Ok(rust_cycle) - } - - // Add the make_accel_trace_py function to the module - m.add_function(wrap_pyfunction!(make_accel_trace_py, m)?)?; - - // Return Ok(()) to indicate successful execution - Ok(()) + #[getter] + pub fn get_udds(&self) -> &PHEVCycleCalc { + &self.udds + } + + #[setter] + pub fn set_udds_py(&mut self, new_value: PHEVCycleCalc) { + self.udds = new_value; + } + + #[getter] + pub fn get_hwy(&self) -> &PHEVCycleCalc { + &self.hwy + } + + #[setter] + pub fn set_hwy_py(&mut self, new_value: PHEVCycleCalc) { + self.hwy = new_value; + } } + From df03345fa8186e35634dec51e36573a1280f5460 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Fri, 23 Jun 2023 14:35:46 -0600 Subject: [PATCH 09/27] add pyo3 --- rust/fastsim-core/src/simdrivelabel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 1c78d086..a4f7e219 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -709,7 +709,7 @@ pub fn get_label_fe_phev( }; } - return Ok(phev_calcs); + return Ok(phev_calcs) } #[cfg(test)] From 12f0a6a3032f8e78e8881ac8dbe784e638881088 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Tue, 27 Jun 2023 11:24:08 -0600 Subject: [PATCH 10/27] add pyo3_api --- rust/fastsim-core/Cargo.toml | 2 +- rust/fastsim-core/src/simdrivelabel.rs | 597 +++++++++++++++++++++++- rust/fastsim-core/src/simdrivelabel4.rs | 352 -------------- 3 files changed, 591 insertions(+), 360 deletions(-) delete mode 100644 rust/fastsim-core/src/simdrivelabel4.rs diff --git a/rust/fastsim-core/Cargo.toml b/rust/fastsim-core/Cargo.toml index 2f36fae5..41d14152 100644 --- a/rust/fastsim-core/Cargo.toml +++ b/rust/fastsim-core/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -pyo3 = { workspace = true, features = ["extension-module"], optional = true } +pyo3 = { workspace = true, version = "0.19", features = ["extension-module"], optional = true } anyhow = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_yaml = {workspace = true} diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index a4f7e219..347e05a0 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -7,14 +7,18 @@ use std::collections::HashMap; use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; -use crate::proc_macros::ApproxEq; +use pyo3::prelude::*; + + +use crate::proc_macros::{add_pyo3_api, ApproxEq}; +#[cfg(feature = "pyo3")] +use crate::pyo3imports::*; + use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -// TODO: Asmaa, this struct (and maybe structs that are in its fields) need to -// be exposed to Python using the `add_pyo3_api` attribute-style procedural macro -/// Label fuel economy values +#[add_pyo3_api] pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, @@ -33,9 +37,7 @@ pub struct LabelFe { pub adj_udds_ess_kwh_per_mi: f64, pub adj_hwy_ess_kwh_per_mi: f64, pub adj_comb_ess_kwh_per_mi: f64, - /// Range for combined city/highway pub net_range_miles: f64, - /// Utility factor pub uf: f64, pub net_accel: f64, pub res_found: String, @@ -46,7 +48,218 @@ pub struct LabelFe { pub trace_miss_speed_mph: f64, } +#[pymethods] +impl LabelFe { + pub fn get_veh(&self) -> &vehicle::RustVehicle { + &self.veh + } + + pub fn set_veh_py(&mut self, new_veh: vehicle::RustVehicle) { + self.veh = new_veh; + } + pub fn get_adj_params(&self) -> &AdjCoef { + &self.adj_params + } + + pub fn set_adj_params_py(&mut self, new_params: AdjCoef) { + self.adj_params = new_params; + } + + pub fn get_lab_udds_mpgge(&self) -> f64 { + self.lab_udds_mpgge + } + + pub fn set_lab_udds_mpgge_py(&mut self, new_value: f64) { + self.lab_udds_mpgge = new_value; + } + + pub fn get_lab_hwy_mpgge(&self) -> f64 { + self.lab_hwy_mpgge + } + + pub fn set_lab_hwy_mpgge_py(&mut self, new_value: f64) { + self.lab_hwy_mpgge = new_value; + } + + pub fn get_lab_comb_mpgge(&self) -> f64 { + self.lab_comb_mpgge + } + + pub fn set_lab_comb_mpgge_py(&mut self, new_value: f64) { + self.lab_comb_mpgge = new_value; + } + + pub fn get_lab_udds_kwh_per_mi(&self) -> f64 { + self.lab_udds_kwh_per_mi + } + + pub fn set_lab_udds_kwh_per_mi_py(&mut self, new_value: f64) { + self.lab_udds_kwh_per_mi = new_value; + } + + pub fn get_lab_hwy_kwh_per_mi(&self) -> f64 { + self.lab_hwy_kwh_per_mi + } + + pub fn set_lab_hwy_kwh_per_mi_py(&mut self, new_value: f64) { + self.lab_hwy_kwh_per_mi = new_value; + } + + pub fn get_lab_comb_kwh_per_mi(&self) -> f64 { + self.lab_comb_kwh_per_mi + } + + pub fn set_lab_comb_kwh_per_mi_py(&mut self, new_value: f64) { + self.lab_comb_kwh_per_mi = new_value; + } + + pub fn get_adj_udds_mpgge(&self) -> f64 { + self.adj_udds_mpgge + } + + pub fn set_adj_udds_mpgge_py(&mut self, new_value: f64) { + self.adj_udds_mpgge = new_value; + } + + pub fn get_adj_hwy_mpgge(&self) -> f64 { + self.adj_hwy_mpgge + } + + pub fn set_adj_hwy_mpgge_py(&mut self, new_value: f64) { + self.adj_hwy_mpgge = new_value; + } + + pub fn get_adj_comb_mpgge(&self) -> f64 { + self.adj_comb_mpgge + } + + pub fn set_adj_comb_mpgge_py(&mut self, new_value: f64) { + self.adj_comb_mpgge = new_value; + } + + pub fn get_adj_udds_kwh_per_mi(&self) -> f64 { + self.adj_udds_kwh_per_mi + } + + pub fn set_adj_udds_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_udds_kwh_per_mi = new_value; + } + + pub fn get_adj_hwy_kwh_per_mi(&self) -> f64 { + self.adj_hwy_kwh_per_mi + } + + pub fn set_adj_hwy_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_hwy_kwh_per_mi = new_value; + } + + pub fn get_adj_comb_kwh_per_mi(&self) -> f64 { + self.adj_comb_kwh_per_mi + } + + pub fn set_adj_comb_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_comb_kwh_per_mi = new_value; + } + + pub fn get_adj_udds_ess_kwh_per_mi(&self) -> f64 { + self.adj_udds_ess_kwh_per_mi + } + + pub fn set_adj_udds_ess_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_udds_ess_kwh_per_mi = new_value; + } + + pub fn get_adj_hwy_ess_kwh_per_mi(&self) -> f64 { + self.adj_hwy_ess_kwh_per_mi + } + + pub fn set_adj_hwy_ess_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_hwy_ess_kwh_per_mi = new_value; + } + + pub fn get_adj_comb_ess_kwh_per_mi(&self) -> f64 { + self.adj_comb_ess_kwh_per_mi + } + + pub fn set_adj_comb_ess_kwh_per_mi_py(&mut self, new_value: f64) { + self.adj_comb_ess_kwh_per_mi = new_value; + } + + pub fn get_net_range_miles(&self) -> f64 { + self.net_range_miles + } + + pub fn set_net_range_miles_py(&mut self, new_value: f64) { + self.net_range_miles = new_value; + } + + pub fn get_uf(&self) -> f64 { + self.uf + } + + pub fn set_uf_py(&mut self, new_value: f64) { + self.uf = new_value; + } + + pub fn get_net_accel(&self) -> f64 { + self.net_accel + } + + pub fn set_net_accel_py(&mut self, new_value: f64) { + self.net_accel = new_value; + } + + pub fn get_res_found(&self) -> &str { + &self.res_found + } + + pub fn set_res_found_py(&mut self, new_value: String) { + self.res_found = new_value; + } + + pub fn get_phev_calcs(&self) -> Option<&LabelFePHEV> { + self.phev_calcs.as_ref() + } + + pub fn set_phev_calcs_py(&mut self, new_value: Option) { + self.phev_calcs = new_value; + } + + pub fn get_adj_cs_comb_mpgge(&self) -> Option { + self.adj_cs_comb_mpgge + } + + pub fn set_adj_cs_comb_mpgge_py(&mut self, new_value: Option) { + self.adj_cs_comb_mpgge = new_value; + } + + pub fn get_adj_cd_comb_mpgge(&self) -> Option { + self.adj_cd_comb_mpgge + } + + pub fn set_adj_cd_comb_mpgge_py(&mut self, new_value: Option) { + self.adj_cd_comb_mpgge = new_value; + } + + pub fn get_net_phev_cd_miles(&self) -> Option { + self.net_phev_cd_miles + } + + pub fn set_net_phev_cd_miles_py(&mut self, new_value: Option) { + self.net_phev_cd_miles = new_value; + } + + pub fn get_trace_miss_speed_mph(&self) -> f64 { + self.trace_miss_speed_mph + } + + pub fn set_trace_miss_speed_mph_py(&mut self, new_value: f64) { + self.trace_miss_speed_mph = new_value; + } +} + #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +#[add_pyo3_api] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { pub regen_soc_buffer: f64, @@ -54,11 +267,41 @@ pub struct LabelFePHEV { pub hwy: PHEVCycleCalc, } +#[pymethods] +impl LabelFePHEV { + + pub fn get_regen_soc_buffer(&self) -> f64 { + self.regen_soc_buffer() + } + + pub fn set_regen_soc_buffer_py(&mut self, new_value: f64) { + self.regen_soc_buffer = new_value; + } + + pub fn get_udds(&self) -> &PHEVCycleCalc { + &self.udds + } + + pub fn set_udds_py(&mut self, new_value: PHEVCycleCalc) { + self.udds = new_value; + } + + pub fn get_hwy(&self) -> &PHEVCycleCalc { + &self.hwy + } + + pub fn set_hwy_py(&mut self, new_value: PHEVCycleCalc) { + self.hwy = new_value; + } +} + + #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +#[add_pyo3_api] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { /// Charge depletion battery kW-hr - pub cd_ess_kwh: f64, + pub(crate) cd_ess_kwh: f64, pub cd_ess_kwh_per_mi: f64, /// Charge depletion fuel gallons pub cd_fs_gal: f64, @@ -110,6 +353,346 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } +impl PHEVCycleCalc { + pub fn get_cd_ess_kwh(&self) -> f64 { + self.cd_ess_kwh() + } + + pub fn set_cd_ess_kwh(&mut self, value: f64) { + self.cd_ess_kwh = value; + } + + pub fn get_cd_ess_kwh_per_mi(&self) -> f64 { + self.cd_ess_kwh_per_mi() + } + + pub fn set_cd_ess_kwh_per_mi(&mut self, value: f64) { + self.cd_ess_kwh_per_mi = value; + } + + pub fn get_cd_fs_gal(&self) -> f64 { + self.cd_fs_gal() + } + + pub fn set_cd_fs_gal(&mut self, value: f64) { + self.cd_fs_gal = value; + } + + pub fn get_cd_fs_kwh(&self) -> f64 { + self.cd_fs_kwh() + } + + pub fn set_cd_fs_kwh(&mut self, value: f64) { + self.cd_fs_kwh = value; + } + + pub fn get_cd_mpg(&self) -> f64 { + self.cd_mpg() + } + + pub fn set_cd_mpg(&mut self, value: f64) { + self.cd_mpg = value; + } + + pub fn get_cd_cycs(&self) -> f64 { + self.cd_cycs() + } + + pub fn set_cd_cycs(&mut self, value: f64) { + self.cd_cycs = value; + } + + pub fn get_cd_miles(&self) -> f64 { + self.cd_miles() + } + + pub fn set_cd_miles(&mut self, value: f64) { + self.cd_miles = value; + } + + pub fn get_cd_lab_mpg(&self) -> f64 { + self.cd_lab_mpg() + } + + pub fn set_cd_lab_mpg(&mut self, value: f64) { + self.cd_lab_mpg = value; + } + + pub fn get_cd_adj_mpg(&self) -> f64 { + self.cd_adj_mpg() + } + + pub fn set_cd_adj_mpg(&mut self, value: f64) { + self.cd_adj_mpg = value; + } + + pub fn get_cd_frac_in_trans(&self) -> f64 { + self.cd_frac_in_trans() + } + + pub fn set_cd_frac_in_trans(&mut self, value: f64) { + self.cd_frac_in_trans = value; + } + + pub fn get_trans_init_soc(&self) -> f64 { + self.trans_init_soc() + } + + pub fn set_trans_init_soc(&mut self, value: f64) { + self.cd_trans_init_soc = value; + } + + pub fn get_trans_ess_kwh(&self) -> f64 { + self.trans_ess_kwh() + } + + pub fn set_trans_ess_kwh(&mut self, value: f64) { + self.cd_trans_ess_kwh = value; + } + + pub fn get_trans_ess_kwh_per_mi(&self) -> f64 { + self.trans_ess_kwh_per_mi() + } + + pub fn set_trans_ess_kwh_per_mi(&mut self, value: f64) { + self.trans_ess_kwh_per_mi = value; + } + + pub fn get_trans_fs_gal(&self) -> f64 { + self.trans_fs_gal() + } + + pub fn set_trans_fs_gal(&mut self, value: f64) { + self.trans_fs_gal = value; + } + + pub fn get_trans_fs_kwh(&self) -> f64 { + self.trans_fs_kwh() + } + + pub fn set_trans_fs_kwh(&mut self, value: f64) { + self.trans_fs_kwh = value; + } + + pub fn get_cs_ess_kwh(&self) -> f64 { + self.cs_ess_kwh() + } + + pub fn set_cs_ess_kwh(&mut self, value: f64) { + self.cs_ess_kwh = value; + } + + pub fn get_cs_ess_kwh_per_mi(&self) -> f64 { + self.cs_ess_kwh_per_mi() + } + + pub fn set_cs_ess_kwh_per_mi(&mut self, value: f64) { + self.cs_ess_kwh_per_mi = value; + } + + + pub fn get_cs_fs_gal(&self) -> f64 { + self.cs_fs_gal() + } + + pub fn set_cs_fs_gal(&mut self, value: f64) { + self.cs_fs_gal = value; + } + + pub fn get_cs_fs_kwh(&self) -> f64 { + self.cs_fs_kwh() + } + + pub fn set_cs_fs_kwh(&mut self, value: f64) { + self.cs_fs_kwh = value; + } + + pub fn get_cs_mpg(&self) -> f64 { + self.cs_mpg() + } + + pub fn set_cs_mpg(&mut self, value: f64) { + self.cs_mpg = value; + } + + pub fn get_lab_mpgge(&self) -> f64 { + self.lab_mpgge() + } + + pub fn set_lab_mpgge(&mut self, value: f64) { + self.lab_mpgge = value; + } + + pub fn get_lab_kwh_per_mi(&self) -> f64 { + self.lab_kwh_per_mi() + } + + pub fn set_lab_kwh_per_mi(&mut self, value: f64) { + self.lab_kwh_per_mi = value; + } + + pub fn get_lab_uf(&self) -> f64 { + self.lab_uf() + } + + pub fn set_lab_uf(&mut self, value: f64) { + self.lab_uf = value; + } + + pub fn get_lab_uf_gpm(&self) -> &Array1 { + &self.lab_uf_gpm() + } + + pub fn set_lab_uf_gpm(&mut self, value: Array1) { + self.lab_uf_gpm = value; + } + + pub fn get_lab_iter_uf(&self) -> &Array1 { + &self.lab_iter_uf() + } + + pub fn set_lab_iter_uf(&mut self, value: Array1) { + self.lab_iter_uf = value; + } + + pub fn get_lab_iter_uf_kwh_per_mi(&self) -> &Array1 { + &self.lab_iter_uf_kwh_per_mi() + } + + pub fn set_lab_iter_uf_kwh_per_mi(&mut self, value: Array1) { + self.lab_iter_uf_kwh_per_mi = value; + } + + pub fn get_lab_iter_kwh_per_mi(&self) -> &Array1 { + &self.lab_iter_kwh_per_mi() + } + + pub fn set_lab_iter_kwh_per_mi(&mut self, value: Array1) { + self.lab_iter_kwh_per_mi = value; + } + + pub fn get_adj_iter_mpgge(&self) -> &Array1 { + &self.adj_iter_mpgge() + } + + pub fn set_adj_iter_mpgge(&mut self, value: Array1) { + self.adj_iter_mpgge = value; + } + + pub fn get_adj_iter_kwh_per_mi(&self) -> &Array1 { + &self.adj_iter_kwh_per_mi() + } + + pub fn set_adj_iter_kwh_per_mi(&mut self, value: Array1) { + self.adj_iter_kwh_per_mi = value; + } + + pub fn get_adj_iter_cd_miles(&self) -> &Array1 { + &self.adj_iter_cd_miles() + } + + pub fn set_adj_iter_cd_miles(&mut self, value: Array1) { + self.adj_iter_cd_miles = value; + } + + pub fn get_adj_iter_uf(&self) -> &Array1 { + &self.adj_iter_uf() + } + + pub fn set_adj_iter_uf(&mut self, value: Array1) { + self.adj_iter_uf = value; + } + + pub fn get_adj_iter_uf_gpm(&self) -> &[f64] { + &self.adj_iter_uf_gpm() + } + + pub fn set_adj_iter_uf_gpm(&mut self, value: Vec) { + self.adj_iter_uf_gpm = value; + } + + pub fn get_adj_iter_uf_kwh_per_mi(&self) -> &Array1 { + &self.adj_iter_uf_kwh_per_mi() + } + + pub fn set_adj_iter_uf_kwh_per_mi(&mut self, value: Array1) { + self.adj_iter_uf_kwh_per_mi = value; + } + + pub fn get_adj_cd_miles(&self) -> f64 { + self.adj_cd_miles() + } + + pub fn set_adj_cd_miles(&mut self, value: f64) { + self.adj_cd_miles = value; + } + + pub fn get_adj_cd_mpgge(&self) -> f64 { + self.adj_cd_mpgge() + } + + pub fn set_adj_cd_mpgge(&mut self, value: f64) { + self.adj_cd_mpgge = value; + } + + pub fn get_adj_cs_mpgge(&self) -> f64 { + self.adj_cs_mpgge() + } + + pub fn set_adj_cs_mpgge(&mut self, value: f64) { + self.adj_cs_mpgge = value; + } + + pub fn get_adj_uf(&self) -> f64 { + self.adj_uf() + } + + pub fn set_adj_uf(&mut self, value: f64) { + self.adj_uf = value; + } + + pub fn get_adj_mpgge(&self) -> f64 { + self.adj_mpgge() + } + + pub fn set_adj_mpgge(&mut self, value: f64) { + self.adj_mpgge = value; + } + + pub fn get_adj_kwh_per_mi(&self) -> f64 { + self.adj_kwh_per_mi() + } + + pub fn set_adj_kwh_per_mi(&mut self, value: f64) { + self.adj_kwh_per_mi = value; + } + + pub fn get_adj_ess_kwh_per_mi(&self) -> f64 { + self.adj_ess_kwh_per_mi() + } + + pub fn set_adj_ess_kwh_per_mi(&mut self, value: f64) { + self.adj_ess_kwh_per_mi = value; + } + + pub fn get_delta_soc(&self) -> f64 { + self.delta_soc() + } + + pub fn set_delta_soc(&mut self, value: f64) { + self.delta_soc = value; + } + + pub fn get_total_cd_miles(&self) -> f64 { + self.total_cd_miles() + } + + pub fn set_total_cd_miles(&mut self, value: f64) { + self.total_cd_miles = value; + } +} + + pub fn make_accel_trace() -> RustCycle { let accel_cyc_secs = Array::range(0., 300., 0.1); let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; diff --git a/rust/fastsim-core/src/simdrivelabel4.rs b/rust/fastsim-core/src/simdrivelabel4.rs deleted file mode 100644 index d381bdaf..00000000 --- a/rust/fastsim-core/src/simdrivelabel4.rs +++ /dev/null @@ -1,352 +0,0 @@ -// Modify the existing code from 1-56 to add pyo3 - -use ndarray::Array; -use std::collections::HashMap; - -// crate local -use crate::cycle::RustCycle; -use crate::imports::*; -use crate::params::*; - -use crate::proc_macros::{add_pyo3_api, ApproxEq}; -#[cfg(feature = "pyo3")] -use crate::pyo3imports::*; - -use crate::simdrive::{RustSimDrive, RustSimDriveParams}; -use crate::vehicle; - -#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] -pub struct LabelFe { - pub veh: vehicle::RustVehicle, - pub adj_params: AdjCoef, - pub lab_udds_mpgge: f64, - pub lab_hwy_mpgge: f64, - pub lab_comb_mpgge: f64, - pub lab_udds_kwh_per_mi: f64, - pub lab_hwy_kwh_per_mi: f64, - pub lab_comb_kwh_per_mi: f64, - pub adj_udds_mpgge: f64, - pub adj_hwy_mpgge: f64, - pub adj_comb_mpgge: f64, - pub adj_udds_kwh_per_mi: f64, - pub adj_hwy_kwh_per_mi: f64, - pub adj_comb_kwh_per_mi: f64, - pub adj_udds_ess_kwh_per_mi: f64, - pub adj_hwy_ess_kwh_per_mi: f64, - pub adj_comb_ess_kwh_per_mi: f64, - pub net_range_miles: f64, - pub uf: f64, - pub net_accel: f64, - pub res_found: String, - pub phev_calcs: Option, - pub adj_cs_comb_mpgge: Option, - pub adj_cd_comb_mpgge: Option, - pub net_phev_cd_miles: Option, - pub trace_miss_speed_mph: f64, -} - -impl LabelFe { - #[getter] - pub fn get_veh(&self) -> &vehicle::RustVehicle { - &self.veh - } - - #[setter] - pub fn set_veh_py(&mut self, new_veh: vehicle::RustVehicle) { - self.veh = new_veh; - } - - #[getter] - pub fn get_adj_params(&self) -> &AdjCoef { - &self.adj_params - } - - #[setter] - pub fn set_adj_params_py(&mut self, new_params: AdjCoef) { - self.adj_params = new_params; - } - - #[getter] - pub fn get_lab_udds_mpgge(&self) -> f64 { - self.lab_udds_mpgge - } - - #[setter] - pub fn set_lab_udds_mpgge_py(&mut self, new_value: f64) { - self.lab_udds_mpgge = new_value; - } - - #[getter] - pub fn get_lab_hwy_mpgge(&self) -> f64 { - self.lab_hwy_mpgge - } - - #[setter] - pub fn set_lab_hwy_mpgge_py(&mut self, new_value: f64) { - self.lab_hwy_mpgge = new_value; - } - - #[getter] - pub fn get_lab_comb_mpgge(&self) -> f64 { - self.lab_comb_mpgge - } - - #[setter] - pub fn set_lab_comb_mpgge_py(&mut self, new_value: f64) { - self.lab_comb_mpgge = new_value; - } - - #[getter] - pub fn get_lab_udds_kwh_per_mi(&self) -> f64 { - self.lab_udds_kwh_per_mi - } - - #[setter] - pub fn set_lab_udds_kwh_per_mi_py(&mut self, new_value: f64) { - self.lab_udds_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_lab_hwy_kwh_per_mi(&self) -> f64 { - self.lab_hwy_kwh_per_mi - } - - #[setter] - pub fn set_lab_hwy_kwh_per_mi_py(&mut self, new_value: f64) { - self.lab_hwy_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_lab_comb_kwh_per_mi(&self) -> f64 { - self.lab_comb_kwh_per_mi - } - - #[setter] - pub fn set_lab_comb_kwh_per_mi_py(&mut self, new_value: f64) { - self.lab_comb_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_adj_udds_mpgge(&self) -> f64 { - self.adj_udds_mpgge - } - - #[setter] - pub fn set_adj_udds_mpgge_py(&mut self, new_value: f64) { - self.adj_udds_mpgge = new_value; - } - - #[getter] - pub fn get_adj_hwy_mpgge(&self) -> f64 { - self.adj_hwy_mpgge - } - - #[setter] - pub fn set_adj_hwy_mpgge_py(&mut self, new_value: f64) { - self.adj_hwy_mpgge = new_value; - } - - #[getter] - pub fn get_adj_comb_mpgge(&self) -> f64 { - self.adj_comb_mpgge - } - - #[setter] - pub fn set_adj_comb_mpgge_py(&mut self, new_value: f64) { - self.adj_comb_mpgge = new_value; - } - - #[getter] - pub fn get_adj_udds_kwh_per_mi(&self) -> f64 { - self.adj_udds_kwh_per_mi - } - - #[setter] - pub fn set_adj_udds_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_udds_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_adj_hwy_kwh_per_mi(&self) -> f64 { - self.adj_hwy_kwh_per_mi - } - - #[setter] - pub fn set_adj_hwy_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_hwy_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_adj_comb_kwh_per_mi(&self) -> f64 { - self.adj_comb_kwh_per_mi - } - - #[setter] - pub fn set_adj_comb_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_comb_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_adj_udds_ess_kwh_per_mi(&self) -> f64 { - self.adj_udds_ess_kwh_per_mi - } - - #[setter] - pub fn set_adj_udds_ess_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_udds_ess_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_adj_hwy_ess_kwh_per_mi(&self) -> f64 { - self.adj_hwy_ess_kwh_per_mi - } - - #[setter] - pub fn set_adj_hwy_ess_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_hwy_ess_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_adj_comb_ess_kwh_per_mi(&self) -> f64 { - self.adj_comb_ess_kwh_per_mi - } - - #[setter] - pub fn set_adj_comb_ess_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_comb_ess_kwh_per_mi = new_value; - } - - #[getter] - pub fn get_net_range_miles(&self) -> f64 { - self.net_range_miles - } - - #[setter] - pub fn set_net_range_miles_py(&mut self, new_value: f64) { - self.net_range_miles = new_value; - } - - #[getter] - pub fn get_uf(&self) -> f64 { - self.uf - } - - #[setter] - pub fn set_uf_py(&mut self, new_value: f64) { - self.uf = new_value; - } - - #[getter] - pub fn get_net_accel(&self) -> f64 { - self.net_accel - } - - #[setter] - pub fn set_net_accel_py(&mut self, new_value: f64) { - self.net_accel = new_value; - } - - #[getter] - pub fn get_res_found(&self) -> &str { - &self.res_found - } - - #[setter] - pub fn set_res_found_py(&mut self, new_value: String) { - self.res_found = new_value; - } - - #[getter] - pub fn get_phev_calcs(&self) -> Option<&LabelFePHEV> { - self.phev_calcs.as_ref() - } - - #[setter] - pub fn set_phev_calcs_py(&mut self, new_value: Option) { - self.phev_calcs = new_value; - } - - #[getter] - pub fn get_adj_cs_comb_mpgge(&self) -> Option { - self.adj_cs_comb_mpgge - } - - #[setter] - pub fn set_adj_cs_comb_mpgge_py(&mut self, new_value: Option) { - self.adj_cs_comb_mpgge = new_value; - } - - #[getter] - pub fn get_adj_cd_comb_mpgge(&self) -> Option { - self.adj_cd_comb_mpgge - } - - #[setter] - pub fn set_adj_cd_comb_mpgge_py(&mut self, new_value: Option) { - self.adj_cd_comb_mpgge = new_value; - } - - #[getter] - pub fn get_net_phev_cd_miles(&self) -> Option { - self.net_phev_cd_miles - } - - #[setter] - pub fn set_net_phev_cd_miles_py(&mut self, new_value: Option) { - self.net_phev_cd_miles = new_value; - } - - #[getter] - pub fn get_trace_miss_speed_mph(&self) -> f64 { - self.trace_miss_speed_mph - } - - #[setter] - pub fn set_trace_miss_speed_mph_py(&mut self, new_value: f64) { - self.trace_miss_speed_mph = new_value; - } -} - -#[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] -/// Label fuel economy values for a PHEV vehicle -pub struct LabelFePHEV { - pub regen_soc_buffer: f64, - pub udds: PHEVCycleCalc, - pub hwy: PHEVCycleCalc, -} - -#[pymethods] -impl LabelFePHEV { - #[getter] - pub fn get_regen_soc_buffer(&self) -> f64 { - self.regen_soc_buffer() - } - - #[setter] - pub fn set_regen_soc_buffer_py(&mut self, new_value: f64) { - self.regen_soc_buffer = new_value; - } - - #[getter] - pub fn get_udds(&self) -> &PHEVCycleCalc { - &self.udds - } - - #[setter] - pub fn set_udds_py(&mut self, new_value: PHEVCycleCalc) { - self.udds = new_value; - } - - #[getter] - pub fn get_hwy(&self) -> &PHEVCycleCalc { - &self.hwy - } - - #[setter] - pub fn set_hwy_py(&mut self, new_value: PHEVCycleCalc) { - self.hwy = new_value; - } -} - From 98964069510f291978cd95d97cbb285c4ab698b2 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Tue, 27 Jun 2023 11:44:22 -0600 Subject: [PATCH 11/27] modify Cargo.toml --- rust/fastsim-core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/fastsim-core/Cargo.toml b/rust/fastsim-core/Cargo.toml index 41d14152..2f36fae5 100644 --- a/rust/fastsim-core/Cargo.toml +++ b/rust/fastsim-core/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -pyo3 = { workspace = true, version = "0.19", features = ["extension-module"], optional = true } +pyo3 = { workspace = true, features = ["extension-module"], optional = true } anyhow = { workspace = true } serde = { workspace = true, features = ["derive"] } serde_yaml = {workspace = true} From f75d197c37c00a66f46d6479e60314ce66cf3646 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Fri, 30 Jun 2023 09:52:26 -0600 Subject: [PATCH 12/27] update add_pyo3_api --- rust/fastsim-core/src/simdrivelabel.rs | 616 +------------------------ 1 file changed, 19 insertions(+), 597 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 347e05a0..a1151636 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -8,6 +8,8 @@ use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; use pyo3::prelude::*; +use pyo3::types::IntoPyDict; +use pyo3::types::PyString; use crate::proc_macros::{add_pyo3_api, ApproxEq}; @@ -48,216 +50,6 @@ pub struct LabelFe { pub trace_miss_speed_mph: f64, } -#[pymethods] -impl LabelFe { - pub fn get_veh(&self) -> &vehicle::RustVehicle { - &self.veh - } - - pub fn set_veh_py(&mut self, new_veh: vehicle::RustVehicle) { - self.veh = new_veh; - } - pub fn get_adj_params(&self) -> &AdjCoef { - &self.adj_params - } - - pub fn set_adj_params_py(&mut self, new_params: AdjCoef) { - self.adj_params = new_params; - } - - pub fn get_lab_udds_mpgge(&self) -> f64 { - self.lab_udds_mpgge - } - - pub fn set_lab_udds_mpgge_py(&mut self, new_value: f64) { - self.lab_udds_mpgge = new_value; - } - - pub fn get_lab_hwy_mpgge(&self) -> f64 { - self.lab_hwy_mpgge - } - - pub fn set_lab_hwy_mpgge_py(&mut self, new_value: f64) { - self.lab_hwy_mpgge = new_value; - } - - pub fn get_lab_comb_mpgge(&self) -> f64 { - self.lab_comb_mpgge - } - - pub fn set_lab_comb_mpgge_py(&mut self, new_value: f64) { - self.lab_comb_mpgge = new_value; - } - - pub fn get_lab_udds_kwh_per_mi(&self) -> f64 { - self.lab_udds_kwh_per_mi - } - - pub fn set_lab_udds_kwh_per_mi_py(&mut self, new_value: f64) { - self.lab_udds_kwh_per_mi = new_value; - } - - pub fn get_lab_hwy_kwh_per_mi(&self) -> f64 { - self.lab_hwy_kwh_per_mi - } - - pub fn set_lab_hwy_kwh_per_mi_py(&mut self, new_value: f64) { - self.lab_hwy_kwh_per_mi = new_value; - } - - pub fn get_lab_comb_kwh_per_mi(&self) -> f64 { - self.lab_comb_kwh_per_mi - } - - pub fn set_lab_comb_kwh_per_mi_py(&mut self, new_value: f64) { - self.lab_comb_kwh_per_mi = new_value; - } - - pub fn get_adj_udds_mpgge(&self) -> f64 { - self.adj_udds_mpgge - } - - pub fn set_adj_udds_mpgge_py(&mut self, new_value: f64) { - self.adj_udds_mpgge = new_value; - } - - pub fn get_adj_hwy_mpgge(&self) -> f64 { - self.adj_hwy_mpgge - } - - pub fn set_adj_hwy_mpgge_py(&mut self, new_value: f64) { - self.adj_hwy_mpgge = new_value; - } - - pub fn get_adj_comb_mpgge(&self) -> f64 { - self.adj_comb_mpgge - } - - pub fn set_adj_comb_mpgge_py(&mut self, new_value: f64) { - self.adj_comb_mpgge = new_value; - } - - pub fn get_adj_udds_kwh_per_mi(&self) -> f64 { - self.adj_udds_kwh_per_mi - } - - pub fn set_adj_udds_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_udds_kwh_per_mi = new_value; - } - - pub fn get_adj_hwy_kwh_per_mi(&self) -> f64 { - self.adj_hwy_kwh_per_mi - } - - pub fn set_adj_hwy_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_hwy_kwh_per_mi = new_value; - } - - pub fn get_adj_comb_kwh_per_mi(&self) -> f64 { - self.adj_comb_kwh_per_mi - } - - pub fn set_adj_comb_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_comb_kwh_per_mi = new_value; - } - - pub fn get_adj_udds_ess_kwh_per_mi(&self) -> f64 { - self.adj_udds_ess_kwh_per_mi - } - - pub fn set_adj_udds_ess_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_udds_ess_kwh_per_mi = new_value; - } - - pub fn get_adj_hwy_ess_kwh_per_mi(&self) -> f64 { - self.adj_hwy_ess_kwh_per_mi - } - - pub fn set_adj_hwy_ess_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_hwy_ess_kwh_per_mi = new_value; - } - - pub fn get_adj_comb_ess_kwh_per_mi(&self) -> f64 { - self.adj_comb_ess_kwh_per_mi - } - - pub fn set_adj_comb_ess_kwh_per_mi_py(&mut self, new_value: f64) { - self.adj_comb_ess_kwh_per_mi = new_value; - } - - pub fn get_net_range_miles(&self) -> f64 { - self.net_range_miles - } - - pub fn set_net_range_miles_py(&mut self, new_value: f64) { - self.net_range_miles = new_value; - } - - pub fn get_uf(&self) -> f64 { - self.uf - } - - pub fn set_uf_py(&mut self, new_value: f64) { - self.uf = new_value; - } - - pub fn get_net_accel(&self) -> f64 { - self.net_accel - } - - pub fn set_net_accel_py(&mut self, new_value: f64) { - self.net_accel = new_value; - } - - pub fn get_res_found(&self) -> &str { - &self.res_found - } - - pub fn set_res_found_py(&mut self, new_value: String) { - self.res_found = new_value; - } - - pub fn get_phev_calcs(&self) -> Option<&LabelFePHEV> { - self.phev_calcs.as_ref() - } - - pub fn set_phev_calcs_py(&mut self, new_value: Option) { - self.phev_calcs = new_value; - } - - pub fn get_adj_cs_comb_mpgge(&self) -> Option { - self.adj_cs_comb_mpgge - } - - pub fn set_adj_cs_comb_mpgge_py(&mut self, new_value: Option) { - self.adj_cs_comb_mpgge = new_value; - } - - pub fn get_adj_cd_comb_mpgge(&self) -> Option { - self.adj_cd_comb_mpgge - } - - pub fn set_adj_cd_comb_mpgge_py(&mut self, new_value: Option) { - self.adj_cd_comb_mpgge = new_value; - } - - pub fn get_net_phev_cd_miles(&self) -> Option { - self.net_phev_cd_miles - } - - pub fn set_net_phev_cd_miles_py(&mut self, new_value: Option) { - self.net_phev_cd_miles = new_value; - } - - pub fn get_trace_miss_speed_mph(&self) -> f64 { - self.trace_miss_speed_mph - } - - pub fn set_trace_miss_speed_mph_py(&mut self, new_value: f64) { - self.trace_miss_speed_mph = new_value; - } -} - #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] #[add_pyo3_api] /// Label fuel economy values for a PHEV vehicle @@ -267,41 +59,12 @@ pub struct LabelFePHEV { pub hwy: PHEVCycleCalc, } -#[pymethods] -impl LabelFePHEV { - - pub fn get_regen_soc_buffer(&self) -> f64 { - self.regen_soc_buffer() - } - - pub fn set_regen_soc_buffer_py(&mut self, new_value: f64) { - self.regen_soc_buffer = new_value; - } - - pub fn get_udds(&self) -> &PHEVCycleCalc { - &self.udds - } - - pub fn set_udds_py(&mut self, new_value: PHEVCycleCalc) { - self.udds = new_value; - } - - pub fn get_hwy(&self) -> &PHEVCycleCalc { - &self.hwy - } - - pub fn set_hwy_py(&mut self, new_value: PHEVCycleCalc) { - self.hwy = new_value; - } -} - - #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] #[add_pyo3_api] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { /// Charge depletion battery kW-hr - pub(crate) cd_ess_kwh: f64, + pub cd_ess_kwh: f64, pub cd_ess_kwh_per_mi: f64, /// Charge depletion fuel gallons pub cd_fs_gal: f64, @@ -353,358 +116,21 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } -impl PHEVCycleCalc { - pub fn get_cd_ess_kwh(&self) -> f64 { - self.cd_ess_kwh() - } - - pub fn set_cd_ess_kwh(&mut self, value: f64) { - self.cd_ess_kwh = value; - } - - pub fn get_cd_ess_kwh_per_mi(&self) -> f64 { - self.cd_ess_kwh_per_mi() - } - - pub fn set_cd_ess_kwh_per_mi(&mut self, value: f64) { - self.cd_ess_kwh_per_mi = value; - } - - pub fn get_cd_fs_gal(&self) -> f64 { - self.cd_fs_gal() - } - - pub fn set_cd_fs_gal(&mut self, value: f64) { - self.cd_fs_gal = value; - } - - pub fn get_cd_fs_kwh(&self) -> f64 { - self.cd_fs_kwh() - } - - pub fn set_cd_fs_kwh(&mut self, value: f64) { - self.cd_fs_kwh = value; - } - - pub fn get_cd_mpg(&self) -> f64 { - self.cd_mpg() - } - - pub fn set_cd_mpg(&mut self, value: f64) { - self.cd_mpg = value; - } - - pub fn get_cd_cycs(&self) -> f64 { - self.cd_cycs() - } - - pub fn set_cd_cycs(&mut self, value: f64) { - self.cd_cycs = value; - } - - pub fn get_cd_miles(&self) -> f64 { - self.cd_miles() - } - - pub fn set_cd_miles(&mut self, value: f64) { - self.cd_miles = value; - } - - pub fn get_cd_lab_mpg(&self) -> f64 { - self.cd_lab_mpg() - } - - pub fn set_cd_lab_mpg(&mut self, value: f64) { - self.cd_lab_mpg = value; - } - - pub fn get_cd_adj_mpg(&self) -> f64 { - self.cd_adj_mpg() - } - - pub fn set_cd_adj_mpg(&mut self, value: f64) { - self.cd_adj_mpg = value; - } - - pub fn get_cd_frac_in_trans(&self) -> f64 { - self.cd_frac_in_trans() - } - - pub fn set_cd_frac_in_trans(&mut self, value: f64) { - self.cd_frac_in_trans = value; - } - - pub fn get_trans_init_soc(&self) -> f64 { - self.trans_init_soc() - } - - pub fn set_trans_init_soc(&mut self, value: f64) { - self.cd_trans_init_soc = value; - } - - pub fn get_trans_ess_kwh(&self) -> f64 { - self.trans_ess_kwh() - } - - pub fn set_trans_ess_kwh(&mut self, value: f64) { - self.cd_trans_ess_kwh = value; - } - - pub fn get_trans_ess_kwh_per_mi(&self) -> f64 { - self.trans_ess_kwh_per_mi() - } - - pub fn set_trans_ess_kwh_per_mi(&mut self, value: f64) { - self.trans_ess_kwh_per_mi = value; - } - - pub fn get_trans_fs_gal(&self) -> f64 { - self.trans_fs_gal() - } - - pub fn set_trans_fs_gal(&mut self, value: f64) { - self.trans_fs_gal = value; - } - - pub fn get_trans_fs_kwh(&self) -> f64 { - self.trans_fs_kwh() - } - - pub fn set_trans_fs_kwh(&mut self, value: f64) { - self.trans_fs_kwh = value; - } - - pub fn get_cs_ess_kwh(&self) -> f64 { - self.cs_ess_kwh() - } - - pub fn set_cs_ess_kwh(&mut self, value: f64) { - self.cs_ess_kwh = value; - } - - pub fn get_cs_ess_kwh_per_mi(&self) -> f64 { - self.cs_ess_kwh_per_mi() - } - - pub fn set_cs_ess_kwh_per_mi(&mut self, value: f64) { - self.cs_ess_kwh_per_mi = value; - } - - - pub fn get_cs_fs_gal(&self) -> f64 { - self.cs_fs_gal() - } - - pub fn set_cs_fs_gal(&mut self, value: f64) { - self.cs_fs_gal = value; - } - - pub fn get_cs_fs_kwh(&self) -> f64 { - self.cs_fs_kwh() - } - - pub fn set_cs_fs_kwh(&mut self, value: f64) { - self.cs_fs_kwh = value; - } - - pub fn get_cs_mpg(&self) -> f64 { - self.cs_mpg() - } - - pub fn set_cs_mpg(&mut self, value: f64) { - self.cs_mpg = value; - } - - pub fn get_lab_mpgge(&self) -> f64 { - self.lab_mpgge() - } - - pub fn set_lab_mpgge(&mut self, value: f64) { - self.lab_mpgge = value; - } - - pub fn get_lab_kwh_per_mi(&self) -> f64 { - self.lab_kwh_per_mi() - } - - pub fn set_lab_kwh_per_mi(&mut self, value: f64) { - self.lab_kwh_per_mi = value; - } - - pub fn get_lab_uf(&self) -> f64 { - self.lab_uf() - } - - pub fn set_lab_uf(&mut self, value: f64) { - self.lab_uf = value; - } - - pub fn get_lab_uf_gpm(&self) -> &Array1 { - &self.lab_uf_gpm() - } - - pub fn set_lab_uf_gpm(&mut self, value: Array1) { - self.lab_uf_gpm = value; - } - - pub fn get_lab_iter_uf(&self) -> &Array1 { - &self.lab_iter_uf() - } - - pub fn set_lab_iter_uf(&mut self, value: Array1) { - self.lab_iter_uf = value; - } - - pub fn get_lab_iter_uf_kwh_per_mi(&self) -> &Array1 { - &self.lab_iter_uf_kwh_per_mi() - } - - pub fn set_lab_iter_uf_kwh_per_mi(&mut self, value: Array1) { - self.lab_iter_uf_kwh_per_mi = value; - } - - pub fn get_lab_iter_kwh_per_mi(&self) -> &Array1 { - &self.lab_iter_kwh_per_mi() - } - - pub fn set_lab_iter_kwh_per_mi(&mut self, value: Array1) { - self.lab_iter_kwh_per_mi = value; - } - - pub fn get_adj_iter_mpgge(&self) -> &Array1 { - &self.adj_iter_mpgge() - } - - pub fn set_adj_iter_mpgge(&mut self, value: Array1) { - self.adj_iter_mpgge = value; - } - - pub fn get_adj_iter_kwh_per_mi(&self) -> &Array1 { - &self.adj_iter_kwh_per_mi() - } - - pub fn set_adj_iter_kwh_per_mi(&mut self, value: Array1) { - self.adj_iter_kwh_per_mi = value; - } - - pub fn get_adj_iter_cd_miles(&self) -> &Array1 { - &self.adj_iter_cd_miles() - } - - pub fn set_adj_iter_cd_miles(&mut self, value: Array1) { - self.adj_iter_cd_miles = value; - } - - pub fn get_adj_iter_uf(&self) -> &Array1 { - &self.adj_iter_uf() - } - - pub fn set_adj_iter_uf(&mut self, value: Array1) { - self.adj_iter_uf = value; - } - - pub fn get_adj_iter_uf_gpm(&self) -> &[f64] { - &self.adj_iter_uf_gpm() - } - - pub fn set_adj_iter_uf_gpm(&mut self, value: Vec) { - self.adj_iter_uf_gpm = value; - } - - pub fn get_adj_iter_uf_kwh_per_mi(&self) -> &Array1 { - &self.adj_iter_uf_kwh_per_mi() - } - - pub fn set_adj_iter_uf_kwh_per_mi(&mut self, value: Array1) { - self.adj_iter_uf_kwh_per_mi = value; - } - - pub fn get_adj_cd_miles(&self) -> f64 { - self.adj_cd_miles() - } - - pub fn set_adj_cd_miles(&mut self, value: f64) { - self.adj_cd_miles = value; - } - - pub fn get_adj_cd_mpgge(&self) -> f64 { - self.adj_cd_mpgge() - } - - pub fn set_adj_cd_mpgge(&mut self, value: f64) { - self.adj_cd_mpgge = value; - } - - pub fn get_adj_cs_mpgge(&self) -> f64 { - self.adj_cs_mpgge() - } - - pub fn set_adj_cs_mpgge(&mut self, value: f64) { - self.adj_cs_mpgge = value; - } - - pub fn get_adj_uf(&self) -> f64 { - self.adj_uf() - } - - pub fn set_adj_uf(&mut self, value: f64) { - self.adj_uf = value; - } - - pub fn get_adj_mpgge(&self) -> f64 { - self.adj_mpgge() - } - - pub fn set_adj_mpgge(&mut self, value: f64) { - self.adj_mpgge = value; - } - - pub fn get_adj_kwh_per_mi(&self) -> f64 { - self.adj_kwh_per_mi() - } - - pub fn set_adj_kwh_per_mi(&mut self, value: f64) { - self.adj_kwh_per_mi = value; - } - - pub fn get_adj_ess_kwh_per_mi(&self) -> f64 { - self.adj_ess_kwh_per_mi() - } - - pub fn set_adj_ess_kwh_per_mi(&mut self, value: f64) { - self.adj_ess_kwh_per_mi = value; - } - - pub fn get_delta_soc(&self) -> f64 { - self.delta_soc() - } - - pub fn set_delta_soc(&mut self, value: f64) { - self.delta_soc = value; - } - - pub fn get_total_cd_miles(&self) -> f64 { - self.total_cd_miles() - } - - pub fn set_total_cd_miles(&mut self, value: f64) { - self.total_cd_miles = value; - } -} - - -pub fn make_accel_trace() -> RustCycle { - let accel_cyc_secs = Array::range(0., 300., 0.1); - let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - accel_cyc_mps[0] = 0.0; - - RustCycle::new( - accel_cyc_secs.to_vec(), - accel_cyc_mps.to_vec(), - Array::zeros(accel_cyc_secs.len()).to_vec(), - Array::zeros(accel_cyc_secs.len()).to_vec(), - String::from("accel"), - ) +pub fn make_accel_trace() -> PyResult { + Python::with_gil(|py| { + let accel_cyc_secs = Array::range(0., 300., 0.1); + let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + accel_cyc_mps[0] = 0.0; + + let dict = PyDict::new(py); + dict.set_item(py, "accel_cyc_secs", accel_cyc_secs.to_vec())?; + dict.set_item(py, "accel_cyc_mps", accel_cyc_mps.to_vec())?; + dict.set_item(py, "zeros1", Array::zeros(accel_cyc_secs.len()).to_vec())?; + dict.set_item(py, "zeros2", Array::zeros(accel_cyc_secs.len()).to_vec())?; + dict.set_item(py, "name", "accel")?; + + Ok(dict.into()) + }) } pub fn get_net_accel( @@ -779,8 +205,6 @@ pub fn get_label_fe( main_separator!(), "..", main_separator!(), - "python", - main_separator!(), "fastsim", main_separator!(), "resources", @@ -796,8 +220,6 @@ pub fn get_label_fe( main_separator!(), "..", main_separator!(), - "python", - main_separator!(), "fastsim", main_separator!(), "resources", @@ -1292,7 +714,7 @@ pub fn get_label_fe_phev( }; } - return Ok(phev_calcs) + return Ok(phev_calcs); } #[cfg(test)] From feb55939f90c018c8ca8cb9fb39c72c6b94fe0be Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:25:18 -0600 Subject: [PATCH 13/27] update ad_pyo3_api --- rust/fastsim-core/src/simdrivelabel.rs | 30 +++++++++++--------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index a1151636..a4b4a18a 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -8,8 +8,7 @@ use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; use pyo3::prelude::*; -use pyo3::types::IntoPyDict; -use pyo3::types::PyString; + use crate::proc_macros::{add_pyo3_api, ApproxEq}; @@ -116,21 +115,18 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } -pub fn make_accel_trace() -> PyResult { - Python::with_gil(|py| { - let accel_cyc_secs = Array::range(0., 300., 0.1); - let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - accel_cyc_mps[0] = 0.0; - - let dict = PyDict::new(py); - dict.set_item(py, "accel_cyc_secs", accel_cyc_secs.to_vec())?; - dict.set_item(py, "accel_cyc_mps", accel_cyc_mps.to_vec())?; - dict.set_item(py, "zeros1", Array::zeros(accel_cyc_secs.len()).to_vec())?; - dict.set_item(py, "zeros2", Array::zeros(accel_cyc_secs.len()).to_vec())?; - dict.set_item(py, "name", "accel")?; - - Ok(dict.into()) - }) +pub fn make_accel_trace() -> RustCycle { + let accel_cyc_secs = Array::range(0., 300., 0.1); + let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + accel_cyc_mps[0] = 0.0; + + RustCycle::new( + accel_cyc_secs.to_vec(), + accel_cyc_mps.to_vec(), + Array::zeros(accel_cyc_secs.len()).to_vec(), + Array::zeros(accel_cyc_secs.len()).to_vec(), + String::from("accel"), + ) } pub fn get_net_accel( From 9184913dbb4272b35fb916c81c694b9c16955c54 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:29:02 -0600 Subject: [PATCH 14/27] return to origin --- rust/fastsim-core/src/simdrivelabel.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index a4b4a18a..4061e655 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -7,19 +7,12 @@ use std::collections::HashMap; use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; -use pyo3::prelude::*; - - - -use crate::proc_macros::{add_pyo3_api, ApproxEq}; -#[cfg(feature = "pyo3")] -use crate::pyo3imports::*; - +use crate::proc_macros::ApproxEq; use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] +/// Label fuel economy values pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, @@ -38,7 +31,9 @@ pub struct LabelFe { pub adj_udds_ess_kwh_per_mi: f64, pub adj_hwy_ess_kwh_per_mi: f64, pub adj_comb_ess_kwh_per_mi: f64, + /// Range for combined city/highway pub net_range_miles: f64, + /// Utility factor pub uf: f64, pub net_accel: f64, pub res_found: String, @@ -50,7 +45,6 @@ pub struct LabelFe { } #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { pub regen_soc_buffer: f64, @@ -59,7 +53,6 @@ pub struct LabelFePHEV { } #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { /// Charge depletion battery kW-hr From 14a839501528f541cc0d6331a97219146bcb6b3f Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Fri, 30 Jun 2023 11:38:51 -0600 Subject: [PATCH 15/27] add pyo3_api --- rust/fastsim-core/src/simdrivelabel.rs | 41 ++++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 4061e655..50112208 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -108,18 +108,35 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } -pub fn make_accel_trace() -> RustCycle { - let accel_cyc_secs = Array::range(0., 300., 0.1); - let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - accel_cyc_mps[0] = 0.0; - - RustCycle::new( - accel_cyc_secs.to_vec(), - accel_cyc_mps.to_vec(), - Array::zeros(accel_cyc_secs.len()).to_vec(), - Array::zeros(accel_cyc_secs.len()).to_vec(), - String::from("accel"), - ) +//pub fn make_accel_trace() -> RustCycle { + //let accel_cyc_secs = Array::range(0., 300., 0.1); + // let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + // accel_cyc_mps[0] = 0.0; + + // RustCycle::new( + //accel_cyc_secs.to_vec(), + //accel_cyc_mps.to_vec(), + //Array::zeros(accel_cyc_secs.len()).to_vec(), + //Array::zeros(accel_cyc_secs.len()).to_vec(), + // String::from("accel"), + // ) +//} +pub fn make_accel_trace() -> PyResult { + Python::with_gil(|py| { + let accel_cyc_secs = Array::range(0., 300., 0.1); + let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + accel_cyc_mps[0] = 0.0; + + + let dict = PyDict::new(py); + dict.set_item(py, "accel_cyc_secs", accel_cyc_secs.to_vec())?; + dict.set_item(py, "accel_cyc_mps", accel_cyc_mps.to_vec())?; + dict.set_item(py, "zeros1", Array::zeros(accel_cyc_secs.len()).to_vec())?; + dict.set_item(py, "zeros2", Array::zeros(accel_cyc_secs.len()).to_vec())?; + dict.set_item(py, "name", "accel")?; + + Ok(dict.into()) + }) } pub fn get_net_accel( From 0a5122e7433a0ca88ad8f342f8dcf540545827cc Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Fri, 30 Jun 2023 11:41:32 -0600 Subject: [PATCH 16/27] add pyo3_api --- rust/fastsim-core/src/simdrivelabel.rs | 44 ++++++++++++++++---------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 50112208..1fd2916c 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -7,12 +7,20 @@ use std::collections::HashMap; use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; -use crate::proc_macros::ApproxEq; +use pyo3::prelude::*; +use pyo3::types::IntoPyDict; +use pyo3::types::PyString; + + +use crate::proc_macros::{add_pyo3_api, ApproxEq}; +#[cfg(feature = "pyo3")] +use crate::pyo3imports::*; + use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -/// Label fuel economy values +#[add_pyo3_api] pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, @@ -31,9 +39,7 @@ pub struct LabelFe { pub adj_udds_ess_kwh_per_mi: f64, pub adj_hwy_ess_kwh_per_mi: f64, pub adj_comb_ess_kwh_per_mi: f64, - /// Range for combined city/highway pub net_range_miles: f64, - /// Utility factor pub uf: f64, pub net_accel: f64, pub res_found: String, @@ -45,6 +51,7 @@ pub struct LabelFe { } #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +#[add_pyo3_api] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { pub regen_soc_buffer: f64, @@ -53,6 +60,7 @@ pub struct LabelFePHEV { } #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] +#[add_pyo3_api] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { /// Charge depletion battery kW-hr @@ -108,19 +116,6 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } -//pub fn make_accel_trace() -> RustCycle { - //let accel_cyc_secs = Array::range(0., 300., 0.1); - // let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - // accel_cyc_mps[0] = 0.0; - - // RustCycle::new( - //accel_cyc_secs.to_vec(), - //accel_cyc_mps.to_vec(), - //Array::zeros(accel_cyc_secs.len()).to_vec(), - //Array::zeros(accel_cyc_secs.len()).to_vec(), - // String::from("accel"), - // ) -//} pub fn make_accel_trace() -> PyResult { Python::with_gil(|py| { let accel_cyc_secs = Array::range(0., 300., 0.1); @@ -139,6 +134,21 @@ pub fn make_accel_trace() -> PyResult { }) } +//pub fn make_accel_trace() -> RustCycle { + //let accel_cyc_secs = Array::range(0., 300., 0.1); + // let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + // accel_cyc_mps[0] = 0.0; + + // RustCycle::new( + //accel_cyc_secs.to_vec(), + //accel_cyc_mps.to_vec(), + //Array::zeros(accel_cyc_secs.len()).to_vec(), + //Array::zeros(accel_cyc_secs.len()).to_vec(), + // String::from("accel"), + // ) +//} + + pub fn get_net_accel( sd_accel: &mut RustSimDrive, scenario_name: &String, From 87d68d992cabde42403526cb307c7845882dc4d4 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:21:48 -0600 Subject: [PATCH 17/27] modify add pyo3 --- rust/fastsim-core/src/simdrivelabel.rs | 70 +++++++++++++------------- rust/fastsim-py/src/lib.rs | 5 ++ 2 files changed, 41 insertions(+), 34 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 1fd2916c..55363f72 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -8,19 +8,16 @@ use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; use pyo3::prelude::*; -use pyo3::types::IntoPyDict; -use pyo3::types::PyString; +use pyo3::PyResult; +use serde::Serialize; +use crate::proc_macros:: ApproxEq; -use crate::proc_macros::{add_pyo3_api, ApproxEq}; -#[cfg(feature = "pyo3")] -use crate::pyo3imports::*; use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, @@ -50,8 +47,9 @@ pub struct LabelFe { pub trace_miss_speed_mph: f64, } + + #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { pub regen_soc_buffer: f64, @@ -59,8 +57,8 @@ pub struct LabelFePHEV { pub hwy: PHEVCycleCalc, } + #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -#[add_pyo3_api] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { /// Charge depletion battery kW-hr @@ -116,37 +114,29 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } -pub fn make_accel_trace() -> PyResult { - Python::with_gil(|py| { - let accel_cyc_secs = Array::range(0., 300., 0.1); - let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - accel_cyc_mps[0] = 0.0; - let dict = PyDict::new(py); - dict.set_item(py, "accel_cyc_secs", accel_cyc_secs.to_vec())?; - dict.set_item(py, "accel_cyc_mps", accel_cyc_mps.to_vec())?; - dict.set_item(py, "zeros1", Array::zeros(accel_cyc_secs.len()).to_vec())?; - dict.set_item(py, "zeros2", Array::zeros(accel_cyc_secs.len()).to_vec())?; - dict.set_item(py, "name", "accel")?; +pub fn make_accel_trace() -> RustCycle { + let accel_cyc_secs = Array::range(0., 300., 0.1); + let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; + accel_cyc_mps[0] = 0.0; - Ok(dict.into()) - }) + RustCycle::new( + accel_cyc_secs.to_vec(), + accel_cyc_mps.to_vec(), + Array::zeros(accel_cyc_secs.len()).to_vec(), + Array::zeros(accel_cyc_secs.len()).to_vec(), + String::from("accel"), + ) } -//pub fn make_accel_trace() -> RustCycle { - //let accel_cyc_secs = Array::range(0., 300., 0.1); - // let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; - // accel_cyc_mps[0] = 0.0; +#[cfg(feature = "pyo3")] +#[pyfunction(rename="make_accel_trace")] +/// pyo3 version of [make_accel_trace] +pub fn make_accel_trace_py() -> RustCycle { + make_accel_trace() +} - // RustCycle::new( - //accel_cyc_secs.to_vec(), - //accel_cyc_mps.to_vec(), - //Array::zeros(accel_cyc_secs.len()).to_vec(), - //Array::zeros(accel_cyc_secs.len()).to_vec(), - // String::from("accel"), - // ) -//} pub fn get_net_accel( @@ -168,6 +158,18 @@ pub fn get_net_accel( } } +#[cfg(feature = "pyo3")] +#[pyfunction(rename = "get_net_accel")] +/// pyo3 version of [get_net_accel] +pub fn get_net_accel_py( + sd_accel: &mut RustSimDrive, + scenario_name: &str, +) -> PyResult { + let result = get_net_accel(sd_accel, &scenario_name.to_string())?; + Ok(result) +} + + pub fn get_label_fe( veh: &vehicle::RustVehicle, full_detail: Option, @@ -783,6 +785,7 @@ mod simdrivelabel_tests { assert!(label_fe.approx_eq(&label_fe_truth, 1e-10)); } +} #[test] fn test_get_label_fe_phev() { let mut veh = vehicle::RustVehicle { @@ -1152,4 +1155,3 @@ mod simdrivelabel_tests { ); assert!(label_fe.approx_eq(&label_fe_truth, tol)); } -} diff --git a/rust/fastsim-py/src/lib.rs b/rust/fastsim-py/src/lib.rs index 1ab03d5e..fc49ca2d 100644 --- a/rust/fastsim-py/src/lib.rs +++ b/rust/fastsim-py/src/lib.rs @@ -21,5 +21,10 @@ fn fastsimrust(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; cycle::register(py, m)?; m.add_function(wrap_pyfunction!(vehicle_utils::abc_to_drag_coeffs, m)?)?; + m.add_function(wrap_pyfunction!(make_accel_trace_py, m)?)?; + m.add_function(wrap_pyfunction!(get_net_accel_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_phev_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_conv_py, m)?)?; Ok(()) } From 1bfe9c89052d679f99b115d1a66700f5e62a90eb Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Thu, 6 Jul 2023 12:32:25 -0600 Subject: [PATCH 18/27] add pyo3 --- rust/fastsim-core/src/simdrivelabel.rs | 38 ++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 55363f72..64ea3e78 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -8,7 +8,6 @@ use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; use pyo3::prelude::*; -use pyo3::PyResult; use serde::Serialize; use crate::proc_macros:: ApproxEq; @@ -170,6 +169,7 @@ pub fn get_net_accel_py( } + pub fn get_label_fe( veh: &vehicle::RustVehicle, full_detail: Option, @@ -436,7 +436,19 @@ pub fn get_label_fe( return Ok((out, None)); } else { return Ok((out, None)); - } + } + +} + +#[cfg(feature = "pyo3")] +/// pyo3 version of [get_label_fe] +pub fn get_label_fe_py( + veh: &vehicle::RustVehicle, + full_detail: Option, + verbose: Option, +) -> PyResult<(LabelFe, Option>)> { + let result = get_label_fe(veh, full_detail, verbose)?; + Ok(result) } pub fn get_label_fe_phev( @@ -735,6 +747,20 @@ pub fn get_label_fe_phev( return Ok(phev_calcs); } +#[cfg(feature = "pyo3")] +/// pyo3 version of [get_label_fe_phev] +pub fn get_label_fe_phev_py( + veh: &vehicle::RustVehicle, + sd: HashMap<&str, RustSimDrive>, + long_params: RustLongParams, + adj_params: AdjCoef, + sim_params: RustSimDriveParams, + props: RustPhysicalProperties, +) -> PyResult { + let result = get_label_fe_phev(veh, &mut sd, &long_params, &adj_params, &sim_params, &props)?; + Ok(result) +} + #[cfg(test)] mod simdrivelabel_tests { use super::*; @@ -785,6 +811,14 @@ mod simdrivelabel_tests { assert!(label_fe.approx_eq(&label_fe_truth, 1e-10)); } +} +#[cfg(feature = "pyo3")] +/// pyo3 version of [get_label_fe_conv] +pub fn get_label_fe_conv_py() -> LabelFe { + let veh: vehicle::RustVehicle = vehicle::RustVehicle::mock_vehicle(); + let (label_fe, _) = get_label_fe(&veh, None, None).unwrap(); + label_fe.veh = vehicle::RustVehicle::default(); + label_fe } #[test] fn test_get_label_fe_phev() { From db419fdd68ce371d69971e82729d658fdbefe674 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Mon, 10 Jul 2023 14:07:38 -0600 Subject: [PATCH 19/27] fixed several warnings and errors --- rust/fastsim-core/src/simdrivelabel.rs | 815 ++++++++++++------------- 1 file changed, 401 insertions(+), 414 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 64ea3e78..4f77c9d9 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -9,9 +9,8 @@ use crate::imports::*; use crate::params::*; use pyo3::prelude::*; +use crate::proc_macros::ApproxEq; use serde::Serialize; -use crate::proc_macros:: ApproxEq; - use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; @@ -46,8 +45,6 @@ pub struct LabelFe { pub trace_miss_speed_mph: f64, } - - #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { @@ -56,7 +53,6 @@ pub struct LabelFePHEV { pub hwy: PHEVCycleCalc, } - #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { @@ -113,8 +109,6 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } - - pub fn make_accel_trace() -> RustCycle { let accel_cyc_secs = Array::range(0., 300., 0.1); let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; @@ -130,14 +124,12 @@ pub fn make_accel_trace() -> RustCycle { } #[cfg(feature = "pyo3")] -#[pyfunction(rename="make_accel_trace")] +#[pyfunction(rename = "make_accel_trace")] /// pyo3 version of [make_accel_trace] pub fn make_accel_trace_py() -> RustCycle { - make_accel_trace() + make_accel_trace() } - - pub fn get_net_accel( sd_accel: &mut RustSimDrive, scenario_name: &String, @@ -160,21 +152,16 @@ pub fn get_net_accel( #[cfg(feature = "pyo3")] #[pyfunction(rename = "get_net_accel")] /// pyo3 version of [get_net_accel] -pub fn get_net_accel_py( - sd_accel: &mut RustSimDrive, - scenario_name: &str, -) -> PyResult { +pub fn get_net_accel_py(sd_accel: &mut RustSimDrive, scenario_name: &str) -> PyResult { let result = get_net_accel(sd_accel, &scenario_name.to_string())?; Ok(result) } - - pub fn get_label_fe( veh: &vehicle::RustVehicle, full_detail: Option, verbose: Option, -) -> Result<(LabelFe, Option>), anyhow::Error> { +) -> anyhow::Result<(LabelFe, Option>)> { // Generates label fuel economy (FE) values for a provided vehicle. // // Arguments: @@ -223,6 +210,8 @@ pub fn get_label_fe( main_separator!(), "..", main_separator!(), + "python", + main_separator!(), "fastsim", main_separator!(), "resources", @@ -238,6 +227,8 @@ pub fn get_label_fe( main_separator!(), "..", main_separator!(), + "python", + main_separator!(), "fastsim", main_separator!(), "resources", @@ -262,11 +253,9 @@ pub fn get_label_fe( for (k, val) in sd.iter_mut() { val.sim_drive(None, None)?; - let key = String::from(k.clone()); + let key = k; let trace_miss_speed_mph = val.trace_miss_speed_mps * MPH_PER_MPS; - if (key == String::from("udds") || key == String::from("hwy")) - && trace_miss_speed_mph > max_trace_miss_in_mph - { + if (key == &"udds" || key == &"hwy") && trace_miss_speed_mph > max_trace_miss_in_mph { max_trace_miss_in_mph = trace_miss_speed_mph; } } @@ -351,9 +340,9 @@ pub fn get_label_fe( out.adj_comb_kwh_per_mi = 0.55 * out.adj_udds_kwh_per_mi + 0.45 * out.adj_hwy_kwh_per_mi; - out.adj_udds_kwh_per_mi = out.adj_udds_kwh_per_mi * CHG_EFF; - out.adj_hwy_kwh_per_mi = out.adj_hwy_kwh_per_mi * CHG_EFF; - out.adj_comb_kwh_per_mi = out.adj_comb_kwh_per_mi * CHG_EFF; + out.adj_udds_kwh_per_mi *= CHG_EFF; + out.adj_hwy_kwh_per_mi *= CHG_EFF; + out.adj_comb_kwh_per_mi *= CHG_EFF; // range for combined city/highway out.net_range_miles = veh.ess_max_kwh / out.adj_comb_ess_kwh_per_mi; @@ -428,16 +417,15 @@ pub fn get_label_fe( if full_detail.unwrap_or(false) && verbose.unwrap_or(false) { println!("{:#?}", out); - return Ok((out, Some(sd))); + Ok((out, Some(sd))) } else if full_detail.unwrap_or(false) { - return Ok((out, Some(sd))); + Ok((out, Some(sd))) } else if verbose.unwrap_or(false) { println!("{:#?}", out); - return Ok((out, None)); + Ok((out, None)) } else { - return Ok((out, None)); - } - + Ok((out, None)) + } } #[cfg(feature = "pyo3")] @@ -471,17 +459,18 @@ pub fn get_label_fe_phev( // props : RustPhysicalProperties // // Returns label fuel economy values for PHEV as a struct. - let mut phev_calcs: LabelFePHEV = LabelFePHEV::default(); - - phev_calcs.regen_soc_buffer = min( - ((0.5 * veh.veh_kg * ((60. * (1. / MPH_PER_MPS)).powi(2))) - * (1. / 3600.) - * (1. / 1000.) - * veh.max_regen - * veh.mc_peak_eff()) - / veh.ess_max_kwh, - (veh.max_soc - veh.min_soc) / 2.0, - ); + let mut phev_calcs = LabelFePHEV { + regen_soc_buffer: min( + ((0.5 * veh.veh_kg * ((60. * (1. / MPH_PER_MPS)).powi(2))) + * (1. / 3600.) + * (1. / 1000.) + * veh.max_regen + * veh.mc_peak_eff()) + / veh.ess_max_kwh, + (veh.max_soc - veh.min_soc) / 2.0, + ), + ..Default::default() + }; // charge sustaining behavior for (key, sd_val) in sd.iter_mut() { @@ -619,7 +608,7 @@ pub fn get_label_fe_phev( * (1.0 - sim_params.max_epa_adj), )); - for c in 0..phev_calc.lab_iter_kwh_per_mi.len() { + for (c, _) in phev_calc.lab_iter_kwh_per_mi.iter().enumerate() { if phev_calc.lab_iter_kwh_per_mi[c] == 0.0 { adj_iter_kwh_per_mi_vals[c] = 0.0; } else { @@ -650,7 +639,7 @@ pub fn get_label_fe_phev( * (1.0 - sim_params.max_epa_adj), )); - for c in 0..phev_calc.lab_iter_kwh_per_mi.len() { + for (c, _) in phev_calc.lab_iter_kwh_per_mi.iter().enumerate() { if phev_calc.lab_iter_kwh_per_mi[c] == 0.0 { adj_iter_kwh_per_mi_vals[c] = 0.0; } else { @@ -744,21 +733,20 @@ pub fn get_label_fe_phev( }; } - return Ok(phev_calcs); + Ok(phev_calcs) } #[cfg(feature = "pyo3")] /// pyo3 version of [get_label_fe_phev] pub fn get_label_fe_phev_py( veh: &vehicle::RustVehicle, - sd: HashMap<&str, RustSimDrive>, + sd: &mut HashMap<&str, RustSimDrive>, long_params: RustLongParams, adj_params: AdjCoef, sim_params: RustSimDriveParams, props: RustPhysicalProperties, -) -> PyResult { - let result = get_label_fe_phev(veh, &mut sd, &long_params, &adj_params, &sim_params, &props)?; - Ok(result) +) -> anyhow::Result { + get_label_fe_phev(veh, sd, &long_params, &adj_params, &sim_params, &props) } #[cfg(test)] @@ -810,382 +798,381 @@ mod simdrivelabel_tests { assert!(label_fe.approx_eq(&label_fe_truth, 1e-10)); } - } #[cfg(feature = "pyo3")] /// pyo3 version of [get_label_fe_conv] pub fn get_label_fe_conv_py() -> LabelFe { let veh: vehicle::RustVehicle = vehicle::RustVehicle::mock_vehicle(); - let (label_fe, _) = get_label_fe(&veh, None, None).unwrap(); + let (mut label_fe, _) = get_label_fe(&veh, None, None).unwrap(); label_fe.veh = vehicle::RustVehicle::default(); label_fe } - #[test] - fn test_get_label_fe_phev() { - let mut veh = vehicle::RustVehicle { - props: RustPhysicalProperties { - air_density_kg_per_m3: 1.2, - a_grav_mps2: 9.81, - kwh_per_gge: 33.7, - fuel_rho_kg__L: 0.75, - fuel_afr_stoich: 14.7, - orphaned: false, - }, - veh_kg: Default::default(), - scenario_name: "2016 Chevrolet Volt".into(), - selection: 13, - veh_year: 2016, - veh_pt_type: "PHEV".into(), - drag_coef: 0.3, - frontal_area_m2: 2.565, - glider_kg: 950.564, - veh_cg_m: 0.53, - drive_axle_weight_frac: 0.59, - wheel_base_m: 2.6, - cargo_kg: 136.0, - veh_override_kg: None, - comp_mass_multiplier: 1.4, - fs_max_kw: 2000.0, - fs_secs_to_peak_pwr: 1.0, - fs_kwh: 297.0, - fs_kwh_per_kg: 9.89, - fc_max_kw: 75.0, - fc_pwr_out_perc: Array1::from(vec![ - 0.0, 0.005, 0.015, 0.04, 0.06, 0.1, 0.14, 0.2, 0.4, 0.6, 0.8, 1.0, - ]), - fc_eff_map: Array1::from(vec![ - 0.1, 0.12, 0.16, 0.22, 0.28, 0.33, 0.35, 0.36, 0.35, 0.34, 0.32, 0.3, - ]), - fc_eff_type: "SI".into(), - fc_sec_to_peak_pwr: 6.0, - fc_base_kg: 61.0, - fc_kw_per_kg: 2.13, - min_fc_time_on: 30.0, - idle_fc_kw: 1.5, - mc_max_kw: 111.0, - mc_pwr_out_perc: Array1::from(vec![ - 0.0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0, - ]), - mc_eff_map: Array1::from(vec![ - 0.84, 0.86, 0.88, 0.9, 0.91, 0.92, 0.94, 0.95, 0.95, 0.94, 0.93, - ]), - mc_sec_to_peak_pwr: 3.0, - mc_pe_kg_per_kw: 0.833, - mc_pe_base_kg: 21.6, - ess_max_kw: 115.0, - ess_max_kwh: 18.4, - ess_kg_per_kwh: 8.0, - ess_base_kg: 75.0, - ess_round_trip_eff: 0.97, - ess_life_coef_a: 110.0, - ess_life_coef_b: -0.6811, - min_soc: 0.15, - max_soc: 0.9, - ess_dischg_to_fc_max_eff_perc: 1.0, - ess_chg_to_fc_max_eff_perc: 0.0, - wheel_inertia_kg_m2: 0.815, - num_wheels: 4.0, - wheel_rr_coef: 0.007, - wheel_radius_m: 0.336, - wheel_coef_of_fric: 0.7, - max_accel_buffer_mph: 60.0, - max_accel_buffer_perc_of_useable_soc: 0.2, - perc_high_acc_buf: 0.0, - mph_fc_on: 85.0, - kw_demand_fc_on: 120.0, - max_regen: 0.98, - stop_start: false, - force_aux_on_fc: false, - alt_eff: 1.0, - chg_eff: 0.86, - aux_kw: 0.3, - trans_kg: 114.0, - trans_eff: 0.98, - ess_to_fuel_ok_error: 0.005, - small_motor_power_kw: 7.5, - large_motor_power_kw: 75.0, - fc_perc_out_array: FC_PERC_OUT_ARRAY.into(), - mc_kw_out_array: Default::default(), - mc_max_elec_in_kw: Default::default(), - mc_full_eff_array: Default::default(), - max_trac_mps2: Default::default(), - ess_mass_kg: Default::default(), - mc_mass_kg: Default::default(), - fc_mass_kg: Default::default(), - fs_mass_kg: Default::default(), - mc_perc_out_array: Default::default(), - regen_a: 500.0, - regen_b: 0.99, - charging_on: false, - no_elec_sys: false, - no_elec_aux: false, - max_roadway_chg_kw: Array1::from(vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), - input_kw_out_array: Array1::from(vec![ - 0.0, - 0.375, - 1.125, - 3.0, - 4.5, - 7.5, - 10.500000000000002, - 15.0, - 30.0, - 45.0, - 60.0, - 75.0, - ]), - fc_kw_out_array: Default::default(), - fc_eff_array: Default::default(), - modern_max: 0.95, - mc_eff_array: Array1::from(vec![ - 0.84, 0.86, 0.88, 0.9, 0.91, 0.92, 0.94, 0.95, 0.95, 0.94, 0.93, - ]), - mc_kw_in_array: Default::default(), - val_udds_mpgge: f64::NAN, - val_hwy_mpgge: f64::NAN, - val_comb_mpgge: 42.0, - val_udds_kwh_per_mile: f64::NAN, - val_hwy_kwh_per_mile: f64::NAN, - val_comb_kwh_per_mile: 0.31, - val_cd_range_mi: 53.0, - val_const65_mph_kwh_per_mile: f64::NAN, - val_const60_mph_kwh_per_mile: f64::NAN, - val_const55_mph_kwh_per_mile: f64::NAN, - val_const45_mph_kwh_per_mile: f64::NAN, - val_unadj_udds_kwh_per_mile: f64::NAN, - val_unadj_hwy_kwh_per_mile: f64::NAN, - val0_to60_mph: 8.4, - val_ess_life_miles: 120000.0, - val_range_miles: f64::NAN, - val_veh_base_cost: 17000.0, - val_msrp: 33170.0, - fc_peak_eff_override: None, - mc_peak_eff_override: None, +#[test] +fn test_get_label_fe_phev() { + let mut veh = vehicle::RustVehicle { + props: RustPhysicalProperties { + air_density_kg_per_m3: 1.2, + a_grav_mps2: 9.81, + kwh_per_gge: 33.7, + fuel_rho_kg__L: 0.75, + fuel_afr_stoich: 14.7, orphaned: false, - }; - veh.set_derived().unwrap(); + }, + veh_kg: Default::default(), + scenario_name: "2016 Chevrolet Volt".into(), + selection: 13, + veh_year: 2016, + veh_pt_type: "PHEV".into(), + drag_coef: 0.3, + frontal_area_m2: 2.565, + glider_kg: 950.564, + veh_cg_m: 0.53, + drive_axle_weight_frac: 0.59, + wheel_base_m: 2.6, + cargo_kg: 136.0, + veh_override_kg: None, + comp_mass_multiplier: 1.4, + fs_max_kw: 2000.0, + fs_secs_to_peak_pwr: 1.0, + fs_kwh: 297.0, + fs_kwh_per_kg: 9.89, + fc_max_kw: 75.0, + fc_pwr_out_perc: Array1::from(vec![ + 0.0, 0.005, 0.015, 0.04, 0.06, 0.1, 0.14, 0.2, 0.4, 0.6, 0.8, 1.0, + ]), + fc_eff_map: Array1::from(vec![ + 0.1, 0.12, 0.16, 0.22, 0.28, 0.33, 0.35, 0.36, 0.35, 0.34, 0.32, 0.3, + ]), + fc_eff_type: "SI".into(), + fc_sec_to_peak_pwr: 6.0, + fc_base_kg: 61.0, + fc_kw_per_kg: 2.13, + min_fc_time_on: 30.0, + idle_fc_kw: 1.5, + mc_max_kw: 111.0, + mc_pwr_out_perc: Array1::from(vec![ + 0.0, 0.02, 0.04, 0.06, 0.08, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0, + ]), + mc_eff_map: Array1::from(vec![ + 0.84, 0.86, 0.88, 0.9, 0.91, 0.92, 0.94, 0.95, 0.95, 0.94, 0.93, + ]), + mc_sec_to_peak_pwr: 3.0, + mc_pe_kg_per_kw: 0.833, + mc_pe_base_kg: 21.6, + ess_max_kw: 115.0, + ess_max_kwh: 18.4, + ess_kg_per_kwh: 8.0, + ess_base_kg: 75.0, + ess_round_trip_eff: 0.97, + ess_life_coef_a: 110.0, + ess_life_coef_b: -0.6811, + min_soc: 0.15, + max_soc: 0.9, + ess_dischg_to_fc_max_eff_perc: 1.0, + ess_chg_to_fc_max_eff_perc: 0.0, + wheel_inertia_kg_m2: 0.815, + num_wheels: 4.0, + wheel_rr_coef: 0.007, + wheel_radius_m: 0.336, + wheel_coef_of_fric: 0.7, + max_accel_buffer_mph: 60.0, + max_accel_buffer_perc_of_useable_soc: 0.2, + perc_high_acc_buf: 0.0, + mph_fc_on: 85.0, + kw_demand_fc_on: 120.0, + max_regen: 0.98, + stop_start: false, + force_aux_on_fc: false, + alt_eff: 1.0, + chg_eff: 0.86, + aux_kw: 0.3, + trans_kg: 114.0, + trans_eff: 0.98, + ess_to_fuel_ok_error: 0.005, + small_motor_power_kw: 7.5, + large_motor_power_kw: 75.0, + fc_perc_out_array: FC_PERC_OUT_ARRAY.into(), + mc_kw_out_array: Default::default(), + mc_max_elec_in_kw: Default::default(), + mc_full_eff_array: Default::default(), + max_trac_mps2: Default::default(), + ess_mass_kg: Default::default(), + mc_mass_kg: Default::default(), + fc_mass_kg: Default::default(), + fs_mass_kg: Default::default(), + mc_perc_out_array: Default::default(), + regen_a: 500.0, + regen_b: 0.99, + charging_on: false, + no_elec_sys: false, + no_elec_aux: false, + max_roadway_chg_kw: Array1::from(vec![0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), + input_kw_out_array: Array1::from(vec![ + 0.0, + 0.375, + 1.125, + 3.0, + 4.5, + 7.5, + 10.500000000000002, + 15.0, + 30.0, + 45.0, + 60.0, + 75.0, + ]), + fc_kw_out_array: Default::default(), + fc_eff_array: Default::default(), + modern_max: 0.95, + mc_eff_array: Array1::from(vec![ + 0.84, 0.86, 0.88, 0.9, 0.91, 0.92, 0.94, 0.95, 0.95, 0.94, 0.93, + ]), + mc_kw_in_array: Default::default(), + val_udds_mpgge: f64::NAN, + val_hwy_mpgge: f64::NAN, + val_comb_mpgge: 42.0, + val_udds_kwh_per_mile: f64::NAN, + val_hwy_kwh_per_mile: f64::NAN, + val_comb_kwh_per_mile: 0.31, + val_cd_range_mi: 53.0, + val_const65_mph_kwh_per_mile: f64::NAN, + val_const60_mph_kwh_per_mile: f64::NAN, + val_const55_mph_kwh_per_mile: f64::NAN, + val_const45_mph_kwh_per_mile: f64::NAN, + val_unadj_udds_kwh_per_mile: f64::NAN, + val_unadj_hwy_kwh_per_mile: f64::NAN, + val0_to60_mph: 8.4, + val_ess_life_miles: 120000.0, + val_range_miles: f64::NAN, + val_veh_base_cost: 17000.0, + val_msrp: 33170.0, + fc_peak_eff_override: None, + mc_peak_eff_override: None, + orphaned: false, + }; + veh.set_derived().unwrap(); - let (mut label_fe, _) = get_label_fe(&veh, None, None).unwrap(); - // For some reason, RustVehicle::mock_vehicle() != RustVehicle::mock_vehicle() - // Therefore, veh field in both structs replaced with Default for comparison purposes - label_fe.veh = vehicle::RustVehicle::default(); - // TODO: Figure out why net_accel values are different - println!("Calculated net accel: {}", label_fe.net_accel); - println!( - "Percent diff to Python calc: {:.3}%", - 100. * (9.451683946821882 - label_fe.net_accel) / 9.451683946821882 - ); - label_fe.net_accel = 1000.; - - let udds: PHEVCycleCalc = PHEVCycleCalc { - cd_ess_kwh: 13.799999999999999, - cd_ess_kwh_per_mi: 0.1670807863534209, - cd_fs_gal: 0.0, - cd_fs_kwh: 0.0, - cd_mpg: 65.0128437991813, - cd_cycs: 11.083418864860784, - cd_miles: 89.42523198551896, - cd_lab_mpg: 59.77814990568397, - cd_adj_mpg: 2968.1305812156647, - cd_frac_in_trans: 0.08341886486078387, - trans_init_soc: 0.15564484203010176, - trans_ess_kwh: 0.10386509335387073, - trans_ess_kwh_per_mi: 0.013937689537649522, - trans_fs_gal: 0.105063189381161, - trans_fs_kwh: 3.5406294821451265, - cs_ess_kwh: -27.842875966770062, - cs_ess_kwh_per_mi: -0.001037845633667792, - cs_fs_gal: 0.11462508375235472, - cs_fs_kwh: 3.8628653224543545, - cs_mpg: 65.01284379918131, - lab_mpgge: 370.06411942132064, - lab_kwh_per_mi: 0.16342111007981494, - lab_uf: 0.8427800000000001, - lab_uf_gpm: Array::from_vec(vec![0.00028394, 0.00241829]), - lab_iter_uf: Array::from_vec(vec![ - 0., 0.16268, 0.28152, 0.41188, 0.51506, 0.59611, 0.64532, 0.69897, 0.74176, - 0.77648, 0.79825, 0.82264, 0.84278, - ]), - lab_iter_uf_kwh_per_mi: Array::from_vec(vec![ - 0., 0.0271807, 0.01985588, 0.02178065, 0.0172394, 0.0135419, 0.00822205, - 0.00896388, 0.00714939, 0.00580104, 0.00363735, 0.0040751, 0.00028071, 0., - ]), - lab_iter_kwh_per_mi: Array::from_vec(vec![ - 0., 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.16708079, - 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.01393769, 0., - ]), - adj_iter_mpgge: Array::from_vec(vec![ - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 0., - 50.2456134, - 46.69198818, - ]), - adj_iter_kwh_per_mi: Array::from_vec(vec![ - 0., 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.23868684, - 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.01991099, 0., - ]), - adj_iter_cd_miles: Array::from_vec(vec![ - 0., - 5.21647187, - 10.43294373, - 15.6494156, - 20.86588746, - 26.08235933, - 31.29883119, - 36.51530306, - 41.73177493, - 46.94824679, - 52.16471866, - 57.38119052, - 62.59766239, - 0., - ]), - adj_iter_uf: Array::from_vec(vec![ - 0., 0.11878, 0.2044, 0.31698, 0.38194, 0.46652, 0.53737, 0.57771, 0.62998, 0.6599, - 0.69897, 0.73185, 0.75126, 0., - ]), - adj_iter_uf_gpm: vec![ - 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.0003863, 0.00532725, - ], - adj_iter_uf_kwh_per_mi: Array::from_vec(vec![ - 0., 0.02835122, 0.02043637, 0.02687136, 0.0155051, 0.02018813, 0.01691096, - 0.00962863, 0.01247616, 0.00714151, 0.00932549, 0.00784802, 0.00038647, 0., - ]), - adj_cd_miles: 62.59766238986325, - adj_cd_mpgge: 1944.7459827561047, - adj_cs_mpgge: 46.69198818435928, - adj_uf: 0.75126, - adj_mpgge: 175.0223917643415, - adj_kwh_per_mi: 0.27097024959679444, - adj_ess_kwh_per_mi: 0.23303441465324323, - delta_soc: 0.0676686507245362, - total_cd_miles: 82.59477526523773, - }; + let (mut label_fe, _) = get_label_fe(&veh, None, None).unwrap(); + // For some reason, RustVehicle::mock_vehicle() != RustVehicle::mock_vehicle() + // Therefore, veh field in both structs replaced with Default for comparison purposes + label_fe.veh = vehicle::RustVehicle::default(); + // TODO: Figure out why net_accel values are different + println!("Calculated net accel: {}", label_fe.net_accel); + println!( + "Percent diff to Python calc: {:.3}%", + 100. * (9.451683946821882 - label_fe.net_accel) / 9.451683946821882 + ); + label_fe.net_accel = 1000.; + + let udds: PHEVCycleCalc = PHEVCycleCalc { + cd_ess_kwh: 13.799999999999999, + cd_ess_kwh_per_mi: 0.1670807863534209, + cd_fs_gal: 0.0, + cd_fs_kwh: 0.0, + cd_mpg: 65.0128437991813, + cd_cycs: 11.083418864860784, + cd_miles: 89.42523198551896, + cd_lab_mpg: 59.77814990568397, + cd_adj_mpg: 2968.1305812156647, + cd_frac_in_trans: 0.08341886486078387, + trans_init_soc: 0.15564484203010176, + trans_ess_kwh: 0.10386509335387073, + trans_ess_kwh_per_mi: 0.013937689537649522, + trans_fs_gal: 0.105063189381161, + trans_fs_kwh: 3.5406294821451265, + cs_ess_kwh: -27.842875966770062, + cs_ess_kwh_per_mi: -0.001037845633667792, + cs_fs_gal: 0.11462508375235472, + cs_fs_kwh: 3.8628653224543545, + cs_mpg: 65.01284379918131, + lab_mpgge: 370.06411942132064, + lab_kwh_per_mi: 0.16342111007981494, + lab_uf: 0.8427800000000001, + lab_uf_gpm: Array::from_vec(vec![0.00028394, 0.00241829]), + lab_iter_uf: Array::from_vec(vec![ + 0., 0.16268, 0.28152, 0.41188, 0.51506, 0.59611, 0.64532, 0.69897, 0.74176, 0.77648, + 0.79825, 0.82264, 0.84278, + ]), + lab_iter_uf_kwh_per_mi: Array::from_vec(vec![ + 0., 0.0271807, 0.01985588, 0.02178065, 0.0172394, 0.0135419, 0.00822205, 0.00896388, + 0.00714939, 0.00580104, 0.00363735, 0.0040751, 0.00028071, 0., + ]), + lab_iter_kwh_per_mi: Array::from_vec(vec![ + 0., 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.16708079, + 0.16708079, 0.16708079, 0.16708079, 0.16708079, 0.01393769, 0., + ]), + adj_iter_mpgge: Array::from_vec(vec![ + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 50.2456134, + 46.69198818, + ]), + adj_iter_kwh_per_mi: Array::from_vec(vec![ + 0., 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.23868684, + 0.23868684, 0.23868684, 0.23868684, 0.23868684, 0.01991099, 0., + ]), + adj_iter_cd_miles: Array::from_vec(vec![ + 0., + 5.21647187, + 10.43294373, + 15.6494156, + 20.86588746, + 26.08235933, + 31.29883119, + 36.51530306, + 41.73177493, + 46.94824679, + 52.16471866, + 57.38119052, + 62.59766239, + 0., + ]), + adj_iter_uf: Array::from_vec(vec![ + 0., 0.11878, 0.2044, 0.31698, 0.38194, 0.46652, 0.53737, 0.57771, 0.62998, 0.6599, + 0.69897, 0.73185, 0.75126, 0., + ]), + adj_iter_uf_gpm: vec![ + 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.0003863, 0.00532725, + ], + adj_iter_uf_kwh_per_mi: Array::from_vec(vec![ + 0., 0.02835122, 0.02043637, 0.02687136, 0.0155051, 0.02018813, 0.01691096, 0.00962863, + 0.01247616, 0.00714151, 0.00932549, 0.00784802, 0.00038647, 0., + ]), + adj_cd_miles: 62.59766238986325, + adj_cd_mpgge: 1944.7459827561047, + adj_cs_mpgge: 46.69198818435928, + adj_uf: 0.75126, + adj_mpgge: 175.0223917643415, + adj_kwh_per_mi: 0.27097024959679444, + adj_ess_kwh_per_mi: 0.23303441465324323, + delta_soc: 0.0676686507245362, + total_cd_miles: 82.59477526523773, + }; - let hwy: PHEVCycleCalc = PHEVCycleCalc { - cd_ess_kwh: 13.799999999999999, - cd_ess_kwh_per_mi: 0.19912462736394723, - cd_fs_gal: 0.0, - cd_fs_kwh: 0.0, - cd_mpg: 61.75832757157714, - cd_cycs: 6.75533367335913, - cd_miles: 71.81337619240335, - cd_lab_mpg: 199.76659107309018, - cd_adj_mpg: 4975.506626976092, - cd_frac_in_trans: 0.7553336733591296, - trans_init_soc: 0.23385969996618272, - trans_ess_kwh: 1.5430184793777608, - trans_ess_kwh_per_mi: 0.15040553624307812, - trans_fs_gal: 0.040643020828268026, - trans_fs_kwh: 1.3696698019126325, - cs_ess_kwh: -27.84287564320177, - cs_ess_kwh_per_mi: -0.0007538835761840731, - cs_fs_gal: 0.1661161198039534, - cs_fs_kwh: 5.59811323739323, - cs_mpg: 61.75832757157714, - lab_mpgge: 282.75893721314793, - lab_kwh_per_mi: 0.19665299886733625, - lab_uf: 0.7914100000000001, - lab_uf_gpm: Array::from_vec(vec![0.00015906, 0.00337752]), - lab_iter_uf: Array::from_vec(vec![ - 0., 0.2044, 0.38194, 0.51506, 0.62998, 0.69897, 0.75126, 0.79141, - ]), - lab_iter_uf_kwh_per_mi: Array::from_vec(vec![ - 0., 0.04070107, 0.03535259, 0.02650747, 0.0228834, 0.01373761, 0.01041223, - 0.00603878, 0., - ]), - lab_iter_kwh_per_mi: Array::from_vec(vec![ - 0., 0.19912463, 0.19912463, 0.19912463, 0.19912463, 0.19912463, 0.19912463, - 0.15040554, 0., - ]), - adj_iter_mpgge: Array::from_vec(vec![0., 0., 0., 0., 0., 0., 176.69300837, 43.2308293]), - adj_iter_kwh_per_mi: Array::from_vec(vec![ - 0., 0.28446375, 0.28446375, 0.28446375, 0.28446375, 0.28446375, 0.28446375, - 0.21486505, 0., - ]), - adj_iter_cd_miles: Array::from_vec(vec![ - 0., - 7.18133762, - 14.36267524, - 21.54401286, - 28.72535048, - 35.9066881, - 43.08802572, - 50.26936333, - 0., - ]), - adj_iter_uf: Array::from_vec(vec![ - 0., 0.16268, 0.28152, 0.41188, 0.49148, 0.57771, 0.64532, 0.68662, 0., - ]), - adj_iter_uf_gpm: vec![0., 0., 0., 0., 0., 0., 0.00023374, 0.00724899], - adj_iter_uf_kwh_per_mi: Array::from_vec(vec![ - 0., 0.04627656, 0.03380567, 0.03708269, 0.02264331, 0.02452931, 0.01923259, - 0.00887393, 0., - ]), - adj_cd_miles: 50.26936333468235, - adj_cd_mpgge: 2937.5533511975764, - adj_cs_mpgge: 43.230829300104, - adj_uf: 0.68662, - adj_mpgge: 133.64102451254365, - adj_kwh_per_mi: 0.3259039663244739, - adj_ess_kwh_per_mi: 0.2802774110390475, - delta_soc: 0.11102338333896955, - total_cd_miles: 69.30333119859274, - }; + let hwy: PHEVCycleCalc = PHEVCycleCalc { + cd_ess_kwh: 13.799999999999999, + cd_ess_kwh_per_mi: 0.19912462736394723, + cd_fs_gal: 0.0, + cd_fs_kwh: 0.0, + cd_mpg: 61.75832757157714, + cd_cycs: 6.75533367335913, + cd_miles: 71.81337619240335, + cd_lab_mpg: 199.76659107309018, + cd_adj_mpg: 4975.506626976092, + cd_frac_in_trans: 0.7553336733591296, + trans_init_soc: 0.23385969996618272, + trans_ess_kwh: 1.5430184793777608, + trans_ess_kwh_per_mi: 0.15040553624307812, + trans_fs_gal: 0.040643020828268026, + trans_fs_kwh: 1.3696698019126325, + cs_ess_kwh: -27.84287564320177, + cs_ess_kwh_per_mi: -0.0007538835761840731, + cs_fs_gal: 0.1661161198039534, + cs_fs_kwh: 5.59811323739323, + cs_mpg: 61.75832757157714, + lab_mpgge: 282.75893721314793, + lab_kwh_per_mi: 0.19665299886733625, + lab_uf: 0.7914100000000001, + lab_uf_gpm: Array::from_vec(vec![0.00015906, 0.00337752]), + lab_iter_uf: Array::from_vec(vec![ + 0., 0.2044, 0.38194, 0.51506, 0.62998, 0.69897, 0.75126, 0.79141, + ]), + lab_iter_uf_kwh_per_mi: Array::from_vec(vec![ + 0., 0.04070107, 0.03535259, 0.02650747, 0.0228834, 0.01373761, 0.01041223, 0.00603878, + 0., + ]), + lab_iter_kwh_per_mi: Array::from_vec(vec![ + 0., 0.19912463, 0.19912463, 0.19912463, 0.19912463, 0.19912463, 0.19912463, 0.15040554, + 0., + ]), + adj_iter_mpgge: Array::from_vec(vec![0., 0., 0., 0., 0., 0., 176.69300837, 43.2308293]), + adj_iter_kwh_per_mi: Array::from_vec(vec![ + 0., 0.28446375, 0.28446375, 0.28446375, 0.28446375, 0.28446375, 0.28446375, 0.21486505, + 0., + ]), + adj_iter_cd_miles: Array::from_vec(vec![ + 0., + 7.18133762, + 14.36267524, + 21.54401286, + 28.72535048, + 35.9066881, + 43.08802572, + 50.26936333, + 0., + ]), + adj_iter_uf: Array::from_vec(vec![ + 0., 0.16268, 0.28152, 0.41188, 0.49148, 0.57771, 0.64532, 0.68662, 0., + ]), + adj_iter_uf_gpm: vec![0., 0., 0., 0., 0., 0., 0.00023374, 0.00724899], + adj_iter_uf_kwh_per_mi: Array::from_vec(vec![ + 0., 0.04627656, 0.03380567, 0.03708269, 0.02264331, 0.02452931, 0.01923259, 0.00887393, + 0., + ]), + adj_cd_miles: 50.26936333468235, + adj_cd_mpgge: 2937.5533511975764, + adj_cs_mpgge: 43.230829300104, + adj_uf: 0.68662, + adj_mpgge: 133.64102451254365, + adj_kwh_per_mi: 0.3259039663244739, + adj_ess_kwh_per_mi: 0.2802774110390475, + delta_soc: 0.11102338333896955, + total_cd_miles: 69.30333119859274, + }; - let phev_calcs: LabelFePHEV = LabelFePHEV { - regen_soc_buffer: 0.00957443430586049, - udds, - hwy, - }; + let phev_calcs: LabelFePHEV = LabelFePHEV { + regen_soc_buffer: 0.00957443430586049, + udds, + hwy, + }; - let label_fe_truth: LabelFe = LabelFe { - veh: vehicle::RustVehicle::default(), - adj_params: RustLongParams::default().ld_fe_adj_coef.adj_coef_map["2008"].clone(), - lab_udds_mpgge: 370.06411942132064, - lab_hwy_mpgge: 282.75893721314793, - lab_comb_mpgge: 324.91895455274005, - lab_udds_kwh_per_mi: 0.16342111007981494, - lab_hwy_kwh_per_mi: 0.19665299886733625, - lab_comb_kwh_per_mi: 0.17837546003419952, - adj_udds_mpgge: 175.0223917643415, - adj_hwy_mpgge: 133.64102451254365, - adj_comb_mpgge: 153.61727461480555, - adj_udds_kwh_per_mi: 0.27097024959679444, - adj_hwy_kwh_per_mi: 0.3259039663244739, - adj_comb_kwh_per_mi: 0.29569042212425023, - adj_udds_ess_kwh_per_mi: 0.23303441465324323, - adj_hwy_ess_kwh_per_mi: 0.2802774110390475, - adj_comb_ess_kwh_per_mi: 0.25429376302685514, - net_range_miles: 453.1180867180584, - uf: 0.73185, - // net_accel: 7.962519496024332, <- Correct accel value - net_accel: 1000., - res_found: String::from("model needs to be implemented for this"), - phev_calcs: Some(phev_calcs), - adj_cs_comb_mpgge: Some(45.06826741586106), - adj_cd_comb_mpgge: Some(2293.5675017498143), - net_phev_cd_miles: Some(57.04992781503185), - trace_miss_speed_mph: 0.0, - }; + let label_fe_truth: LabelFe = LabelFe { + veh: vehicle::RustVehicle::default(), + adj_params: RustLongParams::default().ld_fe_adj_coef.adj_coef_map["2008"].clone(), + lab_udds_mpgge: 370.06411942132064, + lab_hwy_mpgge: 282.75893721314793, + lab_comb_mpgge: 324.91895455274005, + lab_udds_kwh_per_mi: 0.16342111007981494, + lab_hwy_kwh_per_mi: 0.19665299886733625, + lab_comb_kwh_per_mi: 0.17837546003419952, + adj_udds_mpgge: 175.0223917643415, + adj_hwy_mpgge: 133.64102451254365, + adj_comb_mpgge: 153.61727461480555, + adj_udds_kwh_per_mi: 0.27097024959679444, + adj_hwy_kwh_per_mi: 0.3259039663244739, + adj_comb_kwh_per_mi: 0.29569042212425023, + adj_udds_ess_kwh_per_mi: 0.23303441465324323, + adj_hwy_ess_kwh_per_mi: 0.2802774110390475, + adj_comb_ess_kwh_per_mi: 0.25429376302685514, + net_range_miles: 453.1180867180584, + uf: 0.73185, + // net_accel: 7.962519496024332, <- Correct accel value + net_accel: 1000., + res_found: String::from("model needs to be implemented for this"), + phev_calcs: Some(phev_calcs), + adj_cs_comb_mpgge: Some(45.06826741586106), + adj_cd_comb_mpgge: Some(2293.5675017498143), + net_phev_cd_miles: Some(57.04992781503185), + trace_miss_speed_mph: 0.0, + }; - let tol = 1e-8; - assert!(label_fe.veh.approx_eq(&label_fe_truth.veh, tol)); - assert!( - label_fe - .phev_calcs - .approx_eq(&label_fe_truth.phev_calcs, tol), - "label_fe.phev_calcs: {:?}", - &label_fe.phev_calcs - ); - assert!(label_fe.approx_eq(&label_fe_truth, tol)); - } + let tol = 1e-8; + assert!(label_fe.veh.approx_eq(&label_fe_truth.veh, tol)); + assert!( + label_fe + .phev_calcs + .approx_eq(&label_fe_truth.phev_calcs, tol), + "label_fe.phev_calcs: {:?}", + &label_fe.phev_calcs + ); + assert!(label_fe.approx_eq(&label_fe_truth, tol)); +} From d7e9fe829318764d7610913f7d6e616ff7dcbd62 Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Wed, 12 Jul 2023 14:11:25 -0600 Subject: [PATCH 20/27] update lib.rs --- rust/Cargo.toml | 4 ++-- rust/fastsim-core/src/simdrivelabel.rs | 1 + rust/fastsim-py/src/lib.rs | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 61ed446e..2dd9aa1b 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -14,8 +14,8 @@ codegen-units = 1 # optimize connection between modules [workspace.dependencies] anyhow = "1.0.57" -pyo3 = "0.17.2" +pyo3 = "0.19" pyo3-log = "*" serde = "1.0.143" serde_json = "1.0.83" -serde_yaml = "0.8.24" \ No newline at end of file +serde_yaml = "0.9.22" \ No newline at end of file diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 4f77c9d9..9053490a 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -429,6 +429,7 @@ pub fn get_label_fe( } #[cfg(feature = "pyo3")] + /// pyo3 version of [get_label_fe] pub fn get_label_fe_py( veh: &vehicle::RustVehicle, diff --git a/rust/fastsim-py/src/lib.rs b/rust/fastsim-py/src/lib.rs index fc49ca2d..b057d0e9 100644 --- a/rust/fastsim-py/src/lib.rs +++ b/rust/fastsim-py/src/lib.rs @@ -1,6 +1,8 @@ use fastsim_core::*; use pyo3imports::*; +use fastsim_core::simdrivelabel::*; + /// Function for adding Rust structs as Python Classes #[pymodule] @@ -19,12 +21,19 @@ fn fastsimrust(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + cycle::register(py, m)?; m.add_function(wrap_pyfunction!(vehicle_utils::abc_to_drag_coeffs, m)?)?; m.add_function(wrap_pyfunction!(make_accel_trace_py, m)?)?; m.add_function(wrap_pyfunction!(get_net_accel_py, m)?)?; - m.add_function(wrap_pyfunction!(get_label_fe_py, m)?)?; - m.add_function(wrap_pyfunction!(get_label_fe_phev_py, m)?)?; - m.add_function(wrap_pyfunction!(get_label_fe_conv_py, m)?)?; - Ok(()) + #[cfg(feature = "pyo3")] + { + m.add_class::()?; + m.add_function(wrap_pyfunction!(get_label_fe_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_phev_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_conv_py, m)?)?; + + } + + Ok(()) } From 4f86fb32c3a3fb4d3102f7ffa1d113b757d35ea0 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Fri, 14 Jul 2023 10:21:42 -0600 Subject: [PATCH 21/27] ready for handoff to Asmaa --- rust/fastsim-core/src/params.rs | 3 +++ rust/fastsim-core/src/simdrivelabel.rs | 21 +++++++++++++++------ rust/fastsim-py/src/lib.rs | 20 ++++++++------------ 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/rust/fastsim-core/src/params.rs b/rust/fastsim-core/src/params.rs index 9edda1ac..5451bea2 100644 --- a/rust/fastsim-core/src/params.rs +++ b/rust/fastsim-core/src/params.rs @@ -132,11 +132,14 @@ pub struct RustLongParams { } #[derive(Debug, Serialize, Deserialize, PartialEq, ApproxEq)] +#[add_pyo3_api] pub struct AdjCoefMap { #[serde(flatten)] pub adj_coef_map: HashMap, } +impl SerdeAPI for AdjCoefMap {} + #[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct AdjCoef { #[serde(rename = "City Intercept")] diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 9053490a..26edd84f 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -1,20 +1,21 @@ //! Module containing classes and methods for calculating label fuel economy. use ndarray::Array; +use pyo3::prelude::*; +use serde::Serialize; use std::collections::HashMap; // crate local use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; -use pyo3::prelude::*; - -use crate::proc_macros::ApproxEq; -use serde::Serialize; +use crate::proc_macros::{add_pyo3_api, ApproxEq}; +use crate::pyo3imports::*; use crate::simdrive::{RustSimDrive, RustSimDriveParams}; use crate::vehicle; +#[add_pyo3_api] #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] pub struct LabelFe { pub veh: vehicle::RustVehicle, @@ -45,6 +46,9 @@ pub struct LabelFe { pub trace_miss_speed_mph: f64, } +impl SerdeAPI for LabelFe {} + +#[add_pyo3_api] #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] /// Label fuel economy values for a PHEV vehicle pub struct LabelFePHEV { @@ -53,6 +57,9 @@ pub struct LabelFePHEV { pub hwy: PHEVCycleCalc, } +impl SerdeAPI for LabelFePHEV {} + +#[add_pyo3_api] #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] /// Label fuel economy calculations for a specific cycle of a PHEV vehicle pub struct PHEVCycleCalc { @@ -109,6 +116,8 @@ pub struct PHEVCycleCalc { pub total_cd_miles: f64, } +impl SerdeAPI for PHEVCycleCalc {} + pub fn make_accel_trace() -> RustCycle { let accel_cyc_secs = Array::range(0., 300., 0.1); let mut accel_cyc_mps = Array::ones(accel_cyc_secs.len()) * 90.0 / MPH_PER_MPS; @@ -124,7 +133,7 @@ pub fn make_accel_trace() -> RustCycle { } #[cfg(feature = "pyo3")] -#[pyfunction(rename = "make_accel_trace")] +#[pyfunction(name = "make_accel_trace")] /// pyo3 version of [make_accel_trace] pub fn make_accel_trace_py() -> RustCycle { make_accel_trace() @@ -150,7 +159,7 @@ pub fn get_net_accel( } #[cfg(feature = "pyo3")] -#[pyfunction(rename = "get_net_accel")] +#[pyfunction(name = "get_net_accel")] /// pyo3 version of [get_net_accel] pub fn get_net_accel_py(sd_accel: &mut RustSimDrive, scenario_name: &str) -> PyResult { let result = get_net_accel(sd_accel, &scenario_name.to_string())?; diff --git a/rust/fastsim-py/src/lib.rs b/rust/fastsim-py/src/lib.rs index b057d0e9..affe4fde 100644 --- a/rust/fastsim-py/src/lib.rs +++ b/rust/fastsim-py/src/lib.rs @@ -1,8 +1,7 @@ use fastsim_core::*; -use pyo3imports::*; use fastsim_core::simdrivelabel::*; - +use pyo3imports::*; /// Function for adding Rust structs as Python Classes #[pymodule] @@ -21,19 +20,16 @@ fn fastsimrust(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; cycle::register(py, m)?; m.add_function(wrap_pyfunction!(vehicle_utils::abc_to_drag_coeffs, m)?)?; m.add_function(wrap_pyfunction!(make_accel_trace_py, m)?)?; m.add_function(wrap_pyfunction!(get_net_accel_py, m)?)?; - #[cfg(feature = "pyo3")] - { - m.add_class::()?; - m.add_function(wrap_pyfunction!(get_label_fe_py, m)?)?; - m.add_function(wrap_pyfunction!(get_label_fe_phev_py, m)?)?; - m.add_function(wrap_pyfunction!(get_label_fe_conv_py, m)?)?; - - } - - Ok(()) + m.add_function(wrap_pyfunction!(get_label_fe_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_phev_py, m)?)?; + m.add_function(wrap_pyfunction!(get_label_fe_conv_py, m)?)?; + Ok(()) } From da442fc73db8306e93bfc7269133d51d630cb8af Mon Sep 17 00:00:00 2001 From: Romia87 <126118320+Romia87@users.noreply.github.com> Date: Mon, 17 Jul 2023 15:09:11 -0600 Subject: [PATCH 22/27] update add pyo3 --- python/fastsim/fastsimrust.pyi | 1 + rust/fastsim-core/src/params.rs | 17 ++++++++++--- rust/fastsim-core/src/simdrivelabel.rs | 34 +++++++++++++++++--------- rust/fastsim-py/src/lib.rs | 8 +++--- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/python/fastsim/fastsimrust.pyi b/python/fastsim/fastsimrust.pyi index 1f01dc23..8ec297b4 100644 --- a/python/fastsim/fastsimrust.pyi +++ b/python/fastsim/fastsimrust.pyi @@ -480,6 +480,7 @@ class RustSimDrive: i: int impose_coast: Pyo3ArrayBool ke_kj: float + long_params: RustLongParams max_ess_accell_buff_dischg_kw: Pyo3ArrayF64 max_ess_regen_buff_chg_kw: Pyo3ArrayF64 max_trac_mps: Pyo3ArrayF64 diff --git a/rust/fastsim-core/src/params.rs b/rust/fastsim-core/src/params.rs index 5451bea2..359f8377 100644 --- a/rust/fastsim-core/src/params.rs +++ b/rust/fastsim-core/src/params.rs @@ -42,6 +42,8 @@ pub const MODERN_MAX: f64 = 0.95; todo!(); } )] + + pub struct RustPhysicalProperties { pub air_density_kg_per_m3: f64, // = 1.2, Sea level air density at approximately 20C pub a_grav_mps2: f64, // = 9.81 @@ -121,18 +123,24 @@ pub const SMALL_BASELINE_EFF: [f64; 11] = [ pub const CHG_EFF: f64 = 0.86; // charger efficiency for PEVs, this should probably not be hard coded long term -#[derive(Debug, Serialize, Deserialize, PartialEq, ApproxEq)] + +#[add_pyo3_api] + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct RustLongParams { #[serde(rename = "rechgFreqMiles")] pub rechg_freq_miles: Vec, #[serde(rename = "ufArray")] pub uf_array: Vec, #[serde(rename = "LD_FE_Adj_Coef")] - pub ld_fe_adj_coef: AdjCoefMap, + pub ld_fe_adj_coef: AdjCoefMap, } -#[derive(Debug, Serialize, Deserialize, PartialEq, ApproxEq)] +impl SerdeAPI for RustLongParams {} + #[add_pyo3_api] + +#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct AdjCoefMap { #[serde(flatten)] pub adj_coef_map: HashMap, @@ -140,6 +148,8 @@ pub struct AdjCoefMap { impl SerdeAPI for AdjCoefMap {} +#[add_pyo3_api] + #[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct AdjCoef { #[serde(rename = "City Intercept")] @@ -151,6 +161,7 @@ pub struct AdjCoef { #[serde(rename = "Highway Slope")] pub hwy_slope: f64, } +impl SerdeAPI for AdjCoef {} impl Default for RustLongParams { fn default() -> Self { diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 26edd84f..b8ee3288 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -1,15 +1,18 @@ //! Module containing classes and methods for calculating label fuel economy. use ndarray::Array; -use pyo3::prelude::*; use serde::Serialize; use std::collections::HashMap; + // crate local use crate::cycle::RustCycle; use crate::imports::*; use crate::params::*; -use crate::proc_macros::{add_pyo3_api, ApproxEq}; +use crate::proc_macros::add_pyo3_api; +use crate::proc_macros::ApproxEq; + +#[cfg(feature = "pyo3")] use crate::pyo3imports::*; use crate::simdrive::{RustSimDrive, RustSimDriveParams}; @@ -17,7 +20,7 @@ use crate::vehicle; #[add_pyo3_api] #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] -pub struct LabelFe { + pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, pub lab_udds_mpgge: f64, @@ -44,7 +47,7 @@ pub struct LabelFe { pub adj_cd_comb_mpgge: Option, pub net_phev_cd_miles: Option, pub trace_miss_speed_mph: f64, -} + } impl SerdeAPI for LabelFe {} @@ -438,14 +441,14 @@ pub fn get_label_fe( } #[cfg(feature = "pyo3")] - +#[pyfunction(name = "get_label_fe")] /// pyo3 version of [get_label_fe] pub fn get_label_fe_py( veh: &vehicle::RustVehicle, full_detail: Option, verbose: Option, ) -> PyResult<(LabelFe, Option>)> { - let result = get_label_fe(veh, full_detail, verbose)?; + let result: (LabelFe, Option>) = get_label_fe(veh, full_detail, verbose)?; Ok(result) } @@ -747,18 +750,26 @@ pub fn get_label_fe_phev( } #[cfg(feature = "pyo3")] + #[pyfunction(name = "get_label_fe_phev")] + /// pyo3 version of [get_label_fe_phev] pub fn get_label_fe_phev_py( veh: &vehicle::RustVehicle, - sd: &mut HashMap<&str, RustSimDrive>, - long_params: RustLongParams, + sd: HashMap<&str, RustSimDrive>, adj_params: AdjCoef, - sim_params: RustSimDriveParams, + long_params: RustLongParams, + sim_params: &RustSimDriveParams, props: RustPhysicalProperties, -) -> anyhow::Result { - get_label_fe_phev(veh, sd, &long_params, &adj_params, &sim_params, &props) +) -> Result { + let mut sd_mut = HashMap::new(); + for (key, value) in sd { + sd_mut.insert(key, value); + } + + get_label_fe_phev(veh, &mut sd_mut, &long_params, &adj_params, &sim_params, &props) } + #[cfg(test)] mod simdrivelabel_tests { use super::*; @@ -810,6 +821,7 @@ mod simdrivelabel_tests { } } #[cfg(feature = "pyo3")] +#[pyfunction(name = "get_label_fe_conv")] /// pyo3 version of [get_label_fe_conv] pub fn get_label_fe_conv_py() -> LabelFe { let veh: vehicle::RustVehicle = vehicle::RustVehicle::mock_vehicle(); diff --git a/rust/fastsim-py/src/lib.rs b/rust/fastsim-py/src/lib.rs index affe4fde..aec3ab8c 100644 --- a/rust/fastsim-py/src/lib.rs +++ b/rust/fastsim-py/src/lib.rs @@ -1,5 +1,4 @@ use fastsim_core::*; - use fastsim_core::simdrivelabel::*; use pyo3imports::*; @@ -20,9 +19,9 @@ fn fastsimrust(py: Python, m: &PyModule) -> PyResult<()> { m.add_class::()?; m.add_class::()?; m.add_class::()?; - m.add_class::()?; - m.add_class::()?; - m.add_class::()?; + m.add_class::()?; + m.add_class::()?; + m.add_class::()?; cycle::register(py, m)?; m.add_function(wrap_pyfunction!(vehicle_utils::abc_to_drag_coeffs, m)?)?; @@ -31,5 +30,6 @@ fn fastsimrust(py: Python, m: &PyModule) -> PyResult<()> { m.add_function(wrap_pyfunction!(get_label_fe_py, m)?)?; m.add_function(wrap_pyfunction!(get_label_fe_phev_py, m)?)?; m.add_function(wrap_pyfunction!(get_label_fe_conv_py, m)?)?; + Ok(()) } From 0c19191c529a164d8dc5736bd4f8eb450bb2545f Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 18 Jul 2023 09:13:36 -0600 Subject: [PATCH 23/27] removed blank line --- rust/fastsim-core/src/params.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/rust/fastsim-core/src/params.rs b/rust/fastsim-core/src/params.rs index 359f8377..b0e5309f 100644 --- a/rust/fastsim-core/src/params.rs +++ b/rust/fastsim-core/src/params.rs @@ -125,7 +125,6 @@ pub const CHG_EFF: f64 = 0.86; // charger efficiency for PEVs, this should proba #[add_pyo3_api] - #[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct RustLongParams { #[serde(rename = "rechgFreqMiles")] From 320f990fb7e05ffed53e2c5757808e4d9007680b Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 18 Jul 2023 09:14:44 -0600 Subject: [PATCH 24/27] autoformatting --- rust/fastsim-core/src/simdrivelabel.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index b8ee3288..09bcdfb4 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -4,7 +4,6 @@ use ndarray::Array; use serde::Serialize; use std::collections::HashMap; - // crate local use crate::cycle::RustCycle; use crate::imports::*; @@ -20,7 +19,7 @@ use crate::vehicle; #[add_pyo3_api] #[derive(Default, Serialize, Deserialize, Clone, Debug, PartialEq, ApproxEq)] - pub struct LabelFe { +pub struct LabelFe { pub veh: vehicle::RustVehicle, pub adj_params: AdjCoef, pub lab_udds_mpgge: f64, @@ -47,7 +46,7 @@ use crate::vehicle; pub adj_cd_comb_mpgge: Option, pub net_phev_cd_miles: Option, pub trace_miss_speed_mph: f64, - } +} impl SerdeAPI for LabelFe {} @@ -448,7 +447,8 @@ pub fn get_label_fe_py( full_detail: Option, verbose: Option, ) -> PyResult<(LabelFe, Option>)> { - let result: (LabelFe, Option>) = get_label_fe(veh, full_detail, verbose)?; + let result: (LabelFe, Option>) = + get_label_fe(veh, full_detail, verbose)?; Ok(result) } @@ -750,14 +750,14 @@ pub fn get_label_fe_phev( } #[cfg(feature = "pyo3")] - #[pyfunction(name = "get_label_fe_phev")] +#[pyfunction(name = "get_label_fe_phev")] /// pyo3 version of [get_label_fe_phev] pub fn get_label_fe_phev_py( veh: &vehicle::RustVehicle, sd: HashMap<&str, RustSimDrive>, adj_params: AdjCoef, - long_params: RustLongParams, + long_params: RustLongParams, sim_params: &RustSimDriveParams, props: RustPhysicalProperties, ) -> Result { @@ -766,10 +766,16 @@ pub fn get_label_fe_phev_py( sd_mut.insert(key, value); } - get_label_fe_phev(veh, &mut sd_mut, &long_params, &adj_params, &sim_params, &props) + get_label_fe_phev( + veh, + &mut sd_mut, + &long_params, + &adj_params, + &sim_params, + &props, + ) } - #[cfg(test)] mod simdrivelabel_tests { use super::*; From 2979c466da35a0219994d15b97ddb21f53ba9a50 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 18 Jul 2023 09:16:04 -0600 Subject: [PATCH 25/27] removed unneeded reference --- rust/fastsim-core/src/simdrivelabel.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index 09bcdfb4..934a6ebc 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -771,7 +771,7 @@ pub fn get_label_fe_phev_py( &mut sd_mut, &long_params, &adj_params, - &sim_params, + sim_params, &props, ) } From bf435af88c537bc76cbc73dfcb87ec46e061f502 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 18 Jul 2023 11:06:12 -0600 Subject: [PATCH 26/27] fixed numerous clippy recommendations --- rust/fastsim-cli/src/bin/fastsim-cli.rs | 45 ++++++++++--------- .../proc-macros/src/add_pyo3_api.rs | 2 +- .../fastsim-core/proc-macros/src/utilities.rs | 25 +++++------ rust/fastsim-core/src/params.rs | 7 +-- 4 files changed, 38 insertions(+), 41 deletions(-) diff --git a/rust/fastsim-cli/src/bin/fastsim-cli.rs b/rust/fastsim-cli/src/bin/fastsim-cli.rs index 34a3bfa5..0a492604 100644 --- a/rust/fastsim-cli/src/bin/fastsim-cli.rs +++ b/rust/fastsim-cli/src/bin/fastsim-cli.rs @@ -191,7 +191,7 @@ pub fn main() { let adopt_hd_str_lc = adopt_hd_string.to_lowercase(); let true_string = String::from("true"); let false_string = String::from("false"); - let adopt_hd_has_cycle = adopt_hd_str_lc.len() > 0 + let adopt_hd_has_cycle = !adopt_hd_str_lc.is_empty() && adopt_hd_str_lc != true_string && adopt_hd_str_lc != false_string; (true, adopt_hd_string.clone(), adopt_hd_has_cycle) @@ -312,31 +312,37 @@ pub fn main() { "HHDDTCruiseSmooth.csv" )); let cyc = if adopt_hd_has_cycle { - cyc.clone() + cyc } else { RustCycle::from_csv_string(hd_cyc_filestring, "HHDDTCruiseSmooth".to_string()).unwrap() }; - let mut sim_drive = RustSimDrive::new(cyc.clone(), veh.clone()); + let mut sim_drive = RustSimDrive::new(cyc, veh.clone()); sim_drive.sim_drive(None, None).unwrap(); let mut sim_drive_accel = RustSimDrive::new(make_accel_trace(), veh.clone()); let net_accel = get_net_accel(&mut sim_drive_accel, &veh.scenario_name).unwrap(); let mut mpgge = sim_drive.mpgge; - let h2_diesel_results = if hd_h2_diesel_ice_h2share.is_some() && fc_pwr_out_perc.is_some() { - let dist_mi = sim_drive.dist_mi.sum(); - let r = calculate_mpgge_for_h2_diesel_ice( - dist_mi, - sim_drive.veh.fc_max_kw, - sim_drive.props.kwh_per_gge, - &sim_drive.fc_kw_out_ach.to_vec(), - &sim_drive.fs_kwh_out_ach.to_vec(), - &fc_pwr_out_perc.unwrap(), - &hd_h2_diesel_ice_h2share.unwrap(), - ); - mpgge = dist_mi / (r.diesel_gge + r.h2_gge); - Some(r) + + let h2_diesel_results = if let Some(hd_h2_diesel_ice_h2share) = hd_h2_diesel_ice_h2share { + if let Some(fc_pwr_out_perc) = fc_pwr_out_perc { + let dist_mi = sim_drive.dist_mi.sum(); + let r = calculate_mpgge_for_h2_diesel_ice( + dist_mi, + sim_drive.veh.fc_max_kw, + sim_drive.props.kwh_per_gge, + &sim_drive.fc_kw_out_ach.to_vec(), + &sim_drive.fs_kwh_out_ach.to_vec(), + &fc_pwr_out_perc, + &hd_h2_diesel_ice_h2share, + ); + mpgge = dist_mi / (r.diesel_gge + r.h2_gge); + Some(r) + } else { + None + } } else { None }; + let res = AdoptResults { adjCombMpgge: mpgge, rangeMiles: if mpgge > 0.0 { @@ -397,8 +403,7 @@ fn array_to_object_representation(xs: &Vec) -> ArrayObject { fn transform_array_of_value_to_vec_of_f64(array_of_values: &Vec) -> Vec { let mut vec_of_f64 = Vec::::new(); - for idx in 0..array_of_values.len() { - let item_raw = &array_of_values[idx]; + for item_raw in array_of_values { if item_raw.is_number() { let item = item_raw.as_f64().unwrap(); vec_of_f64.push(item); @@ -437,7 +442,7 @@ fn json_rewrite(x: String) -> (String, Option>, Option>) { let fc_eff_type_value = fc_eff_type_raw.as_str().unwrap(); let fc_eff_type = String::from(fc_eff_type_value); parsed_data["fcEffType"] = Value::String(fc_eff_type.clone()); - if fc_eff_type == String::from("HDH2DieselIce") { + if fc_eff_type == *"HDH2DieselIce" { let fc_pwr_out_perc_raw = &parsed_data["fuelConverter"]["fcPwrOutPerc"]; if fc_pwr_out_perc_raw.is_array() { fc_pwr_out_perc = Some(transform_array_of_value_to_vec_of_f64( @@ -517,5 +522,5 @@ fn json_rewrite(x: String) -> (String, Option>, Option>) { let adoptstring = ParsedValue(parsed_data).to_json(); - return (adoptstring, fc_pwr_out_perc, hd_h2_diesel_ice_h2share); + (adoptstring, fc_pwr_out_perc, hd_h2_diesel_ice_h2share) } diff --git a/rust/fastsim-core/proc-macros/src/add_pyo3_api.rs b/rust/fastsim-core/proc-macros/src/add_pyo3_api.rs index 36675b2e..cb174d69 100644 --- a/rust/fastsim-core/proc-macros/src/add_pyo3_api.rs +++ b/rust/fastsim-core/proc-macros/src/add_pyo3_api.rs @@ -11,7 +11,7 @@ pub fn add_pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream { let mut impl_block = TokenStream2::default(); let mut py_impl_block = TokenStream2::default(); py_impl_block.extend::(crate::utilities::parse_ts_as_fn_defs( - attr.into(), + attr, vec![], false, vec![], diff --git a/rust/fastsim-core/proc-macros/src/utilities.rs b/rust/fastsim-core/proc-macros/src/utilities.rs index 72baf33e..914d551a 100644 --- a/rust/fastsim-core/proc-macros/src/utilities.rs +++ b/rust/fastsim-core/proc-macros/src/utilities.rs @@ -265,26 +265,23 @@ pub fn parse_ts_as_fn_defs( let sig_str = &item_meth.sig.ident.to_token_stream().to_string(); fn_from_attr.extend(item_meth.clone().to_token_stream()); // check signature - if expected_exclusive { - if forbidden_fn_names.contains(sig_str) || !expected_fn_names.contains(sig_str) - { - emit_error!( - &item_meth.sig.ident.span(), - format!("Function name `{}` is forbidden", sig_str) - ) - } + if expected_exclusive + && (forbidden_fn_names.contains(sig_str) + || !expected_fn_names.contains(sig_str)) + { + emit_error!( + &item_meth.sig.ident.span(), + format!("Function name `{}` is forbidden", sig_str) + ) } let index = expected_fn_names.iter().position(|x| x == sig_str); - match index { - Some(i) => { - expected_fn_names.remove(i); - } - _ => {} - } // remove the matching name from the vec to avoid checking again // at the end of iteration, this vec should be empty + if let Some(i) = index { + expected_fn_names.remove(i); + } } _ => abort_call_site!(ONLY_FN_MSG), } diff --git a/rust/fastsim-core/src/params.rs b/rust/fastsim-core/src/params.rs index b0e5309f..7a01f7b0 100644 --- a/rust/fastsim-core/src/params.rs +++ b/rust/fastsim-core/src/params.rs @@ -42,8 +42,6 @@ pub const MODERN_MAX: f64 = 0.95; todo!(); } )] - - pub struct RustPhysicalProperties { pub air_density_kg_per_m3: f64, // = 1.2, Sea level air density at approximately 20C pub a_grav_mps2: f64, // = 9.81 @@ -123,7 +121,6 @@ pub const SMALL_BASELINE_EFF: [f64; 11] = [ pub const CHG_EFF: f64 = 0.86; // charger efficiency for PEVs, this should probably not be hard coded long term - #[add_pyo3_api] #[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct RustLongParams { @@ -132,13 +129,12 @@ pub struct RustLongParams { #[serde(rename = "ufArray")] pub uf_array: Vec, #[serde(rename = "LD_FE_Adj_Coef")] - pub ld_fe_adj_coef: AdjCoefMap, + pub ld_fe_adj_coef: AdjCoefMap, } impl SerdeAPI for RustLongParams {} #[add_pyo3_api] - #[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct AdjCoefMap { #[serde(flatten)] @@ -148,7 +144,6 @@ pub struct AdjCoefMap { impl SerdeAPI for AdjCoefMap {} #[add_pyo3_api] - #[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)] pub struct AdjCoef { #[serde(rename = "City Intercept")] From e3dfdcefdb389f03cdce0914f5de574c80b59838 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 18 Jul 2023 11:26:36 -0600 Subject: [PATCH 27/27] fixed failing test --- python/fastsim/parameters.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/python/fastsim/parameters.py b/python/fastsim/parameters.py index 00cc170c..70a262cb 100644 --- a/python/fastsim/parameters.py +++ b/python/fastsim/parameters.py @@ -10,6 +10,8 @@ from pathlib import Path import copy from copy import deepcopy +import json + import fastsim.fastsimrust as fsr from . import inspect_utils @@ -100,7 +102,7 @@ def copy_physical_properties(p: PhysicalProperties, return_type: str = None, dee elif return_type == 'python': return PhysicalProperties.from_dict(p_dict) elif return_type == 'rust': - return fsr.RustPhysicalProperties(**p_dict) + return fsr.RustPhysicalProperties.from_json(json.dumps(p_dict)) else: raise ValueError(f"Invalid return_type: '{return_type}'")