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

Return numpy arrays from Rust #155

Open
wants to merge 3 commits into
base: fastsim-2
Choose a base branch
from
Open
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
13 changes: 0 additions & 13 deletions python/fastsim/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,3 @@ def package_root() -> Path:

__doc__ += "\nhttps://pypi.org/project/fastsim/"
__doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html"

# Enable np.array() on array structs
import numpy as np


def _as_numpy_array(self, *args, **kwargs):
return np.array(list(self), *args, **kwargs)


setattr(fsr.Pyo3ArrayF64, "__array__", _as_numpy_array)
setattr(fsr.Pyo3ArrayU32, "__array__", _as_numpy_array)
setattr(fsr.Pyo3ArrayBool, "__array__", _as_numpy_array)
setattr(fsr.Pyo3VecF64, "__array__", _as_numpy_array)
28 changes: 14 additions & 14 deletions python/fastsim/auxiliaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,13 @@ def get_err(x):
sd_coast.impose_coast = [True] * len(sd_coast.impose_coast)
sd_coast.sim_drive()

cutoff = np.where(np.array(sd_coast.mps_ach) < 0.1)[0][0]
cutoff = np.where(sd_coast.mps_ach < 0.1)[0][0]

err = fsim.cal.get_error_val(
(1000 * (np.array(sd_coast.drag_kw) + np.array(sd_coast.rr_kw)) /
np.array(sd_coast.mps_ach))[:cutoff],
(1000 * (sd_coast.drag_kw + sd_coast.rr_kw) /
sd_coast.mps_ach)[:cutoff],
(dyno_func_lb(sd_coast.mph_ach) * fsim.params.N_PER_LBF)[:cutoff],
np.array(cyc.time_s)[:cutoff],
cyc.time_s[:cutoff],
)

return err
Expand All @@ -118,16 +118,16 @@ def get_err(x):
sd_coast.impose_coast = [True] * len(sd_coast.impose_coast)
sd_coast.sim_drive()

cutoff_val = np.where(np.array(sd_coast.mps_ach) < 0.1)[0][0]
cutoff_val = np.where(sd_coast.mps_ach < 0.1)[0][0]

if show_plots:
plt.figure()
plt.plot(
np.array(sd_coast.mph_ach)[:cutoff_val],
(1000 * (np.array(sd_coast.drag_kw) + np.array(sd_coast.rr_kw)) /
np.array(sd_coast.mps_ach) / fsim.params.N_PER_LBF)[:cutoff_val],
sd_coast.mph_ach[:cutoff_val],
(1000 * (sd_coast.drag_kw + sd_coast.rr_kw) /
sd_coast.mps_ach / fsim.params.N_PER_LBF)[:cutoff_val],
label='sim_drive simulated road load')
plt.plot(np.array(sd_coast.mph_ach)[:cutoff_val], (dyno_func_lb(
plt.plot(sd_coast.mph_ach[:cutoff_val], (dyno_func_lb(
sd_coast.mph_ach))[:cutoff_val], label='ABCs calculated road load')
plt.legend()
plt.xlabel('Speed [mph]')
Expand All @@ -136,14 +136,14 @@ def get_err(x):
plt.show()

fig, ax = plt.subplots(2, 1, sharex=True)
ax[0].plot(np.array(cyc.time_s)[:cutoff_val],
(1000 * (np.array(sd_coast.drag_kw) + np.array(sd_coast.rr_kw)
) / np.array(sd_coast.mps_ach))[:cutoff_val]
ax[0].plot(cyc.time_s[:cutoff_val],
(1000 * (sd_coast.drag_kw + sd_coast.rr_kw
) / sd_coast.mps_ach)[:cutoff_val]
)
ax[0].set_ylabel("Road Load [N]")

ax[-1].plot(np.array(cyc.time_s)[:cutoff_val],
np.array(sd_coast.mph_ach)[:cutoff_val])
ax[-1].plot(cyc.time_s[:cutoff_val],
sd_coast.mph_ach[:cutoff_val])
ax[-1].set_ylabel("mph")
ax[-1].set_xlabel('Time [s]')
plt.show()
Expand Down
8 changes: 4 additions & 4 deletions python/fastsim/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ def get_errors(
ax_multiplier = 2 if plot_perc_err else 1
# extract speed trace for plotting
if not self.use_simdrivehot:
time_hr = np.array(sim_drive.cyc.time_s) / 3_600 # type: ignore
time_hr = sim_drive.cyc.time_s / 3_600 # type: ignore
mph_ach = sim_drive.mph_ach # type: ignore
else:
time_hr = np.array(sim_drive.sd.cyc.time_s) / 3_600 # type: ignore
time_hr = sim_drive.sd.cyc.time_s / 3_600 # type: ignore
mph_ach = sim_drive.sd.mph_ach # type: ignore
fig, ax, pltly_fig = self.setup_plots(
plot or show,
Expand Down Expand Up @@ -523,12 +523,12 @@ def run_minimize(
for obj in problem.mod_obj.obj_names
]
f_df = pd.DataFrame(
data=[f for f in res.F.tolist()],
data=[f for f in res.F],
columns=f_columns,
)

x_df = pd.DataFrame(
data=[x for x in res.X.tolist()],
data=[x for x in res.X],
columns=[param for param in problem.mod_obj.params],
)

Expand Down
10 changes: 4 additions & 6 deletions python/fastsim/cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ class CycleCache:

def __init__(self, cyc: Cycle):
tol = 1e-6
self.grade_all_zero = (np.array(cyc.grade) == 0.0).all()
self.grade_all_zero = (cyc.grade == 0.0).all()
self.trapz_step_distances_m = trapz_step_distances(cyc)
self.trapz_distances_m = self.trapz_step_distances_m.cumsum()
if (self.grade_all_zero):
self.trapz_elevations_m = np.zeros(len(cyc))
else:
self.trapz_elevations_m = np.cumsum(np.cos(np.arctan(cyc.grade)) * self.trapz_step_distances_m * np.array(cyc.grade))
self.stops = np.array(cyc.mps) <= tol
self.trapz_elevations_m = np.cumsum(np.cos(np.arctan(cyc.grade)) * self.trapz_step_distances_m * cyc.grade)
self.stops = cyc.mps <= tol
interp_ds = []
interp_is = []
interp_hs = []
Expand Down Expand Up @@ -882,9 +882,7 @@ def trapz_step_start_distance(cyc: Cycle, i: int) -> float:
(i.e., distance traveled up to sample point i-1)
Distance is in meters.
"""
time_s = np.array(cyc.time_s)
mps = np.array(cyc.mps)
return (np.diff(time_s[:i]) * (0.5 * (mps[:max(i-1,0)] + mps[1:i]))).sum()
return (np.diff(cyc.time_s[:i]) * (0.5 * (cyc.mps[:max(i-1,0)] + cyc.mps[1:i]))).sum()

def trapz_distance_for_step(cyc: Cycle, i: int) -> float:
"""
Expand Down
4 changes: 2 additions & 2 deletions python/fastsim/demos/2017_Ford_F150_thermal_val.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,13 @@ def load_resampled_data() -> Dict[str, pd.DataFrame]:
df.iloc[-1]['Fuel Cumu. [Gal.]']

fig, ax = plt.subplots(3, 1, sharex=True, figsize=(10, 6))
ax[0].plot(sdh.sd.cyc.time_s, np.array(sdh.sd.fs_cumu_mj_out_ach) *
ax[0].plot(sdh.sd.cyc.time_s, sdh.sd.fs_cumu_mj_out_ach *
1e3 / lhv_fuel_kj_per_kg / rho_fuel_kg_per_ml / cc_per_liter / liter_per_gal)
ax[0].plot(df['Time[s]'], df["Fuel Cumu. [Gal.]"])
ax[0].set_ylabel("Cumu. Fuel\nEnergy [MJ]")

mod_enrgy_tract_cumu_mj = (
np.array(sdh.sd.cyc_trans_kw_out_req) / 1e3 * np.diff(
sdh.sd.cyc_trans_kw_out_req / 1e3 * np.diff(
sdh.sd.cyc.time_s, prepend=0.0)).cumsum()
exp_enrgy_tract_cumu_mj = (
df["Tractive Power [kW]"] * df['Time[s]'].diff().fillna(0.0) / 1e3).cumsum()
Expand Down
2 changes: 1 addition & 1 deletion python/fastsim/demos/accel_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def main():
sd_accel = simdrive.RustSimDrive(accel_cyc, veh)

simdrive.run_simdrive_for_accel_test(sd_accel)
if (np.array(sd_accel.mph_ach) >= 60).any():
if (sd_accel.mph_ach >= 60).any():
net_accel = np.interp(
x=60, xp=sd_accel.mph_ach, fp=sd_accel.cyc.time_s)
else:
Expand Down
2 changes: 1 addition & 1 deletion python/fastsim/demos/cav_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
idm_decel_m_per_s2=-2.5,
idm_dt_headway_s=2.0,
idm_minimum_gap_m=0.0,
idm_v_desired_m_per_s=np.average(np.array(cyc.mps)),
idm_v_desired_m_per_s=np.average(cyc.mps),
)
sd.sim_drive()

Expand Down
2 changes: 1 addition & 1 deletion python/fastsim/demos/cav_sweep.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ def make_debug_plot(
ax2.grid(False)
color = "tab:blue"
axs[1].plot(
sd.cyc.time_s, sd.coast_delay_index.tolist(), "b.", lw=2, label="coast delay"
sd.cyc.time_s, sd.coast_delay_index, "b.", lw=2, label="coast delay"
)
axs[1].set_ylabel("Coast Delay", color=color)
axs[1].tick_params(axis="y", labelcolor=color)
Expand Down
14 changes: 6 additions & 8 deletions python/fastsim/demos/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
# NOTE: we need to copy out and in the entire array to work with the
# Rust version that is, we can't set just a specific element of an
# array in rust via python bindings at this time
aux_in_kw = sim_drive.aux_in_kw.tolist()
aux_in_kw = sim_drive.aux_in_kw
aux_in_kw[sim_drive.i] = sim_drive.i / cyc.time_s[-1] * 10
sim_drive.aux_in_kw = aux_in_kw
# above could be a function of some internal sim_drive state
Expand Down Expand Up @@ -229,7 +229,7 @@
# args)
sim_drive.init_for_step(
0.5,
aux_in_kw_override=np.array(cyc.time_s) / cyc.time_s[-1] * 10
aux_in_kw_override=cyc.time_s / cyc.time_s[-1] * 10
)
while sim_drive.i < len(sim_drive.cyc.time_s):
sim_drive.sim_drive_step()
Expand All @@ -256,7 +256,7 @@
t0 = time.perf_counter()

sim_drive = fsim.simdrive.RustSimDrive(cyc, veh)
aux_in_kw_override = np.array(cyc.time_s) / cyc.time_s[-1] * 10
aux_in_kw_override = cyc.time_s / cyc.time_s[-1] * 10
sim_drive.sim_drive(None)

plt.figure()
Expand Down Expand Up @@ -387,11 +387,9 @@ def get_sim_drive_vec(
cyc['cycGrade'] = np.zeros(len(pnts))
cyc['mps'] = np.array(
pnts['speed_mph'] / fsim.params.MPH_PER_MPS) # MPH to MPS conversion
cyc['time_s'] = np.array(
np.cumsum(
(pnts['time_local'] -
pnts['time_local'].shift()).fillna(pd.Timedelta(seconds=0)).astype('timedelta64[s]')
)
cyc['time_s'] = np.cumsum(
(pnts['time_local'] -
pnts['time_local'].shift()).fillna(pd.Timedelta(seconds=0)).astype('timedelta64[s]')
)
cyc['road_type'] = np.zeros(len(pnts))
# example of loading cycle from dict
Expand Down
10 changes: 5 additions & 5 deletions python/fastsim/demos/demo_eu_vehicle_wltp.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ def hybrid_eu_veh_wltp_fe_test():
sim = fsim.simdrive.RustSimDrive(cyc_wltp_combined, veh_2022_yaris)
sim.sim_drive()

dist_miles_combined = np.array(sim.dist_mi).sum()
dist_miles_combined = sim.dist_mi.sum()
print(f"Distance modelled in miles:\t{dist_miles_combined:.2f}")
energy_combined = np.array(sim.fs_kwh_out_ach).sum()
energy_combined = sim.fs_kwh_out_ach.sum()
print(f"Fuel Supply achieved in kilowatts-hours:\t{energy_combined:.2f}")
fe_mpgge_combined = sim.mpgge
fe_l__100km_combined = utils.mpg_to_l__100km(fe_mpgge_combined)
Expand All @@ -85,12 +85,12 @@ def hybrid_veh_fe_soc_correction(cur_veh, raw_simdrive, phase_slice_list):
'''
fe_liter__100km_list = []
for cur_phase_slice in phase_slice_list:
cur_dist_miles = sum(np.array(raw_simdrive.dist_mi)[cur_phase_slice])
cur_dist_miles = raw_simdrive.dist_mi[cur_phase_slice].sum()
cur_dist_km = cur_dist_miles * params.M_PER_MI / 1000
cur_energy_consumption_kwh = sum(np.array(sim.fs_kwh_out_ach)[cur_phase_slice])
cur_energy_consumption_kwh = sim.fs_kwh_out_ach[cur_phase_slice].sum()
cur_fe_mpgge = cur_dist_miles / (cur_energy_consumption_kwh/sim.props.kwh_per_gge)
cur_fe_liter__100km = utils.mpg_to_l__100km(cur_fe_mpgge)
cur_dSOC = np.array(sim.soc)[cur_phase_slice][-1] - np.array(sim.soc)[cur_phase_slice][0]
cur_dSOC = sim.soc[cur_phase_slice][-1] - sim.soc[cur_phase_slice][0]
cur_dE_wh = -cur_dSOC * cur_veh.ess_max_kwh * 1000
cur_dM_CO2_gram__100km = 0.0036 * cur_dE_wh * 1/cur_veh.alt_eff * WILLANS_FACTOR_gram_CO2__MJ * 1/cur_dist_km
cur_dfe_liter__100km = cur_dE_wh/1000 * 1/cur_veh.alt_eff * 1/E10_HEAT_VALUE_kWh__liter * 100/cur_dist_km
Expand Down
8 changes: 4 additions & 4 deletions python/fastsim/demos/fusion_thermal_cal_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@

def get_mgp_from_sdh(sdh: fsr.SimDriveHot) -> float:
fuel_gal_mod = (
(np.array(sdh.sd.fs_kw_out_ach) * np.diff(np.array(sdh.sd.cyc.time_s), prepend=0)
(sdh.sd.fs_kw_out_ach * np.diff(sdh.sd.cyc.time_s, prepend=0)
).sum() / ftc.lhv_fuel_kj_per_kg / ftc.rho_fuel_kg_per_ml * gal_per_ml)
dist_mi_mod = np.array(sdh.sd.dist_mi).sum()
dist_mi_mod = sdh.sd.dist_mi.sum()
return dist_mi_mod / fuel_gal_mod


Expand All @@ -78,7 +78,7 @@ def get_mgp_from_sdh(sdh: fsr.SimDriveHot) -> float:

for key in cal_mods.keys():
sdh = cal_mods[key]
cal_te_amb_degc.append(np.array(sdh.state.amb_te_deg_c).mean())
cal_te_amb_degc.append(sdh.state.amb_te_deg_c.mean())
mpg = get_mgp_from_sdh(sdh)
cal_mod_mpg.append(mpg)
df = cal_objectives.dfs[key]
Expand All @@ -94,7 +94,7 @@ def get_mgp_from_sdh(sdh: fsr.SimDriveHot) -> float:

for key in val_objectives.models.keys():
sdh = val_mods[key]
val_te_amb_degc.append(np.array(sdh.state.amb_te_deg_c).mean())
val_te_amb_degc.append(sdh.state.amb_te_deg_c.mean())
mpg = get_mgp_from_sdh(sdh)
val_mod_mpg.append(mpg)
df = val_objectives.dfs[key]
Expand Down
24 changes: 11 additions & 13 deletions python/fastsim/demos/stop_start_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@
# cycle.clip_by_times(cycle.Cycle.from_file("udds").to_dict(), 130))
cyc = cycle.Cycle.from_file('udds').to_dict()
cyc = cycle.RustCycle.from_dict(cycle.clip_by_times(cyc, 130))
time_s = np.array(cyc.time_s)
dt_s = np.array(cyc.dt_s)
print(f"Elapsed time: {time.time() - t0:.3e} s")


Expand Down Expand Up @@ -65,9 +63,9 @@
# %%
if SHOW_PLOTS:
fig, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(9,5))
ax0.plot(time_s, sim_drive0.fc_kw_in_ach,
ax0.plot(cyc.time_s, sim_drive0.fc_kw_in_ach,
label='base')
ax0.plot(time_s, sim_drive1.fc_kw_in_ach,
ax0.plot(cyc.time_s, sim_drive1.fc_kw_in_ach,
label='stop-start', linestyle='--')
# ax.plot(time_s, dfco_fcKwOutAchPos, label='dfco', linestyle='--', color='blue')
ax0.legend(loc='upper left')
Expand All @@ -76,12 +74,12 @@
ax2 = ax1.twinx()
ax2.yaxis.label.set_color('red')
ax2.tick_params(axis='y', colors='red')
ax2.plot(time_s, sim_drive1.can_pwr_all_elec,
ax2.plot(cyc.time_s, sim_drive1.can_pwr_all_elec,
color='red')
ax2.set_ylabel('SS active')
ax2.grid()

ax1.plot(time_s, cyc.mph)
ax1.plot(cyc.time_s, cyc.mph)
ax1.yaxis.label.set_color('blue')
ax1.tick_params(axis='y', colors='blue')
ax1.set_ylabel('Speed [mph]')
Expand All @@ -90,32 +88,32 @@

# %%
fig, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(9,5))
ax0.plot(time_s, (sim_drive0.fc_kw_in_ach * dt_s).cumsum() / 1e3,
ax0.plot(cyc.time_s, (sim_drive0.fc_kw_in_ach * cyc.dt_s).cumsum() / 1e3,
label='base')
ax0.plot(time_s, (sim_drive1.fc_kw_in_ach * dt_s).cumsum() / 1e3,
ax0.plot(cyc.time_s, (sim_drive1.fc_kw_in_ach * cyc.dt_s).cumsum() / 1e3,
label='stop-start')
ax0.legend(loc='upper left')
ax0.set_ylabel('Fuel Energy [MJ]')

ax2 = ax1.twinx()
ax2.yaxis.label.set_color('red')
ax2.tick_params(axis='y', colors='red')
ax2.plot(time_s, sim_drive1.can_pwr_all_elec,
ax2.plot(cyc.time_s, sim_drive1.can_pwr_all_elec,
color='red', alpha=0.25)
ax2.set_ylabel('SS active')
ax2.set_xlim(ax0.get_xlim())
ax2.set_yticks([0, 1])
ax2.grid()

ax1.plot(time_s, cyc.mph)
ax1.plot(cyc.time_s, cyc.mph)
ax1.yaxis.label.set_color('blue')
ax1.tick_params(axis='y', colors='blue')
ax1.set_ylabel('Speed [mph]')
ax1.set_xlabel('Time [s]')

diff = ((sim_drive0.fc_kw_out_ach * dt_s).sum() -
(sim_drive1.fc_kw_out_ach * dt_s).sum()) / (
sim_drive0.fc_kw_out_ach * dt_s).sum()
diff = ((sim_drive0.fc_kw_out_ach * cyc.dt_s).sum() -
(sim_drive1.fc_kw_out_ach * cyc.dt_s).sum()) / (
sim_drive0.fc_kw_out_ach * cyc.dt_s).sum()

print(f'Stop/start produces a {diff:.2%} reduction in fuel consumption.\n')
# %%
Loading
Loading