1use crate::imports::*;
4use crate::proc_macros::{add_pyo3_api, ApproxEq};
5#[cfg(feature = "pyo3")]
6use crate::pyo3imports::*;
7
8use std::collections::HashMap;
9
10pub const MPH_PER_MPS: f64 = 2.2369;
12pub const M_PER_MI: f64 = 1609.00;
13pub 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
20pub const MODERN_MAX: f64 = 0.95;
22
23#[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, pub a_grav_mps2: f64, pub kwh_per_gge: f64, pub fuel_rho_kg__L: f64, pub fuel_afr_stoich: f64, #[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 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 self.kwh_per_gge = fuel_lhv_kj_per_kg * 3.785 * self.fuel_rho_kg__L / 3.6e3;
87 }
88}
89
90pub 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; #[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}