Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dummy PR: changed to drag_coef: VehicleField<f64> #43

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions rust/fastsim-core/src/simdrive/cyc_mods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -332,8 +332,9 @@ impl RustSimDrive {
};
let g = self.props.a_grav_mps2;
let m = self.veh.veh_kg;
let rho_cdfa =
self.props.air_density_kg_per_m3 * self.veh.drag_coef * self.veh.frontal_area_m2;
let rho_cdfa = self.veh.drag_coef.clone()
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylecarow , VehiclField<f64> can be multiplied by f64 but not the other order. Because types that are used in math operations normally implement the std::markers::Copy trait and VehicleField<f64> cannot implement that trait due to fields that can't do it, we need to use .clone() a lot, which in my mind negates the benefit of the std::ops implementations.

* self.props.air_density_kg_per_m3
* self.veh.frontal_area_m2;
let rrc = self.veh.wheel_rr_coef;
-1.0 * ((g / v) * (atan_grade_sin + rrc * atan_grade_cos)
+ (0.5 * rho_cdfa * (1.0 / m) * v))
Expand Down Expand Up @@ -533,7 +534,7 @@ impl RustSimDrive {
let grade_by_distance = Array::from_vec(grade_by_distance);
let veh_mass_kg = self.veh.veh_kg;
let air_density_kg_per_m3 = self.props.air_density_kg_per_m3;
let cdfa_m2 = self.veh.drag_coef * self.veh.frontal_area_m2;
let cdfa_m2 = self.veh.drag_coef.clone() * self.veh.frontal_area_m2;
let rrc = self.veh.wheel_rr_coef;
let gravity_m_per_s2 = self.props.a_grav_mps2;
// distance traveled while stopping via friction-braking (i.e., distance to brake)
Expand Down
16 changes: 6 additions & 10 deletions rust/fastsim-core/src/simdrive/simdrive_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -843,9 +843,9 @@ impl RustSimDrive {

let grade = self.lookup_grade_for_step(i, Some(mps_ach));

self.drag_kw[i] = 0.5
self.drag_kw[i] = self.veh.drag_coef.clone()
* 0.5
* self.props.air_density_kg_per_m3
* self.veh.drag_coef
* self.veh.frontal_area_m2
* ((self.mps_ach[i - 1] + mps_ach) / 2.0).powf(3.0)
/ 1e3;
Expand Down Expand Up @@ -952,21 +952,18 @@ impl RustSimDrive {
grade_iter += 1;
grade = grade_estimate;

let drag3 = 1.0 / 16.0
let drag3 = self.veh.drag_coef.clone() * 1.0 / 16.0
* self.props.air_density_kg_per_m3
* self.veh.drag_coef
* self.veh.frontal_area_m2;
let accel2 = 0.5 * self.veh.veh_kg / self.cyc.dt_s_at_i(i);
let drag2 = 3.0 / 16.0
let drag2 = self.veh.drag_coef.clone() * 3.0 / 16.0
* self.props.air_density_kg_per_m3
* self.veh.drag_coef
* self.veh.frontal_area_m2
* self.mps_ach[i - 1];
let wheel2 = 0.5 * self.veh.wheel_inertia_kg_m2 * self.veh.num_wheels
/ (self.cyc.dt_s_at_i(i) * self.veh.wheel_radius_m.powf(2.0));
let drag1 = 3.0 / 16.0
let drag1 = self.veh.drag_coef.clone() * 3.0 / 16.0
* self.props.air_density_kg_per_m3
* self.veh.drag_coef
* self.veh.frontal_area_m2
* self.mps_ach[i - 1].powf(2.0);
let roll1 = 0.5
Expand All @@ -977,9 +974,8 @@ impl RustSimDrive {
let ascent1 = 0.5 * self.props.a_grav_mps2 * grade.atan().sin() * self.veh.veh_kg;
let accel0 =
-0.5 * self.veh.veh_kg * self.mps_ach[i - 1].powf(2.0) / self.cyc.dt_s_at_i(i);
let drag0 = 1.0 / 16.0
let drag0 = self.veh.drag_coef.clone() * 1.0 / 16.0
* self.props.air_density_kg_per_m3
* self.veh.drag_coef
* self.veh.frontal_area_m2
* self.mps_ach[i - 1].powf(3.0);
let roll0 = 0.5
Expand Down
5 changes: 2 additions & 3 deletions rust/fastsim-core/src/simdrivelabel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ use crate::imports::*;
use crate::params::*;
use crate::proc_macros::add_pyo3_api;
use crate::proc_macros::ApproxEq;

#[cfg(feature = "pyo3")]
use crate::pyo3imports::*;

use crate::simdrive::{RustSimDrive, RustSimDriveParams};
use crate::vehicle;

Expand Down Expand Up @@ -759,6 +757,7 @@ pub fn get_label_fe_phev_py(
#[cfg(test)]
mod simdrivelabel_tests {
use super::*;
use crate::vehicle_utils::VehicleField;

#[test]
fn test_get_label_fe_conv() {
Expand Down Expand Up @@ -821,7 +820,7 @@ mod simdrivelabel_tests {
selection: 13,
veh_year: 2016,
veh_pt_type: "PHEV".into(),
drag_coef: 0.3,
drag_coef: VehicleField::new(0.3),
frontal_area_m2: 2.565,
glider_kg: 950.564,
veh_cg_m: 0.53,
Expand Down
15 changes: 6 additions & 9 deletions rust/fastsim-core/src/vehicle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::params::*;
use crate::proc_macros::{add_pyo3_api, doc_field, ApproxEq};
#[cfg(feature = "pyo3")]
use crate::pyo3imports::*;
use crate::vehicle_utils::VehicleField;

use lazy_static::lazy_static;
use regex::Regex;
Expand Down Expand Up @@ -102,32 +103,28 @@ pub struct RustVehicle {
#[serde(skip)]
#[api(has_orphaned)]
/// Physical properties, see [RustPhysicalProperties](RustPhysicalProperties)
#[doc_field(skip_doc)]
pub props: RustPhysicalProperties,
/// Vehicle name
#[serde(alias = "name")]
#[doc_field(skip_doc)]
pub scenario_name: String,
/// Vehicle database ID
#[serde(skip)]
#[doc_field(skip_doc)]
pub selection: u32,
/// Vehicle year
#[serde(alias = "vehModelYear")]
#[doc_field(skip_doc)]
pub veh_year: u32,
/// Vehicle powertrain type, one of \[[CONV](CONV), [HEV](HEV), [PHEV](PHEV), [BEV](BEV)\]
#[serde(alias = "vehPtType")]
#[validate(regex(
path = "VEH_PT_TYPE_OPTIONS_REGEX",
message = "must be one of [\"Conv\", \"HEV\", \"PHEV\", \"BEV\"]"
))]
#[doc_field(skip_doc)]
pub veh_pt_type: String,
/// Aerodynamic drag coefficient
#[serde(alias = "dragCoef")]
#[validate(range(min = 0))]
pub drag_coef: f64,
// #[validate(range(min = 0))]
#[api(skip_get, skip_set)]
pub drag_coef: VehicleField<f64>,
/// Frontal area, $m^2$
#[serde(alias = "frontalAreaM2")]
#[validate(range(min = 0))]
Expand Down Expand Up @@ -852,7 +849,7 @@ impl RustVehicle {
selection: 5,
veh_year: 2016,
veh_pt_type: String::from("Conv"),
drag_coef: 0.355,
drag_coef: VehicleField::new(0.355),
frontal_area_m2: 3.066,
glider_kg: 1359.166,
veh_cg_m: 0.53,
Expand Down Expand Up @@ -1175,7 +1172,7 @@ mod tests {
selection,
veh_year,
veh_pt_type, // bad input
drag_coef,
drag_coef: VehicleField::new(drag_coef),
frontal_area_m2,
glider_kg, // bad input
veh_cg_m,
Expand Down
135 changes: 131 additions & 4 deletions rust/fastsim-core/src/vehicle_utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! Module for utility functions that support the vehicle struct.

// rust crates
use argmin::core::{CostFunction, Error, Executor, OptimizationResult, State};
use argmin::solver::neldermead::NelderMead;
use ndarray::{array, Array1};
use polynomial::Polynomial;
use validator::ValidationError;

// local
use crate::air::*;
use crate::cycle::RustCycle;
use crate::imports::*;
Expand Down Expand Up @@ -96,7 +99,7 @@ pub fn abc_to_drag_coeffs(
wheel_rr_coef = a_newton / veh.veh_kg / props.a_grav_mps2;
}

veh.drag_coef = drag_coef;
veh.drag_coef.value = drag_coef;
veh.wheel_rr_coef = wheel_rr_coef;

(drag_coef, wheel_rr_coef)
Expand Down Expand Up @@ -131,7 +134,7 @@ pub fn get_error_val(model: Array1<f64>, test: Array1<f64>, time_steps: Array1<f
err += 0.5 * (time_steps[index + 1] - time_steps[index]) * (y[index] + y[index + 1]);
}

return err / (time_steps.last().unwrap() - time_steps[0]);
return err / (time_steps.last().unwrap() - time_steps.first().unwrap());
}

struct GetError<'a> {
Expand All @@ -149,7 +152,7 @@ impl CostFunction for GetError<'_> {
let cyc: RustCycle = self.cycle.clone();
let dyno_func_lb: Polynomial<f64> = self.dyno_func_lb.clone();

veh.drag_coef = x[0];
veh.drag_coef.value = x[0];
veh.wheel_rr_coef = x[1];

let mut sd_coast: RustSimDrive = RustSimDrive::new(self.cycle.clone(), veh);
Expand Down Expand Up @@ -180,6 +183,130 @@ impl CostFunction for GetError<'_> {
}
}

macro_rules! array_and_scalar_ops {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylecarow , this is where I've implemented the std::ops traits.

($vft: ty) => {
impl std::ops::Mul for VehicleField<$vft> {
type Output = $vft;
fn mul(self, rhs: Self) -> Self::Output {
self.value * rhs.value
}
}
impl std::ops::Mul<$vft> for VehicleField<$vft> {
type Output = $vft;
fn mul(self, rhs: $vft) -> Self::Output {
self.value * rhs
}
}
impl std::ops::Add for VehicleField<$vft> {
type Output = $vft;
fn add(self, rhs: Self) -> Self::Output {
self.value + rhs.value
}
}
impl std::ops::Add<$vft> for VehicleField<$vft> {
type Output = $vft;
fn add(self, rhs: $vft) -> Self::Output {
self.value + rhs
}
}
impl std::ops::Div for VehicleField<$vft> {
type Output = $vft;
fn div(self, rhs: Self) -> Self::Output {
self.value / rhs.value
}
}
impl std::ops::Div<$vft> for VehicleField<$vft> {
type Output = $vft;
fn div(self, rhs: $vft) -> Self::Output {
self.value / rhs
}
}
impl std::ops::Sub for VehicleField<$vft> {
type Output = $vft;
fn sub(self, rhs: Self) -> Self::Output {
self.value - rhs.value
}
}
impl std::ops::Sub<$vft> for VehicleField<$vft> {
type Output = $vft;
fn sub(self, rhs: $vft) -> Self::Output {
self.value - rhs
}
}
impl std::ops::Rem for VehicleField<$vft> {
type Output = $vft;
fn rem(self, rhs: Self) -> Self::Output {
self.value % rhs.value
}
}
};
}

impl std::cmp::PartialEq<VehicleField<f64>> for VehicleField<f64> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}

impl std::cmp::PartialEq<f64> for VehicleField<f64> {
fn eq(&self, other: &f64) -> bool {
&self.value == other
}
}

#[derive(Default, Serialize, Deserialize, Clone, Debug)]
pub struct VehicleField<T>
where
T: PartialEq,
{
value: T,
doc: Option<String>,
orphaned: bool,
}

impl<T> ApproxEq for VehicleField<T>
where
T: ApproxEq + PartialEq,
{
/// Returns `true` if `value` fields are approximately equal
fn approx_eq(&self, other: &Self, tol: f64) -> bool {
self.value.approx_eq(&other.value, tol)
}
}

impl<T> VehicleField<T>
where
T: PartialOrd + PartialEq + Default,
{
pub fn new(value: T) -> Self {
Self {
value,
..Default::default()
}
}
}

array_and_scalar_ops!(f64);
array_and_scalar_ops!(u32);
array_and_scalar_ops!(Array1<f64>);

impl core::ops::Index<usize> for VehicleField<Array1<f64>> {
type Output = f64;
fn index(&self, index: usize) -> &Self::Output {
&self.value[index]
}
}

/// Validate range of f64
pub(crate) fn validate_greater_than_zero_f64(
value: &VehicleField<f64>,
) -> Result<(), ValidationError> {
match value.value {
v if v > 0. => Ok(()),
_ => Err(ValidationError::new("Value not in specified range.")),
}
}

#[cfg(test)]
mod vehicle_utils_tests {
use super::*;
Expand Down Expand Up @@ -219,7 +346,7 @@ mod vehicle_utils_tests {

assert!(drag_coef.approx_eq(&0.24676817210529464, 1e-5));
assert!(wheel_rr_coef.approx_eq(&0.0068603812443132645, 1e-6));
assert_eq!(drag_coef, veh.drag_coef);
assert_eq!(veh.drag_coef, drag_coef);
assert_eq!(wheel_rr_coef, veh.wheel_rr_coef);
}
}
Loading