fastsim_core/
params.rs

1//! Module containing FASTSim parameters.
2
3use crate::imports::*;
4use crate::proc_macros::{add_pyo3_api, ApproxEq};
5#[cfg(feature = "pyo3")]
6use crate::pyo3imports::*;
7
8use std::collections::HashMap;
9
10/// Unit conversions that should NEVER change
11pub const MPH_PER_MPS: f64 = 2.2369;
12pub const M_PER_MI: f64 = 1609.00;
13// Newtons per pound-force
14pub const N_PER_LBF: f64 = 4.448;
15pub const L_PER_GAL: f64 = 3.78541;
16pub const HP_PER_KW: f64 = 1.34102;
17pub const IN_PER_M: f64 = 39.3701;
18pub const LBS_PER_KG: f64 = 2.20462;
19
20/// Misc Constants
21pub const MODERN_MAX: f64 = 0.95;
22
23/// Struct containing time trace data
24#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, ApproxEq)]
25#[allow(non_snake_case)]
26#[add_pyo3_api(
27    #[allow(non_snake_case)]
28    #[new]
29    pub fn __new__() -> Self {
30        Self::default()
31    }
32
33    #[pyo3(name = "get_fuel_lhv_kj_per_kg")]
34    pub fn get_fuel_lhv_kj_per_kg_py(&self) -> f64 {
35        self.get_fuel_lhv_kj_per_kg()
36    }
37
38    #[pyo3(name = "set_fuel_lhv_kj_per_kg")]
39    pub fn set_fuel_lhv_kj_per_kg_py(&mut self, fuel_lhv_kj_per_kg: f64) {
40        self.set_fuel_lhv_kj_per_kg(fuel_lhv_kj_per_kg);
41    }
42
43    pub fn __getnewargs__(&self) {
44        todo!();
45    }
46)]
47pub struct RustPhysicalProperties {
48    pub air_density_kg_per_m3: f64, // = 1.2, Sea level air density at approximately 20C
49    pub a_grav_mps2: f64,           // = 9.81
50    pub kwh_per_gge: f64,           // = 33.7 # kWh per gallon of gasoline
51    pub fuel_rho_kg__L: f64, // = 0.75 # gasoline density in kg/L https://inchem.org/documents/icsc/icsc/eics1400.htm
52    pub fuel_afr_stoich: f64, // = 14.7 # gasoline stoichiometric air-fuel ratio https://en.wikipedia.org/wiki/Air%E2%80%93fuel_ratio
53    #[serde(skip)]
54    pub orphaned: bool,
55}
56
57impl SerdeAPI for RustPhysicalProperties {}
58
59impl Default for RustPhysicalProperties {
60    fn default() -> Self {
61        let air_density_kg_per_m3 = 1.2;
62        let a_grav_mps2 = 9.81;
63        let kwh_per_gge = 33.7;
64        #[allow(non_snake_case)]
65        let fuel_rho_kg__L = 0.75;
66        let fuel_afr_stoich = 14.7;
67        Self {
68            air_density_kg_per_m3,
69            a_grav_mps2,
70            kwh_per_gge,
71            fuel_rho_kg__L,
72            fuel_afr_stoich,
73            orphaned: false,
74        }
75    }
76}
77
78impl RustPhysicalProperties {
79    pub fn get_fuel_lhv_kj_per_kg(&self) -> f64 {
80        // fuel_lhv_kj_per_kg = kWhPerGGE / 3.785 [L/gal] / fuel_rho_kg_per_L [kg/L] * 3_600 [s/hr] = [kJ/kg]
81        self.kwh_per_gge / 3.785 / self.fuel_rho_kg__L * 3.6e3
82    }
83
84    pub fn set_fuel_lhv_kj_per_kg(&mut self, fuel_lhv_kj_per_kg: f64) {
85        // kWhPerGGE = fuel_lhv_kj_per_kg * fuel_rho_kg_per_L [kg/L] * 3.785 [L/gal] / 3_600 [s/hr] = [kJ/kg]
86        self.kwh_per_gge = fuel_lhv_kj_per_kg * 3.785 * self.fuel_rho_kg__L / 3.6e3;
87    }
88}
89
90// Vehicle model parameters that should be changed only by advanced users
91
92/// Relatively continuous power out percentages for assigning FC efficiencies
93pub const FC_PERC_OUT_ARRAY: [f64; 100] = [
94    0., 0.001, 0.002, 0.003, 0.004, 0.005, 0.006, 0.007, 0.008, 0.009, 0.01, 0.011, 0.012, 0.013,
95    0.014, 0.015, 0.016, 0.017, 0.018, 0.019, 0.02, 0.021, 0.022, 0.023, 0.024, 0.025, 0.026,
96    0.027, 0.028, 0.029, 0.03, 0.035, 0.04, 0.045, 0.05, 0.055, 0.06, 0.065, 0.07, 0.08, 0.09, 0.1,
97    0.11, 0.12, 0.13, 0.14, 0.15, 0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26,
98    0.27, 0.28, 0.29, 0.3, 0.31, 0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42,
99    0.43, 0.44, 0.45, 0.46, 0.47, 0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58,
100    0.59, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95, 1.,
101];
102
103pub const MC_PERC_OUT_ARRAY: [f64; 101] = [
104    0., 0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09, 0.1, 0.11, 0.12, 0.13, 0.14, 0.15,
105    0.16, 0.17, 0.18, 0.19, 0.2, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.3, 0.31,
106    0.32, 0.33, 0.34, 0.35, 0.36, 0.37, 0.38, 0.39, 0.4, 0.41, 0.42, 0.43, 0.44, 0.45, 0.46, 0.47,
107    0.48, 0.49, 0.5, 0.51, 0.52, 0.53, 0.54, 0.55, 0.56, 0.57, 0.58, 0.59, 0.6, 0.61, 0.62, 0.63,
108    0.64, 0.65, 0.66, 0.67, 0.68, 0.69, 0.7, 0.71, 0.72, 0.73, 0.74, 0.75, 0.76, 0.77, 0.78, 0.79,
109    0.8, 0.81, 0.82, 0.83, 0.84, 0.85, 0.86, 0.87, 0.88, 0.89, 0.9, 0.91, 0.92, 0.93, 0.94, 0.95,
110    0.96, 0.97, 0.98, 0.99, 1.,
111];
112
113pub const SMALL_MOTOR_POWER_KW: f64 = 7.5;
114pub const LARGE_MOTOR_POWER_KW: f64 = 75.0;
115
116pub const LARGE_BASELINE_EFF: [f64; 11] = [
117    0.83, 0.85, 0.87, 0.89, 0.90, 0.91, 0.93, 0.94, 0.94, 0.93, 0.92,
118];
119
120pub const SMALL_BASELINE_EFF: [f64; 11] = [
121    0.12, 0.16, 0.21, 0.29, 0.35, 0.42, 0.75, 0.92, 0.93, 0.93, 0.92,
122];
123
124pub const CHG_EFF: f64 = 0.86; // charger efficiency for PEVs, this should probably not be hard coded long term
125
126#[add_pyo3_api]
127#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)]
128pub struct RustLongParams {
129    #[serde(rename = "rechgFreqMiles")]
130    pub rechg_freq_miles: Vec<f64>,
131    #[serde(rename = "ufArray")]
132    pub uf_array: Vec<f64>,
133    #[serde(rename = "LD_FE_Adj_Coef")]
134    pub ld_fe_adj_coef: AdjCoefMap,
135}
136
137impl SerdeAPI for RustLongParams {}
138
139#[add_pyo3_api]
140#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)]
141pub struct AdjCoefMap {
142    #[serde(flatten)]
143    pub adj_coef_map: HashMap<String, AdjCoef>,
144}
145
146impl SerdeAPI for AdjCoefMap {}
147
148#[add_pyo3_api]
149#[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone, ApproxEq)]
150pub struct AdjCoef {
151    #[serde(rename = "City Intercept")]
152    pub city_intercept: f64,
153    #[serde(rename = "City Slope")]
154    pub city_slope: f64,
155    #[serde(rename = "Highway Intercept")]
156    pub hwy_intercept: f64,
157    #[serde(rename = "Highway Slope")]
158    pub hwy_slope: f64,
159}
160impl SerdeAPI for AdjCoef {}
161
162impl Default for RustLongParams {
163    fn default() -> Self {
164        let long_params_str = include_str!("../resources/longparams.json");
165        let long_params = Self::from_json(long_params_str, false).unwrap();
166        long_params
167    }
168}
169
170#[cfg(test)]
171mod params_test {
172    use super::*;
173
174    #[test]
175    fn test_get_long_params() {
176        let long_params = RustLongParams::default();
177
178        let adj_coef_2008 = AdjCoef {
179            city_intercept: 0.003259,
180            city_slope: 1.1805,
181            hwy_intercept: 0.001376,
182            hwy_slope: 1.3466,
183        };
184        let adj_coef_2017 = AdjCoef {
185            city_intercept: 0.004091,
186            city_slope: 1.1601,
187            hwy_intercept: 0.003191,
188            hwy_slope: 1.2945,
189        };
190
191        let mut adj_coef_map = HashMap::new();
192        adj_coef_map.insert(String::from("2008"), adj_coef_2008);
193        adj_coef_map.insert(String::from("2017"), adj_coef_2017);
194
195        assert_eq!(long_params.rechg_freq_miles.len(), 602);
196        assert_eq!(long_params.uf_array.len(), 602);
197        assert_eq!(long_params.ld_fe_adj_coef.adj_coef_map, adj_coef_map);
198    }
199}