diff --git a/Cargo.toml b/Cargo.toml index 996897f2..131907e7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ opt-level = 0 opt-level = 3 [workspace.dependencies] -# TODO: uncomment and correct version `version = "~0.0.1"` document-features = "0.2.10" fastsim-core = { path = "fastsim-core" } anyhow = "1.0.71" diff --git a/benchmarks/f3-save-int-1.py b/benchmarks/f3-save-int-1.py index d57a94f2..234ccbbe 100755 --- a/benchmarks/f3-save-int-1.py +++ b/benchmarks/f3-save-int-1.py @@ -4,10 +4,7 @@ @profile(precision=3) def build_and_run_sim_drive(): - veh = fsim.Vehicle.from_file( - # TODO: figure out why `str` is needed here - str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") - ) + veh = fsim.Vehicle.from_resource("2012_Ford_Fusion.yaml") fsim.set_param_from_path(veh, "save_interval", 1) cyc = fsim.Cycle.from_resource("udds.csv") sd = fsim.SimDrive(veh, cyc) @@ -23,8 +20,8 @@ def build_and_run_sim_drive(): # 5 61.562 MiB 61.562 MiB 1 @profile(precision=3) # 6 def build_and_run_sim_drive(): # 7 62.125 MiB 0.562 MiB 2 veh = fsim.Vehicle.from_file( - # 8 # TODO: figure out why `str` is needed here - # 9 61.562 MiB 0.000 MiB 1 str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") + # 8 + # 9 61.562 MiB 0.000 MiB 1 fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml" # 10 ) # 11 62.125 MiB 0.000 MiB 1 veh.save_interval = 1 # 12 62.312 MiB 0.188 MiB 1 cyc = fsim.Cycle.from_resource("udds.csv") diff --git a/benchmarks/f3-save-int-none.py b/benchmarks/f3-save-int-none.py index d260e493..a89efc43 100755 --- a/benchmarks/f3-save-int-none.py +++ b/benchmarks/f3-save-int-none.py @@ -4,10 +4,7 @@ @profile(precision=3) def build_and_run_sim_drive(): - veh = fsim.Vehicle.from_file( - # TODO: figure out why `str` is needed here - str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") - ) + veh = fsim.Vehicle.from_resource("2012_Ford_Fusion.yaml") fsim.set_param_from_path(veh, "save_interval", None) cyc = fsim.Cycle.from_resource("udds.csv") sd = fsim.SimDrive(veh, cyc) @@ -23,8 +20,8 @@ def build_and_run_sim_drive(): # 5 61.203 MiB 61.203 MiB 1 @profile(precision=3) # 6 def build_and_run_sim_drive(): # 7 61.766 MiB 0.562 MiB 2 veh = fsim.Vehicle.from_file( -# 8 # TODO: figure out why `str` is needed here -# 9 61.203 MiB 0.000 MiB 1 str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") +# 8 +# 9 61.203 MiB 0.000 MiB 1 fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml" # 10 ) # 11 61.766 MiB 0.000 MiB 1 veh.save_interval = None # 12 61.938 MiB 0.172 MiB 1 cyc = fsim.Cycle.from_resource("udds.csv") diff --git a/fastsim-core/fastsim-proc-macros/src/cumu_method_derive.rs b/fastsim-core/fastsim-proc-macros/src/cumu_method_derive.rs index abc39f8d..356dd5f1 100644 --- a/fastsim-core/fastsim-proc-macros/src/cumu_method_derive.rs +++ b/fastsim-core/fastsim-proc-macros/src/cumu_method_derive.rs @@ -1,7 +1,5 @@ use crate::imports::*; -// TODO: make sure this macro is propagated and implementd everywhere it's needed - pub(crate) fn cumu_method_derive(input: TokenStream) -> TokenStream { let item_struct = syn::parse_macro_input!(input as syn::ItemStruct); let ident = &item_struct.ident; diff --git a/fastsim-core/fastsim-proc-macros/src/cycle_derive.rs b/fastsim-core/fastsim-proc-macros/src/cycle_derive.rs index 07faf193..cfb3412d 100644 --- a/fastsim-core/fastsim-proc-macros/src/cycle_derive.rs +++ b/fastsim-core/fastsim-proc-macros/src/cycle_derive.rs @@ -53,7 +53,7 @@ pub(crate) fn cycle_derive(input: TokenStream) -> TokenStream { .unwrap(); generated.append_all(quote! { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] - #[pyo3_api( + #[fastsim_api( #[pyo3(name = "len")] fn len_py(&self) -> usize { self.len() diff --git a/fastsim-core/fastsim-proc-macros/src/pyo3_api.rs b/fastsim-core/fastsim-proc-macros/src/fastsim_api.rs similarity index 99% rename from fastsim-core/fastsim-proc-macros/src/pyo3_api.rs rename to fastsim-core/fastsim-proc-macros/src/fastsim_api.rs index 9687fcc1..5950ae3a 100644 --- a/fastsim-core/fastsim-proc-macros/src/pyo3_api.rs +++ b/fastsim-core/fastsim-proc-macros/src/fastsim_api.rs @@ -1,9 +1,9 @@ use crate::imports::*; -mod pyo3_api_utils; +mod fastsim_api_utils; use crate::utilities::parse_ts_as_fn_defs; -use pyo3_api_utils::*; +use fastsim_api_utils::*; -pub(crate) fn pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream { +pub(crate) fn fastsim_api(attr: TokenStream, item: TokenStream) -> TokenStream { let mut ast = syn::parse_macro_input!(item as syn::ItemStruct); let ident = &ast.ident; // println!("{}", String::from("*").repeat(30)); diff --git a/fastsim-core/fastsim-proc-macros/src/pyo3_api/pyo3_api_utils.rs b/fastsim-core/fastsim-proc-macros/src/fastsim_api/fastsim_api_utils.rs similarity index 91% rename from fastsim-core/fastsim-proc-macros/src/pyo3_api/pyo3_api_utils.rs rename to fastsim-core/fastsim-proc-macros/src/fastsim_api/fastsim_api_utils.rs index d26630d3..52034b80 100644 --- a/fastsim-core/fastsim-proc-macros/src/pyo3_api/pyo3_api_utils.rs +++ b/fastsim-core/fastsim-proc-macros/src/fastsim_api/fastsim_api_utils.rs @@ -207,35 +207,34 @@ fn extract_type_path(ty: &syn::Type) -> Option<&syn::Path> { } } -#[allow(unused)] /// adapted from https://stackoverflow.com/questions/55271857/how-can-i-get-the-t-from-an-optiont-when-using-syn fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> { - use syn::{GenericArgument, Path, PathArguments, PathSegment}; - - // TODO store (with lazy static) the vec of string - // TODO maybe optimization, reverse the order of segments - fn extract_option_segment(path: &Path) -> Option<&PathSegment> { - let idents_of_path = path.segments.iter().fold(String::new(), |mut acc, v| { - acc.push_str(&v.ident.to_string()); - acc.push('|'); - acc - }); - vec!["Option|", "std|option|Option|", "core|option|Option|"] - .into_iter() - .find(|s| idents_of_path == *s) - .and_then(|_| path.segments.last()) + fn extract_option_argument(path: &Path) -> Option<&GenericArgument> { + let mut ident_path = String::new(); + for segment in &path.segments { + ident_path.push_str(&segment.ident.to_string()); + + // Exit when the inner brackets are found + match &segment.arguments { + syn::PathArguments::AngleBracketed(params) => { + return match ident_path.as_str() { + "Option" | "std::option::Option" | "core::option::Option" => { + params.args.first() + } + _ => None, + }; + } + syn::PathArguments::None => {} + _ => return None, + } + + ident_path.push_str("::"); + } + None } extract_type_path(ty) - .and_then(extract_option_segment) - .and_then(|path_seg| { - let type_params = &path_seg.arguments; - // It should have only on angle-bracketed param (""): - match *type_params { - PathArguments::AngleBracketed(ref params) => params.args.first(), - _ => None, - } - }) + .and_then(extract_option_argument) .and_then(|generic_arg| match *generic_arg { GenericArgument::Type(ref ty) => Some(ty), _ => None, @@ -310,11 +309,9 @@ pub(crate) fn impl_getters_and_setters( let mut vec_layers: u8 = 0; let mut inner_type = &ftype; - // TODO: figure this out and uncomment. Then check that all `Option` fields are handled appropriately. - // pull out `inner_type` from `Option` - // if let Some(opt_inner_type) = extract_type_from_option(inner_type) { - // inner_type = opt_inner_type; - // } + if let Some(opt_inner_type) = extract_type_from_option(inner_type) { + inner_type = opt_inner_type; + } // pull out `inner_type` from `Vec`, recursively if there is any nesting while let Some(vec_inner_type) = extract_type_from_vec(inner_type) { @@ -346,6 +343,7 @@ pub(crate) fn impl_getters_and_setters( "Mass" => extract_units!(uom::si::mass::kilogram), "MomentOfInertia" => extract_units!(uom::si::moment_of_inertia::kilogram_square_meter), "Power" => extract_units!(uom::si::power::watt), + "SpecificPower" => extract_units!(uom::si::specific_power::watt_per_kilogram), "PowerRate" => extract_units!(uom::si::power_rate::watt_per_second), "Pressure" => extract_units!(uom::si::pressure::kilopascal, uom::si::pressure::bar), "Ratio" => extract_units!(uom::si::ratio::ratio), diff --git a/fastsim-core/fastsim-proc-macros/src/history_vec_derive.rs b/fastsim-core/fastsim-proc-macros/src/history_vec_derive.rs index 94591e1b..8f19e6b6 100644 --- a/fastsim-core/fastsim-proc-macros/src/history_vec_derive.rs +++ b/fastsim-core/fastsim-proc-macros/src/history_vec_derive.rs @@ -58,7 +58,7 @@ pub(crate) fn history_vec_derive(input: TokenStream) -> TokenStream { .unwrap(); generated.append_all(quote! { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] - #[pyo3_api( + #[fastsim_api( #[pyo3(name = "len")] fn len_py(&self) -> usize { self.len() diff --git a/fastsim-core/fastsim-proc-macros/src/imports.rs b/fastsim-core/fastsim-proc-macros/src/imports.rs index d83ad604..0368a86d 100644 --- a/fastsim-core/fastsim-proc-macros/src/imports.rs +++ b/fastsim-core/fastsim-proc-macros/src/imports.rs @@ -3,4 +3,6 @@ pub(crate) use proc_macro2::TokenStream as TokenStream2; pub(crate) use proc_macro_error::{abort, abort_call_site, emit_error, proc_macro_error}; pub(crate) use quote::{quote, ToTokens, TokenStreamExt}; // ToTokens is implicitly used as a trait pub(crate) use regex::Regex; -pub(crate) use syn::{spanned::Spanned, Ident, MetaNameValue, Meta, NestedMeta}; +pub(crate) use syn::{ + spanned::Spanned, GenericArgument, Ident, Meta, MetaNameValue, NestedMeta, Path, +}; diff --git a/fastsim-core/fastsim-proc-macros/src/lib.rs b/fastsim-core/fastsim-proc-macros/src/lib.rs index a101d4c0..d0909d20 100644 --- a/fastsim-core/fastsim-proc-macros/src/lib.rs +++ b/fastsim-core/fastsim-proc-macros/src/lib.rs @@ -2,9 +2,9 @@ mod imports; use imports::*; mod cumu_method_derive; mod cycle_derive; +mod fastsim_api; mod history_vec_derive; mod hm_derive; -mod pyo3_api; mod timer; mod utilities; @@ -12,8 +12,8 @@ mod utilities; #[proc_macro_attribute] /// macro for creating appropriate setters and getters for pyo3 struct attributes /// and other, non-python API functionality -pub fn pyo3_api(attr: TokenStream, item: TokenStream) -> TokenStream { - pyo3_api::pyo3_api(attr, item) +pub fn fastsim_api(attr: TokenStream, item: TokenStream) -> TokenStream { + fastsim_api::fastsim_api(attr, item) } #[proc_macro_error] diff --git a/fastsim-core/resources/vehicles/2012_Ford_Fusion.yaml b/fastsim-core/resources/vehicles/2012_Ford_Fusion.yaml index 87cd0124..6d152f84 100644 --- a/fastsim-core/resources/vehicles/2012_Ford_Fusion.yaml +++ b/fastsim-core/resources/vehicles/2012_Ford_Fusion.yaml @@ -8,8 +8,8 @@ pt_type: pwr_ramp_lag_seconds: 1.0 energy_capacity_joules: 2124000000.0 fc: - mass: ~ - specific_pwr: ~ + mass_kilograms: ~ + specific_pwr_watts_per_kilogram: ~ pwr_out_max_watts: 130500.0 pwr_out_max_init_watts: 21750.0 pwr_ramp_lag_seconds: 6.0 @@ -53,13 +53,13 @@ chassis: wheel_rr_coef: 0.007 wheel_inertia_kilogram_square_meters: 0.82 num_wheels: 4 - wheel_radius: 0.326 + wheel_radius_meters: 0.326 cg_height_meters: 0.53 wheel_fric_coef: 0.7 drive_type: FWD drive_axle_weight_frac: 0.59 wheel_base_meters: 2.72 -mass: 1644.2724500334996 +mass_kilograms: 1644.2724500334996 pwr_aux_watts: 700.0 trans_eff: 0.875 save_interval: 1 diff --git a/tests/assets/2016_TOYOTA_Prius_Two.yaml b/fastsim-core/resources/vehicles/2016_TOYOTA_Prius_Two.yaml similarity index 88% rename from tests/assets/2016_TOYOTA_Prius_Two.yaml rename to fastsim-core/resources/vehicles/2016_TOYOTA_Prius_Two.yaml index 24dd4df8..a6891492 100644 --- a/tests/assets/2016_TOYOTA_Prius_Two.yaml +++ b/fastsim-core/resources/vehicles/2016_TOYOTA_Prius_Two.yaml @@ -4,8 +4,8 @@ year: 2016 pt_type: HybridElectricVehicle: res: - mass: ~ - specific_energy: ~ + mass_kilograms: ~ + specific_energy_joules_per_kilogram: ~ pwr_out_max_watts: 100000.0 energy_capacity_joules: 2700000.0 min_soc: 0.25 @@ -16,8 +16,8 @@ pt_type: pwr_ramp_lag_seconds: 1.1 energy_capacity_joules: 1392840000.0 fc: - mass: ~ - specific_pwr: ~ + mass_kilograms: ~ + specific_pwr_watts_per_kilogram: ~ pwr_out_max_watts: 71000.0 pwr_out_max_init_watts: 11639.344262295082 pwr_ramp_lag_seconds: 6.1 @@ -79,8 +79,8 @@ pt_type: - 0.93 - 0.92 pwr_out_max_watts: 53000.0 - specific_pwr: ~ - mass: ~ + specific_pwr_watts_per_kilogram: ~ + mass_kilograms: ~ save_interval: 1 hev_controls: RESGreedy mass: ~ @@ -90,13 +90,13 @@ chassis: wheel_rr_coef: 0.0064 wheel_inertia_kilogram_square_meters: 0.815 num_wheels: 4 - wheel_radius: 0.3175 + wheel_radius_meters: 0.3175 cg_height_meters: 0.53 wheel_fric_coef: 0.7 drive_type: FWD drive_axle_weight_frac: 0.59 wheel_base_meters: 2.7 -mass: 1635.0 +mass_kilograms: 1635.0 pwr_aux_watts: 1050.0 trans_eff: 0.98 save_interval: 1 diff --git a/fastsim-core/src/bin/f3-2012-ford-fusion-udds.rs b/fastsim-core/src/bin/f3-2012-ford-fusion-udds.rs index 8e277ac8..08d9d49d 100644 --- a/fastsim-core/src/bin/f3-2012-ford-fusion-udds.rs +++ b/fastsim-core/src/bin/f3-2012-ford-fusion-udds.rs @@ -1,4 +1,4 @@ -/// Binary for running the 2012 Ford Fusion in fastsim-3 with `cargo build +/// Binary for profiling the 2012 Ford Fusion in fastsim-3 with `cargo build /// --profile profiling --bin f3-2012-ford-fusion-udds`. To run this for /// profiling, install [samply] (https://github.com/mstange/samply) and then run /// `samply record ./target/profiling/f3-2012-ford-fusion-udds` diff --git a/fastsim-core/src/drive_cycle.rs b/fastsim-core/src/drive_cycle.rs index c1ec1b98..1b6e452a 100644 --- a/fastsim-core/src/drive_cycle.rs +++ b/fastsim-core/src/drive_cycle.rs @@ -1,7 +1,7 @@ use crate::imports::*; use fastsim_2::cycle::RustCycle as Cycle2; -#[pyo3_api( +#[fastsim_api( fn __len__(&self) -> usize { self.len() } @@ -372,7 +372,7 @@ impl Cycle { } } -#[pyo3_api] +#[fastsim_api] #[derive(Default, Debug, Serialize, Deserialize, PartialEq, Clone)] /// Element of `Cycle`. Used for vec-like operations. pub struct CycleElement { @@ -382,12 +382,12 @@ pub struct CycleElement { /// simulation power \[W\] #[serde(alias = "speed_mps", alias = "cycMps")] speed: si::Velocity, - // TODO: make `pyo3_api` handle Option or write custom getter/setter + // TODO: make `fastsim_api` handle Option or write custom getter/setter #[api(skip_get, skip_set)] /// road grade #[serde(skip_serializing_if = "Option::is_none", alias = "cycGrade")] pub grade: Option, - // TODO: make `pyo3_api` handle Option or write custom getter/setter + // TODO: make `fastsim_api` handle Option or write custom getter/setter #[api(skip_get, skip_set)] /// road charging/discharing capacity pub pwr_max_charge: Option, diff --git a/fastsim-core/src/imports.rs b/fastsim-core/src/imports.rs index cf6d7f16..27fa19ff 100644 --- a/fastsim-core/src/imports.rs +++ b/fastsim-core/src/imports.rs @@ -16,7 +16,9 @@ pub(crate) use crate::utils::{ pub(crate) use crate::utils::{Pyo3Vec2Wrapper, Pyo3Vec3Wrapper, Pyo3VecWrapper}; pub(crate) use derive_more::IsVariant; pub(crate) use eng_fmt::FormatEng; -pub(crate) use fastsim_proc_macros::{pyo3_api, HistoryMethods, HistoryVec, SetCumulative, timer}; +pub(crate) use fastsim_proc_macros::{ + fastsim_api, timer, HistoryMethods, HistoryVec, SetCumulative, +}; pub(crate) use anyhow::{anyhow, bail, ensure, Context}; pub(crate) use duplicate::duplicate_item; diff --git a/fastsim-core/src/simdrive.rs b/fastsim-core/src/simdrive.rs index 95a1ec1d..2ad33dd7 100644 --- a/fastsim-core/src/simdrive.rs +++ b/fastsim-core/src/simdrive.rs @@ -5,14 +5,14 @@ use super::vehicle::Vehicle; use crate::air_properties as air; use crate::imports::*; -#[pyo3_api] +#[fastsim_api] #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, HistoryMethods)] /// Solver parameters pub struct SimParams { pub ach_speed_max_iter: u32, pub ach_speed_tol: si::Ratio, pub ach_speed_solver_gain: f64, - #[api(skip_get, skip_set)] // TODO: manually write out getter and setter + #[api(skip_get, skip_set)] pub trace_miss_tol: TraceMissTolerance, } @@ -30,7 +30,7 @@ impl Default for SimParams { } } -#[pyo3_api( +#[fastsim_api( #[new] fn __new__(veh: Vehicle, cyc: Cycle, sim_params: Option) -> anyhow::Result { Ok(SimDrive{ @@ -80,7 +80,6 @@ impl SimDrive { } } - // #[timer] TODO: fix and uncomment pub fn walk(&mut self) -> anyhow::Result<()> { ensure!(self.cyc.len() >= 2, format_dbg!(self.cyc.len() < 2)); self.save_state(); @@ -398,7 +397,7 @@ mod tests { #[test] #[cfg(feature = "resources")] fn test_sim_drive_conv() { - let _veh = mock_f2_conv_veh(); + let _veh = mock_conv_veh(); let _cyc = Cycle::from_resource("udds.csv", false).unwrap(); let mut sd = SimDrive { veh: _veh, @@ -413,7 +412,7 @@ mod tests { #[test] #[cfg(feature = "resources")] fn test_sim_drive_hev() { - let _veh = mock_f2_hev(); + let _veh = mock_hev(); let _cyc = Cycle::from_resource("udds.csv", false).unwrap(); let mut sd = SimDrive { veh: _veh, diff --git a/fastsim-core/src/utils/interp/wrapper.rs b/fastsim-core/src/utils/interp/wrapper.rs index 680be925..245b7d41 100644 --- a/fastsim-core/src/utils/interp/wrapper.rs +++ b/fastsim-core/src/utils/interp/wrapper.rs @@ -12,7 +12,7 @@ use super::*; -#[pyo3_api( +#[fastsim_api( /// Function to get x variable from enum variants #[getter("x")] pub fn x_py(&self) -> anyhow::Result> { diff --git a/fastsim-core/src/utils/mod.rs b/fastsim-core/src/utils/mod.rs index f260a679..98e1403b 100644 --- a/fastsim-core/src/utils/mod.rs +++ b/fastsim-core/src/utils/mod.rs @@ -159,12 +159,10 @@ pub fn interp1d( let y_first = y_data .first() .with_context(|| anyhow!("Unable to extract first element"))?; - // TODO: do this once on init if y_data.iter().all(|y| y == y_first) { // return first if all data is equal to first Ok(*y_first) } else { - // TODO: when `Interpolator` struct is implemented, make sure this sort of check happens on init let size = x_data.len(); let mut i = 0; @@ -303,20 +301,20 @@ make_uom_cmp_fn!(almost_lt); make_uom_cmp_fn!(almost_ge); make_uom_cmp_fn!(almost_le); -#[pyo3_api] +#[fastsim_api] #[derive(Default, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Pyo3VecBoolWrapper(pub Vec); impl SerdeAPI for Pyo3VecBoolWrapper {} impl Init for Pyo3VecBoolWrapper {} -#[pyo3_api] +#[fastsim_api] #[derive(Default, Serialize, Deserialize, Clone, PartialEq)] pub struct Pyo3VecWrapper(pub Vec); impl SerdeAPI for Pyo3VecWrapper {} impl Init for Pyo3VecWrapper {} #[allow(non_snake_case)] -#[pyo3_api] +#[fastsim_api] #[derive(Default, Serialize, Deserialize, Clone, PartialEq)] pub struct Pyo3Vec2Wrapper(pub Vec>); impl From>> for Pyo3Vec2Wrapper { @@ -327,7 +325,7 @@ impl From>> for Pyo3Vec2Wrapper { impl SerdeAPI for Pyo3Vec2Wrapper {} impl Init for Pyo3Vec2Wrapper {} -#[pyo3_api] +#[fastsim_api] #[derive(Default, Serialize, Deserialize, Clone, PartialEq)] pub struct Pyo3Vec3Wrapper(pub Vec>>); impl From>>> for Pyo3Vec3Wrapper { @@ -566,12 +564,6 @@ mod tests { ); } - // TODO: turn this back on and fix the problem it catches - // #[test] - // fn test_interp1d_with_duplicate_x_data() { - // assert!(interp1d(&0.5, &[0.0, 0.0], &[0.0, 1.0], Extrapolate::Yes).is_err()); - // } - #[test] fn test_linspace() { assert_eq!(Vec::linspace(0.0, 1.0, 3), vec![0.0, 0.5, 1.0]); diff --git a/fastsim-core/src/vehicle/chassis.rs b/fastsim-core/src/vehicle/chassis.rs index b36aaf92..6f973d3e 100644 --- a/fastsim-core/src/vehicle/chassis.rs +++ b/fastsim-core/src/vehicle/chassis.rs @@ -16,7 +16,7 @@ pub enum DriveTypes { impl SerdeAPI for DriveTypes {} impl Init for DriveTypes {} -#[pyo3_api] +#[fastsim_api] #[derive(PartialEq, Clone, Debug, Serialize, Deserialize, HistoryMethods)] /// Struct for simulating vehicle pub struct Chassis { diff --git a/fastsim-core/src/vehicle/powertrain/electric_machine.rs b/fastsim-core/src/vehicle/powertrain/electric_machine.rs index ec8691bc..4b4d6b6c 100644 --- a/fastsim-core/src/vehicle/powertrain/electric_machine.rs +++ b/fastsim-core/src/vehicle/powertrain/electric_machine.rs @@ -7,7 +7,7 @@ use super::*; use crate::pyo3::*; use crate::utils::abs_checked_x_val; -#[pyo3_api( +#[fastsim_api( // #[new] // fn __new__( // pwr_out_frac_interp: Vec, @@ -367,7 +367,7 @@ impl Mass for ElectricMachine { #[derive( Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, HistoryVec, SetCumulative, )] -#[pyo3_api] +#[fastsim_api] pub struct ElectricMachineState { /// time step index pub i: usize, diff --git a/fastsim-core/src/vehicle/powertrain/fuel_converter.rs b/fastsim-core/src/vehicle/powertrain/fuel_converter.rs index c77b8018..6bd4cfb7 100644 --- a/fastsim-core/src/vehicle/powertrain/fuel_converter.rs +++ b/fastsim-core/src/vehicle/powertrain/fuel_converter.rs @@ -2,7 +2,7 @@ use super::*; // TODO: think about how to incorporate life modeling for Fuel Cells and other tech -#[pyo3_api( +#[fastsim_api( // // optional, custom, struct-specific pymethods // #[getter("eff_max")] // fn get_eff_max_py(&self) -> f64 { @@ -289,7 +289,7 @@ impl FuelConverter { #[derive( Clone, Copy, Debug, Default, Deserialize, Serialize, PartialEq, HistoryVec, SetCumulative, )] -#[pyo3_api] +#[fastsim_api] pub struct FuelConverterState { /// time step index pub i: usize, diff --git a/fastsim-core/src/vehicle/powertrain/fuel_storage.rs b/fastsim-core/src/vehicle/powertrain/fuel_storage.rs index bc20286d..718bf654 100644 --- a/fastsim-core/src/vehicle/powertrain/fuel_storage.rs +++ b/fastsim-core/src/vehicle/powertrain/fuel_storage.rs @@ -1,6 +1,6 @@ use super::*; -#[pyo3_api( +#[fastsim_api( // TODO: decide on way to deal with `side_effect` coming after optional arg and uncomment // #[setter("__mass_kg")] // fn set_mass_py(&mut self, mass_kg: Option) -> anyhow::Result<()> { diff --git a/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs b/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs index b875066b..5cd0314c 100644 --- a/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs +++ b/fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs @@ -6,7 +6,7 @@ use crate::pyo3::*; const TOL: f64 = 1e-3; -#[pyo3_api( +#[fastsim_api( #[allow(clippy::too_many_arguments)] #[new] fn __new__( @@ -609,7 +609,7 @@ pub enum SpecificEnergySideEffect { } #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, HistoryVec, SetCumulative)] -#[pyo3_api] +#[fastsim_api] // component limits /// ReversibleEnergyStorage state variables pub struct ReversibleEnergyStorageState { diff --git a/fastsim-core/src/vehicle/vehicle_model.rs b/fastsim-core/src/vehicle/vehicle_model.rs index c51ce783..3eed35a9 100644 --- a/fastsim-core/src/vehicle/vehicle_model.rs +++ b/fastsim-core/src/vehicle/vehicle_model.rs @@ -16,7 +16,7 @@ pub enum AuxSource { impl SerdeAPI for AuxSource {} impl Init for AuxSource {} -#[pyo3_api( +#[fastsim_api( #[staticmethod] fn try_from_fastsim2(veh: fastsim_2::vehicle::RustVehicle) -> PyResult { Ok(Self::try_from(veh.clone())?) @@ -826,7 +826,7 @@ impl Vehicle { /// Vehicle state for current time step #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, HistoryVec, SetCumulative)] -#[pyo3_api] +#[fastsim_api] pub struct VehicleState { /// time step index pub i: usize, @@ -924,8 +924,12 @@ impl Default for VehicleState { pub(crate) mod tests { use super::*; + fn vehicles_dir() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/vehicles") + } + #[cfg(feature = "yaml")] - pub(crate) fn mock_f2_conv_veh() -> Vehicle { + pub(crate) fn mock_conv_veh() -> Vehicle { let file_contents = include_str!("fastsim-2_2012_Ford_Fusion.yaml"); use fastsim_2::traits::SerdeAPI; let veh = { @@ -934,21 +938,14 @@ pub(crate) mod tests { veh.unwrap() }; + veh.to_file(vehicles_dir().join("2012_Ford_Fusion.yaml")) + .unwrap(); assert!(veh.pt_type.is_conventional_vehicle()); - - // TODO: come up with a fancier solution - // uncomment this if the fastsim-3 version needs to be rewritten - // veh.to_file( - // project_root::get_project_root() - // .unwrap() - // .join("tests/assets/2012_Ford_Fusion.yaml"), - // ) - // .unwrap(); veh } #[cfg(feature = "yaml")] - pub(crate) fn mock_f2_hev() -> Vehicle { + pub(crate) fn mock_hev() -> Vehicle { let file_contents = include_str!("fastsim-2_2016_TOYOTA_Prius_Two.yaml"); use fastsim_2::traits::SerdeAPI; let veh = { @@ -957,16 +954,9 @@ pub(crate) mod tests { veh.unwrap() }; + veh.to_file(vehicles_dir().join("2016_TOYOTA_Prius_Two.yaml")) + .unwrap(); assert!(veh.pt_type.is_hybrid_electric_vehicle()); - - // TODO: come up with a fancier solution - // uncomment this if the fastsim-3 version needs to be rewritten - // veh.to_file( - // project_root::get_project_root() - // .unwrap() - // .join("tests/assets/2016_TOYOTA_Prius_Two.yaml"), - // ) - // .unwrap(); veh } @@ -974,7 +964,7 @@ pub(crate) mod tests { #[test] #[cfg(feature = "yaml")] pub(crate) fn test_conv_veh_init() { - let veh = mock_f2_conv_veh(); + let veh = mock_conv_veh(); let mut veh1 = veh.clone(); assert!(veh == veh1); veh1.init().unwrap(); @@ -984,7 +974,7 @@ pub(crate) mod tests { #[test] #[cfg(all(feature = "csv", feature = "resources"))] fn test_to_fastsim2_conv() { - let veh = mock_f2_conv_veh(); + let veh = mock_conv_veh(); let cyc = crate::drive_cycle::Cycle::from_resource("udds.csv", false).unwrap(); let sd = crate::simdrive::SimDrive { veh, @@ -998,7 +988,7 @@ pub(crate) mod tests { #[test] #[cfg(all(feature = "csv", feature = "resources"))] fn test_to_fastsim2_hev() { - let veh = mock_f2_hev(); + let veh = mock_hev(); let cyc = crate::drive_cycle::Cycle::from_resource("udds.csv", false).unwrap(); let sd = crate::simdrive::SimDrive { veh, @@ -1008,19 +998,4 @@ pub(crate) mod tests { let mut sd2 = sd.to_fastsim2().unwrap(); sd2.sim_drive(None, None).unwrap(); } - - #[test] - #[cfg(feature = "yaml")] - fn test_hev_deserialize() { - let veh = mock_f2_hev(); - - let veh_from_file = Vehicle::from_file( - project_root::get_project_root() - .unwrap() - .join("tests/assets/2016_TOYOTA_Prius_Two.yaml"), - false, - ) - .unwrap(); - assert!(veh == veh_from_file); - } } diff --git a/python/fastsim/demos/demo_conv.py b/python/fastsim/demos/demo_conv.py index e05b3c61..34c1ba23 100644 --- a/python/fastsim/demos/demo_conv.py +++ b/python/fastsim/demos/demo_conv.py @@ -27,9 +27,7 @@ # %% # load 2012 Ford Fusion from file -veh = fsim.Vehicle.from_file( - str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") -) +veh = fsim.Vehicle.from_resource("2012_Ford_Fusion.yaml") veh_no_save = veh.copy() fsim.set_param_from_path(veh_no_save, "save_interval", None) @@ -361,8 +359,8 @@ def get_uni_cycler(): # 5 61.562 MiB 61.562 MiB 1 @profile(precision=3) # 6 def build_and_run_sim_drive(): # 7 62.125 MiB 0.562 MiB 2 veh = fsim.Vehicle.from_file( -# 8 # TODO: figure out why `str` is needed here -# 9 61.562 MiB 0.000 MiB 1 str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") +# 8 +# 9 61.562 MiB 0.000 MiB 1 fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml" # 10 ) # 11 62.125 MiB 0.000 MiB 1 veh.save_interval = 1 # 12 62.312 MiB 0.188 MiB 1 cyc = fsim.Cycle.from_resource("cycles/udds.csv") @@ -379,8 +377,8 @@ def get_uni_cycler(): # 5 61.203 MiB 61.203 MiB 1 @profile(precision=3) # 6 def build_and_run_sim_drive(): # 7 61.766 MiB 0.562 MiB 2 veh = fsim.Vehicle.from_file( -# 8 # TODO: figure out why `str` is needed here -# 9 61.203 MiB 0.000 MiB 1 str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") +# 8 +# 9 61.203 MiB 0.000 MiB 1 fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml" # 10 ) # 11 61.766 MiB 0.000 MiB 1 veh.save_interval = None # 12 61.938 MiB 0.172 MiB 1 cyc = fsim.Cycle.from_resource("cycles/udds.csv") diff --git a/python/fastsim/demos/demo_hev.py b/python/fastsim/demos/demo_hev.py index aa2e5c42..29a3d8ba 100644 --- a/python/fastsim/demos/demo_hev.py +++ b/python/fastsim/demos/demo_hev.py @@ -27,9 +27,8 @@ # %% # load 2016 Toyota Prius Two from file -veh = fsim.Vehicle.from_file( - str(fsim.package_root() / "../../tests/assets/2016_TOYOTA_Prius_Two.yaml") -) +veh = fsim.Vehicle.from_resource("2016_TOYOTA_Prius_Two.yaml") + veh_no_save = veh.copy() fsim.set_param_from_path(veh_no_save, "save_interval", None) diff --git a/python/fastsim/demos/demo_variable_paths.py b/python/fastsim/demos/demo_variable_paths.py index 7b87f917..bba00e18 100644 --- a/python/fastsim/demos/demo_variable_paths.py +++ b/python/fastsim/demos/demo_variable_paths.py @@ -7,9 +7,7 @@ import polars as pl # load 2012 Ford Fusion from file -veh = fsim.Vehicle.from_file( - str(fsim.package_root() / "../../tests/assets/2016_TOYOTA_Prius_Two.yaml") -) +veh = fsim.Vehicle.from_resource("2016_TOYOTA_Prius_Two.yaml") # Set `save_interval` at vehicle level -- cascades to all sub-components with time-varying states fsim.set_param_from_path(veh, "save_interval", 1) @@ -28,7 +26,6 @@ # directory for reference files for checking sim results against expected results ref_dir = fsim.resources_root() / "demos/demo_variable_paths/" - # print out all subpaths for variables in SimDrive print("List of variable paths for SimDrive:" + "\n".join(sd.variable_path_list())) if ENABLE_REF_OVERRIDE: diff --git a/python/fastsim/resources/demos/demo_variable_paths/variable_path_list_expected.txt b/python/fastsim/resources/demos/demo_variable_paths/variable_path_list_expected.txt index c9ee97a7..d83991ec 100644 --- a/python/fastsim/resources/demos/demo_variable_paths/variable_path_list_expected.txt +++ b/python/fastsim/resources/demos/demo_variable_paths/variable_path_list_expected.txt @@ -21,8 +21,8 @@ ['veh']['pt_type']['HybridElectricVehicle']['res']['state']['max_soc'] ['veh']['pt_type']['HybridElectricVehicle']['res']['state']['min_soc'] ['veh']['pt_type']['HybridElectricVehicle']['res']['state']['temperature_celsius'] -['veh']['pt_type']['HybridElectricVehicle']['res']['mass'] -['veh']['pt_type']['HybridElectricVehicle']['res']['specific_energy'] +['veh']['pt_type']['HybridElectricVehicle']['res']['mass_kilograms'] +['veh']['pt_type']['HybridElectricVehicle']['res']['specific_energy_joules_per_kilogram'] ['veh']['pt_type']['HybridElectricVehicle']['res']['pwr_out_max_watts'] ['veh']['pt_type']['HybridElectricVehicle']['res']['energy_capacity_joules'] ['veh']['pt_type']['HybridElectricVehicle']['res']['min_soc'] @@ -67,8 +67,8 @@ ['veh']['pt_type']['HybridElectricVehicle']['fc']['state']['pwr_loss'] ['veh']['pt_type']['HybridElectricVehicle']['fc']['state']['energy_loss'] ['veh']['pt_type']['HybridElectricVehicle']['fc']['state']['fc_on'] -['veh']['pt_type']['HybridElectricVehicle']['fc']['mass'] -['veh']['pt_type']['HybridElectricVehicle']['fc']['specific_pwr'] +['veh']['pt_type']['HybridElectricVehicle']['fc']['mass_kilograms'] +['veh']['pt_type']['HybridElectricVehicle']['fc']['specific_pwr_watts_per_kilogram'] ['veh']['pt_type']['HybridElectricVehicle']['fc']['pwr_out_max_watts'] ['veh']['pt_type']['HybridElectricVehicle']['fc']['pwr_out_max_init_watts'] ['veh']['pt_type']['HybridElectricVehicle']['fc']['pwr_ramp_lag_seconds'] @@ -108,8 +108,8 @@ ['veh']['pt_type']['HybridElectricVehicle']['em']['pwr_out_frac_interp'] ['veh']['pt_type']['HybridElectricVehicle']['em']['eff_interp'] ['veh']['pt_type']['HybridElectricVehicle']['em']['pwr_out_max_watts'] -['veh']['pt_type']['HybridElectricVehicle']['em']['specific_pwr'] -['veh']['pt_type']['HybridElectricVehicle']['em']['mass'] +['veh']['pt_type']['HybridElectricVehicle']['em']['specific_pwr_watts_per_kilogram'] +['veh']['pt_type']['HybridElectricVehicle']['em']['mass_kilograms'] ['veh']['pt_type']['HybridElectricVehicle']['em']['save_interval'] ['veh']['pt_type']['HybridElectricVehicle']['em']['history']['i'] ['veh']['pt_type']['HybridElectricVehicle']['em']['history']['eff'] @@ -134,12 +134,12 @@ ['veh']['chassis']['wheel_rr_coef'] ['veh']['chassis']['wheel_inertia_kilogram_square_meters'] ['veh']['chassis']['num_wheels'] -['veh']['chassis']['wheel_radius'] +['veh']['chassis']['wheel_radius_meters'] ['veh']['chassis']['cg_height_meters'] ['veh']['chassis']['wheel_fric_coef'] ['veh']['chassis']['drive_axle_weight_frac'] ['veh']['chassis']['wheel_base_meters'] -['veh']['mass'] +['veh']['mass_kilograms'] ['veh']['pwr_aux_watts'] ['veh']['trans_eff'] ['veh']['save_interval'] @@ -193,7 +193,7 @@ ['veh']['history']['dist'] ['veh']['history']['grade_curr'] ['veh']['history']['air_density'] -['cyc']['init_elev'] +['cyc']['init_elev_meters'] ['cyc']['time_seconds'] ['cyc']['speed_meters_per_second'] ['cyc']['dist_meters'] diff --git a/python/fastsim/tests/test_speedup.py b/python/fastsim/tests/test_speedup.py index b1356ce9..3ab9eefd 100644 --- a/python/fastsim/tests/test_speedup.py +++ b/python/fastsim/tests/test_speedup.py @@ -7,9 +7,7 @@ def test_hev_speedup(): min_allowed_speed_ratio = 8. # load 2016 Toyota Prius Two from file - veh = fsim.Vehicle.from_file( - str(fsim.package_root() / "../../tests/assets/2016_TOYOTA_Prius_Two.yaml") - ) + veh = fsim.Vehicle.from_resource("2016_TOYOTA_Prius_Two.yaml") # Set `save_interval` at vehicle level -- cascades to all sub-components with time-varying states fsim.set_param_from_path(veh, "save_interval", 1) @@ -58,9 +56,7 @@ def test_conv_speedup(): min_speed_ratio_si_1 = 2.5 # load 2016 Toyota Prius Two from file - veh = fsim.Vehicle.from_file( - str(fsim.package_root() / "../../tests/assets/2012_Ford_Fusion.yaml") - ) + veh = fsim.Vehicle.from_resource("2012_Ford_Fusion.yaml") # Set `save_interval` at vehicle level -- cascades to all sub-components with time-varying states fsim.set_param_from_path(veh, "save_interval", 1) diff --git a/tests/assets/2012_Ford_Fusion.yaml b/tests/assets/2012_Ford_Fusion.yaml deleted file mode 100644 index 87cd0124..00000000 --- a/tests/assets/2012_Ford_Fusion.yaml +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: 2012 Ford Fusion -year: 2012 -pt_type: - ConventionalVehicle: - fs: - pwr_out_max_watts: 1000000.0 - pwr_ramp_lag_seconds: 1.0 - energy_capacity_joules: 2124000000.0 - fc: - mass: ~ - specific_pwr: ~ - pwr_out_max_watts: 130500.0 - pwr_out_max_init_watts: 21750.0 - pwr_ramp_lag_seconds: 6.0 - eff_interp: - Interp1D: - x: - - 0.0 - - 0.005 - - 0.015 - - 0.04 - - 0.06 - - 0.1 - - 0.14 - - 0.2 - - 0.4 - - 0.6 - - 0.8 - - 1.0 - f_x: - - 0.1 - - 0.12 - - 0.16 - - 0.22 - - 0.28 - - 0.33 - - 0.35 - - 0.36 - - 0.35 - - 0.34 - - 0.32 - - 0.3 - strategy: LeftNearest - extrapolate: Error - pwr_idle_fuel_watts: 6999.999999999999 - save_interval: 1 - mass: ~ - alt_eff: 1.0 -chassis: - drag_coef: 0.393 - frontal_area_square_meters: 2.12 - wheel_rr_coef: 0.007 - wheel_inertia_kilogram_square_meters: 0.82 - num_wheels: 4 - wheel_radius: 0.326 - cg_height_meters: 0.53 - wheel_fric_coef: 0.7 - drive_type: FWD - drive_axle_weight_frac: 0.59 - wheel_base_meters: 2.72 -mass: 1644.2724500334996 -pwr_aux_watts: 700.0 -trans_eff: 0.875 -save_interval: 1 diff --git a/tests/assets/2012_Ford_Fusion_2D_test.yaml b/tests/assets/2012_Ford_Fusion_2D_test.yaml deleted file mode 100644 index 2e402058..00000000 --- a/tests/assets/2012_Ford_Fusion_2D_test.yaml +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: 2012 Ford Fusion -year: 2012 -pt_type: - ConventionalVehicle: - fs: - pwr_out_max: 1000000.0 - pwr_ramp_lag: 1.0 - energy_capacity: 2124000000.0 - fc: - mass: ~ - specific_pwr: ~ - pwr_out_max_watts: 130500.0 - pwr_out_max_init: 21750.0 - pwr_ramp_lag_seconds: 6.0 - eff_interp: - Interp2D: - x: - - 0.05 - - 0.1 - - 0.15 - y: - - 0.1 - - 0.2 - - 0.3 - f_xy: - - - 0.0 - - 1.0 - - 2.0 - - - 3.0 - - 4.0 - - 5.0 - - - 6.0 - - 7.0 - - 8.0 - strategy: Linear - extrapolate: Error - pwr_idle_fuel_watts: 6999.999999999999 - save_interval: 1 - mass: ~ - alt_eff: 1.0 -chassis: - drag_coef: 0.393 - frontal_area: 2.12 - wheel_rr_coef: 0.007 - wheel_inertia: 0.82 - num_wheels: 4 - wheel_radius: 0.326 - cg_height: 0.53 - wheel_fric_coef: 0.7 - drive_type: FWD - drive_axle_weight_frac: 0.59 - wheel_base: 2.72 -mass: 1644.2724500334996 -pwr_aux: 700.0 -trans_eff: 0.875 -save_interval: 1 diff --git a/tests/assets/2012_Ford_Fusion_3D_test.yaml b/tests/assets/2012_Ford_Fusion_3D_test.yaml deleted file mode 100644 index cceb0f6f..00000000 --- a/tests/assets/2012_Ford_Fusion_3D_test.yaml +++ /dev/null @@ -1,79 +0,0 @@ ---- -name: 2012 Ford Fusion -year: 2012 -pt_type: - ConventionalVehicle: - fs: - pwr_out_max: 1000000.0 - pwr_ramp_lag: 1.0 - energy_capacity: 2124000000.0 - fc: - mass: ~ - specific_pwr: ~ - pwr_out_max_watts: 130500.0 - pwr_out_max_init: 21750.0 - pwr_ramp_lag_seconds: 6.0 - eff_interp: - Interp3D: - x: - - 0.05 - - 0.1 - - 0.15 - y: - - 0.1 - - 0.2 - - 0.3 - z: - - 0.2 - - 0.4 - - 0.6 - f_xyz: - - - - 0.0 - - 1.0 - - 2.0 - - - 3.0 - - 4.0 - - 5.0 - - - 6.0 - - 7.0 - - 8.0 - - - - 9.0 - - 10.0 - - 11.0 - - - 12.0 - - 13.0 - - 14.0 - - - 15.0 - - 16.0 - - 17.0 - - - - 18.0 - - 19.0 - - 20.0 - - - 21.0 - - 22.0 - - 23.0 - - - 24.0 - - 25.0 - - 26.0 - strategy: Linear - extrapolate: Error - pwr_idle_fuel_watts: 6999.999999999999 - save_interval: 1 - mass: ~ - alt_eff: 1.0 -chassis: - drag_coef: 0.393 - frontal_area: 2.12 - wheel_rr_coef: 0.007 - wheel_inertia: 0.82 - num_wheels: 4 - wheel_radius: 0.326 - cg_height: 0.53 - wheel_fric_coef: 0.7 - drive_type: FWD - drive_axle_weight_frac: 0.59 - wheel_base: 2.72 -mass: 1644.2724500334996 -pwr_aux: 700.0 -trans_eff: 0.875 -save_interval: 1 diff --git a/tests/assets/2012_Ford_Fusion_ND_test.yaml b/tests/assets/2012_Ford_Fusion_ND_test.yaml deleted file mode 100644 index 5faceae5..00000000 --- a/tests/assets/2012_Ford_Fusion_ND_test.yaml +++ /dev/null @@ -1,83 +0,0 @@ ---- -name: 2012 Ford Fusion -year: 2012 -pt_type: - ConventionalVehicle: - fs: - pwr_out_max: 1000000.0 - pwr_ramp_lag: 1.0 - energy_capacity: 2124000000.0 - fc: - mass: ~ - specific_pwr: ~ - pwr_out_max_watts: 130500.0 - pwr_out_max_init: 21750.0 - pwr_ramp_lag_seconds: 6.0 - eff_interp: - InterpND: - grid: - - - 0.05 - - 0.1 - - 0.15 - - - 0.1 - - 0.2 - - 0.3 - - - 0.2 - - 0.4 - - 0.6 - values: - v: 1 - dim: - - 3 - - 3 - - 3 - data: - - 0.0 - - 1.0 - - 2.0 - - 3.0 - - 4.0 - - 5.0 - - 6.0 - - 7.0 - - 8.0 - - 9.0 - - 10.0 - - 11.0 - - 12.0 - - 13.0 - - 14.0 - - 15.0 - - 16.0 - - 17.0 - - 18.0 - - 19.0 - - 20.0 - - 21.0 - - 22.0 - - 23.0 - - 24.0 - - 25.0 - - 26.0 - extrapolate: Error - strategy: Linear - pwr_idle_fuel_watts: 6999.999999999999 - save_interval: 1 - mass: ~ - alt_eff: 1.0 -chassis: - drag_coef: 0.393 - frontal_area: 2.12 - wheel_rr_coef: 0.007 - wheel_inertia: 0.82 - num_wheels: 4 - wheel_radius: 0.326 - cg_height: 0.53 - wheel_fric_coef: 0.7 - drive_type: FWD - drive_axle_weight_frac: 0.59 - wheel_base: 2.72 -mass: 1644.2724500334996 -pwr_aux: 700.0 -trans_eff: 0.875 -save_interval: 1