From 3ea2802d7c83829f4c152ac4c1e969b0905c379d Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Wed, 4 Oct 2023 15:35:51 -0600 Subject: [PATCH 01/21] [DRAFT] adding demo files to build_and_test.sh run --- build_and_test.sh | 3 ++- python/fastsim/demos/run_all_demos.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 python/fastsim/demos/run_all_demos.py diff --git a/build_and_test.sh b/build_and_test.sh index 69467be0..f16dca93 100755 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -2,4 +2,5 @@ (cd rust/fastsim-core/ && cargo test) && \ (cd rust/fastsim-cli/ && cargo test) && \ pip install -qe ".[dev]" && \ -pytest -v python/fastsim/tests/ \ No newline at end of file +pytest -v python/fastsim/tests/ +(cd python/fastsim/demos/ && python run_all_demos.py) \ No newline at end of file diff --git a/python/fastsim/demos/run_all_demos.py b/python/fastsim/demos/run_all_demos.py new file mode 100644 index 00000000..1b9c2ee7 --- /dev/null +++ b/python/fastsim/demos/run_all_demos.py @@ -0,0 +1,18 @@ +files_to_run = [ + 'accel_demo.py', + 'cav_demo.py', + 'demo_abc_drag_coef_conv.py', + 'demo_eu_vehicle_wltp.py', + 'demo.py', + 'fusion_thermal_demo.py', + 'mp_parallel_demo.py', + 'stop_start_demo.py', + 'time_dilation_demo.py', + 'timing_demo.py', + 'test_demo.py', + 'test_cav_demo.py', +] + +for file in files_to_run: + with open(file) as f: + exec(f.read()) \ No newline at end of file From 178448ce365023c8d5c0d6ad6819e194b37d007e Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Wed, 11 Oct 2023 20:57:29 -0600 Subject: [PATCH 02/21] making run_all.py, running all .py files with demo in title, adding to build_and_test.sh --- build_and_test.sh | 2 +- python/fastsim/demos/run_all.py | 8 ++++++++ python/fastsim/demos/run_all_demos.py | 18 ------------------ 3 files changed, 9 insertions(+), 19 deletions(-) create mode 100644 python/fastsim/demos/run_all.py delete mode 100644 python/fastsim/demos/run_all_demos.py diff --git a/build_and_test.sh b/build_and_test.sh index f16dca93..994aabbf 100755 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -3,4 +3,4 @@ (cd rust/fastsim-cli/ && cargo test) && \ pip install -qe ".[dev]" && \ pytest -v python/fastsim/tests/ -(cd python/fastsim/demos/ && python run_all_demos.py) \ No newline at end of file +(cd python/fastsim/demos/ && python run_all.py) \ No newline at end of file diff --git a/python/fastsim/demos/run_all.py b/python/fastsim/demos/run_all.py new file mode 100644 index 00000000..6f15f4fa --- /dev/null +++ b/python/fastsim/demos/run_all.py @@ -0,0 +1,8 @@ +import pathlib + +p = pathlib.Path('run_all.py').parent + +for file in p.glob('*demo*.py'): + with open(file) as f: + exec(f.read()) + print('{} ran successfully'.format(f)) \ No newline at end of file diff --git a/python/fastsim/demos/run_all_demos.py b/python/fastsim/demos/run_all_demos.py deleted file mode 100644 index 1b9c2ee7..00000000 --- a/python/fastsim/demos/run_all_demos.py +++ /dev/null @@ -1,18 +0,0 @@ -files_to_run = [ - 'accel_demo.py', - 'cav_demo.py', - 'demo_abc_drag_coef_conv.py', - 'demo_eu_vehicle_wltp.py', - 'demo.py', - 'fusion_thermal_demo.py', - 'mp_parallel_demo.py', - 'stop_start_demo.py', - 'time_dilation_demo.py', - 'timing_demo.py', - 'test_demo.py', - 'test_cav_demo.py', -] - -for file in files_to_run: - with open(file) as f: - exec(f.read()) \ No newline at end of file From c9de773b4671f4556b2799ff78f21c8d223e5a0d Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Thu, 12 Oct 2023 14:22:41 -0600 Subject: [PATCH 03/21] first attempt at getting the demos files to download with proper version and without overriding local files --- python/fastsim/__init__.py | 33 +++++++++++++++++++++++++++++++++ python/fastsim/demos/run_all.py | 2 +- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index 4147d7c9..cb8c5af2 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -33,6 +33,39 @@ def package_root() -> Path: __version__ = get_distribution("fastsim").version +#download demo files +import fastsim +import os +import pathlib +import fnmatch +import requests + +p = 'https://github.com/NREL/fastsim/tree/' + fastsim.__version__ + '/python/fastsim/demos' +d = pathlib.Path(__file__).parent +has_demos = False +demos_dir = '' +for dir in os.walk(d): + if fnmatch.fnmatch(dir[0], '*demos'): + has_demos = True + demos_dir = dir[0] + break +if has_demos: + #the problem is I can't figure out how to list the contents of the online demos file + for f in p.get_dir_contents(): + already_downloaded = False + for file in demos_dir.glob('*demo*.py'): + #need a way to get the "basename" for the online demos files as well for this to work + if f == os.path.basename(file.replace('\\', '/')): #necessary to ensure command works on all operating systems + already_downloaded = True + print('{} = {} already downloaded'.format(file, f)) #placeholder until I figure out how to download the file + break + if already_downloaded == False: + #download file + print('{} != {} needs downloading'.format(file, f)) #placeholder under I figure out how to download the folder +else: + #just download demos folder + print('demos folder needs downloading') + __doc__ += "\nhttps://pypi.org/project/fastsim/" __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" diff --git a/python/fastsim/demos/run_all.py b/python/fastsim/demos/run_all.py index 6f15f4fa..eca256f3 100644 --- a/python/fastsim/demos/run_all.py +++ b/python/fastsim/demos/run_all.py @@ -1,6 +1,6 @@ import pathlib -p = pathlib.Path('run_all.py').parent +p = pathlib.Path(__file__).parent for file in p.glob('*demo*.py'): with open(file) as f: From 87eaa624d5d5427313ac2e1ad5ac6fe7c6be64a2 Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Thu, 12 Oct 2023 14:30:03 -0600 Subject: [PATCH 04/21] updating comments --- python/fastsim/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index cb8c5af2..8dc2d7b1 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -57,14 +57,14 @@ def package_root() -> Path: #need a way to get the "basename" for the online demos files as well for this to work if f == os.path.basename(file.replace('\\', '/')): #necessary to ensure command works on all operating systems already_downloaded = True - print('{} = {} already downloaded'.format(file, f)) #placeholder until I figure out how to download the file + print('{} = {} already downloaded'.format(file, f)) break if already_downloaded == False: #download file - print('{} != {} needs downloading'.format(file, f)) #placeholder under I figure out how to download the folder + print('{} != {} needs downloading'.format(file, f)) #placeholder under I figure out how to download the file else: #just download demos folder - print('demos folder needs downloading') + print('demos folder needs downloading') #placeholder until I figure out how to download the file __doc__ += "\nhttps://pypi.org/project/fastsim/" __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" From 7ab893a7becd16597bba55ee57b53972bdb2e603 Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Mon, 30 Oct 2023 20:02:36 -0400 Subject: [PATCH 05/21] adding demos testing to sh file like in altrios --- build_and_test.sh | 8 +- python/fastsim/__init__.py | 78 +-- python/fastsim/demos/cav_demo.py | 38 +- python/fastsim/demos/demo.py | 55 +- .../fastsim/demos/demo_abc_drag_coef_conv.py | 8 +- python/fastsim/demos/fusion_thermal_demo.py | 138 +++-- python/fastsim/demos/run_all.py | 8 - python/fastsim/demos/stop_start_demo.py | 101 ++-- python/fastsim/demos/test_demos.py | 22 + python/fastsim/demos/time_dilation_demo.py | 39 +- python/fastsim/tests/test_cav_demo.py | 36 +- python/fastsim/tests/test_demo.py | 572 +++++++++--------- python/fastsim/utilities.py | 56 +- 13 files changed, 639 insertions(+), 520 deletions(-) delete mode 100644 python/fastsim/demos/run_all.py create mode 100644 python/fastsim/demos/test_demos.py diff --git a/build_and_test.sh b/build_and_test.sh index 994aabbf..6525f2fd 100755 --- a/build_and_test.sh +++ b/build_and_test.sh @@ -1,6 +1,10 @@ # build and test with local version of `fastsim-proc-macros` +echo "Testing rust" && \ (cd rust/fastsim-core/ && cargo test) && \ (cd rust/fastsim-cli/ && cargo test) && \ pip install -qe ".[dev]" && \ -pytest -v python/fastsim/tests/ -(cd python/fastsim/demos/ && python run_all.py) \ No newline at end of file +echo "Running python tests" && \ +pytest -v python/fastsim/tests/ && \ +echo "Verifying that demos run" && \ +pytest -v python/fastsim/demos/ && \ +echo "Complete success!" \ No newline at end of file diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index 8dc2d7b1..793514c5 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -29,45 +29,45 @@ def package_root() -> Path: from .resample import resample from . import auxiliaries -from pkg_resources import get_distribution - -__version__ = get_distribution("fastsim").version - -#download demo files -import fastsim -import os -import pathlib -import fnmatch -import requests - -p = 'https://github.com/NREL/fastsim/tree/' + fastsim.__version__ + '/python/fastsim/demos' -d = pathlib.Path(__file__).parent -has_demos = False -demos_dir = '' -for dir in os.walk(d): - if fnmatch.fnmatch(dir[0], '*demos'): - has_demos = True - demos_dir = dir[0] - break -if has_demos: - #the problem is I can't figure out how to list the contents of the online demos file - for f in p.get_dir_contents(): - already_downloaded = False - for file in demos_dir.glob('*demo*.py'): - #need a way to get the "basename" for the online demos files as well for this to work - if f == os.path.basename(file.replace('\\', '/')): #necessary to ensure command works on all operating systems - already_downloaded = True - print('{} = {} already downloaded'.format(file, f)) - break - if already_downloaded == False: - #download file - print('{} != {} needs downloading'.format(file, f)) #placeholder under I figure out how to download the file -else: - #just download demos folder - print('demos folder needs downloading') #placeholder until I figure out how to download the file - -__doc__ += "\nhttps://pypi.org/project/fastsim/" -__doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" +# from pkg_resources import get_distribution + +# __version__ = get_distribution("fastsim").version + +# #download demo files +# import fastsim +# import os +# import pathlib +# import fnmatch +# import requests + +# p = 'https://github.com/NREL/fastsim/tree/' + fastsim.__version__ + '/python/fastsim/demos' +# d = pathlib.Path(__file__).parent +# has_demos = False +# demos_dir = '' +# for dir in os.walk(d): +# if fnmatch.fnmatch(dir[0], '*demos'): +# has_demos = True +# demos_dir = dir[0] +# break +# if has_demos: +# #the problem is I can't figure out how to list the contents of the online demos file +# for f in p.get_dir_contents(): +# already_downloaded = False +# for file in demos_dir.glob('*demo*.py'): +# #need a way to get the "basename" for the online demos files as well for this to work +# if f == os.path.basename(file.replace('\\', '/')): #necessary to ensure command works on all operating systems +# already_downloaded = True +# print('{} = {} already downloaded'.format(file, f)) +# break +# if already_downloaded == False: +# #download file +# print('{} != {} needs downloading'.format(file, f)) #placeholder under I figure out how to download the file +# else: +# #just download demos folder +# print('demos folder needs downloading') #placeholder until I figure out how to download the file + +# __doc__ += "\nhttps://pypi.org/project/fastsim/" +# __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" # Enable np.array() on array structs import numpy as np diff --git a/python/fastsim/demos/cav_demo.py b/python/fastsim/demos/cav_demo.py index c61f09d6..f09d6671 100644 --- a/python/fastsim/demos/cav_demo.py +++ b/python/fastsim/demos/cav_demo.py @@ -13,8 +13,10 @@ import fastsim as fsim from fastsim.tests.test_coasting import make_coasting_plot +import fastsim.utilities as utils -RAN_SUCCESSFULLY = False +#for testing demo files, false when running automatic tests +SHOW_PLOTS = fsim.utils.show_plots() def maybe_str_to_bool(x, default=True): """ @@ -37,8 +39,6 @@ def maybe_str_to_bool(x, default=True): except: return default -IS_INTERACTIVE = maybe_str_to_bool(os.getenv('FASTSIM_DEMO_IS_INTERACTIVE')) - # %% [markdown] # ## Create a Vehicle and Cycle @@ -52,9 +52,9 @@ def maybe_str_to_bool(x, default=True): sd.sim_drive() base_mpg = sd.mpgge -if IS_INTERACTIVE: +if SHOW_PLOTS: print(f"Base fuel economy over UDDS: {sd.mpgge} mpg") - make_coasting_plot(sd.cyc0, sd.cyc, do_show=True) + make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTS) # %% [markdown] # ## Eco-Coasting @@ -70,11 +70,11 @@ def maybe_str_to_bool(x, default=True): sd.sim_drive() coast_mpg = sd.mpgge -if IS_INTERACTIVE: +if SHOW_PLOTS: print(f"Coast fuel economy over UDDS: {sd.mpgge} mpg") pct_savings = ((1.0/base_mpg) - (1.0/coast_mpg)) * 100.0 / ((1.0/base_mpg)) print(f"Percent Savings: {pct_savings} %") - make_coasting_plot(sd.cyc0, sd.cyc, do_show=True) + make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTSe) # %% [markdown] # # Car Following at Average Speed @@ -103,11 +103,11 @@ def maybe_str_to_bool(x, default=True): sd.sim_drive() cruise_mpg = sd.mpgge -if IS_INTERACTIVE: +if SHOW_PLOTS: print(f"Cruise fuel economy over UDDS: {sd.mpgge} mpg") pct_savings = ((1.0/base_mpg) - (1.0/cruise_mpg)) * 100.0 / ((1.0/base_mpg)) print(f"Percent Savings: {pct_savings} %") - make_coasting_plot(sd.cyc0, sd.cyc, do_show=True) + make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTS) # %% [markdown] # # Eco-Cruising at Multiple Average Speeds @@ -135,7 +135,7 @@ def maybe_str_to_bool(x, default=True): mt_dist_m = sum(mt_cyc.dist_m) mt_time_s = mt_cyc.time_s[-1] mt_avg_spd_m_per_s = mt_dist_m / mt_time_s if mt_time_s > 0.0 else 0.0 - if IS_INTERACTIVE: + if SHOW_PLOTS: print(f"mt num points : {len(mt_cyc.time_s)}") print(f"mt dist (m) : {mt_dist_m}") print(f"mt time (s) : {mt_time_s}") @@ -144,7 +144,7 @@ def maybe_str_to_bool(x, default=True): (dist_at_start_of_microtrip_m, mt_avg_spd_m_per_s) ) dist_at_start_of_microtrip_m += mt_dist_m -if IS_INTERACTIVE: +if SHOW_PLOTS: print(f"Found speeds for {len(dist_and_avg_speeds)} microtrips") sd.sim_params = fsim.auxiliaries.set_nested_values(sd.sim_params, idm_allow=True, @@ -167,18 +167,17 @@ def maybe_str_to_bool(x, default=True): sd.sim_params = fsim.auxiliaries.set_nested_values(sd.sim_params, idm_v_desired_m_per_s=mt_avg_spd_m_per_s ) - if IS_INTERACTIVE: - print(f"... setting idm_v_desired_m_per_s = {sd.sim_params.idm_v_desired_m_per_s}") + print(f"... setting idm_v_desired_m_per_s = {sd.sim_params.idm_v_desired_m_per_s}") current_mt_idx += 1 sd.sim_drive_step() sd.set_post_scalars() cruise_mpg = sd.mpgge -if IS_INTERACTIVE: +if SHOW_PLOTS: print(f"Cruise fuel economy over UDDS: {sd.mpgge} mpg") pct_savings = ((1.0/base_mpg) - (1.0/cruise_mpg)) * 100.0 / ((1.0/base_mpg)) print(f"Percent Savings: {pct_savings} %") - make_coasting_plot(sd.cyc0, sd.cyc, do_show=True) + make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTS) # %% [markdown] # # Eco-Cruise and Eco-Approach running at the same time @@ -208,15 +207,10 @@ def maybe_str_to_bool(x, default=True): sd.sim_params = params sd.sim_drive() -if IS_INTERACTIVE: +if SHOW_PLOTS: eco_mpg = sd.mpgge print(f"Cruise and Coast fuel economy over UDDS: {sd.mpgge} mpg") pct_savings = ((1.0/base_mpg) - (1.0/eco_mpg)) * 100.0 / ((1.0/base_mpg)) print(f"Percent Savings: {pct_savings} %") - make_coasting_plot(sd.cyc0, sd.cyc, do_show=True) - + make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTS) -# %% -# The flag below lets us know if this module ran successfully without error -RAN_SUCCESSFULLY = True -# %% diff --git a/python/fastsim/demos/demo.py b/python/fastsim/demos/demo.py index 7c1abf71..e76ca542 100644 --- a/python/fastsim/demos/demo.py +++ b/python/fastsim/demos/demo.py @@ -41,8 +41,12 @@ # local modules import fastsim as fsim +import fastsim.utilities as utils # importlib.reload(simdrive) importlib.reload(cycle) +#for testing demo files, false when running automatic tests +SHOW_PLOTS = fsim.utils.show_plots() + #%% v0 = fsim.vehicle.Vehicle.from_vehdb(10, to_rust=False) @@ -128,7 +132,8 @@ ax[1].set_xlabel('Cycle Time [s]') ax[1].set_ylabel('Speed [MPH]') -plt.show() +if SHOW_PLOTS: + plt.show() # %% fig, ax = plt.subplots(2, 1, figsize=(9, 5)) @@ -144,7 +149,8 @@ ax[1].set_xlabel('Cycle Time [s]') ax[1].set_ylabel('Speed [MPH]') -plt.show() +if SHOW_PLOTS: + plt.show() # %% [markdown] # ## Running sim_drive_step() with modified auxInKw @@ -174,7 +180,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') # %% @@ -205,7 +212,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') # %% [markdown] @@ -230,7 +238,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') @@ -253,7 +262,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') @@ -286,7 +296,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') @@ -316,7 +327,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') @@ -339,7 +351,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') @@ -362,7 +375,8 @@ plt.xlabel('Time [s]') plt.ylabel('Power [kW]') plt.legend() -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') @@ -580,7 +594,8 @@ def get_sim_drive_vec( df_fltr.mpgge.hist(bins=20, rwidth=.9) plt.xlabel('Miles per Gallon') plt.ylabel('Number of Cycles') -plt.show() +if SHOW_PLOTS: + plt.show() # %% @@ -607,7 +622,8 @@ def get_sim_drive_vec( scatterpoints=1) plt.xlabel('Average Cycle Speed [MPH]') plt.ylabel('Fuel Economy [MPG]') -plt.show() +if SHOW_PLOTS: + plt.show() # %% [markdown] # # Cycle manipulation tools @@ -661,7 +677,8 @@ def get_sim_drive_vec( ax2.set_ylabel('Speed [MPH]', weight='bold', color='xkcd:pale red') ax2.grid(False) ax2.tick_params('y', colors='xkcd:pale red') -plt.show() +if SHOW_PLOTS: + plt.show() # %% [markdown] # ## Concat cycles/trips @@ -717,7 +734,8 @@ def get_sim_drive_vec( ax2.set_ylabel('Speed [MPH]', weight='bold', color='xkcd:pale red') ax2.grid(False) ax2.tick_params('y', colors='xkcd:pale red') -plt.show() +if SHOW_PLOTS: + plt.show() # %% [markdown] # ## Cycle comparison @@ -751,7 +769,8 @@ def get_sim_drive_vec( plt.plot(cyc10s.time_s, cyc10s.mph, marker=',') plt.xlabel('Cycle Time [s]') plt.ylabel('Vehicle Speed [mph]') -plt.show() +if SHOW_PLOTS: + plt.show() print(f'Time to load and resample: {time.perf_counter() - t0:.2e} s') # %% [markdown] @@ -811,7 +830,8 @@ def get_sim_drive_vec( ax2.set_ylabel('Speed [MPH]', weight='bold', color='xkcd:pale red') ax2.grid(False) ax2.tick_params('y', colors='xkcd:pale red') -plt.show() +if SHOW_PLOTS: + plt.show() # %% [markdown] # ## Clip by times @@ -861,7 +881,8 @@ def get_sim_drive_vec( ax2.set_ylabel('Speed [MPH]', weight='bold', color='xkcd:pale red') ax2.grid(False) ax2.tick_params('y', colors='xkcd:pale red') -plt.show() +if SHOW_PLOTS: + plt.show() # %% [markdown] # ### Test Coefficients Calculation diff --git a/python/fastsim/demos/demo_abc_drag_coef_conv.py b/python/fastsim/demos/demo_abc_drag_coef_conv.py index 7ac487f2..4c97a92e 100644 --- a/python/fastsim/demos/demo_abc_drag_coef_conv.py +++ b/python/fastsim/demos/demo_abc_drag_coef_conv.py @@ -1,8 +1,12 @@ import fastsim as fsim from fastsim.auxiliaries import abc_to_drag_coeffs, drag_coeffs_to_abc +import fastsim.utilities as utils v = fsim.vehicle.Vehicle.from_vehdb(1).to_rust() v2 = fsim.vehicle.Vehicle.from_vehdb(1).to_rust() +#for testing demo files, false when running automatic tests +SHOW_PLOTS = fsim.utils.show_plots() + a = 25.91 b = 0.1943 c = 0.01796 @@ -13,12 +17,12 @@ c_lbf__mph2=c, custom_rho=False, simdrive_optimize=True, - show_plots=True, + show_plots=SHOW_PLOTS, use_rust=True) print(drag_coef) print(wheel_rr_coef) a_test, b_test, c_test = drag_coeffs_to_abc(veh=v, fit_with_curve=False, - show_plots=True) + show_plots=SHOW_PLOTS) print(a_test,b_test,c_test) \ No newline at end of file diff --git a/python/fastsim/demos/fusion_thermal_demo.py b/python/fastsim/demos/fusion_thermal_demo.py index 20285d73..253148cb 100644 --- a/python/fastsim/demos/fusion_thermal_demo.py +++ b/python/fastsim/demos/fusion_thermal_demo.py @@ -11,6 +11,10 @@ from pathlib import Path import os import sys +import fastsim.utilities as utils + +#for testing demo files, false when running automatic tests +SHOW_PLOTS = fsim.utils.show_plots() # %% sns.set() @@ -41,18 +45,18 @@ # %% fig, ax = plt.subplots(3, 1, figsize=(10, 6), sharex=True) +if SHOW_PLOTS: + ax[0].plot(sdh.sd.cyc.time_s, sdh.history.fc_te_deg_c) + ax[0].set_xlabel("Time") + ax[0].set_ylabel("Engine Temp. [°C]") -ax[0].plot(sdh.sd.cyc.time_s, sdh.history.fc_te_deg_c) -ax[0].set_xlabel("Time") -ax[0].set_ylabel("Engine Temp. [°C]") - -ax[1].plot(sdh.sd.cyc.time_s, sdh.sd.fs_kw_out_ach) -ax[1].set_xlabel("Time") -ax[1].set_ylabel("Fuel Power [kW]") + ax[1].plot(sdh.sd.cyc.time_s, sdh.sd.fs_kw_out_ach) + ax[1].set_xlabel("Time") + ax[1].set_ylabel("Fuel Power [kW]") -ax[-1].plot(sdh.sd.cyc.time_s, sdh.sd.mph_ach) -ax[-1].set_xlabel("Time") -ax[-1].set_ylabel("Speed [mph]") + ax[-1].plot(sdh.sd.cyc.time_s, sdh.sd.mph_ach) + ax[-1].set_xlabel("Time") + ax[-1].set_ylabel("Speed [mph]") # %% Case with cabin heating @@ -76,29 +80,29 @@ fig, ax = plt.subplots(5, 1, figsize=(10, 10), sharex=True) plt.suptitle('Cold Start, Cold Ambient') -ax[0].plot(sdh.sd.cyc.time_s, sdh.history.fc_te_deg_c) -ax[0].set_xlabel("Time") -ax[0].set_ylabel("Engine\nTemp. [°C]") - -ax[1].plot(sdh.sd.cyc.time_s, sdh.sd.fs_kw_out_ach) -ax[1].set_xlabel("Time") -ax[1].set_ylabel("Fuel Power [kW]") - -ax[2].plot(sdh.sd.cyc.time_s, sdh.history.cab_te_deg_c) -ax[2].set_xlabel("Time") -ax[2].set_ylabel("Cabin\nTemp. [°C]") - -ax[3].plot(sdh.sd.cyc.time_s, - sdh.history.cab_qdot_from_hvac_kw, label='to cabin') -ax[3].plot(sdh.sd.cyc.time_s, sdh.sd.aux_in_kw, label='aux') -ax[3].legend() -ax[3].set_xlabel("Time") -ax[3].set_ylabel("Climate Power [kW]") - -ax[-1].plot(sdh.sd.cyc.time_s, sdh.sd.mph_ach) -ax[-1].set_xlabel("Time") -ax[-1].set_ylabel("Speed [mph]") -plt.tight_layout() +if SHOW_PLOTS: + ax[0].plot(sdh.sd.cyc.time_s, sdh.history.fc_te_deg_c) + ax[0].set_xlabel("Time") + ax[0].set_ylabel("Engine\nTemp. [°C]") + + ax[1].plot(sdh.sd.cyc.time_s, sdh.sd.fs_kw_out_ach) + ax[1].set_xlabel("Time") + ax[1].set_ylabel("Fuel Power [kW]") + + ax[2].plot(sdh.sd.cyc.time_s, sdh.history.cab_te_deg_c) + ax[2].set_xlabel("Time") + ax[2].set_ylabel("Cabin\nTemp. [°C]") + + ax[3].plot(sdh.sd.cyc.time_s, sdh.history.cab_qdot_from_hvac_kw, label='to cabin') + ax[3].plot(sdh.sd.cyc.time_s, sdh.sd.aux_in_kw, label='aux') + ax[3].legend() + ax[3].set_xlabel("Time") + ax[3].set_ylabel("Climate Power [kW]") + + ax[-1].plot(sdh.sd.cyc.time_s, sdh.sd.mph_ach) + ax[-1].set_xlabel("Time") + ax[-1].set_ylabel("Speed [mph]") + plt.tight_layout() # plt.savefig("plots/fusion udds cold start.png") # plt.savefig("plots/fusion udds cold start.svg") @@ -123,30 +127,31 @@ fig, ax = plt.subplots(5, 1, figsize=(10, 10), sharex=True) -plt.suptitle('Hot Start, Hot Ambient') -ax[0].plot(sdh.sd.cyc.time_s, sdh.history.fc_te_deg_c) -ax[0].set_xlabel("Time") -ax[0].set_ylabel("Engine\nTemp. [°C]") - -ax[1].plot(sdh.sd.cyc.time_s, sdh.sd.fs_kw_out_ach) -ax[1].set_xlabel("Time") -ax[1].set_ylabel("Fuel Power [kW]") - -ax[2].plot(sdh.sd.cyc.time_s, sdh.history.cab_te_deg_c) -ax[2].set_xlabel("Time") -ax[2].set_ylabel("Cabin\nTemp. [°C]") - -ax[3].plot(sdh.sd.cyc.time_s, - sdh.history.cab_qdot_from_hvac_kw, label='to cabin') -ax[3].plot(sdh.sd.cyc.time_s, sdh.sd.aux_in_kw, label='aux') -ax[3].legend() -ax[3].set_xlabel("Time") -ax[3].set_ylabel("Climate Power [kW]") - -ax[-1].plot(sdh.sd.cyc.time_s, sdh.sd.mph_ach) -ax[-1].set_xlabel("Time") -ax[-1].set_ylabel("Speed [mph]") -plt.tight_layout() +if SHOW_PLOTS: + plt.suptitle('Hot Start, Hot Ambient') + ax[0].plot(sdh.sd.cyc.time_s, sdh.history.fc_te_deg_c) + ax[0].set_xlabel("Time") + ax[0].set_ylabel("Engine\nTemp. [°C]") + + ax[1].plot(sdh.sd.cyc.time_s, sdh.sd.fs_kw_out_ach) + ax[1].set_xlabel("Time") + ax[1].set_ylabel("Fuel Power [kW]") + + ax[2].plot(sdh.sd.cyc.time_s, sdh.history.cab_te_deg_c) + ax[2].set_xlabel("Time") + ax[2].set_ylabel("Cabin\nTemp. [°C]") + + ax[3].plot(sdh.sd.cyc.time_s, + sdh.history.cab_qdot_from_hvac_kw, label='to cabin') + ax[3].plot(sdh.sd.cyc.time_s, sdh.sd.aux_in_kw, label='aux') + ax[3].legend() + ax[3].set_xlabel("Time") + ax[3].set_ylabel("Climate Power [kW]") + + ax[-1].plot(sdh.sd.cyc.time_s, sdh.sd.mph_ach) + ax[-1].set_xlabel("Time") + ax[-1].set_ylabel("Speed [mph]") + plt.tight_layout() # plt.savefig("plots/fusion udds hot start.png") # plt.savefig("plots/fusion udds hot start.svg") @@ -183,15 +188,16 @@ colors = ['#7fc97f', '#beaed4', '#fdc086'] -fig, ax = plt.subplots() -plt.suptitle('2012 Ford Fusion V6 FE v. Ambient/Init. Temp.') -ax.plot(amb_te_deg_c_arr, mpg, color=colors[0], label='w/ HVAC') -ax.plot(amb_te_deg_c_arr, mpg_no_hvac, color=colors[1], label='w/o HVAC') -ax.axhline(sdh_no_thrml.mpgge, color=colors[2], label='no thermal') -ax.legend() -ax.set_xlabel('Ambient/Init. Temp [°C]') -ax.set_ylabel('Fuel Economy [mpg]') -plt.tight_layout() +if SHOW_PLOTS: + fig, ax = plt.subplots() + plt.suptitle('2012 Ford Fusion V6 FE v. Ambient/Init. Temp.') + ax.plot(amb_te_deg_c_arr, mpg, color=colors[0], label='w/ HVAC') + ax.plot(amb_te_deg_c_arr, mpg_no_hvac, color=colors[1], label='w/o HVAC') + ax.axhline(sdh_no_thrml.mpgge, color=colors[2], label='no thermal') + ax.legend() + ax.set_xlabel('Ambient/Init. Temp [°C]') + ax.set_ylabel('Fuel Economy [mpg]') + plt.tight_layout() # plt.savefig("plots/fusion FE vs temp sweep.png") # plt.savefig("plots/fusion FE vs temp sweep.svg") # %% diff --git a/python/fastsim/demos/run_all.py b/python/fastsim/demos/run_all.py deleted file mode 100644 index eca256f3..00000000 --- a/python/fastsim/demos/run_all.py +++ /dev/null @@ -1,8 +0,0 @@ -import pathlib - -p = pathlib.Path(__file__).parent - -for file in p.glob('*demo*.py'): - with open(file) as f: - exec(f.read()) - print('{} ran successfully'.format(f)) \ No newline at end of file diff --git a/python/fastsim/demos/stop_start_demo.py b/python/fastsim/demos/stop_start_demo.py index 0b77feb4..e558fc0c 100644 --- a/python/fastsim/demos/stop_start_demo.py +++ b/python/fastsim/demos/stop_start_demo.py @@ -12,9 +12,13 @@ import matplotlib.pyplot as plt import importlib import seaborn as sns +import fastsim as fsim +import fastsim.utilities as utils sns.set() +#for testing demo files, false when running automatic tests +SHOW_PLOTS = fsim.utils.show_plots() # %% # local modules @@ -58,54 +62,55 @@ # %% -fig, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(9,5)) -ax0.plot(cyc.time_s, sim_drive0.fc_kw_in_ach, - label='base') -ax0.plot(cyc.time_s, sim_drive1.fc_kw_in_ach, - label='stop-start', linestyle='--') -# ax.plot(cyc.time_s, dfco_fcKwOutAchPos, label='dfco', linestyle='--', color='blue') -ax0.legend(loc='upper left') -ax0.set_ylabel('Fuel Power [kW]') - -ax2 = ax1.twinx() -ax2.yaxis.label.set_color('red') -ax2.tick_params(axis='y', colors='red') -ax2.plot(cyc.time_s, sim_drive1.can_pwr_all_elec, - color='red') -ax2.set_ylabel('SS active') -ax2.grid() - -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_ylim([0, 35]) -ax1.set_xlabel('Time [s]') - -# %% -fig, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(9,5)) -ax0.plot(cyc.time_s, (sim_drive0.fc_kw_in_ach * cyc.dt_s).cumsum() / 1e3, - label='base') -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(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(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]') +if SHOW_PLOTS: + fig, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(9,5)) + ax0.plot(cyc.time_s, sim_drive0.fc_kw_in_ach, + label='base') + ax0.plot(cyc.time_s, sim_drive1.fc_kw_in_ach, + label='stop-start', linestyle='--') + # ax.plot(cyc.time_s, dfco_fcKwOutAchPos, label='dfco', linestyle='--', color='blue') + ax0.legend(loc='upper left') + ax0.set_ylabel('Fuel Power [kW]') + + ax2 = ax1.twinx() + ax2.yaxis.label.set_color('red') + ax2.tick_params(axis='y', colors='red') + ax2.plot(cyc.time_s, sim_drive1.can_pwr_all_elec, + color='red') + ax2.set_ylabel('SS active') + ax2.grid() + + 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_ylim([0, 35]) + ax1.set_xlabel('Time [s]') + + # %% + fig, (ax0, ax1) = plt.subplots(2, 1, sharex=True, figsize=(9,5)) + ax0.plot(cyc.time_s, (sim_drive0.fc_kw_in_ach * cyc.dt_s).cumsum() / 1e3, + label='base') + 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(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(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 * cyc.dt_s).sum() - (sim_drive1.fc_kw_out_ach * cyc.dt_s).sum()) / ( diff --git a/python/fastsim/demos/test_demos.py b/python/fastsim/demos/test_demos.py new file mode 100644 index 00000000..0ecc1882 --- /dev/null +++ b/python/fastsim/demos/test_demos.py @@ -0,0 +1,22 @@ +import subprocess +import os +from pathlib import Path +import pytest + + +def demo_paths(): + demo_paths = list(Path(__file__).parent.glob("*demo*.py")) + demo_paths.remove(Path(__file__).resolve()) + return demo_paths + +@pytest.mark.parametrize("demo_path", demo_paths(), ids=[dp.name for dp in demo_paths()]) +def test_demo(demo_path: Path): + os.environ['SHOW_PLOTS'] = "false" + rslt = subprocess.run( + ["python", demo_path], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + + assert rslt.returncode == 0, rslt.stderr \ No newline at end of file diff --git a/python/fastsim/demos/time_dilation_demo.py b/python/fastsim/demos/time_dilation_demo.py index 67235c55..b1f62f0f 100644 --- a/python/fastsim/demos/time_dilation_demo.py +++ b/python/fastsim/demos/time_dilation_demo.py @@ -16,8 +16,14 @@ from fastsim import simdrive, vehicle, cycle from fastsim import parameters as params +import fastsim as fsim +import fastsim.utilities as utils + # importlib.reload(simdrive) +#for testing demo files, false when running automatic tests +SHOW_PLOTS = fsim.utils.show_plots() + # %% t0 = time.time() @@ -72,7 +78,8 @@ plt.xlabel('Time [s]') plt.ylabel('Speed [mps]') plt.title('Speed v. Time, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() plt.figure() plt.plot(cyc.mps, label='trace') @@ -82,7 +89,8 @@ plt.xlabel('Index') plt.ylabel('Speed [mps]') plt.title('Speed v. Index, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() # distance @@ -97,7 +105,8 @@ plt.xlabel('Time [s]') plt.ylabel('Distance [km]') plt.title('Distance v. Time, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() plt.figure() plt.plot((cyc.mps * cyc.dt_s).cumsum() / 1e3, label='trace') @@ -110,7 +119,8 @@ plt.xlabel('Index') plt.ylabel('Distance [km]') plt.title('Distance v. Index, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() plt.figure() plt.plot(sd_fixed.cyc.time_s, @@ -124,7 +134,8 @@ plt.ylabel('Distance (trace - achieved) [km]') plt.title('Trace Miss v. Time, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) plt.tight_layout() -plt.show() +if SHOW_PLOTS: + plt.show() plt.figure() plt.plot((cyc.dist_m.cumsum() - @@ -134,7 +145,8 @@ plt.ylabel('Distance (trace - achieved) [m]') plt.title('Trace Miss v. Index, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) plt.tight_layout() -plt.show() +if SHOW_PLOTS: + plt.show() # elevation change @@ -149,7 +161,8 @@ plt.xlabel('Time [s]') plt.ylabel('Delta Elevation [m]') plt.title('Delta Elev. v. Time, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() plt.figure() @@ -163,7 +176,8 @@ plt.xlabel('Index') plt.ylabel('Delta Elevation [m]') plt.title('Delta Elev. v. Index, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() # grade @@ -175,7 +189,8 @@ plt.xlabel('Time [s]') plt.ylabel('Grade [-]') plt.title('Grade v. Time, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() plt.figure() plt.plot(cyc.grade, label='trace') @@ -185,7 +200,8 @@ plt.xlabel('Index') plt.ylabel('Grade [-]') plt.title('Grade v. Index, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() # time dilation @@ -195,5 +211,6 @@ plt.xlabel('Index') plt.ylabel('Time Dilation') plt.title('Time Dilation, veh wt = {:,.0f} lbs'.format(round(veh.veh_kg * 2.205 / 1000) * 1000)) -plt.show() +if SHOW_PLOTS: + plt.show() # %% diff --git a/python/fastsim/tests/test_cav_demo.py b/python/fastsim/tests/test_cav_demo.py index 1d09e334..01e66efa 100644 --- a/python/fastsim/tests/test_cav_demo.py +++ b/python/fastsim/tests/test_cav_demo.py @@ -1,24 +1,24 @@ """ Tests running the docs/cavs_demo.py file. """ -import os -import unittest -import fastsim as fsim +# import os +# import unittest +# import fastsim as fsim -class TestCavDemo(unittest.TestCase): - def setUp(self): - fsim.utils.disable_logging() +# class TestCavDemo(unittest.TestCase): +# def setUp(self): +# fsim.utils.disable_logging() - def test_that_demo_runs_without_error(self): - is_interactive_key = 'FASTSIM_DEMO_IS_INTERACTIVE' - original_value = os.getenv(is_interactive_key) - os.environ[is_interactive_key] = 'False' - from fastsim.demos.cav_demo import RAN_SUCCESSFULLY - if original_value is not None: - os.environ[is_interactive_key] = original_value - else: - del os.environ[is_interactive_key] - self.assertTrue(RAN_SUCCESSFULLY) +# def test_that_demo_runs_without_error(self): +# is_interactive_key = 'FASTSIM_DEMO_IS_INTERACTIVE' +# original_value = os.getenv(is_interactive_key) +# os.environ[is_interactive_key] = 'False' +# from fastsim.demos.cav_demo import RAN_SUCCESSFULLY +# if original_value is not None: +# os.environ[is_interactive_key] = original_value +# else: +# del os.environ[is_interactive_key] +# self.assertTrue(RAN_SUCCESSFULLY) -if __name__ == '__main__': - unittest.main() +# if __name__ == '__main__': +# unittest.main() diff --git a/python/fastsim/tests/test_demo.py b/python/fastsim/tests/test_demo.py index 47f63a61..135242e5 100644 --- a/python/fastsim/tests/test_demo.py +++ b/python/fastsim/tests/test_demo.py @@ -1,289 +1,289 @@ """ Tests the code from fastsim/demos/demo.py """ -import unittest -import pytest -import time - -import numpy as np -import pandas as pd -import matplotlib.pyplot as plt - -import fastsim as fsim -import fastsim.fastsimrust as fsr - -VERBOSE = False -TOL = 1e-6 - - -def load_cycle(use_rust=False, verbose=False): - t0 = time.perf_counter() - cyc = fsim.cycle.Cycle.from_file("udds") - if use_rust: - cyc = cyc.to_rust() - t1 = time.perf_counter() - if verbose: - print(f'Time to load cycle: {t1 - t0:.2e} s') - return cyc - - -def load_vehicle(use_rust=False, verbose=False): - t0 = time.perf_counter() - veh = fsim.vehicle.Vehicle.from_vehdb(11) - if use_rust: - veh = veh.to_rust() - print(f'Time to load vehicle: {time.perf_counter() - t0:.2e} s') - return veh - - -def run_simdrive(cyc=None, veh=None, use_rust=False, verbose=False): - if cyc is None: - cyc = load_cycle(use_rust=use_rust, verbose=verbose) - if veh is None: - veh = load_vehicle(use_rust=use_rust, verbose=verbose) - if use_rust: - sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) - else: - sim_drive = fsim.simdrive.SimDrive(cyc, veh) - t0 = time.perf_counter() - with np.errstate(divide='ignore'): - sim_drive.sim_drive() - dt = time.perf_counter() - t0 - if verbose: - if use_rust: - print(f'Time to simulate in rust: {dt:.2e} s') - else: - print(f'Time to simulate: {dt:.2e} s') - return sim_drive, dt - - -def run_by_step_with_varying_aux_loads(use_rust=False, verbose=False): - t0 = time.perf_counter() - - veh = fsim.vehicle.Vehicle.from_vehdb(9) - cyc = fsim.cycle.Cycle.from_file('udds') - if use_rust: - cyc = cyc.to_rust() - veh = veh.to_rust() - sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) - else: - sim_drive = fsim.simdrive.SimDrive(cyc, veh) - - sim_drive.init_for_step(init_soc=0.7935) - - while sim_drive.i < len(cyc.time_s): - # 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 = np.array(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 - sim_drive.sim_drive_step() - - if verbose: - print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') - - return sim_drive - - -def run_with_aux_overrides_in_simdrive(use_rust=False): - veh = fsim.vehicle.Vehicle.from_vehdb(9) - cyc = fsim.cycle.Cycle.from_file('udds') - if use_rust: - veh = veh.to_rust() - cyc = cyc.to_rust() - sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) - else: - sim_drive = fsim.simdrive.SimDrive(cyc, veh) - auxInKwConst = 12 - sim_drive.sim_drive(None, np.ones(len(cyc.time_s))*auxInKwConst) - return sim_drive - - -def run_with_aux_override_direct_set(use_rust=False, verbose=False): - t0 = time.perf_counter() - veh = fsim.vehicle.Vehicle.from_vehdb(9) - cyc = fsim.cycle.Cycle.from_file('udds') - if use_rust: - veh = veh.to_rust() - cyc = cyc.to_rust() - sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) - else: - sim_drive = fsim.simdrive.SimDrive(cyc, veh) - # by assigning the value directly (this is faster than using positional args) - sim_drive.init_for_step( - init_soc=veh.max_soc, - aux_in_kw_override=np.array(cyc.time_s) / cyc.time_s[-1] * 10 - ) - while sim_drive.i < len(sim_drive.cyc.time_s): - sim_drive.sim_drive_step() - if verbose: - print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') - return sim_drive - - -def use_simdrive_post(use_rust=False, verbose=False): - t0 = time.perf_counter() - veh = fsim.vehicle.Vehicle.from_vehdb(19) - # veh = veh - if verbose: - print(f'Time to load vehicle: {time.perf_counter() - t0:.2e} s') - # generate micro-trip - t0 = time.perf_counter() - cyc = fsim.cycle.Cycle.from_file("udds") - microtrips = fsim.cycle.to_microtrips(cyc.get_cyc_dict()) - cyc = fsim.cycle.Cycle.from_dict(microtrips[1]) - if verbose: - print(f'Time to load cycle: {time.perf_counter() - t0:.2e} s') - - t0 = time.perf_counter() - if use_rust: - veh = veh.to_rust() - cyc = cyc.to_rust() - sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) - else: - sim_drive = fsim.simdrive.SimDrive(cyc, veh) - sim_drive.sim_drive() - # sim_drive = fsim.simdrive.SimDriveClassic(cyc, veh) - # sim_drive.sim_drive() - if verbose: - print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') - - t0 = time.perf_counter() - sim_drive_post = fsim.simdrive.SimDrivePost(sim_drive) - sim_drive_post.set_battery_wear() - diag = sim_drive_post.get_diagnostics() - if verbose: - print(f'Time to post process: {time.perf_counter() - t0:.2e} s') - return diag - - -class TestDemo(unittest.TestCase): - def setUp(self): - fsim.utils.disable_logging() - - def test_load_cycle(self): - for use_rust in [False, True]: - try: - c = load_cycle(use_rust=use_rust, verbose=VERBOSE) - if use_rust: - self.assertEqual(type(c), fsr.RustCycle) - else: - self.assertEqual(type(c), fsim.cycle.Cycle) - except Exception as ex: - self.assertTrue( - False, - msg=f"Exception (Rust: {use_rust}): {ex}" - ) - - def test_load_vehicle(self): - for use_rust in [False, True]: - try: - v = load_vehicle(use_rust=use_rust, verbose=VERBOSE) - if use_rust: - self.assertEqual(type(v), fsr.RustVehicle) - else: - self.assertEqual(type(v), fsim.vehicle.Vehicle) - except Exception as ex: - self.assertTrue( - False, - msg=f"Exception (Rust: {use_rust}): {ex}" - ) - @pytest.mark.filterwarnings("ignore:.*divide by zero*.") - def test_run_simdrive(self): - py_cyc = load_cycle(use_rust=False) - py_veh = load_vehicle(use_rust=False) - ru_cyc = load_cycle(use_rust=True) - ru_veh = load_vehicle(use_rust=True) - try: - py_sd, py_dt = run_simdrive(py_cyc, py_veh, use_rust=False, verbose=VERBOSE) - self.assertEqual(type(py_sd), fsim.simdrive.SimDrive) - except Exception as ex: - self.assertTrue( - False, - msg=f"Exception (Rust: False): {ex}" - ) - try: - ru_sd, ru_dt = run_simdrive(ru_cyc, ru_veh, use_rust=True, verbose=VERBOSE) - self.assertEqual(type(ru_sd), fsr.RustSimDrive) - except Exception as ex: - self.assertTrue( - False, - msg=f"Exception (Rust: False): {ex}" - ) - speedup = py_dt / ru_dt - if VERBOSE: - print(f"Rust provides a {speedup:.5g}x speedup") - self.assertTrue( - speedup > 10.0, - msg=f"Expected a speedup greater than 10, got {speedup}" - ) - fc_kw_in_ach_max_abs_diff = np.abs( - np.array(ru_sd.fc_kw_in_ach) - - np.array(py_sd.fc_kw_in_ach) - ).max() - self.assertTrue(fc_kw_in_ach_max_abs_diff < TOL) - - def test_running_by_step_with_modified_aux_loads(self): - py_sd = run_by_step_with_varying_aux_loads( - use_rust=False, verbose=VERBOSE) - ru_sd = run_by_step_with_varying_aux_loads( - use_rust=True, verbose=VERBOSE) - fc_out_max_abs_diff = np.abs( - py_sd.fc_kw_out_ach - - np.array(ru_sd.fc_kw_out_ach) - ).max() - ess_out_max_abs_diff = np.abs( - py_sd.ess_kw_out_ach - - np.array(ru_sd.ess_kw_out_ach) - ).max() - self.assertTrue(fc_out_max_abs_diff < TOL) - self.assertTrue(ess_out_max_abs_diff < TOL) - - def test_running_with_aux_overrides(self): - py_sd = run_with_aux_overrides_in_simdrive(use_rust=False) - ru_sd = run_with_aux_overrides_in_simdrive(use_rust=True) - fc_out_max_abs_diff = np.abs( - py_sd.fc_kw_out_ach - - np.array(ru_sd.fc_kw_out_ach) - ).max() - ess_out_max_abs_diff = np.abs( - py_sd.ess_kw_out_ach - - np.array(ru_sd.ess_kw_out_ach) - ).max() - self.assertTrue(fc_out_max_abs_diff < TOL) - self.assertTrue(ess_out_max_abs_diff < TOL) - - def test_running_with_aux_overrides_v2(self): - py_sd = run_with_aux_override_direct_set(use_rust=False, verbose=VERBOSE) - ru_sd = run_with_aux_override_direct_set(use_rust=True, verbose=VERBOSE) - fc_out_max_abs_diff = np.abs( - py_sd.fc_kw_out_ach - - np.array(ru_sd.fc_kw_out_ach) - ).max() - ess_out_max_abs_diff = np.abs( - py_sd.ess_kw_out_ach - - np.array(ru_sd.ess_kw_out_ach) - ).max() - self.assertTrue(fc_out_max_abs_diff < TOL) - self.assertTrue(ess_out_max_abs_diff < TOL) - - def test_using_simdrive_post(self): - py_diag = use_simdrive_post(use_rust=False, verbose=VERBOSE) - ru_diag = use_simdrive_post(use_rust=True, verbose=VERBOSE) - py_diag_keys = {k for k in py_diag} - ru_diag_keys = {k for k in ru_diag} - self.assertEqual(py_diag_keys, ru_diag_keys) - - def test_cycle_to_dict(self): - py_cyc = fsim.cycle.Cycle.from_file('udds') - ru_cyc = py_cyc.to_rust() - py_dict = py_cyc.get_cyc_dict() - ru_dict = ru_cyc.get_cyc_dict() - py_keys = {k for k in py_dict} - ru_keys = {k for k in ru_dict} - ru_keys.add("name") # Rust doesn't provide 'name' - self.assertEqual(py_keys, ru_keys) - -if __name__ == '__main__': - unittest.main() +# import unittest +# import pytest +# import time + +# import numpy as np +# import pandas as pd +# import matplotlib.pyplot as plt + +# import fastsim as fsim +# import fastsim.fastsimrust as fsr + +# VERBOSE = False +# TOL = 1e-6 + + +# def load_cycle(use_rust=False, verbose=False): +# t0 = time.perf_counter() +# cyc = fsim.cycle.Cycle.from_file("udds") +# if use_rust: +# cyc = cyc.to_rust() +# t1 = time.perf_counter() +# if verbose: +# print(f'Time to load cycle: {t1 - t0:.2e} s') +# return cyc + + +# def load_vehicle(use_rust=False, verbose=False): +# t0 = time.perf_counter() +# veh = fsim.vehicle.Vehicle.from_vehdb(11) +# if use_rust: +# veh = veh.to_rust() +# print(f'Time to load vehicle: {time.perf_counter() - t0:.2e} s') +# return veh + + +# def run_simdrive(cyc=None, veh=None, use_rust=False, verbose=False): +# if cyc is None: +# cyc = load_cycle(use_rust=use_rust, verbose=verbose) +# if veh is None: +# veh = load_vehicle(use_rust=use_rust, verbose=verbose) +# if use_rust: +# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) +# else: +# sim_drive = fsim.simdrive.SimDrive(cyc, veh) +# t0 = time.perf_counter() +# with np.errstate(divide='ignore'): +# sim_drive.sim_drive() +# dt = time.perf_counter() - t0 +# if verbose: +# if use_rust: +# print(f'Time to simulate in rust: {dt:.2e} s') +# else: +# print(f'Time to simulate: {dt:.2e} s') +# return sim_drive, dt + + +# def run_by_step_with_varying_aux_loads(use_rust=False, verbose=False): +# t0 = time.perf_counter() + +# veh = fsim.vehicle.Vehicle.from_vehdb(9) +# cyc = fsim.cycle.Cycle.from_file('udds') +# if use_rust: +# cyc = cyc.to_rust() +# veh = veh.to_rust() +# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) +# else: +# sim_drive = fsim.simdrive.SimDrive(cyc, veh) + +# sim_drive.init_for_step(init_soc=0.7935) + +# while sim_drive.i < len(cyc.time_s): +# # 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 = np.array(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 +# sim_drive.sim_drive_step() + +# if verbose: +# print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') + +# return sim_drive + + +# def run_with_aux_overrides_in_simdrive(use_rust=False): +# veh = fsim.vehicle.Vehicle.from_vehdb(9) +# cyc = fsim.cycle.Cycle.from_file('udds') +# if use_rust: +# veh = veh.to_rust() +# cyc = cyc.to_rust() +# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) +# else: +# sim_drive = fsim.simdrive.SimDrive(cyc, veh) +# auxInKwConst = 12 +# sim_drive.sim_drive(None, np.ones(len(cyc.time_s))*auxInKwConst) +# return sim_drive + + +# def run_with_aux_override_direct_set(use_rust=False, verbose=False): +# t0 = time.perf_counter() +# veh = fsim.vehicle.Vehicle.from_vehdb(9) +# cyc = fsim.cycle.Cycle.from_file('udds') +# if use_rust: +# veh = veh.to_rust() +# cyc = cyc.to_rust() +# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) +# else: +# sim_drive = fsim.simdrive.SimDrive(cyc, veh) +# # by assigning the value directly (this is faster than using positional args) +# sim_drive.init_for_step( +# init_soc=veh.max_soc, +# aux_in_kw_override=np.array(cyc.time_s) / cyc.time_s[-1] * 10 +# ) +# while sim_drive.i < len(sim_drive.cyc.time_s): +# sim_drive.sim_drive_step() +# if verbose: +# print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') +# return sim_drive + + +# def use_simdrive_post(use_rust=False, verbose=False): +# t0 = time.perf_counter() +# veh = fsim.vehicle.Vehicle.from_vehdb(19) +# # veh = veh +# if verbose: +# print(f'Time to load vehicle: {time.perf_counter() - t0:.2e} s') +# # generate micro-trip +# t0 = time.perf_counter() +# cyc = fsim.cycle.Cycle.from_file("udds") +# microtrips = fsim.cycle.to_microtrips(cyc.get_cyc_dict()) +# cyc = fsim.cycle.Cycle.from_dict(microtrips[1]) +# if verbose: +# print(f'Time to load cycle: {time.perf_counter() - t0:.2e} s') + +# t0 = time.perf_counter() +# if use_rust: +# veh = veh.to_rust() +# cyc = cyc.to_rust() +# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) +# else: +# sim_drive = fsim.simdrive.SimDrive(cyc, veh) +# sim_drive.sim_drive() +# # sim_drive = fsim.simdrive.SimDriveClassic(cyc, veh) +# # sim_drive.sim_drive() +# if verbose: +# print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') + +# t0 = time.perf_counter() +# sim_drive_post = fsim.simdrive.SimDrivePost(sim_drive) +# sim_drive_post.set_battery_wear() +# diag = sim_drive_post.get_diagnostics() +# if verbose: +# print(f'Time to post process: {time.perf_counter() - t0:.2e} s') +# return diag + + +# class TestDemo(unittest.TestCase): +# def setUp(self): +# fsim.utils.disable_logging() + +# def test_load_cycle(self): +# for use_rust in [False, True]: +# try: +# c = load_cycle(use_rust=use_rust, verbose=VERBOSE) +# if use_rust: +# self.assertEqual(type(c), fsr.RustCycle) +# else: +# self.assertEqual(type(c), fsim.cycle.Cycle) +# except Exception as ex: +# self.assertTrue( +# False, +# msg=f"Exception (Rust: {use_rust}): {ex}" +# ) + +# def test_load_vehicle(self): +# for use_rust in [False, True]: +# try: +# v = load_vehicle(use_rust=use_rust, verbose=VERBOSE) +# if use_rust: +# self.assertEqual(type(v), fsr.RustVehicle) +# else: +# self.assertEqual(type(v), fsim.vehicle.Vehicle) +# except Exception as ex: +# self.assertTrue( +# False, +# msg=f"Exception (Rust: {use_rust}): {ex}" +# ) +# @pytest.mark.filterwarnings("ignore:.*divide by zero*.") +# def test_run_simdrive(self): +# py_cyc = load_cycle(use_rust=False) +# py_veh = load_vehicle(use_rust=False) +# ru_cyc = load_cycle(use_rust=True) +# ru_veh = load_vehicle(use_rust=True) +# try: +# py_sd, py_dt = run_simdrive(py_cyc, py_veh, use_rust=False, verbose=VERBOSE) +# self.assertEqual(type(py_sd), fsim.simdrive.SimDrive) +# except Exception as ex: +# self.assertTrue( +# False, +# msg=f"Exception (Rust: False): {ex}" +# ) +# try: +# ru_sd, ru_dt = run_simdrive(ru_cyc, ru_veh, use_rust=True, verbose=VERBOSE) +# self.assertEqual(type(ru_sd), fsr.RustSimDrive) +# except Exception as ex: +# self.assertTrue( +# False, +# msg=f"Exception (Rust: False): {ex}" +# ) +# speedup = py_dt / ru_dt +# if VERBOSE: +# print(f"Rust provides a {speedup:.5g}x speedup") +# self.assertTrue( +# speedup > 10.0, +# msg=f"Expected a speedup greater than 10, got {speedup}" +# ) +# fc_kw_in_ach_max_abs_diff = np.abs( +# np.array(ru_sd.fc_kw_in_ach) +# - np.array(py_sd.fc_kw_in_ach) +# ).max() +# self.assertTrue(fc_kw_in_ach_max_abs_diff < TOL) + +# def test_running_by_step_with_modified_aux_loads(self): +# py_sd = run_by_step_with_varying_aux_loads( +# use_rust=False, verbose=VERBOSE) +# ru_sd = run_by_step_with_varying_aux_loads( +# use_rust=True, verbose=VERBOSE) +# fc_out_max_abs_diff = np.abs( +# py_sd.fc_kw_out_ach +# - np.array(ru_sd.fc_kw_out_ach) +# ).max() +# ess_out_max_abs_diff = np.abs( +# py_sd.ess_kw_out_ach +# - np.array(ru_sd.ess_kw_out_ach) +# ).max() +# self.assertTrue(fc_out_max_abs_diff < TOL) +# self.assertTrue(ess_out_max_abs_diff < TOL) + +# def test_running_with_aux_overrides(self): +# py_sd = run_with_aux_overrides_in_simdrive(use_rust=False) +# ru_sd = run_with_aux_overrides_in_simdrive(use_rust=True) +# fc_out_max_abs_diff = np.abs( +# py_sd.fc_kw_out_ach +# - np.array(ru_sd.fc_kw_out_ach) +# ).max() +# ess_out_max_abs_diff = np.abs( +# py_sd.ess_kw_out_ach +# - np.array(ru_sd.ess_kw_out_ach) +# ).max() +# self.assertTrue(fc_out_max_abs_diff < TOL) +# self.assertTrue(ess_out_max_abs_diff < TOL) + +# def test_running_with_aux_overrides_v2(self): +# py_sd = run_with_aux_override_direct_set(use_rust=False, verbose=VERBOSE) +# ru_sd = run_with_aux_override_direct_set(use_rust=True, verbose=VERBOSE) +# fc_out_max_abs_diff = np.abs( +# py_sd.fc_kw_out_ach +# - np.array(ru_sd.fc_kw_out_ach) +# ).max() +# ess_out_max_abs_diff = np.abs( +# py_sd.ess_kw_out_ach +# - np.array(ru_sd.ess_kw_out_ach) +# ).max() +# self.assertTrue(fc_out_max_abs_diff < TOL) +# self.assertTrue(ess_out_max_abs_diff < TOL) + +# def test_using_simdrive_post(self): +# py_diag = use_simdrive_post(use_rust=False, verbose=VERBOSE) +# ru_diag = use_simdrive_post(use_rust=True, verbose=VERBOSE) +# py_diag_keys = {k for k in py_diag} +# ru_diag_keys = {k for k in ru_diag} +# self.assertEqual(py_diag_keys, ru_diag_keys) + +# def test_cycle_to_dict(self): +# py_cyc = fsim.cycle.Cycle.from_file('udds') +# ru_cyc = py_cyc.to_rust() +# py_dict = py_cyc.get_cyc_dict() +# ru_dict = ru_cyc.get_cyc_dict() +# py_keys = {k for k in py_dict} +# ru_keys = {k for k in ru_dict} +# ru_keys.add("name") # Rust doesn't provide 'name' +# self.assertEqual(py_keys, ru_keys) + +# if __name__ == '__main__': +# unittest.main() diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index 04a00138..69e929c6 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -5,11 +5,14 @@ import numpy as np from fastsim import parameters as params import seaborn as sns -import re import datetime import logging from pathlib import Path +import re from contextlib import contextmanager +import requests +import os +from pkg_resources import get_distribution sns.set() @@ -394,3 +397,54 @@ def calculate_tire_radius(tire_code: str, units: str = "m"): # Return result # print(f"Tire radius: {radius} {units}") return radius + +def show_plots() -> bool: + """ + Returns true if plots should be displayed + """ + return os.environ.get("SHOW_PLOTS", "true").lower() == "true" + +#do I need a different default path? +def download_demo_files(demo_path: Path=Path("demos")): + """ + Downloads demo files from github repo into local directory. + + # Arguments + demo_path: path (relative or absolute in ) + + # Warning + Running this function will overwrite existing files so make sure any files with + changes you'd like to keep are renamed. + """ + __version__ = get_distribution("fastsim").version + + v = f"v{__version__}" + + api_url = f"https://api.github.com/repos/NREL/fastsim/contents/python/fastsim/demos?reg={v}" + response = requests.get(api_url) + + if response.status_code == 200: + contents = response.json() + + for item in contents: + if item["type"] == "file" and item["name"].endswith(".py"): + file_url = item["download_url"] + file_name = item["name"] + + demo_path.mkdir(exist_ok=True) + + with open(demo_path / file_name, "wb") as file: + file_content = requests.get(file_url).content + file.write(file_content) + + with open(demo_path / file_name, "r+") as file: + file_content = file.readlines() + prepend_str = f"# %% Downloaded from FASTSIM version '{v}'. Guaranteed compatibility with this version only.\n" + prepend = [prepend_str] + file_content = prepend + file_content + file.seek(0) + file.writelines(file_content) + + print(f"Saved {file_name} to {str(demo_path / file_name)}") + else: + print("Failed to download demo files") \ No newline at end of file From 5ba2efb22b0393d778cf6ec23cca1e88e3c4a0e4 Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Mon, 30 Oct 2023 21:21:01 -0400 Subject: [PATCH 06/21] adding requests to pyproject.toml --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 8b39bf5d..677f0e8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ dependencies = [ "typing_extensions", "pyyaml", "pytest", + "requests", ] [project.urls] From 8110144a69e43cfecfdf8eb746c956923a10a9e7 Mon Sep 17 00:00:00 2001 From: Chad Baker Date: Tue, 31 Oct 2023 13:13:54 -0600 Subject: [PATCH 07/21] tests are now (hopefully) triggered on push to `fastsim-2` or `fastsim-3` --- .github/workflows/tests.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 537a3d62..70b59cd8 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -1,6 +1,8 @@ name: tests on: + push: + branches: [fastsim-2, fastsim-3] pull_request: workflow_dispatch: From 145328a137c9af3dab8719f07daf390dab2f6cac Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Tue, 31 Oct 2023 20:03:56 -0400 Subject: [PATCH 08/21] adding demo tests to git tests and attempt at copy files function --- .github/workflows/tests.yaml | 1 + python/fastsim/utilities.py | 91 +++++++++++++++++++++++------------- 2 files changed, 59 insertions(+), 33 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 70b59cd8..8556d65b 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -39,3 +39,4 @@ jobs: - name: Python unit tests run: | pip install -e ".[dev]" && pytest -v python/fastsim/tests/ + pytest -v python/fastsim/demos/ diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index 69e929c6..8424159a 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -13,6 +13,8 @@ import requests import os from pkg_resources import get_distribution +import pathlib +import shutil sns.set() @@ -405,46 +407,69 @@ def show_plots() -> bool: return os.environ.get("SHOW_PLOTS", "true").lower() == "true" #do I need a different default path? -def download_demo_files(demo_path: Path=Path("demos")): - """ - Downloads demo files from github repo into local directory. +# def download_demo_files(demo_path: Path=Path("demos")): +# """ +# Downloads demo files from github repo into local directory. - # Arguments - demo_path: path (relative or absolute in ) +# # Arguments +# demo_path: path (relative or absolute in ) - # Warning - Running this function will overwrite existing files so make sure any files with - changes you'd like to keep are renamed. - """ - __version__ = get_distribution("fastsim").version +# # Warning +# Running this function will overwrite existing files so make sure any files with +# changes you'd like to keep are renamed. +# """ +# __version__ = get_distribution("fastsim").version - v = f"v{__version__}" +# v = f"v{__version__}" - api_url = f"https://api.github.com/repos/NREL/fastsim/contents/python/fastsim/demos?reg={v}" - response = requests.get(api_url) +# api_url = f"https://api.github.com/repos/NREL/fastsim/contents/python/fastsim/demos?reg={v}" +# response = requests.get(api_url) - if response.status_code == 200: - contents = response.json() +# if response.status_code == 200: +# contents = response.json() - for item in contents: - if item["type"] == "file" and item["name"].endswith(".py"): - file_url = item["download_url"] - file_name = item["name"] +# for item in contents: +# if item["type"] == "file" and item["name"].endswith(".py"): +# file_url = item["download_url"] +# file_name = item["name"] - demo_path.mkdir(exist_ok=True) +# demo_path.mkdir(exist_ok=True) - with open(demo_path / file_name, "wb") as file: - file_content = requests.get(file_url).content - file.write(file_content) +# with open(demo_path / file_name, "wb") as file: +# file_content = requests.get(file_url).content +# file.write(file_content) - with open(demo_path / file_name, "r+") as file: - file_content = file.readlines() - prepend_str = f"# %% Downloaded from FASTSIM version '{v}'. Guaranteed compatibility with this version only.\n" - prepend = [prepend_str] - file_content = prepend + file_content - file.seek(0) - file.writelines(file_content) +# with open(demo_path / file_name, "r+") as file: +# file_content = file.readlines() +# prepend_str = f"# %% Downloaded from FASTSIM version '{v}'. Guaranteed compatibility with this version only.\n" +# prepend = [prepend_str] +# file_content = prepend + file_content +# file.seek(0) +# file.writelines(file_content) - print(f"Saved {file_name} to {str(demo_path / file_name)}") - else: - print("Failed to download demo files") \ No newline at end of file +# print(f"Saved {file_name} to {str(demo_path / file_name)}") +# else: +# print("Failed to download demo files") + +#what exactly should I make the default path and how -- would the working directory potentially cause problems? (check when back at +# NREL about notes from internal repo) +def copy_demo_files(current_demo_path, path_for_copies): + """ + Copies demo files from demos folder into specified local directory + + # Arguments + current_demo_path: path to demos folder (relative or absolute in ) + path_for_copies: path to copy files into + + # Warning + Running this function will overwrite existing files in the specified directory so make sure any files with + changes you'd like to keep are renamed. + """ + + p = current_demo_path + demo_files = list(p.glob('*demo*.py')) + test_demo_files = list(p.glob('*test*.py')) + for file in test_demo_files: + demo_files.remove(file) + for file in demo_files: + shutil.copy(file, path_for_copies) \ No newline at end of file From 5a3e0cdd499e8df65b9aa7b32781261d97b436b4 Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Tue, 31 Oct 2023 20:08:49 -0400 Subject: [PATCH 09/21] adding comments --- python/fastsim/utilities.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index 8424159a..a886d7c5 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -453,6 +453,8 @@ def show_plots() -> bool: #what exactly should I make the default path and how -- would the working directory potentially cause problems? (check when back at # NREL about notes from internal repo) +#perhaps there can be instructions for where to run this file, and a default option for current_demo_path and path_for_copies +#based on that instruction, and then users can add their own paths if they run it from somewhere other than the default location def copy_demo_files(current_demo_path, path_for_copies): """ Copies demo files from demos folder into specified local directory From d911bb49646e9589d3bbae774f783146629a1aab Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Tue, 31 Oct 2023 20:10:10 -0400 Subject: [PATCH 10/21] updated attempt at adding demos tests to git --- .github/workflows/tests.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 8556d65b..9ac50693 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -38,5 +38,4 @@ jobs: - name: Python unit tests run: | - pip install -e ".[dev]" && pytest -v python/fastsim/tests/ - pytest -v python/fastsim/demos/ + pip install -e ".[dev]" && pytest -v python/fastsim/tests/ && pytest -v python/fastsim/demos/ From 70d34a02283ba795635f6b47ee3a32c5ab4d31ee Mon Sep 17 00:00:00 2001 From: Robin Steuteville Date: Tue, 31 Oct 2023 20:29:26 -0400 Subject: [PATCH 11/21] third attempt at adding demos test to git --- .github/workflows/tests.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 9ac50693..ac1c06a6 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -38,4 +38,5 @@ jobs: - name: Python unit tests run: | - pip install -e ".[dev]" && pytest -v python/fastsim/tests/ && pytest -v python/fastsim/demos/ + pip install -e ".[dev]" && pytest -v python/fastsim/tests/ + pip install -e ".[dev]" && pytest -v python/fastsim/demos/ From 127f6aa0e2124435a9eae9a3eaf8edc78ae55ede Mon Sep 17 00:00:00 2001 From: Steuteville Date: Sat, 4 Nov 2023 20:34:54 -0600 Subject: [PATCH 12/21] updating demo copy function --- python/fastsim/utilities.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index a886d7c5..046d800f 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -455,21 +455,24 @@ def show_plots() -> bool: # NREL about notes from internal repo) #perhaps there can be instructions for where to run this file, and a default option for current_demo_path and path_for_copies #based on that instruction, and then users can add their own paths if they run it from somewhere other than the default location -def copy_demo_files(current_demo_path, path_for_copies): +def copy_demo_files(current_demo_path='fastsim/python/fastsim/demos', path_for_copies='pwd/demos/'): """ Copies demo files from demos folder into specified local directory # Arguments - current_demo_path: path to demos folder (relative or absolute in ) + current_demo_path: path to demos folder (relative or absolute) path_for_copies: path to copy files into # Warning - Running this function will overwrite existing files in the specified directory so make sure any files with - changes you'd like to keep are renamed. + Running this function will overwrite existing files with the same name in the specified directory so + make sure any files with changes you'd like to keep are renamed. """ + #include something for if the default demo path is used but is incorrect -- could test this by whether it results in no p.glob being empty list + assert Path(path_for_copies).resolve() != Path(current_demo_path), "Can't copy demos inside site-packages" p = current_demo_path demo_files = list(p.glob('*demo*.py')) + assert demo_files != [], "Demos files not found in current_demo_path. Please input correct path to demos folder." test_demo_files = list(p.glob('*test*.py')) for file in test_demo_files: demo_files.remove(file) From 6846c89ae32e9a2ee2e5ba61399ce206cfa48da4 Mon Sep 17 00:00:00 2001 From: Steuteville Date: Wed, 8 Nov 2023 15:41:52 -0700 Subject: [PATCH 13/21] adding working copy_demo_files function to utilities --- python/fastsim/utilities.py | 43 +++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index 046d800f..a15e0023 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -3,6 +3,7 @@ from __future__ import annotations from typing import Dict, Any, Optional, Tuple import numpy as np +import fastsim as fsim from fastsim import parameters as params import seaborn as sns import datetime @@ -455,26 +456,46 @@ def show_plots() -> bool: # NREL about notes from internal repo) #perhaps there can be instructions for where to run this file, and a default option for current_demo_path and path_for_copies #based on that instruction, and then users can add their own paths if they run it from somewhere other than the default location -def copy_demo_files(current_demo_path='fastsim/python/fastsim/demos', path_for_copies='pwd/demos/'): +def copy_demo_files(path_for_copies: Path=Path("demos")): """ Copies demo files from demos folder into specified local directory # Arguments - current_demo_path: path to demos folder (relative or absolute) - path_for_copies: path to copy files into + - `path_for_copies`: path to copy files into (relative or absolute in) # Warning Running this function will overwrite existing files with the same name in the specified directory so make sure any files with changes you'd like to keep are renamed. """ - #include something for if the default demo path is used but is incorrect -- could test this by whether it results in no p.glob being empty list - - assert Path(path_for_copies).resolve() != Path(current_demo_path), "Can't copy demos inside site-packages" - p = current_demo_path - demo_files = list(p.glob('*demo*.py')) - assert demo_files != [], "Demos files not found in current_demo_path. Please input correct path to demos folder." - test_demo_files = list(p.glob('*test*.py')) + __version__ = get_distribution("fastsim").version + v = f"v{__version__}" + current_demo_path = fsim.package_root() / "demos" + assert path_for_copies.resolve() != Path(current_demo_path), "Can't copy demos inside site-packages" + demo_files = list(current_demo_path.glob('*demo*.py')) + test_demo_files = list(current_demo_path.glob('*test*.py')) for file in test_demo_files: demo_files.remove(file) for file in demo_files: - shutil.copy(file, path_for_copies) \ No newline at end of file + if os.path.exists(path_for_copies): + dest_file = path_for_copies / file.name + shutil.copy(file, path_for_copies) + with open(dest_file, "r+") as file: + file_content = file.readlines() + prepend_str = f"# %% Copied from FASTSim version '{v}'. Guaranteed compatibility with this version only.\n" + prepend = [prepend_str] + file_content = prepend + file_content + file.seek(0) + file.writelines(file_content) + print(f"Saved {dest_file.name} to {dest_file}") + else: + os.makedirs(path_for_copies) + dest_file = path_for_copies / file.name + shutil.copy(file, path_for_copies) + with open(dest_file, "r+") as file: + file_content = file.readlines() + prepend_str = f"# %% Copied from FASTSim version '{v}'. Guaranteed compatibility with this version only.\n" + prepend = [prepend_str] + file_content = prepend + file_content + file.seek(0) + file.writelines(file_content) + print(f"Saved {dest_file.name} to {dest_file}") \ No newline at end of file From 9bbbdf8b05dfa2587bc3044322f081c6ca014e47 Mon Sep 17 00:00:00 2001 From: Steuteville Date: Thu, 9 Nov 2023 16:35:15 -0700 Subject: [PATCH 14/21] adding test for copy_demo_files function, deleting unneeded test demo files --- python/fastsim/__init__.py | 39 +--- python/fastsim/tests/test_cav_demo.py | 24 --- python/fastsim/tests/test_demo.py | 289 -------------------------- python/fastsim/tests/test_utils.py | 14 ++ python/fastsim/utilities.py | 52 +---- 5 files changed, 18 insertions(+), 400 deletions(-) delete mode 100644 python/fastsim/tests/test_cav_demo.py delete mode 100644 python/fastsim/tests/test_demo.py diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index 793514c5..79ae3379 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -1,6 +1,9 @@ """Package containing modules for running FASTSim. For example usage, see """ +from pkg_resources import get_distribution +__version__ = get_distribution("fastsim").version + from pathlib import Path import sys import logging @@ -29,42 +32,6 @@ def package_root() -> Path: from .resample import resample from . import auxiliaries -# from pkg_resources import get_distribution - -# __version__ = get_distribution("fastsim").version - -# #download demo files -# import fastsim -# import os -# import pathlib -# import fnmatch -# import requests - -# p = 'https://github.com/NREL/fastsim/tree/' + fastsim.__version__ + '/python/fastsim/demos' -# d = pathlib.Path(__file__).parent -# has_demos = False -# demos_dir = '' -# for dir in os.walk(d): -# if fnmatch.fnmatch(dir[0], '*demos'): -# has_demos = True -# demos_dir = dir[0] -# break -# if has_demos: -# #the problem is I can't figure out how to list the contents of the online demos file -# for f in p.get_dir_contents(): -# already_downloaded = False -# for file in demos_dir.glob('*demo*.py'): -# #need a way to get the "basename" for the online demos files as well for this to work -# if f == os.path.basename(file.replace('\\', '/')): #necessary to ensure command works on all operating systems -# already_downloaded = True -# print('{} = {} already downloaded'.format(file, f)) -# break -# if already_downloaded == False: -# #download file -# print('{} != {} needs downloading'.format(file, f)) #placeholder under I figure out how to download the file -# else: -# #just download demos folder -# print('demos folder needs downloading') #placeholder until I figure out how to download the file # __doc__ += "\nhttps://pypi.org/project/fastsim/" # __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" diff --git a/python/fastsim/tests/test_cav_demo.py b/python/fastsim/tests/test_cav_demo.py deleted file mode 100644 index 01e66efa..00000000 --- a/python/fastsim/tests/test_cav_demo.py +++ /dev/null @@ -1,24 +0,0 @@ -""" -Tests running the docs/cavs_demo.py file. -""" -# import os -# import unittest -# import fastsim as fsim - -# class TestCavDemo(unittest.TestCase): -# def setUp(self): -# fsim.utils.disable_logging() - -# def test_that_demo_runs_without_error(self): -# is_interactive_key = 'FASTSIM_DEMO_IS_INTERACTIVE' -# original_value = os.getenv(is_interactive_key) -# os.environ[is_interactive_key] = 'False' -# from fastsim.demos.cav_demo import RAN_SUCCESSFULLY -# if original_value is not None: -# os.environ[is_interactive_key] = original_value -# else: -# del os.environ[is_interactive_key] -# self.assertTrue(RAN_SUCCESSFULLY) - -# if __name__ == '__main__': -# unittest.main() diff --git a/python/fastsim/tests/test_demo.py b/python/fastsim/tests/test_demo.py deleted file mode 100644 index 135242e5..00000000 --- a/python/fastsim/tests/test_demo.py +++ /dev/null @@ -1,289 +0,0 @@ -""" -Tests the code from fastsim/demos/demo.py -""" -# import unittest -# import pytest -# import time - -# import numpy as np -# import pandas as pd -# import matplotlib.pyplot as plt - -# import fastsim as fsim -# import fastsim.fastsimrust as fsr - -# VERBOSE = False -# TOL = 1e-6 - - -# def load_cycle(use_rust=False, verbose=False): -# t0 = time.perf_counter() -# cyc = fsim.cycle.Cycle.from_file("udds") -# if use_rust: -# cyc = cyc.to_rust() -# t1 = time.perf_counter() -# if verbose: -# print(f'Time to load cycle: {t1 - t0:.2e} s') -# return cyc - - -# def load_vehicle(use_rust=False, verbose=False): -# t0 = time.perf_counter() -# veh = fsim.vehicle.Vehicle.from_vehdb(11) -# if use_rust: -# veh = veh.to_rust() -# print(f'Time to load vehicle: {time.perf_counter() - t0:.2e} s') -# return veh - - -# def run_simdrive(cyc=None, veh=None, use_rust=False, verbose=False): -# if cyc is None: -# cyc = load_cycle(use_rust=use_rust, verbose=verbose) -# if veh is None: -# veh = load_vehicle(use_rust=use_rust, verbose=verbose) -# if use_rust: -# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) -# else: -# sim_drive = fsim.simdrive.SimDrive(cyc, veh) -# t0 = time.perf_counter() -# with np.errstate(divide='ignore'): -# sim_drive.sim_drive() -# dt = time.perf_counter() - t0 -# if verbose: -# if use_rust: -# print(f'Time to simulate in rust: {dt:.2e} s') -# else: -# print(f'Time to simulate: {dt:.2e} s') -# return sim_drive, dt - - -# def run_by_step_with_varying_aux_loads(use_rust=False, verbose=False): -# t0 = time.perf_counter() - -# veh = fsim.vehicle.Vehicle.from_vehdb(9) -# cyc = fsim.cycle.Cycle.from_file('udds') -# if use_rust: -# cyc = cyc.to_rust() -# veh = veh.to_rust() -# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) -# else: -# sim_drive = fsim.simdrive.SimDrive(cyc, veh) - -# sim_drive.init_for_step(init_soc=0.7935) - -# while sim_drive.i < len(cyc.time_s): -# # 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 = np.array(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 -# sim_drive.sim_drive_step() - -# if verbose: -# print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') - -# return sim_drive - - -# def run_with_aux_overrides_in_simdrive(use_rust=False): -# veh = fsim.vehicle.Vehicle.from_vehdb(9) -# cyc = fsim.cycle.Cycle.from_file('udds') -# if use_rust: -# veh = veh.to_rust() -# cyc = cyc.to_rust() -# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) -# else: -# sim_drive = fsim.simdrive.SimDrive(cyc, veh) -# auxInKwConst = 12 -# sim_drive.sim_drive(None, np.ones(len(cyc.time_s))*auxInKwConst) -# return sim_drive - - -# def run_with_aux_override_direct_set(use_rust=False, verbose=False): -# t0 = time.perf_counter() -# veh = fsim.vehicle.Vehicle.from_vehdb(9) -# cyc = fsim.cycle.Cycle.from_file('udds') -# if use_rust: -# veh = veh.to_rust() -# cyc = cyc.to_rust() -# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) -# else: -# sim_drive = fsim.simdrive.SimDrive(cyc, veh) -# # by assigning the value directly (this is faster than using positional args) -# sim_drive.init_for_step( -# init_soc=veh.max_soc, -# aux_in_kw_override=np.array(cyc.time_s) / cyc.time_s[-1] * 10 -# ) -# while sim_drive.i < len(sim_drive.cyc.time_s): -# sim_drive.sim_drive_step() -# if verbose: -# print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') -# return sim_drive - - -# def use_simdrive_post(use_rust=False, verbose=False): -# t0 = time.perf_counter() -# veh = fsim.vehicle.Vehicle.from_vehdb(19) -# # veh = veh -# if verbose: -# print(f'Time to load vehicle: {time.perf_counter() - t0:.2e} s') -# # generate micro-trip -# t0 = time.perf_counter() -# cyc = fsim.cycle.Cycle.from_file("udds") -# microtrips = fsim.cycle.to_microtrips(cyc.get_cyc_dict()) -# cyc = fsim.cycle.Cycle.from_dict(microtrips[1]) -# if verbose: -# print(f'Time to load cycle: {time.perf_counter() - t0:.2e} s') - -# t0 = time.perf_counter() -# if use_rust: -# veh = veh.to_rust() -# cyc = cyc.to_rust() -# sim_drive = fsim.simdrive.RustSimDrive(cyc, veh) -# else: -# sim_drive = fsim.simdrive.SimDrive(cyc, veh) -# sim_drive.sim_drive() -# # sim_drive = fsim.simdrive.SimDriveClassic(cyc, veh) -# # sim_drive.sim_drive() -# if verbose: -# print(f'Time to simulate: {time.perf_counter() - t0:.2e} s') - -# t0 = time.perf_counter() -# sim_drive_post = fsim.simdrive.SimDrivePost(sim_drive) -# sim_drive_post.set_battery_wear() -# diag = sim_drive_post.get_diagnostics() -# if verbose: -# print(f'Time to post process: {time.perf_counter() - t0:.2e} s') -# return diag - - -# class TestDemo(unittest.TestCase): -# def setUp(self): -# fsim.utils.disable_logging() - -# def test_load_cycle(self): -# for use_rust in [False, True]: -# try: -# c = load_cycle(use_rust=use_rust, verbose=VERBOSE) -# if use_rust: -# self.assertEqual(type(c), fsr.RustCycle) -# else: -# self.assertEqual(type(c), fsim.cycle.Cycle) -# except Exception as ex: -# self.assertTrue( -# False, -# msg=f"Exception (Rust: {use_rust}): {ex}" -# ) - -# def test_load_vehicle(self): -# for use_rust in [False, True]: -# try: -# v = load_vehicle(use_rust=use_rust, verbose=VERBOSE) -# if use_rust: -# self.assertEqual(type(v), fsr.RustVehicle) -# else: -# self.assertEqual(type(v), fsim.vehicle.Vehicle) -# except Exception as ex: -# self.assertTrue( -# False, -# msg=f"Exception (Rust: {use_rust}): {ex}" -# ) -# @pytest.mark.filterwarnings("ignore:.*divide by zero*.") -# def test_run_simdrive(self): -# py_cyc = load_cycle(use_rust=False) -# py_veh = load_vehicle(use_rust=False) -# ru_cyc = load_cycle(use_rust=True) -# ru_veh = load_vehicle(use_rust=True) -# try: -# py_sd, py_dt = run_simdrive(py_cyc, py_veh, use_rust=False, verbose=VERBOSE) -# self.assertEqual(type(py_sd), fsim.simdrive.SimDrive) -# except Exception as ex: -# self.assertTrue( -# False, -# msg=f"Exception (Rust: False): {ex}" -# ) -# try: -# ru_sd, ru_dt = run_simdrive(ru_cyc, ru_veh, use_rust=True, verbose=VERBOSE) -# self.assertEqual(type(ru_sd), fsr.RustSimDrive) -# except Exception as ex: -# self.assertTrue( -# False, -# msg=f"Exception (Rust: False): {ex}" -# ) -# speedup = py_dt / ru_dt -# if VERBOSE: -# print(f"Rust provides a {speedup:.5g}x speedup") -# self.assertTrue( -# speedup > 10.0, -# msg=f"Expected a speedup greater than 10, got {speedup}" -# ) -# fc_kw_in_ach_max_abs_diff = np.abs( -# np.array(ru_sd.fc_kw_in_ach) -# - np.array(py_sd.fc_kw_in_ach) -# ).max() -# self.assertTrue(fc_kw_in_ach_max_abs_diff < TOL) - -# def test_running_by_step_with_modified_aux_loads(self): -# py_sd = run_by_step_with_varying_aux_loads( -# use_rust=False, verbose=VERBOSE) -# ru_sd = run_by_step_with_varying_aux_loads( -# use_rust=True, verbose=VERBOSE) -# fc_out_max_abs_diff = np.abs( -# py_sd.fc_kw_out_ach -# - np.array(ru_sd.fc_kw_out_ach) -# ).max() -# ess_out_max_abs_diff = np.abs( -# py_sd.ess_kw_out_ach -# - np.array(ru_sd.ess_kw_out_ach) -# ).max() -# self.assertTrue(fc_out_max_abs_diff < TOL) -# self.assertTrue(ess_out_max_abs_diff < TOL) - -# def test_running_with_aux_overrides(self): -# py_sd = run_with_aux_overrides_in_simdrive(use_rust=False) -# ru_sd = run_with_aux_overrides_in_simdrive(use_rust=True) -# fc_out_max_abs_diff = np.abs( -# py_sd.fc_kw_out_ach -# - np.array(ru_sd.fc_kw_out_ach) -# ).max() -# ess_out_max_abs_diff = np.abs( -# py_sd.ess_kw_out_ach -# - np.array(ru_sd.ess_kw_out_ach) -# ).max() -# self.assertTrue(fc_out_max_abs_diff < TOL) -# self.assertTrue(ess_out_max_abs_diff < TOL) - -# def test_running_with_aux_overrides_v2(self): -# py_sd = run_with_aux_override_direct_set(use_rust=False, verbose=VERBOSE) -# ru_sd = run_with_aux_override_direct_set(use_rust=True, verbose=VERBOSE) -# fc_out_max_abs_diff = np.abs( -# py_sd.fc_kw_out_ach -# - np.array(ru_sd.fc_kw_out_ach) -# ).max() -# ess_out_max_abs_diff = np.abs( -# py_sd.ess_kw_out_ach -# - np.array(ru_sd.ess_kw_out_ach) -# ).max() -# self.assertTrue(fc_out_max_abs_diff < TOL) -# self.assertTrue(ess_out_max_abs_diff < TOL) - -# def test_using_simdrive_post(self): -# py_diag = use_simdrive_post(use_rust=False, verbose=VERBOSE) -# ru_diag = use_simdrive_post(use_rust=True, verbose=VERBOSE) -# py_diag_keys = {k for k in py_diag} -# ru_diag_keys = {k for k in ru_diag} -# self.assertEqual(py_diag_keys, ru_diag_keys) - -# def test_cycle_to_dict(self): -# py_cyc = fsim.cycle.Cycle.from_file('udds') -# ru_cyc = py_cyc.to_rust() -# py_dict = py_cyc.get_cyc_dict() -# ru_dict = ru_cyc.get_cyc_dict() -# py_keys = {k for k in py_dict} -# ru_keys = {k for k in ru_dict} -# ru_keys.add("name") # Rust doesn't provide 'name' -# self.assertEqual(py_keys, ru_keys) - -# if __name__ == '__main__': -# unittest.main() diff --git a/python/fastsim/tests/test_utils.py b/python/fastsim/tests/test_utils.py index 55360a68..8428c863 100644 --- a/python/fastsim/tests/test_utils.py +++ b/python/fastsim/tests/test_utils.py @@ -1,4 +1,7 @@ +import tempfile import unittest +from pathlib import Path +import fastsim as fsim from fastsim import utils class TestUtils(unittest.TestCase): @@ -10,5 +13,16 @@ def test_camel_to_snake(self): self.assertEqual("ess_ae_kw_out", utils.camel_to_snake("essAEKwOut")) self.assertEqual("elect_kw_req4_ae", utils.camel_to_snake("electKwReq4AE")) + def test_copy_demo_files(self): + v = f"v{fsim.__version__}" + prepend_str = f"# %% Copied from FASTSim version '{v}'. Guaranteed compatibility with this version only.\n" + with tempfile.TemporaryDirectory() as tmpdir: + tf_path = Path(tmpdir) + utils.copy_demo_files(tf_path) + with open(next(tf_path.glob("*demo*.py")), 'r') as file: + lines = file.readlines() + assert prepend_str in lines[0] + assert len(lines) > 3 + if __name__ == '__main__': unittest.main() diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index a15e0023..a0e42b0a 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -407,55 +407,6 @@ def show_plots() -> bool: """ return os.environ.get("SHOW_PLOTS", "true").lower() == "true" -#do I need a different default path? -# def download_demo_files(demo_path: Path=Path("demos")): -# """ -# Downloads demo files from github repo into local directory. - -# # Arguments -# demo_path: path (relative or absolute in ) - -# # Warning -# Running this function will overwrite existing files so make sure any files with -# changes you'd like to keep are renamed. -# """ -# __version__ = get_distribution("fastsim").version - -# v = f"v{__version__}" - -# api_url = f"https://api.github.com/repos/NREL/fastsim/contents/python/fastsim/demos?reg={v}" -# response = requests.get(api_url) - -# if response.status_code == 200: -# contents = response.json() - -# for item in contents: -# if item["type"] == "file" and item["name"].endswith(".py"): -# file_url = item["download_url"] -# file_name = item["name"] - -# demo_path.mkdir(exist_ok=True) - -# with open(demo_path / file_name, "wb") as file: -# file_content = requests.get(file_url).content -# file.write(file_content) - -# with open(demo_path / file_name, "r+") as file: -# file_content = file.readlines() -# prepend_str = f"# %% Downloaded from FASTSIM version '{v}'. Guaranteed compatibility with this version only.\n" -# prepend = [prepend_str] -# file_content = prepend + file_content -# file.seek(0) -# file.writelines(file_content) - -# print(f"Saved {file_name} to {str(demo_path / file_name)}") -# else: -# print("Failed to download demo files") - -#what exactly should I make the default path and how -- would the working directory potentially cause problems? (check when back at -# NREL about notes from internal repo) -#perhaps there can be instructions for where to run this file, and a default option for current_demo_path and path_for_copies -#based on that instruction, and then users can add their own paths if they run it from somewhere other than the default location def copy_demo_files(path_for_copies: Path=Path("demos")): """ Copies demo files from demos folder into specified local directory @@ -467,8 +418,7 @@ def copy_demo_files(path_for_copies: Path=Path("demos")): Running this function will overwrite existing files with the same name in the specified directory so make sure any files with changes you'd like to keep are renamed. """ - __version__ = get_distribution("fastsim").version - v = f"v{__version__}" + v = f"v{fsim.__version__}" current_demo_path = fsim.package_root() / "demos" assert path_for_copies.resolve() != Path(current_demo_path), "Can't copy demos inside site-packages" demo_files = list(current_demo_path.glob('*demo*.py')) From fcc1ecb720cf25d6c63a8a623385addf89564f7f Mon Sep 17 00:00:00 2001 From: Steuteville Date: Thu, 9 Nov 2023 16:46:48 -0700 Subject: [PATCH 15/21] attempting to fix conflict with main --- python/fastsim/__init__.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index 79ae3379..8e222c0e 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -1,9 +1,6 @@ """Package containing modules for running FASTSim. For example usage, see """ -from pkg_resources import get_distribution -__version__ = get_distribution("fastsim").version - from pathlib import Path import sys import logging @@ -32,6 +29,8 @@ def package_root() -> Path: from .resample import resample from . import auxiliaries +from pkg_resources import get_distribution +__version__ = get_distribution("fastsim").version # __doc__ += "\nhttps://pypi.org/project/fastsim/" # __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" From ab7407249559449249266d0c18381af7f86b3574 Mon Sep 17 00:00:00 2001 From: Steuteville Date: Tue, 28 Nov 2023 10:37:17 -0700 Subject: [PATCH 16/21] troubleshooting fusion thermal demo --- pyproject.toml | 1 - python/fastsim/demos/fusion_thermal_demo.py | 4 ++- python/fastsim/fastsimrust.pyi | 30 ++++++++++++++++ .../vehdb/thermal/2012_Ford_fusion_thrml.csv | 34 +++++++++++++++++++ python/fastsim/utilities.py | 1 - python/fastsim/vehicle.py | 2 +- 6 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv diff --git a/pyproject.toml b/pyproject.toml index 677f0e8a..8b39bf5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,6 @@ dependencies = [ "typing_extensions", "pyyaml", "pytest", - "requests", ] [project.urls] diff --git a/python/fastsim/demos/fusion_thermal_demo.py b/python/fastsim/demos/fusion_thermal_demo.py index 253148cb..8d61c87d 100644 --- a/python/fastsim/demos/fusion_thermal_demo.py +++ b/python/fastsim/demos/fusion_thermal_demo.py @@ -28,7 +28,9 @@ fusion = fsr.RustVehicle.from_file( str(fsim.vehicle.VEHICLE_DIR / "2012_Ford_Fusion.yaml")) fusion_thermal_base = fsr.VehicleThermal.from_file( - str(fsim.vehicle.VEHICLE_DIR / "thermal/2012_Ford_Fusion_thrml.yaml")) + # str("2012_Ford_Fusion_thrml")) + str(fsim.vehicle.VEHICLE_DIR / "thermal/2012_Ford_Fusion_thrml.yaml")) + # ! tag:vehiclethermal:fordfusion) cyc = fsr.RustCycle.from_file(str(fsim.cycle.CYCLES_DIR / "udds.csv")) # no arguments use default of 22°C diff --git a/python/fastsim/fastsimrust.pyi b/python/fastsim/fastsimrust.pyi index 7480bd2c..fe40c567 100644 --- a/python/fastsim/fastsimrust.pyi +++ b/python/fastsim/fastsimrust.pyi @@ -2,6 +2,9 @@ from __future__ import annotations from typing_extensions import Self from typing import Dict, List, Tuple, Optional, ByteString from abc import ABC +from fastsim.vehicle import VEHICLE_DIR +import yaml +from pathlib import Path class RustVec(ABC): def __repr__(self) -> str: @@ -782,6 +785,33 @@ class VehicleThermal: """Reset the orphaned flag to false.""" ... + @classmethod + def from_file(filename: str) -> Self: + ... + # """ + # Loads VehicleThermal from file `filename` (str). Looks in working dir and then + # fastsim/resources/vehdb/thermal. + # Argument: + # filename: path to vehicle database file + # """ + # filename = str(filename) + # if str(filename).endswith('.yaml'): + # str.replace('.yaml', '.csv') + # if not(str(filename).endswith('.csv')): + # filename = str(filename) + '.csv' + # if Path(filename).exists(): + # filename = Path(filename) + # elif (VEHICLE_DIR / filename).exists(): + # filename = VEHICLE_DIR / filename + # else: + # raise ValueError("Invalid vehicle filename.") + + # vehdf = pd.read_csv(filename) + + # veh_file = filename + + # return cls.from_df(vehdf, veh_file) + class ThermalStateHistoryVec(SerdeAPI, RustVec): ... diff --git a/python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv b/python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv new file mode 100644 index 00000000..5d0c36a9 --- /dev/null +++ b/python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv @@ -0,0 +1,34 @@ +Param Name,Param Value +fc_c_kj__k,193.6134296 +fc_l,0.276223689 +fc_htc_to_amb_stop,7.231333272 +fc_coeff_from_comb,0.000370665 +tstat_te_sto_deg_c,85 +tstat_te_delta_deg_c,5 +rad_eps,6.330558106 +fc_model, +Internal, +Exponential, +offset,4.036805344 +lag,53.02434113 +minimum,0.380851487 +FuelConverter, +ess_c_kj_k,200 +ess_htc_to_amb,5 +cabin_hvac_model,External +cab_c_kj__k,125 +cab_l_length,2 +cab_l_width,2 +cab_r_to_amb,0.02 +cab_htc_to_amb_stop,10 +exhport_model,External +exhport_ha_to_amb,5 +exhport_ha_int,100 +exhport_c_kj__k,10 +cat_model,External +cat_l,0.5 +cat_c_kj__K,15 +cat_htc_to_amb_stop,10 +cat_te_lightoff_deg_c,400 +cat_fc_eta_coeff,0.3 +hvac_model,External diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index a0e42b0a..afe136f1 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -11,7 +11,6 @@ from pathlib import Path import re from contextlib import contextmanager -import requests import os from pkg_resources import get_distribution import pathlib diff --git a/python/fastsim/vehicle.py b/python/fastsim/vehicle.py index ca7e842d..0c6c7706 100644 --- a/python/fastsim/vehicle.py +++ b/python/fastsim/vehicle.py @@ -287,7 +287,7 @@ def from_vehdb(cls, vnum: int, veh_file: str = None, to_rust: bool = False) -> S vehdf.set_index('selection', inplace=True, drop=False) return cls.from_df(vehdf, vnum, veh_file, to_rust) - + #need to duplicate this function for VehicleThermal -- but first need a csv file from the yaml @classmethod def from_file(cls, filename: str, vnum: int = None, to_rust: bool = False) -> Self: """ From d5f3ba2e22b5491b0947f0c3925605c1e3633d32 Mon Sep 17 00:00:00 2001 From: Steuteville Date: Wed, 29 Nov 2023 11:46:40 -0700 Subject: [PATCH 17/21] continuing troubleshooting fusion_thermal_demo --- python/fastsim/demos/cav_demo.py | 2 +- python/fastsim/fastsimrust.pyi | 2 +- python/fastsim/vehicle.py | 2 +- rust/fastsim-core/src/traits.rs | 8 +++++++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/python/fastsim/demos/cav_demo.py b/python/fastsim/demos/cav_demo.py index f09d6671..c586ae69 100644 --- a/python/fastsim/demos/cav_demo.py +++ b/python/fastsim/demos/cav_demo.py @@ -74,7 +74,7 @@ def maybe_str_to_bool(x, default=True): print(f"Coast fuel economy over UDDS: {sd.mpgge} mpg") pct_savings = ((1.0/base_mpg) - (1.0/coast_mpg)) * 100.0 / ((1.0/base_mpg)) print(f"Percent Savings: {pct_savings} %") - make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTSe) + make_coasting_plot(sd.cyc0, sd.cyc, do_show=SHOW_PLOTS) # %% [markdown] # # Car Following at Average Speed diff --git a/python/fastsim/fastsimrust.pyi b/python/fastsim/fastsimrust.pyi index fe40c567..01b02aa7 100644 --- a/python/fastsim/fastsimrust.pyi +++ b/python/fastsim/fastsimrust.pyi @@ -786,7 +786,7 @@ class VehicleThermal: ... @classmethod - def from_file(filename: str) -> Self: + def from_file(cls, filename: str) -> Self: ... # """ # Loads VehicleThermal from file `filename` (str). Looks in working dir and then diff --git a/python/fastsim/vehicle.py b/python/fastsim/vehicle.py index 0c6c7706..6fc0fe90 100644 --- a/python/fastsim/vehicle.py +++ b/python/fastsim/vehicle.py @@ -287,7 +287,7 @@ def from_vehdb(cls, vnum: int, veh_file: str = None, to_rust: bool = False) -> S vehdf.set_index('selection', inplace=True, drop=False) return cls.from_df(vehdf, vnum, veh_file, to_rust) - #need to duplicate this function for VehicleThermal -- but first need a csv file from the yaml + @classmethod def from_file(cls, filename: str, vnum: int = None, to_rust: bool = False) -> Self: """ diff --git a/rust/fastsim-core/src/traits.rs b/rust/fastsim-core/src/traits.rs index 0507a66b..6fb50fc1 100644 --- a/rust/fastsim-core/src/traits.rs +++ b/rust/fastsim-core/src/traits.rs @@ -1,5 +1,6 @@ use crate::imports::*; use std::collections::HashMap; +//use serde_json::de::Read; pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> { /// runs any initialization steps that might be needed @@ -42,16 +43,21 @@ pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> { /// /// A Rust Result wrapping data structure if method is called successfully; otherwise a dynamic /// Error. + + //this is the root of it then -- I was looking in the wrong place all along. I guess + //the question is what is going wrong fn from_file(filename: &str) -> Result where Self: std::marker::Sized, + //for<'a> Self: Read<'a>, for<'de> Self: Deserialize<'de>, { let extension = Path::new(filename) .extension() .and_then(OsStr::to_str) .unwrap_or(""); - + //perhaps the file::open is not opening in a way that can be accessable for later steps + //might be good to figure out how to print contents of opened file to make sure it makes sense let file = File::open(filename)?; // deserialized file let mut file_de: Self = match extension { From 139c5f9a01b110ae08e28c52e3ba53eb2a0be7d0 Mon Sep 17 00:00:00 2001 From: Steuteville Date: Wed, 29 Nov 2023 15:18:07 -0700 Subject: [PATCH 18/21] fixed fusion_thermal_demo.py file --- python/fastsim/demos/fusion_thermal_demo.py | 6 ++-- python/fastsim/fastsimrust.pyi | 24 ------------- .../vehdb/thermal/2012_Ford_Fusion_thrml.yaml | 5 ++- .../vehdb/thermal/2012_Ford_fusion_thrml.csv | 34 ------------------- python/fastsim/utilities.py | 2 +- python/fastsim/vehicle.py | 2 +- rust/fastsim-core/src/traits.rs | 6 ---- 7 files changed, 6 insertions(+), 73 deletions(-) delete mode 100644 python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv diff --git a/python/fastsim/demos/fusion_thermal_demo.py b/python/fastsim/demos/fusion_thermal_demo.py index 8d61c87d..85b71649 100644 --- a/python/fastsim/demos/fusion_thermal_demo.py +++ b/python/fastsim/demos/fusion_thermal_demo.py @@ -26,11 +26,9 @@ # %% Case with no cabin thermal modeling or HVAC fusion = fsr.RustVehicle.from_file( - str(fsim.vehicle.VEHICLE_DIR / "2012_Ford_Fusion.yaml")) + str(fsim.vehicle.VEHICLE_DIR / "2012_Ford_Fusion.yaml")) fusion_thermal_base = fsr.VehicleThermal.from_file( - # str("2012_Ford_Fusion_thrml")) - str(fsim.vehicle.VEHICLE_DIR / "thermal/2012_Ford_Fusion_thrml.yaml")) - # ! tag:vehiclethermal:fordfusion) + str(fsim.vehicle.VEHICLE_DIR / "thermal/2012_Ford_Fusion_thrml.yaml")) cyc = fsr.RustCycle.from_file(str(fsim.cycle.CYCLES_DIR / "udds.csv")) # no arguments use default of 22°C diff --git a/python/fastsim/fastsimrust.pyi b/python/fastsim/fastsimrust.pyi index 01b02aa7..bdcf9f66 100644 --- a/python/fastsim/fastsimrust.pyi +++ b/python/fastsim/fastsimrust.pyi @@ -788,30 +788,6 @@ class VehicleThermal: @classmethod def from_file(cls, filename: str) -> Self: ... - # """ - # Loads VehicleThermal from file `filename` (str). Looks in working dir and then - # fastsim/resources/vehdb/thermal. - # Argument: - # filename: path to vehicle database file - # """ - # filename = str(filename) - # if str(filename).endswith('.yaml'): - # str.replace('.yaml', '.csv') - # if not(str(filename).endswith('.csv')): - # filename = str(filename) + '.csv' - # if Path(filename).exists(): - # filename = Path(filename) - # elif (VEHICLE_DIR / filename).exists(): - # filename = VEHICLE_DIR / filename - # else: - # raise ValueError("Invalid vehicle filename.") - - # vehdf = pd.read_csv(filename) - - # veh_file = filename - - # return cls.from_df(vehdf, veh_file) - class ThermalStateHistoryVec(SerdeAPI, RustVec): ... diff --git a/python/fastsim/resources/vehdb/thermal/2012_Ford_Fusion_thrml.yaml b/python/fastsim/resources/vehdb/thermal/2012_Ford_Fusion_thrml.yaml index 0cce74cd..f84969fc 100644 --- a/python/fastsim/resources/vehdb/thermal/2012_Ford_Fusion_thrml.yaml +++ b/python/fastsim/resources/vehdb/thermal/2012_Ford_Fusion_thrml.yaml @@ -6,9 +6,8 @@ fc_coeff_from_comb: 0.0003706654943757363 tstat_te_sto_deg_c: 85.0 tstat_te_delta_deg_c: 5.0 rad_eps: 6.330558106102167 -fc_model: - Internal: - - Exponential: +fc_model: !Internal + - !Exponential offset: 4.036805344402077 lag: 53.024341127793704 minimum: 0.3808514871387067 diff --git a/python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv b/python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv deleted file mode 100644 index 5d0c36a9..00000000 --- a/python/fastsim/resources/vehdb/thermal/2012_Ford_fusion_thrml.csv +++ /dev/null @@ -1,34 +0,0 @@ -Param Name,Param Value -fc_c_kj__k,193.6134296 -fc_l,0.276223689 -fc_htc_to_amb_stop,7.231333272 -fc_coeff_from_comb,0.000370665 -tstat_te_sto_deg_c,85 -tstat_te_delta_deg_c,5 -rad_eps,6.330558106 -fc_model, -Internal, -Exponential, -offset,4.036805344 -lag,53.02434113 -minimum,0.380851487 -FuelConverter, -ess_c_kj_k,200 -ess_htc_to_amb,5 -cabin_hvac_model,External -cab_c_kj__k,125 -cab_l_length,2 -cab_l_width,2 -cab_r_to_amb,0.02 -cab_htc_to_amb_stop,10 -exhport_model,External -exhport_ha_to_amb,5 -exhport_ha_int,100 -exhport_c_kj__k,10 -cat_model,External -cat_l,0.5 -cat_c_kj__K,15 -cat_htc_to_amb_stop,10 -cat_te_lightoff_deg_c,400 -cat_fc_eta_coeff,0.3 -hvac_model,External diff --git a/python/fastsim/utilities.py b/python/fastsim/utilities.py index afe136f1..6e08c0c5 100644 --- a/python/fastsim/utilities.py +++ b/python/fastsim/utilities.py @@ -414,7 +414,7 @@ def copy_demo_files(path_for_copies: Path=Path("demos")): - `path_for_copies`: path to copy files into (relative or absolute in) # Warning - Running this function will overwrite existing files with the same name in the specified directory so + Running this function will overwrite existing files with the same name in the specified directory, so make sure any files with changes you'd like to keep are renamed. """ v = f"v{fsim.__version__}" diff --git a/python/fastsim/vehicle.py b/python/fastsim/vehicle.py index 6fc0fe90..ca7e842d 100644 --- a/python/fastsim/vehicle.py +++ b/python/fastsim/vehicle.py @@ -287,7 +287,7 @@ def from_vehdb(cls, vnum: int, veh_file: str = None, to_rust: bool = False) -> S vehdf.set_index('selection', inplace=True, drop=False) return cls.from_df(vehdf, vnum, veh_file, to_rust) - + @classmethod def from_file(cls, filename: str, vnum: int = None, to_rust: bool = False) -> Self: """ diff --git a/rust/fastsim-core/src/traits.rs b/rust/fastsim-core/src/traits.rs index 6fb50fc1..d0868c18 100644 --- a/rust/fastsim-core/src/traits.rs +++ b/rust/fastsim-core/src/traits.rs @@ -1,6 +1,5 @@ use crate::imports::*; use std::collections::HashMap; -//use serde_json::de::Read; pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> { /// runs any initialization steps that might be needed @@ -44,20 +43,15 @@ pub trait SerdeAPI: Serialize + for<'a> Deserialize<'a> { /// A Rust Result wrapping data structure if method is called successfully; otherwise a dynamic /// Error. - //this is the root of it then -- I was looking in the wrong place all along. I guess - //the question is what is going wrong fn from_file(filename: &str) -> Result where Self: std::marker::Sized, - //for<'a> Self: Read<'a>, for<'de> Self: Deserialize<'de>, { let extension = Path::new(filename) .extension() .and_then(OsStr::to_str) .unwrap_or(""); - //perhaps the file::open is not opening in a way that can be accessable for later steps - //might be good to figure out how to print contents of opened file to make sure it makes sense let file = File::open(filename)?; // deserialized file let mut file_de: Self = match extension { From 1bf29fc562da290eceefda5ccdea5055b253da1d Mon Sep 17 00:00:00 2001 From: Robin Steuteville <124463463+robinsteuteville@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:31:57 -0700 Subject: [PATCH 19/21] Update .github/workflows/tests.yaml Co-authored-by: Kyle Carow <40699307+kylecarow@users.noreply.github.com> --- .github/workflows/tests.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index ac1c06a6..efd09180 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -39,4 +39,4 @@ jobs: - name: Python unit tests run: | pip install -e ".[dev]" && pytest -v python/fastsim/tests/ - pip install -e ".[dev]" && pytest -v python/fastsim/demos/ + pytest -v python/fastsim/demos/ From 615ebf31dd9b29fbaf8db65cbdd49d030f56b863 Mon Sep 17 00:00:00 2001 From: Robin Steuteville <124463463+robinsteuteville@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:34:12 -0700 Subject: [PATCH 20/21] Update python/fastsim/__init__.py Co-authored-by: Kyle Carow <40699307+kylecarow@users.noreply.github.com> --- python/fastsim/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index cee61807..90ce2329 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -32,7 +32,7 @@ def package_root() -> Path: __version__ = get_distribution("fastsim").version # __doc__ += "\nhttps://pypi.org/project/fastsim/" -# __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" +__doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" # Enable np.array() on array structs import numpy as np From 775285420c9aaebc537bea10ba185de2593558e3 Mon Sep 17 00:00:00 2001 From: Robin Steuteville <124463463+robinsteuteville@users.noreply.github.com> Date: Thu, 30 Nov 2023 16:34:35 -0700 Subject: [PATCH 21/21] Update python/fastsim/__init__.py Co-authored-by: Kyle Carow <40699307+kylecarow@users.noreply.github.com> --- python/fastsim/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/fastsim/__init__.py b/python/fastsim/__init__.py index 90ce2329..583bb5c2 100644 --- a/python/fastsim/__init__.py +++ b/python/fastsim/__init__.py @@ -31,7 +31,7 @@ def package_root() -> Path: from pkg_resources import get_distribution __version__ = get_distribution("fastsim").version -# __doc__ += "\nhttps://pypi.org/project/fastsim/" +__doc__ += "\nhttps://pypi.org/project/fastsim/" __doc__ += "\nhttps://www.nrel.gov/transportation/fastsim.html" # Enable np.array() on array structs