diff --git a/rust/fastsim-cli/src/bin/fastsim-cli.rs b/rust/fastsim-cli/src/bin/fastsim-cli.rs index 334ff477..6c9899b9 100644 --- a/rust/fastsim-cli/src/bin/fastsim-cli.rs +++ b/rust/fastsim-cli/src/bin/fastsim-cli.rs @@ -196,7 +196,7 @@ pub fn main() -> anyhow::Result<()> { && adopt_hd_str_lc != false_string; (true, adopt_hd_string.clone(), adopt_hd_has_cycle) } else { - (false, String::from(""), false) + (false, String::default(), false) }; let cyc = if let Some(cyc_file_path) = fastsim_api.cyc_file { if cyc_file_path == *"coastdown" { @@ -231,7 +231,7 @@ pub fn main() -> anyhow::Result<()> { vec![0.0], vec![0.0], vec![0.0], - String::from(""), + "", )) }?; diff --git a/rust/fastsim-core/build.rs b/rust/fastsim-core/build.rs index 59113740..2ffeec99 100644 --- a/rust/fastsim-core/build.rs +++ b/rust/fastsim-core/build.rs @@ -11,12 +11,12 @@ fn main() { // path when building using build_and_test.sh let build_path = "../../python/fastsim/resources".to_string(); - let prepath: String = match PathBuf::from(publish_path.clone()).exists() { + let prepath: String = match PathBuf::from(&publish_path).exists() { true => publish_path, false => build_path, }; - if !PathBuf::from(prepath.clone()).exists() { + if !PathBuf::from(&prepath).exists() { // no need for further checks since this indicates that it's // likely that python fastsim is not available and thus // fastsim-core is likely being compiled as a dependency @@ -59,7 +59,7 @@ fn main() { for (tf, cf) in truth_files.iter().zip(compare_files) { let tfc = fs::read_to_string(tf).unwrap_or_else(|_| panic!("{tf} does not exist.")); - let cfc = fs::read_to_string(cf.clone()).unwrap_or_else(|_| panic!("{cf} does not exist.")); + let cfc = fs::read_to_string(&cf).unwrap_or_else(|_| panic!("{cf} does not exist.")); if tfc != cfc { panic!("Reference file {tf} does not match file being compared: {cf}. Copy {tf} to {cf} to fix this.") diff --git a/rust/fastsim-core/src/air.rs b/rust/fastsim-core/src/air.rs index 1d93aaaa..fb5d54d1 100644 --- a/rust/fastsim-core/src/air.rs +++ b/rust/fastsim-core/src/air.rs @@ -192,7 +192,7 @@ impl Default for AirProperties { .into(), ); - let pr_array = mu_array.clone() * c_p_array.clone() / k_array.clone(); + let pr_array = &mu_array * &c_p_array / &k_array; Self { te_array_degc, diff --git a/rust/fastsim-core/src/cycle.rs b/rust/fastsim-core/src/cycle.rs index 61c5d4e1..4fa9baec 100644 --- a/rust/fastsim-core/src/cycle.rs +++ b/rust/fastsim-core/src/cycle.rs @@ -181,7 +181,7 @@ pub fn trapz_distance_over_range(cyc: &RustCycle, i_start: usize, i_end: usize) pub fn time_spent_moving(cyc: &RustCycle, stopped_speed_m_per_s: Option) -> f64 { let mut t_move_s = 0.0; let stopped_speed_m_per_s = stopped_speed_m_per_s.unwrap_or(0.0); - for idx in 1..cyc.time_s.len() { + for idx in 1..cyc.len() { let dt = cyc.time_s[idx] - cyc.time_s[idx - 1]; let vavg = (cyc.mps[idx] + cyc.mps[idx - 1]) / 2.0; if vavg > stopped_speed_m_per_s { @@ -229,7 +229,7 @@ pub fn to_microtrips(cycle: &RustCycle, stop_speed_m_per_s: Option) -> Vec< mt_vs.clone(), mt_gs.clone(), mt_rs.clone(), - cycle.name.clone(), + &cycle.name, )); mt_ts = vec![last_t]; mt_vs = vec![last_v]; @@ -244,13 +244,7 @@ pub fn to_microtrips(cycle: &RustCycle, stop_speed_m_per_s: Option) -> Vec< } if !mt_ts.is_empty() { mt_ts = mt_ts.iter().map(|t| -> f64 { t - mt_ts[0] }).collect(); - microtrips.push(RustCycle::new( - mt_ts, - mt_vs, - mt_gs, - mt_rs, - cycle.name.clone(), - )); + microtrips.push(RustCycle::new(mt_ts, mt_vs, mt_gs, mt_rs, &cycle.name)); } microtrips } @@ -344,7 +338,7 @@ pub fn extend_cycle( rs.push(0.0); idx += 1; } - RustCycle::new(ts, vs, gs, rs, cyc.name.clone()) + RustCycle::new(ts, vs, gs, rs, &cyc.name) } #[cfg(feature = "pyo3")] @@ -399,7 +393,7 @@ impl SerdeAPI for RustCycleCache {} impl RustCycleCache { pub fn new(cyc: &RustCycle) -> Self { let tol = 1e-6; - let num_items = cyc.time_s.len(); + let num_items = cyc.len(); let grade_all_zero = cyc.grade.iter().all(|g| *g == 0.0); let trapz_step_distances_m = trapz_step_distances(cyc); let trapz_distances_m = ndarrcumsum(&trapz_step_distances_m); @@ -686,17 +680,18 @@ impl SerdeAPI for RustCycle { /// pure Rust methods that need to be separate due to pymethods incompatibility impl RustCycle { - pub fn new( + pub fn new>( time_s: Vec, mps: Vec, grade: Vec, road_type: Vec, - name: String, + name: S, ) -> Self { let time_s = Array::from_vec(time_s); let mps = Array::from_vec(mps); let grade = Array::from_vec(grade); let road_type = Array::from_vec(road_type); + let name = name.as_ref().to_string(); Self { time_s, mps, @@ -1014,7 +1009,7 @@ impl RustCycle { /// elevation change w.r.t. to initial pub fn delta_elev_m(&self) -> Array1 { - ndarrcumsum(&(self.dist_m() * self.grade.clone())) + ndarrcumsum(&(self.dist_m() * &self.grade)) } } @@ -1051,7 +1046,7 @@ pub fn detect_passing( i: usize, dist_tol_m: Option, ) -> PassingInfo { - if i >= cyc.time_s.len() { + if i >= cyc.len() { return PassingInfo { has_collision: false, idx: 0, @@ -1127,7 +1122,7 @@ mod tests { let speed_mps = vec![0.0, 10.0, 10.0, 0.0, 0.0]; let grade = Array::zeros(5).to_vec(); let road_type = Array::zeros(5).to_vec(); - let name = String::from("test"); + let name = "test"; let cyc = RustCycle::new(time_s, speed_mps, grade, road_type, name); let avg_mps = average_step_speeds(&cyc); let expected_avg_mps = Array::from_vec(vec![0.0, 5.0, 10.0, 5.0, 0.0]); @@ -1148,10 +1143,10 @@ mod tests { let cyc_file_path = resources_path().join("cycles/udds.csv"); let expected_udds_length: usize = 1370; let cyc = RustCycle::from_csv_file(cyc_file_path).unwrap(); - let num_entries = cyc.time_s.len(); + let num_entries = cyc.len(); assert_eq!(cyc.name, String::from("udds")); assert!(num_entries > 0); - assert_eq!(num_entries, cyc.time_s.len()); + assert_eq!(num_entries, cyc.len()); assert_eq!(num_entries, cyc.mps.len()); assert_eq!(num_entries, cyc.grade.len()); assert_eq!(num_entries, cyc.road_type.len()); diff --git a/rust/fastsim-core/src/simdrive.rs b/rust/fastsim-core/src/simdrive.rs index c929a691..c90c8cd6 100644 --- a/rust/fastsim-core/src/simdrive.rs +++ b/rust/fastsim-core/src/simdrive.rs @@ -345,11 +345,11 @@ impl Default for RustSimDriveParams { #[getter] pub fn get_fs_cumu_mj_out_ach(&self) -> Pyo3ArrayF64 { - Pyo3ArrayF64::new(ndarrcumsum(&(self.fs_kw_out_ach.clone() * self.cyc.dt_s() * 1e-3))) + Pyo3ArrayF64::new(ndarrcumsum(&(&self.fs_kw_out_ach * self.cyc.dt_s() * 1e-3))) } #[getter] pub fn get_fc_cumu_mj_out_ach(&self) -> Pyo3ArrayF64 { - Pyo3ArrayF64::new(ndarrcumsum(&(self.fc_kw_out_ach.clone() * self.cyc.dt_s() * 1e-3))) + Pyo3ArrayF64::new(ndarrcumsum(&(&self.fc_kw_out_ach * self.cyc.dt_s() * 1e-3))) } )] pub struct RustSimDrive { diff --git a/rust/fastsim-core/src/simdrive/cyc_mods.rs b/rust/fastsim-core/src/simdrive/cyc_mods.rs index 59a3544e..d99fb744 100644 --- a/rust/fastsim-core/src/simdrive/cyc_mods.rs +++ b/rust/fastsim-core/src/simdrive/cyc_mods.rs @@ -374,14 +374,13 @@ impl RustSimDrive { let a_brake = self.sim_params.coast_brake_accel_m_per_s2; assert![a_brake <= 0.0]; let ds = &self.cyc0_cache.trapz_distances_m; - let gs = self.cyc0.grade.clone(); let d0 = trapz_step_start_distance(&self.cyc, i); let mut distances_m: Vec = Vec::with_capacity(ds.len()); let mut grade_by_distance: Vec = Vec::with_capacity(ds.len()); for idx in 0..ds.len() { if ds[idx] >= d0 { distances_m.push(ds[idx] - d0); - grade_by_distance.push(gs[idx]) + grade_by_distance.push(self.cyc0.grade[idx]) } } if distances_m.is_empty() { @@ -754,7 +753,7 @@ impl RustSimDrive { fn set_coast_delay(&mut self, i: usize) { let speed_tol = 0.01; // m/s let dist_tol = 0.1; // meters - for idx in i..self.cyc.time_s.len() { + for idx in i..self.cyc.len() { self.coast_delay_index[idx] = 0; // clear all future coast-delays } let mut coast_delay: Option = None; @@ -848,7 +847,7 @@ impl RustSimDrive { if n < 2 { break; } - if (idx - 1 + full_brake_steps) >= self.cyc.time_s.len() { + if (idx - 1 + full_brake_steps) >= self.cyc.len() { break; } let dt = collision.time_step_duration_s; @@ -873,7 +872,7 @@ impl RustSimDrive { let mut accels_m_per_s2: Vec = vec![]; let mut trace_accels_m_per_s2: Vec = vec![]; for ni in 0..n { - if (ni + idx + full_brake_steps) >= self.cyc.time_s.len() { + if (ni + idx + full_brake_steps) >= self.cyc.len() { break; } accels_m_per_s2.push(accel_for_constant_jerk( @@ -889,9 +888,9 @@ impl RustSimDrive { ); } let all_sub_coast: bool = trace_accels_m_per_s2 - .clone() - .into_iter() - .zip(accels_m_per_s2.clone().into_iter()) + .iter() + .copied() + .zip(accels_m_per_s2.iter().copied()) .fold( true, |all_sc_flag: bool, (trace_accel, accel): (f64, f64)| { @@ -934,7 +933,7 @@ impl RustSimDrive { return self.prevent_collisions(i, Some(new_passing_tol_m)); } for fbs in 0..best.full_brake_steps { - if (best.idx + fbs) >= self.cyc.time_s.len() { + if (best.idx + fbs) >= self.cyc.len() { break; } let dt = self.cyc.time_s[best.idx + fbs] - self.cyc.time_s[best.idx - 1]; @@ -1037,7 +1036,7 @@ impl RustSimDrive { i, None, )?; - for idx in i..self.cyc.time_s.len() { + for idx in i..self.cyc.len() { self.impose_coast[idx] = idx < (i + num_steps); } adjusted_current_speed = true; diff --git a/rust/fastsim-core/src/simdrive/simdrive_impl.rs b/rust/fastsim-core/src/simdrive/simdrive_impl.rs index fcdfa07b..002a7beb 100644 --- a/rust/fastsim-core/src/simdrive/simdrive_impl.rs +++ b/rust/fastsim-core/src/simdrive/simdrive_impl.rs @@ -28,11 +28,11 @@ pub struct CoastTrajectory { impl RustSimDrive { pub fn new(cyc: RustCycle, veh: RustVehicle) -> Self { let hev_sim_count: usize = 0; - let cyc0: RustCycle = cyc.clone(); + let cyc0 = cyc.clone(); let sim_params = RustSimDriveParams::default(); let props = params::RustPhysicalProperties::default(); let i: usize = 1; // 1 # initialize step counter for possible use outside sim_drive_walk() - let cyc_len = cyc.time_s.len(); //get_len() as usize; + let cyc_len = cyc.len(); let cur_max_fs_kw_out = Array::zeros(cyc_len); let fc_trans_lim_kw = Array::zeros(cyc_len); let fc_fs_lim_kw = Array::zeros(cyc_len); @@ -123,29 +123,29 @@ impl RustSimDrive { let cur_max_roadway_chg_kw = Array::zeros(cyc_len); let trace_miss_iters = Array::zeros(cyc_len); let newton_iters = Array::zeros(cyc_len); - let fuel_kj: f64 = 0.0; - let ess_dischg_kj: f64 = 0.0; - let energy_audit_error: f64 = 0.0; - let mpgge: f64 = 0.0; - let roadway_chg_kj: f64 = 0.0; - let battery_kwh_per_mi: f64 = 0.0; - let electric_kwh_per_mi: f64 = 0.0; - let ess2fuel_kwh: f64 = 0.0; - let drag_kj: f64 = 0.0; - let ascent_kj: f64 = 0.0; - let rr_kj: f64 = 0.0; - let brake_kj: f64 = 0.0; - let trans_kj: f64 = 0.0; - let mc_kj: f64 = 0.0; - let ess_eff_kj: f64 = 0.0; - let aux_kj: f64 = 0.0; - let fc_kj: f64 = 0.0; - let net_kj: f64 = 0.0; - let ke_kj: f64 = 0.0; + let fuel_kj = 0.0; + let ess_dischg_kj = 0.0; + let energy_audit_error = 0.0; + let mpgge = 0.0; + let roadway_chg_kj = 0.0; + let battery_kwh_per_mi = 0.0; + let electric_kwh_per_mi = 0.0; + let ess2fuel_kwh = 0.0; + let drag_kj = 0.0; + let ascent_kj = 0.0; + let rr_kj = 0.0; + let brake_kj = 0.0; + let trans_kj = 0.0; + let mc_kj = 0.0; + let ess_eff_kj = 0.0; + let aux_kj = 0.0; + let fc_kj = 0.0; + let net_kj = 0.0; + let ke_kj = 0.0; let trace_miss = false; - let trace_miss_dist_frac: f64 = 0.0; - let trace_miss_time_frac: f64 = 0.0; - let trace_miss_speed_mps: f64 = 0.0; + let trace_miss_dist_frac = 0.0; + let trace_miss_time_frac = 0.0; + let trace_miss_speed_mps = 0.0; let coast_delay_index = Array::zeros(cyc_len); let idm_target_speed_m_per_s = Array::zeros(cyc_len); let cyc0_cache = RustCycleCache::new(&cyc0); @@ -474,7 +474,7 @@ impl RustSimDrive { aux_in_kw_override: Option>, ) -> anyhow::Result<()> { // Initialize and run sim_drive_walk as appropriate for vehicle attribute vehPtType. - let init_soc_auto: f64 = match self.veh.veh_pt_type.as_str() { + let init_soc_auto = match self.veh.veh_pt_type.as_str() { // If no EV / Hybrid components, no SOC considerations. CONV => (self.veh.max_soc + self.veh.min_soc) / 2.0, HEV => (self.veh.max_soc + self.veh.min_soc) / 2.0, @@ -503,17 +503,22 @@ impl RustSimDrive { aux_in_kw_override: Option>, ) -> anyhow::Result<()> { self.init_for_step(init_soc, aux_in_kw_override)?; - while self.i < self.cyc.time_s.len() { + while self.i < self.cyc.len() { self.step()?; } - // TODO: uncomment and implement logging - // if (self.cyc.dt_s > 5).any() and self.sim_params.verbose: - // if self.sim_params.missed_trace_correction: - // print('Max time dilation factor =', (round((self.cyc.dt_s / self.cyc0.dt_s).max(), 3))) - // print("Warning: large time steps affect accuracy significantly.") - // print("To suppress this message, view the doc string for simdrive.SimDriveParams.") - // print('Max time step =', (round(self.cyc.dt_s.max(), 3))) + if self.cyc.dt_s().iter().any(|&dt| dt > 5.0) { + if self.sim_params.missed_trace_correction { + log::info!( + "Max time dilation factor = {:.3}", + ndarrmax(&(self.cyc.dt_s() / self.cyc0.dt_s())) + ); + } + log::warn!( + "Large time steps affect accuracy significantly (max time step = {:.3})", + ndarrmax(&self.cyc.dt_s()) + ); + } Ok(()) } @@ -1775,7 +1780,7 @@ impl RustSimDrive { self.mpgge = self.dist_mi.sum() / (self.fs_kwh_out_ach.sum() / self.props.kwh_per_gge); } - self.roadway_chg_kj = (self.roadway_chg_kw_out_ach.clone() * self.cyc.dt_s()).sum(); + self.roadway_chg_kj = (&self.roadway_chg_kw_out_ach * self.cyc.dt_s()).sum(); self.ess_dischg_kj = -1.0 * (self .soc @@ -1795,7 +1800,7 @@ impl RustSimDrive { } else { 0.0 }; - self.fuel_kj = (self.fs_kw_out_ach.clone() * self.cyc.dt_s()).sum(); + self.fuel_kj = (&self.fs_kw_out_ach * self.cyc.dt_s()).sum(); if (self.fuel_kj + self.roadway_chg_kj) == 0.0 { self.ess2fuel_kwh = 1.0 @@ -1804,11 +1809,11 @@ impl RustSimDrive { } // energy audit calcs - self.drag_kj = (self.drag_kw.clone() * self.cyc.dt_s()).sum(); - self.ascent_kj = (self.ascent_kw.clone() * self.cyc.dt_s()).sum(); - self.rr_kj = (self.rr_kw.clone() * self.cyc.dt_s()).sum(); + self.drag_kj = (&self.drag_kw * self.cyc.dt_s()).sum(); + self.ascent_kj = (&self.ascent_kw * self.cyc.dt_s()).sum(); + self.rr_kj = (&self.rr_kw * self.cyc.dt_s()).sum(); - for i in 1..self.cyc.time_s.len() { + for i in 1..self.cyc.len() { if self.veh.ess_max_kw == 0.0 || self.veh.ess_max_kwh == 0.0 { self.ess_loss_kw[i] = 0.0; } else if self.ess_kw_out_ach[i] < 0.0 { @@ -1821,17 +1826,12 @@ impl RustSimDrive { } } - self.brake_kj = (self.cyc_fric_brake_kw.clone() * self.cyc.dt_s()).sum(); - self.trans_kj = ((self.trans_kw_in_ach.clone() - self.trans_kw_out_ach.clone()) - * self.cyc.dt_s()) - .sum(); - self.mc_kj = ((self.mc_elec_kw_in_ach.clone() - self.mc_mech_kw_out_ach.clone()) - * self.cyc.dt_s()) - .sum(); - self.ess_eff_kj = (self.ess_loss_kw.clone() * self.cyc.dt_s()).sum(); - self.aux_kj = (self.aux_in_kw.clone() * self.cyc.dt_s()).sum(); - self.fc_kj = - ((self.fc_kw_in_ach.clone() - self.fc_kw_out_ach.clone()) * self.cyc.dt_s()).sum(); + self.brake_kj = (&self.cyc_fric_brake_kw * self.cyc.dt_s()).sum(); + self.trans_kj = ((&self.trans_kw_in_ach - &self.trans_kw_out_ach) * self.cyc.dt_s()).sum(); + self.mc_kj = ((&self.mc_elec_kw_in_ach - &self.mc_mech_kw_out_ach) * self.cyc.dt_s()).sum(); + self.ess_eff_kj = (&self.ess_loss_kw * self.cyc.dt_s()).sum(); + self.aux_kj = (&self.aux_in_kw * self.cyc.dt_s()).sum(); + self.fc_kj = ((&self.fc_kw_in_ach - &self.fc_kw_out_ach) * self.cyc.dt_s()).sum(); self.net_kj = self.drag_kj + self.ascent_kj @@ -1909,8 +1909,7 @@ impl RustSimDrive { ); } - self.trace_miss_speed_mps = - ndarrmax(&(self.mps_ach.clone() - self.cyc.mps.clone()).map(|x| x.abs())); + self.trace_miss_speed_mps = ndarrmax(&(&self.mps_ach - &self.cyc.mps).map(|x| x.abs())); if self.trace_miss_speed_mps > self.sim_params.trace_miss_speed_mps_tol { self.trace_miss = true; log::warn!( diff --git a/rust/fastsim-core/src/simdrivelabel.rs b/rust/fastsim-core/src/simdrivelabel.rs index fe1b94c3..2edb7f3f 100644 --- a/rust/fastsim-core/src/simdrivelabel.rs +++ b/rust/fastsim-core/src/simdrivelabel.rs @@ -130,7 +130,7 @@ pub fn make_accel_trace() -> RustCycle { accel_cyc_mps.to_vec(), Array::zeros(accel_cyc_secs.len()).to_vec(), Array::zeros(accel_cyc_secs.len()).to_vec(), - String::from("accel"), + "accel", ) } diff --git a/rust/fastsim-core/src/thermal.rs b/rust/fastsim-core/src/thermal.rs index c3398cbc..c53e9721 100644 --- a/rust/fastsim-core/src/thermal.rs +++ b/rust/fastsim-core/src/thermal.rs @@ -311,7 +311,7 @@ impl SimDriveHot { pub fn walk(&mut self, init_soc: f64, aux_in_kw_override: Option>) { self.init_for_step(init_soc, aux_in_kw_override); - while self.sd.i < self.sd.cyc.time_s.len() { + while self.sd.i < self.sd.cyc.len() { self.step().unwrap(); } } @@ -703,7 +703,7 @@ impl SimDriveHot { pub fn thermal_soak_walk(&mut self) { self.sd.i = 1; - while self.sd.i < self.sd.cyc.time_s.len() { + while self.sd.i < self.sd.cyc.len() { self.set_thermal_calcs(self.sd.i); self.sd.i += 1; } diff --git a/rust/fastsim-core/src/vehicle.rs b/rust/fastsim-core/src/vehicle.rs index d7a8b4ee..d301f6b8 100644 --- a/rust/fastsim-core/src/vehicle.rs +++ b/rust/fastsim-core/src/vehicle.rs @@ -731,7 +731,7 @@ impl RustVehicle { self.fc_perc_out_array = FC_PERC_OUT_ARRAY.clone().to_vec(); // # discrete array of possible engine power outputs - self.input_kw_out_array = self.fc_pwr_out_perc.clone() * self.fc_max_kw; + self.input_kw_out_array = &self.fc_pwr_out_perc * self.fc_max_kw; // # Relatively continuous array of possible engine power outputs self.fc_kw_out_array = self .fc_perc_out_array @@ -787,7 +787,7 @@ impl RustVehicle { self.mc_eff_array = self.mc_eff_map.clone(); // println!("{:?}",self.mc_eff_map); // self.mc_eff_array = mc_kw_adj_perc * large_baseline_eff_adj - // + (1.0 - mc_kw_adj_perc) * self.small_baseline_eff.clone(); + // + (1.0 - mc_kw_adj_perc) * &self.small_baseline_eff; // self.mc_eff_map = self.mc_eff_array.clone(); self.mc_perc_out_array = MC_PERC_OUT_ARRAY.clone().to_vec(); @@ -1103,7 +1103,7 @@ mod tests { if idx == 0 { 0.0 } else { - interpolate(&x, &mc_pwr_out_perc, &mc_eff_map.clone(), false) + interpolate(&x, &mc_pwr_out_perc, &mc_eff_map, false) } }) .collect(); diff --git a/rust/fastsim-core/src/vehicle_utils.rs b/rust/fastsim-core/src/vehicle_utils.rs index 337f07a9..38fe57aa 100644 --- a/rust/fastsim-core/src/vehicle_utils.rs +++ b/rust/fastsim-core/src/vehicle_utils.rs @@ -67,7 +67,7 @@ pub fn abc_to_drag_coeffs( Array::linspace(vmax_mph / super::params::MPH_PER_MPS, 0.0, cd_len).to_vec(), vec![0.0; cd_len], vec![0.0; cd_len], - String::from("cycle"), + "cycle", ); // polynomial function for pounds vs speed