From 29733fec61271cd35be4c56f10b956af832cc027 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 18 Feb 2025 17:56:50 +0100 Subject: [PATCH 01/17] extend excamples status 1 --- .../{simba.cfg => configs/extensive.cfg} | 16 +- data/examples/{ => configs}/minimal.cfg | 0 .../examples/{ => configs}/minimal_pickle.cfg | 0 .../{ => consumption}/all_stations.csv | 0 .../default_level_of_loading_over_day.csv | 0 .../{ => consumption}/default_temp_summer.csv | 0 .../{ => consumption}/default_temp_winter.csv | 0 .../energy_consumption_example.csv | 0 data/examples/{ => costs}/cost_params.json | 0 .../examples/{ => costs}/price_timeseries.csv | 0 .../{ => costs}/price_timeseries_extended.csv | 0 .../electrified_stations.json | 0 .../example_external_load.csv | 338 +++++++++--------- .../{ => energy_system}/example_pv_feedin.csv | 0 data/examples/{ => trips}/trips_example.csv | 0 .../{ => vehicle_types}/vehicle_types.json | 0 .../vehicle_types_constant_mileage.json | 0 17 files changed, 177 insertions(+), 177 deletions(-) rename data/examples/{simba.cfg => configs/extensive.cfg} (92%) rename data/examples/{ => configs}/minimal.cfg (100%) rename data/examples/{ => configs}/minimal_pickle.cfg (100%) rename data/examples/{ => consumption}/all_stations.csv (100%) rename data/examples/{ => consumption}/default_level_of_loading_over_day.csv (100%) rename data/examples/{ => consumption}/default_temp_summer.csv (100%) rename data/examples/{ => consumption}/default_temp_winter.csv (100%) rename data/examples/{ => consumption}/energy_consumption_example.csv (100%) rename data/examples/{ => costs}/cost_params.json (100%) rename data/examples/{ => costs}/price_timeseries.csv (100%) rename data/examples/{ => costs}/price_timeseries_extended.csv (100%) rename data/examples/{ => electrified_stations}/electrified_stations.json (100%) rename data/examples/{ => energy_system}/example_external_load.csv (96%) rename data/examples/{ => energy_system}/example_pv_feedin.csv (100%) rename data/examples/{ => trips}/trips_example.csv (100%) rename data/examples/{ => vehicle_types}/vehicle_types.json (100%) rename data/examples/{ => vehicle_types}/vehicle_types_constant_mileage.json (100%) diff --git a/data/examples/simba.cfg b/data/examples/configs/extensive.cfg similarity index 92% rename from data/examples/simba.cfg rename to data/examples/configs/extensive.cfg index d0cb7e1b..a34aac81 100644 --- a/data/examples/simba.cfg +++ b/data/examples/configs/extensive.cfg @@ -4,28 +4,28 @@ scenario_name = example ##### Paths ##### ### Input and output files and paths ### # Input file containing trip information (required) -schedule_path = data/examples/trips_example.csv +schedule_path = data/examples/trips/trips_example.csv # Output files are stored here (defaults to: data/sim_outputs) # Attention: In Windows the path-length is limited to 256 characters! # Deactivate storage of output by setting output_path = null output_path = data/sim_outputs/ # Electrified stations (required) -electrified_stations_path = data/examples/electrified_stations.json +electrified_stations_path = data/examples/electrified_stations/electrified_stations.json # Vehicle types (defaults to: ./data/examples/vehicle_types.json) -vehicle_types_path = data/examples/vehicle_types.json +vehicle_types_path = data/examples/vehicle_types/vehicle_types.json # Path to station data with stations heights # (Optional: needed if mileage in vehicle types not constant and inclination should be considered) -station_data_path = data/examples/all_stations.csv +station_data_path = data/examples/consumption/all_stations.csv # Path to temperature csv. data with temperatures in deg Celsius over 0-23 hours # (Optional: needed if mileage in vehicle types not constant) -outside_temperature_over_day_path = data/examples/default_temp_winter.csv +outside_temperature_over_day_path = data/examples/consumption/default_temp_winter.csv # Path to level of loading csv. data with temperatures in deg Celsius over 0-23 hours # (Optional: needed if mileage in vehicle types not constant) -level_of_loading_over_day_path = data/examples/default_level_of_loading_over_day.csv +level_of_loading_over_day_path = data/examples/consumption/default_level_of_loading_over_day.csv # Path to configuration file for the station optimization. Only needed for mode "station_optimization" -optimizer_config_path = data/examples/default_optimizer.cfg +optimizer_config_path = data/examples/configs/default_optimizer.cfg # Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) -cost_parameters_path = data/examples/cost_params.json +cost_parameters_path = data/examples/costs/cost_params.json # Path to rotation filter rotation_filter_path = data/examples/rotation_filter.csv diff --git a/data/examples/minimal.cfg b/data/examples/configs/minimal.cfg similarity index 100% rename from data/examples/minimal.cfg rename to data/examples/configs/minimal.cfg diff --git a/data/examples/minimal_pickle.cfg b/data/examples/configs/minimal_pickle.cfg similarity index 100% rename from data/examples/minimal_pickle.cfg rename to data/examples/configs/minimal_pickle.cfg diff --git a/data/examples/all_stations.csv b/data/examples/consumption/all_stations.csv similarity index 100% rename from data/examples/all_stations.csv rename to data/examples/consumption/all_stations.csv diff --git a/data/examples/default_level_of_loading_over_day.csv b/data/examples/consumption/default_level_of_loading_over_day.csv similarity index 100% rename from data/examples/default_level_of_loading_over_day.csv rename to data/examples/consumption/default_level_of_loading_over_day.csv diff --git a/data/examples/default_temp_summer.csv b/data/examples/consumption/default_temp_summer.csv similarity index 100% rename from data/examples/default_temp_summer.csv rename to data/examples/consumption/default_temp_summer.csv diff --git a/data/examples/default_temp_winter.csv b/data/examples/consumption/default_temp_winter.csv similarity index 100% rename from data/examples/default_temp_winter.csv rename to data/examples/consumption/default_temp_winter.csv diff --git a/data/examples/energy_consumption_example.csv b/data/examples/consumption/energy_consumption_example.csv similarity index 100% rename from data/examples/energy_consumption_example.csv rename to data/examples/consumption/energy_consumption_example.csv diff --git a/data/examples/cost_params.json b/data/examples/costs/cost_params.json similarity index 100% rename from data/examples/cost_params.json rename to data/examples/costs/cost_params.json diff --git a/data/examples/price_timeseries.csv b/data/examples/costs/price_timeseries.csv similarity index 100% rename from data/examples/price_timeseries.csv rename to data/examples/costs/price_timeseries.csv diff --git a/data/examples/price_timeseries_extended.csv b/data/examples/costs/price_timeseries_extended.csv similarity index 100% rename from data/examples/price_timeseries_extended.csv rename to data/examples/costs/price_timeseries_extended.csv diff --git a/data/examples/electrified_stations.json b/data/examples/electrified_stations/electrified_stations.json similarity index 100% rename from data/examples/electrified_stations.json rename to data/examples/electrified_stations/electrified_stations.json diff --git a/data/examples/example_external_load.csv b/data/examples/energy_system/example_external_load.csv similarity index 96% rename from data/examples/example_external_load.csv rename to data/examples/energy_system/example_external_load.csv index 67939e4a..a6e10456 100644 --- a/data/examples/example_external_load.csv +++ b/data/examples/energy_system/example_external_load.csv @@ -1,169 +1,169 @@ -time,External Load (kW) -2018-01-01 00:00:00+01:00,5.16 -2018-01-01 01:00:00+01:00,35.48 -2018-01-01 02:00:00+01:00,6.00 -2018-01-01 03:00:00+01:00,4.11 -2018-01-01 04:00:00+01:00,33.82 -2018-01-01 05:00:00+01:00,15.24 -2018-01-01 06:00:00+01:00,8.14 -2018-01-01 07:00:00+01:00,14.29 -2018-01-01 08:00:00+01:00,28.21 -2018-01-01 09:00:00+01:00,11.47 -2018-01-01 10:00:00+01:00,10.48 -2018-01-01 11:00:00+01:00,18.22 -2018-01-01 12:00:00+01:00,37.40 -2018-01-01 13:00:00+01:00,34.82 -2018-01-01 14:00:00+01:00,4.60 -2018-01-01 15:00:00+01:00,31.82 -2018-01-01 16:00:00+01:00,29.10 -2018-01-01 17:00:00+01:00,22.37 -2018-01-01 18:00:00+01:00,15.62 -2018-01-01 19:00:00+01:00,8.29 -2018-01-01 20:00:00+01:00,33.94 -2018-01-01 21:00:00+01:00,3.23 -2018-01-01 22:00:00+01:00,23.44 -2018-01-01 23:00:00+01:00,17.28 -2018-01-02 00:00:00+01:00,10.01 -2018-01-02 01:00:00+01:00,32.82 -2018-01-02 02:00:00+01:00,12.49 -2018-01-02 03:00:00+01:00,7.27 -2018-01-02 04:00:00+01:00,37.27 -2018-01-02 05:00:00+01:00,34.28 -2018-01-02 06:00:00+01:00,25.58 -2018-01-02 07:00:00+01:00,18.00 -2018-01-02 08:00:00+01:00,7.90 -2018-01-02 09:00:00+01:00,1.88 -2018-01-02 10:00:00+01:00,19.48 -2018-01-02 11:00:00+01:00,21.86 -2018-01-02 12:00:00+01:00,0.67 -2018-01-02 13:00:00+01:00,3.62 -2018-01-02 14:00:00+01:00,4.61 -2018-01-02 15:00:00+01:00,17.42 -2018-01-02 16:00:00+01:00,39.72 -2018-01-02 17:00:00+01:00,26.93 -2018-01-02 18:00:00+01:00,7.25 -2018-01-02 19:00:00+01:00,6.29 -2018-01-02 20:00:00+01:00,15.48 -2018-01-02 21:00:00+01:00,1.89 -2018-01-02 22:00:00+01:00,38.54 -2018-01-02 23:00:00+01:00,36.71 -2018-01-03 00:00:00+01:00,0.63 -2018-01-03 01:00:00+01:00,15.72 -2018-01-03 02:00:00+01:00,14.13 -2018-01-03 03:00:00+01:00,6.39 -2018-01-03 04:00:00+01:00,11.81 -2018-01-03 05:00:00+01:00,30.54 -2018-01-03 06:00:00+01:00,1.67 -2018-01-03 07:00:00+01:00,10.25 -2018-01-03 08:00:00+01:00,19.56 -2018-01-03 09:00:00+01:00,28.35 -2018-01-03 10:00:00+01:00,30.06 -2018-01-03 11:00:00+01:00,12.46 -2018-01-03 12:00:00+01:00,21.00 -2018-01-03 13:00:00+01:00,16.93 -2018-01-03 14:00:00+01:00,26.33 -2018-01-03 15:00:00+01:00,11.79 -2018-01-03 16:00:00+01:00,31.70 -2018-01-03 17:00:00+01:00,33.23 -2018-01-03 18:00:00+01:00,15.07 -2018-01-03 19:00:00+01:00,6.85 -2018-01-03 20:00:00+01:00,18.43 -2018-01-03 21:00:00+01:00,15.52 -2018-01-03 22:00:00+01:00,3.19 -2018-01-03 23:00:00+01:00,1.38 -2018-01-04 00:00:00+01:00,38.34 -2018-01-04 01:00:00+01:00,22.72 -2018-01-04 02:00:00+01:00,6.04 -2018-01-04 03:00:00+01:00,5.20 -2018-01-04 04:00:00+01:00,13.89 -2018-01-04 05:00:00+01:00,1.95 -2018-01-04 06:00:00+01:00,17.37 -2018-01-04 07:00:00+01:00,10.18 -2018-01-04 08:00:00+01:00,31.57 -2018-01-04 09:00:00+01:00,1.85 -2018-01-04 10:00:00+01:00,27.54 -2018-01-04 11:00:00+01:00,15.15 -2018-01-04 12:00:00+01:00,27.39 -2018-01-04 13:00:00+01:00,1.07 -2018-01-04 14:00:00+01:00,15.87 -2018-01-04 15:00:00+01:00,8.68 -2018-01-04 16:00:00+01:00,11.23 -2018-01-04 17:00:00+01:00,32.89 -2018-01-04 18:00:00+01:00,36.06 -2018-01-04 19:00:00+01:00,17.42 -2018-01-04 20:00:00+01:00,26.70 -2018-01-04 21:00:00+01:00,32.41 -2018-01-04 22:00:00+01:00,27.35 -2018-01-04 23:00:00+01:00,2.69 -2018-01-05 00:00:00+01:00,36.49 -2018-01-05 01:00:00+01:00,36.07 -2018-01-05 02:00:00+01:00,28.91 -2018-01-05 03:00:00+01:00,29.32 -2018-01-05 04:00:00+01:00,39.44 -2018-01-05 05:00:00+01:00,7.89 -2018-01-05 06:00:00+01:00,8.04 -2018-01-05 07:00:00+01:00,33.84 -2018-01-05 08:00:00+01:00,26.80 -2018-01-05 09:00:00+01:00,38.52 -2018-01-05 10:00:00+01:00,33.08 -2018-01-05 11:00:00+01:00,11.39 -2018-01-05 12:00:00+01:00,39.39 -2018-01-05 13:00:00+01:00,29.03 -2018-01-05 14:00:00+01:00,12.59 -2018-01-05 15:00:00+01:00,30.77 -2018-01-05 16:00:00+01:00,37.99 -2018-01-05 17:00:00+01:00,27.89 -2018-01-05 18:00:00+01:00,0.32 -2018-01-05 19:00:00+01:00,22.43 -2018-01-05 20:00:00+01:00,0.25 -2018-01-05 21:00:00+01:00,25.04 -2018-01-05 22:00:00+01:00,11.68 -2018-01-05 23:00:00+01:00,6.74 -2018-01-06 00:00:00+01:00,36.65 -2018-01-06 01:00:00+01:00,17.65 -2018-01-06 02:00:00+01:00,9.48 -2018-01-06 03:00:00+01:00,27.64 -2018-01-06 04:00:00+01:00,22.12 -2018-01-06 05:00:00+01:00,17.45 -2018-01-06 06:00:00+01:00,11.22 -2018-01-06 07:00:00+01:00,9.37 -2018-01-06 08:00:00+01:00,35.61 -2018-01-06 09:00:00+01:00,8.27 -2018-01-06 10:00:00+01:00,11.68 -2018-01-06 11:00:00+01:00,33.98 -2018-01-06 12:00:00+01:00,36.31 -2018-01-06 13:00:00+01:00,33.21 -2018-01-06 14:00:00+01:00,37.04 -2018-01-06 15:00:00+01:00,8.37 -2018-01-06 16:00:00+01:00,4.22 -2018-01-06 17:00:00+01:00,12.98 -2018-01-06 18:00:00+01:00,14.96 -2018-01-06 19:00:00+01:00,19.94 -2018-01-06 20:00:00+01:00,5.09 -2018-01-06 21:00:00+01:00,37.47 -2018-01-06 22:00:00+01:00,16.43 -2018-01-06 23:00:00+01:00,31.26 -2018-01-07 00:00:00+01:00,10.79 -2018-01-07 01:00:00+01:00,7.06 -2018-01-07 02:00:00+01:00,39.06 -2018-01-07 03:00:00+01:00,12.52 -2018-01-07 04:00:00+01:00,34.01 -2018-01-07 05:00:00+01:00,9.36 -2018-01-07 06:00:00+01:00,22.25 -2018-01-07 07:00:00+01:00,31.88 -2018-01-07 08:00:00+01:00,27.65 -2018-01-07 09:00:00+01:00,5.76 -2018-01-07 10:00:00+01:00,38.97 -2018-01-07 11:00:00+01:00,22.58 -2018-01-07 12:00:00+01:00,18.30 -2018-01-07 13:00:00+01:00,8.78 -2018-01-07 14:00:00+01:00,37.14 -2018-01-07 15:00:00+01:00,9.10 -2018-01-07 16:00:00+01:00,38.67 -2018-01-07 17:00:00+01:00,36.16 -2018-01-07 18:00:00+01:00,4.79 -2018-01-07 19:00:00+01:00,12.90 -2018-01-07 20:00:00+01:00,28.39 -2018-01-07 21:00:00+01:00,20.73 -2018-01-07 22:00:00+01:00,39.39 -2018-01-07 23:00:00+01:00,23.12 +time,External Load (kW) +2018-01-01 00:00:00+01:00,5.16 +2018-01-01 01:00:00+01:00,35.48 +2018-01-01 02:00:00+01:00,6.00 +2018-01-01 03:00:00+01:00,4.11 +2018-01-01 04:00:00+01:00,33.82 +2018-01-01 05:00:00+01:00,15.24 +2018-01-01 06:00:00+01:00,8.14 +2018-01-01 07:00:00+01:00,14.29 +2018-01-01 08:00:00+01:00,28.21 +2018-01-01 09:00:00+01:00,11.47 +2018-01-01 10:00:00+01:00,10.48 +2018-01-01 11:00:00+01:00,18.22 +2018-01-01 12:00:00+01:00,37.40 +2018-01-01 13:00:00+01:00,34.82 +2018-01-01 14:00:00+01:00,4.60 +2018-01-01 15:00:00+01:00,31.82 +2018-01-01 16:00:00+01:00,29.10 +2018-01-01 17:00:00+01:00,22.37 +2018-01-01 18:00:00+01:00,15.62 +2018-01-01 19:00:00+01:00,8.29 +2018-01-01 20:00:00+01:00,33.94 +2018-01-01 21:00:00+01:00,3.23 +2018-01-01 22:00:00+01:00,23.44 +2018-01-01 23:00:00+01:00,17.28 +2018-01-02 00:00:00+01:00,10.01 +2018-01-02 01:00:00+01:00,32.82 +2018-01-02 02:00:00+01:00,12.49 +2018-01-02 03:00:00+01:00,7.27 +2018-01-02 04:00:00+01:00,37.27 +2018-01-02 05:00:00+01:00,34.28 +2018-01-02 06:00:00+01:00,25.58 +2018-01-02 07:00:00+01:00,18.00 +2018-01-02 08:00:00+01:00,7.90 +2018-01-02 09:00:00+01:00,1.88 +2018-01-02 10:00:00+01:00,19.48 +2018-01-02 11:00:00+01:00,21.86 +2018-01-02 12:00:00+01:00,0.67 +2018-01-02 13:00:00+01:00,3.62 +2018-01-02 14:00:00+01:00,4.61 +2018-01-02 15:00:00+01:00,17.42 +2018-01-02 16:00:00+01:00,39.72 +2018-01-02 17:00:00+01:00,26.93 +2018-01-02 18:00:00+01:00,7.25 +2018-01-02 19:00:00+01:00,6.29 +2018-01-02 20:00:00+01:00,15.48 +2018-01-02 21:00:00+01:00,1.89 +2018-01-02 22:00:00+01:00,38.54 +2018-01-02 23:00:00+01:00,36.71 +2018-01-03 00:00:00+01:00,0.63 +2018-01-03 01:00:00+01:00,15.72 +2018-01-03 02:00:00+01:00,14.13 +2018-01-03 03:00:00+01:00,6.39 +2018-01-03 04:00:00+01:00,11.81 +2018-01-03 05:00:00+01:00,30.54 +2018-01-03 06:00:00+01:00,1.67 +2018-01-03 07:00:00+01:00,10.25 +2018-01-03 08:00:00+01:00,19.56 +2018-01-03 09:00:00+01:00,28.35 +2018-01-03 10:00:00+01:00,30.06 +2018-01-03 11:00:00+01:00,12.46 +2018-01-03 12:00:00+01:00,21.00 +2018-01-03 13:00:00+01:00,16.93 +2018-01-03 14:00:00+01:00,26.33 +2018-01-03 15:00:00+01:00,11.79 +2018-01-03 16:00:00+01:00,31.70 +2018-01-03 17:00:00+01:00,33.23 +2018-01-03 18:00:00+01:00,15.07 +2018-01-03 19:00:00+01:00,6.85 +2018-01-03 20:00:00+01:00,18.43 +2018-01-03 21:00:00+01:00,15.52 +2018-01-03 22:00:00+01:00,3.19 +2018-01-03 23:00:00+01:00,1.38 +2018-01-04 00:00:00+01:00,38.34 +2018-01-04 01:00:00+01:00,22.72 +2018-01-04 02:00:00+01:00,6.04 +2018-01-04 03:00:00+01:00,5.20 +2018-01-04 04:00:00+01:00,13.89 +2018-01-04 05:00:00+01:00,1.95 +2018-01-04 06:00:00+01:00,17.37 +2018-01-04 07:00:00+01:00,10.18 +2018-01-04 08:00:00+01:00,31.57 +2018-01-04 09:00:00+01:00,1.85 +2018-01-04 10:00:00+01:00,27.54 +2018-01-04 11:00:00+01:00,15.15 +2018-01-04 12:00:00+01:00,27.39 +2018-01-04 13:00:00+01:00,1.07 +2018-01-04 14:00:00+01:00,15.87 +2018-01-04 15:00:00+01:00,8.68 +2018-01-04 16:00:00+01:00,11.23 +2018-01-04 17:00:00+01:00,32.89 +2018-01-04 18:00:00+01:00,36.06 +2018-01-04 19:00:00+01:00,17.42 +2018-01-04 20:00:00+01:00,26.70 +2018-01-04 21:00:00+01:00,32.41 +2018-01-04 22:00:00+01:00,27.35 +2018-01-04 23:00:00+01:00,2.69 +2018-01-05 00:00:00+01:00,36.49 +2018-01-05 01:00:00+01:00,36.07 +2018-01-05 02:00:00+01:00,28.91 +2018-01-05 03:00:00+01:00,29.32 +2018-01-05 04:00:00+01:00,39.44 +2018-01-05 05:00:00+01:00,7.89 +2018-01-05 06:00:00+01:00,8.04 +2018-01-05 07:00:00+01:00,33.84 +2018-01-05 08:00:00+01:00,26.80 +2018-01-05 09:00:00+01:00,38.52 +2018-01-05 10:00:00+01:00,33.08 +2018-01-05 11:00:00+01:00,11.39 +2018-01-05 12:00:00+01:00,39.39 +2018-01-05 13:00:00+01:00,29.03 +2018-01-05 14:00:00+01:00,12.59 +2018-01-05 15:00:00+01:00,30.77 +2018-01-05 16:00:00+01:00,37.99 +2018-01-05 17:00:00+01:00,27.89 +2018-01-05 18:00:00+01:00,0.32 +2018-01-05 19:00:00+01:00,22.43 +2018-01-05 20:00:00+01:00,0.25 +2018-01-05 21:00:00+01:00,25.04 +2018-01-05 22:00:00+01:00,11.68 +2018-01-05 23:00:00+01:00,6.74 +2018-01-06 00:00:00+01:00,36.65 +2018-01-06 01:00:00+01:00,17.65 +2018-01-06 02:00:00+01:00,9.48 +2018-01-06 03:00:00+01:00,27.64 +2018-01-06 04:00:00+01:00,22.12 +2018-01-06 05:00:00+01:00,17.45 +2018-01-06 06:00:00+01:00,11.22 +2018-01-06 07:00:00+01:00,9.37 +2018-01-06 08:00:00+01:00,35.61 +2018-01-06 09:00:00+01:00,8.27 +2018-01-06 10:00:00+01:00,11.68 +2018-01-06 11:00:00+01:00,33.98 +2018-01-06 12:00:00+01:00,36.31 +2018-01-06 13:00:00+01:00,33.21 +2018-01-06 14:00:00+01:00,37.04 +2018-01-06 15:00:00+01:00,8.37 +2018-01-06 16:00:00+01:00,4.22 +2018-01-06 17:00:00+01:00,12.98 +2018-01-06 18:00:00+01:00,14.96 +2018-01-06 19:00:00+01:00,19.94 +2018-01-06 20:00:00+01:00,5.09 +2018-01-06 21:00:00+01:00,37.47 +2018-01-06 22:00:00+01:00,16.43 +2018-01-06 23:00:00+01:00,31.26 +2018-01-07 00:00:00+01:00,10.79 +2018-01-07 01:00:00+01:00,7.06 +2018-01-07 02:00:00+01:00,39.06 +2018-01-07 03:00:00+01:00,12.52 +2018-01-07 04:00:00+01:00,34.01 +2018-01-07 05:00:00+01:00,9.36 +2018-01-07 06:00:00+01:00,22.25 +2018-01-07 07:00:00+01:00,31.88 +2018-01-07 08:00:00+01:00,27.65 +2018-01-07 09:00:00+01:00,5.76 +2018-01-07 10:00:00+01:00,38.97 +2018-01-07 11:00:00+01:00,22.58 +2018-01-07 12:00:00+01:00,18.30 +2018-01-07 13:00:00+01:00,8.78 +2018-01-07 14:00:00+01:00,37.14 +2018-01-07 15:00:00+01:00,9.10 +2018-01-07 16:00:00+01:00,38.67 +2018-01-07 17:00:00+01:00,36.16 +2018-01-07 18:00:00+01:00,4.79 +2018-01-07 19:00:00+01:00,12.90 +2018-01-07 20:00:00+01:00,28.39 +2018-01-07 21:00:00+01:00,20.73 +2018-01-07 22:00:00+01:00,39.39 +2018-01-07 23:00:00+01:00,23.12 diff --git a/data/examples/example_pv_feedin.csv b/data/examples/energy_system/example_pv_feedin.csv similarity index 100% rename from data/examples/example_pv_feedin.csv rename to data/examples/energy_system/example_pv_feedin.csv diff --git a/data/examples/trips_example.csv b/data/examples/trips/trips_example.csv similarity index 100% rename from data/examples/trips_example.csv rename to data/examples/trips/trips_example.csv diff --git a/data/examples/vehicle_types.json b/data/examples/vehicle_types/vehicle_types.json similarity index 100% rename from data/examples/vehicle_types.json rename to data/examples/vehicle_types/vehicle_types.json diff --git a/data/examples/vehicle_types_constant_mileage.json b/data/examples/vehicle_types/vehicle_types_constant_mileage.json similarity index 100% rename from data/examples/vehicle_types_constant_mileage.json rename to data/examples/vehicle_types/vehicle_types_constant_mileage.json From 28003cc8456e9630b344af6bd1d506d659c67c10 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 18 Feb 2025 17:57:07 +0100 Subject: [PATCH 02/17] extend excamples status 1 --- data/examples/configs/basic.cfg | 162 ++++++++++++++++++ data/examples/configs/extensive.cfg | 6 +- .../electrified_stations.json | 42 +---- .../electrified_stations_minimal.json | 97 +++++++++++ .../examples/vehicle_types/vehicle_types.json | 4 +- 5 files changed, 269 insertions(+), 42 deletions(-) create mode 100644 data/examples/configs/basic.cfg create mode 100644 data/examples/electrified_stations/electrified_stations_minimal.json diff --git a/data/examples/configs/basic.cfg b/data/examples/configs/basic.cfg new file mode 100644 index 00000000..862d920a --- /dev/null +++ b/data/examples/configs/basic.cfg @@ -0,0 +1,162 @@ +# general info: identifier of scenario, appended to results +scenario_name = basic_example + +##### Paths ##### +### Input and output files and paths ### +# Input file containing trip information (required) +schedule_path = data/examples/trips/trips_example.csv +# Output files are stored here (defaults to: data/sim_outputs) +# Attention: In Windows the path-length is limited to 256 characters! +# Deactivate storage of output by setting output_path = null +output_path = data/sim_outputs/ +# Electrified stations (required) +electrified_stations_path = data/examples/electrified_stations/electrified_stations.json +# Vehicle types (defaults to: ./data/examples/vehicle_types.json) +vehicle_types_path = data/examples/vehicle_types/vehicle_types.json +# Path to station data with stations heights +# (Optional: needed if mileage in vehicle types not constant and inclination should be considered) +station_data_path = data/examples/consumption/all_stations.csv +# Path to temperature csv. data with temperatures in deg Celsius over 0-23 hours +# (Optional: needed if mileage in vehicle types not constant) +outside_temperature_over_day_path = data/examples/consumption/default_temp_winter.csv +# Path to level of loading csv. data with temperatures in deg Celsius over 0-23 hours +# (Optional: needed if mileage in vehicle types not constant) +level_of_loading_over_day_path = data/examples/consumption/default_level_of_loading_over_day.csv +# Path to configuration file for the station optimization. Only needed for mode "station_optimization" +optimizer_config_path = data/examples/configs/default_optimizer.cfg +# Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) +cost_parameters_path = data/examples/costs/cost_params.json +# Path to rotation filter +rotation_filter_path = data/examples/rotation_filter.csv + +##### Modes ##### +### Specify how you want to simulate the scenario ### +# Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. +# sim runs a single simulation with the given inputs. +# neg_depb_to_oppb changes negative depb-rotations to oppb charging. +# neg_oppb_to_depb changes negative oppb-rotations to depb charging. +# service_optimization finds the largest set of electrified rotations, rotations SOC<0 are removed. +# station_optimization finds the set of fewest stations to electrify all rotations. +# remove_negative removes all negative rotations. +# split_negative_depb splits and merges negative rotations to use the optimal number of busses +# report generates simulation output files, including costs. +mode = ["sim", "report"] +#mode = ["sim", "load_pickle", "neg_depb_to_oppb", "service_optimization", "station_optimization", "remove_negative", "split_negative_depb", "report"] + +##### Flags ##### +### Activate optional functions ### +# Set flag for cost calculation: (default: false) +cost_calculation = true +# Check rotation assumptions when building schedule? (default: false) +check_rotation_consistency = false +# Remove rotations from schedule that violate assumptions? +# Needs check_rotation_consistency to have an effect (default: false) +skip_inconsistent_rotations = false +# Show plots for users to view, only used in mode report (default: false) +show_plots = false +# generate special plots in report mode (default: false) +extended_output_plots = false +# Rotation filter variable, options: +# "include": include only the rotations from file 'rotation_filter' +# "exclude": exclude the rotations from file 'rotation_filter' from the schedule +# null: deactivate function +rotation_filter_variable = null +# Write a new trips.csv during report mode to output directory? (default: false) +create_trips_in_report = false +# Pickle current schedule and scenario during report mode +# create_pickle_in_report = false +# Load this pickle file, expects load_pickle as first mode +# load_pickle_path = "example.pkl" + + +##### Charging strategy ##### +# Preferred charging type. Options: depb, oppb (default: depb) +preferred_charging_type = depb +# strategy to use at depot and electrified station +# refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html +strategy_deps = balanced +strategy_opps = greedy +# additional options for depot or station strategies +# refer to https://spice-ev.readthedocs.io/en/latest/simulating_with_spiceev.html#strategy-options +strategy_options_deps = {"CONCURRENCY": 1} +strategy_options_opps = {} + +# Cost calculation to use. Remove to use default for strategy. +# Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window +cost_calculation_method_deps = fixed_wo_plw +cost_calculation_method_opps = fixed_wo_plw + +##### Physical setup of environment ##### +### Parametrization of the physical setup ### +# Default max power [kW] of grid connectors at depot and opp stations, +# Individual gc_power per gc can be defined in electrified stations +# For unlimited gc power: set very large value (default: 100000) +gc_power_opps = 100000 +gc_power_deps = 100000 +# Default max power [kW] of charging station at depot and opp stations (default at opps: 300) +# At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) +# Individual cs_power per gc and cs type can be defined in electrified stations +cs_power_opps = 300 +cs_power_deps_depb = 150 +cs_power_deps_oppb = 150 +# Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) +desired_soc_deps = 1.0 +desired_soc_opps = 1.0 +# Minimum fraction of capacity for recharge when leaving the depot. +# Helps calculating the minimum standing time at depot. Between 0 - 1. (default: 1) +min_recharge_deps_oppb = 1 +min_recharge_deps_depb = 1 +# Min charging time at depots and opp stations in minutes (default: 0) +min_charging_time = 0 +# Buffer time in min at opp station if no specific buffer time is given in electrified_stations.json +# Time specific buffer times can be set via a dict e.g.: {"10-22": 5, "else": 2} +# NOTE: else clause is a MUST! The buffer time is deducted off of the planned standing time. +# It may resemble things like delays and/or docking procedures (default: 0) +default_buffer_time_opps = 0 +# Buffer time in min at depot stations (default: 0). +default_buffer_time_deps = 0 + +# Assign vehicles using the "adaptive" or "fixed_recharge" algorithm (default: "adaptive"). +# "adaptive" uses vehicles with socs above the consumption of the next rotation. +# "fixed_recharge" uses vehicles for rotations if the vehicles reached the soc values defined with min_recharge_deps_oppb or depb. +assign_strategy = "adaptive" +#assign_strategy = ["adaptive", "fixed_recharge"] + +# Default voltage level for charging stations if not set in electrified_stations file +# Options: HV, HV/MV, MV, MV/LV, LV (default: MV) +default_voltage_level = "MV" +# use peak load windows from file to force lower power during times of high grid load +time_windows = data/examples/time_windows.json +# reduced power of opp/depot stations during peak load windows +peak_load_window_power_opps = 1000 +peak_load_window_power_deps = 1000 +# default values for generating new depot trips in mode split_negative_depb +# average assumed vehicle speed in km/h +default_mean_speed = 30 +# average assumed distance of any station to a depot in km +default_depot_distance = 5 + +##### LOGGING ##### +# Minimum log level. Used for console and file if not specified otherwise in "loglevel_file". +# Allowed/useful: DEBUG, INFO, WARN, ERROR (default: INFO) +# INFO includes INFO, WARN and ERROR but excludes DEBUG +loglevel = INFO +# log file name. Placed in output directory +# set to null to disable logfile creation +# leave empty to have default [timestamp].log +logfile = +# can set different log level for log file +loglevel_file = + +##### SIMULATION PARAMETERS ##### +# Maximum number of days to simulate, if not set simulate entire schedule +#days = 10 +# Set length of time step in minutes (default: 1) +interval = 1 +# Time difference between signal time and actual start time of a vehicle event in min. (default: 10) +signal_time_dif = 10 +# Show estimated time to finish simulation after each step. Not recommended for fast computations +# (default: false) +eta = false +# Save time by skipping often not needed flex_report in SpiceEV +skip_flex_report = true diff --git a/data/examples/configs/extensive.cfg b/data/examples/configs/extensive.cfg index a34aac81..a40b3e81 100644 --- a/data/examples/configs/extensive.cfg +++ b/data/examples/configs/extensive.cfg @@ -1,5 +1,5 @@ # general info: identifier of scenario, appended to results -scenario_name = example +scenario_name = extensive_example ##### Paths ##### ### Input and output files and paths ### @@ -23,7 +23,7 @@ outside_temperature_over_day_path = data/examples/consumption/default_temp_wint # (Optional: needed if mileage in vehicle types not constant) level_of_loading_over_day_path = data/examples/consumption/default_level_of_loading_over_day.csv # Path to configuration file for the station optimization. Only needed for mode "station_optimization" -optimizer_config_path = data/examples/configs/default_optimizer.cfg +optimizer_config_path = data/examples/default_optimizer.cfg # Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) cost_parameters_path = data/examples/costs/cost_params.json # Path to rotation filter @@ -71,7 +71,7 @@ create_trips_in_report = false ##### Charging strategy ##### # Preferred charging type. Options: depb, oppb (default: depb) -preferred_charging_type = depb +preferred_charging_type = oppb # strategy to use at depot and electrified station # refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html strategy_deps = balanced diff --git a/data/examples/electrified_stations/electrified_stations.json b/data/examples/electrified_stations/electrified_stations.json index af4935d6..4164b6f5 100644 --- a/data/examples/electrified_stations/electrified_stations.json +++ b/data/examples/electrified_stations/electrified_stations.json @@ -10,7 +10,7 @@ "voltage_level": "MV", // optional: voltage_level for this station, default defined in config "peak_load_window_power": 100, // optional: power during peak load window (if time_windowds file given), default defined in config "energy_feed_in": { // optional: energy feed in e.g. by local renewables - "csv_file": "data/examples/example_pv_feedin.csv", // path to feedin.csv + "csv_file": "data/examples/energy_system/example_pv_feedin.csv", // path to feedin.csv "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss (defaults to first timestamp in CSV) "step_duration_s": 3600, // timestep in seconds "column": "Feed-in Total (kW)", // column name in .csv @@ -18,14 +18,14 @@ "factor": 1 // factor to multiply column values, eg 0.001 for conversion from W to kW }, "external_load": { // optional: local external loads - "csv_file": "data/examples/example_external_load.csv", // path to external_load.csv + "csv_file": "data/examples/energy_system/example_external_load.csv", // path to external_load.csv "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss (defaults to first timestamp in CSV) "step_duration_s": 3600, // timestep in seconds "column": "External Load (kW)", // column name in .csv "factor": 2 // factor to multiply column values, eg 0.001 for conversion from W to kW }, "price_csv": { // optional: price timeseries for this station - "csv_file": "data/examples/price_timeseries_extended.csv", // path to price csv + "csv_file": "data/examples/costs/price_timeseries_extended.csv", // path to price csv "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss. If not given, use CSV timestamps (first column) "step_duration_s": 21600, // timestep in seconds, required if start_time is given "procurement_column": "procurement", // optional: procurement column name in .csv @@ -46,13 +46,13 @@ "type": "opps", "n_charging_stations": 3, "energy_feed_in": { - "csv_file": "data/examples/example_pv_feedin.csv", + "csv_file": "data/examples/energy_system/example_pv_feedin.csv", "column": "Feed-in Total (kW)", "nominal_power": 2, "factor": 0.5 }, "price_csv": { - "csv_file": "data/examples/price_timeseries.csv" + "csv_file": "data/examples/costs/price_timeseries.csv" } }, "Station-10": { @@ -61,37 +61,5 @@ "gc_power": 250, // optional: maximum gc power can be defined per station "cs_power_opps" : 140, // optional: maximum cs power can be defined per station "voltage_level": "LV" // optional: voltage_level can be defined per station, influences cost - }, - "Station-21": { - "type": "opps", - "n_charging_stations": 2 - }, - "Station-22": { - "type": "deps", - "n_charging_stations": null - }, - "Station-26": { - "type": "opps", - "n_charging_stations": 5 - }, - "Station-28": { - "type": "opps", - "n_charging_stations": 4 - }, - "Station-30": { - "type": "opps", - "n_charging_stations": 4 - }, - "Station-32": { - "type": "opps", - "n_charging_stations": 3 - }, - "Station-39": { - "type": "opps", - "n_charging_stations": 5 - }, - "Station-42": { - "type": "deps", - "n_charging_stations": null } } diff --git a/data/examples/electrified_stations/electrified_stations_minimal.json b/data/examples/electrified_stations/electrified_stations_minimal.json new file mode 100644 index 00000000..8c6346ce --- /dev/null +++ b/data/examples/electrified_stations/electrified_stations_minimal.json @@ -0,0 +1,97 @@ +{ + "Station-0": { // name of station + "type": "deps", // type: "deps" or "opps" + "n_charging_stations": null, // nr of charging stataions, "null" for unlimited + "distance_to_grid": 150, // optional: distance to grid, default defined in cost_params + "gc_power": 5000, // optional: maximum gc power for this station, default defined in config + "cs_power_deps_oppb" : 50, // optional: maximum cs power for this station, default defined in config + "cs_power_deps_depb" : 120, // optional: maximum cs power for this station, default defined in config + "grid_operator" : "default_grid_operator", // optional: set grid operator for cost calculation. Default is "default_grid_operator" + "voltage_level": "MV", // optional: voltage_level for this station, default defined in config + "peak_load_window_power": 100, // optional: power during peak load window (if time_windowds file given), default defined in config + "energy_feed_in": { // optional: energy feed in e.g. by local renewables + "csv_file": "data/examples/energy_system/example_pv_feedin.csv", // path to feedin.csv + "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss (defaults to first timestamp in CSV) + "step_duration_s": 3600, // timestep in seconds + "column": "Feed-in Total (kW)", // column name in .csv + "nominal_power": 10, // nominal power in kW, needed for calculation of PV remuneration and cost of feed-in + "factor": 1 // factor to multiply column values, eg 0.001 for conversion from W to kW + }, + "external_load": { // optional: local external loads + "csv_file": "data/examples/energy_system/example_external_load.csv", // path to external_load.csv + "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss (defaults to first timestamp in CSV) + "step_duration_s": 3600, // timestep in seconds + "column": "External Load (kW)", // column name in .csv + "factor": 2 // factor to multiply column values, eg 0.001 for conversion from W to kW + }, + "price_csv": { // optional: price timeseries for this station + "csv_file": "data/examples/costs/price_timeseries_extended.csv", // path to price csv + "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss. If not given, use CSV timestamps (first column) + "step_duration_s": 21600, // timestep in seconds, required if start_time is given + "procurement_column": "procurement", // optional: procurement column name in .csv + "commodity_column": "commodity", // optional: commodity column name in .csv + "virtual_column": "virtual", // optional: column name for virtual costs in .csv + "factor": 0.5 // optional: factor to multiply column values, default 1. Simulation expects €/kWh + }, + "battery": { // optional: local stationary battery + "charging_curve": [[0,50], [1,50]], // piecewise linear function that maps SoC to power, from 0 to 1, required + "capacity": 300, // kWh, assumed to be infinite if not given + "min_charging_power": 0, // kW, optional + "soc": 0, // initial state of charge [0-1], optional + "efficiency": 0.95, // optional + "discharge_curve": null // optional, same as charging curve + } + }, + "Station-3": { + "type": "opps", + "n_charging_stations": 3, + "energy_feed_in": { + "csv_file": "data/examples/energy_system/example_pv_feedin.csv", + "column": "Feed-in Total (kW)", + "nominal_power": 2, + "factor": 0.5 + }, + "price_csv": { + "csv_file": "data/examples/costs/price_timeseries.csv" + } + }, + "Station-10": { + "type": "opps", + "n_charging_stations": 1, + "gc_power": 250, // optional: maximum gc power can be defined per station + "cs_power_opps" : 140, // optional: maximum cs power can be defined per station + "voltage_level": "LV" // optional: voltage_level can be defined per station, influences cost + }, + "Station-21": { + "type": "opps", + "n_charging_stations": 2 + }, + "Station-22": { + "type": "deps", + "n_charging_stations": null + }, + "Station-26": { + "type": "opps", + "n_charging_stations": 5 + }, + "Station-28": { + "type": "opps", + "n_charging_stations": 4 + }, + "Station-30": { + "type": "opps", + "n_charging_stations": 4 + }, + "Station-32": { + "type": "opps", + "n_charging_stations": 3 + }, + "Station-39": { + "type": "opps", + "n_charging_stations": 5 + }, + "Station-42": { + "type": "deps", + "n_charging_stations": null + } +} diff --git a/data/examples/vehicle_types/vehicle_types.json b/data/examples/vehicle_types/vehicle_types.json index ddb024b4..59eb3a01 100644 --- a/data/examples/vehicle_types/vehicle_types.json +++ b/data/examples/vehicle_types/vehicle_types.json @@ -6,7 +6,7 @@ "charging_curve": [[0, 150], [0.8, 150], [1, 15]], // charging curve [SoC, kW] "min_charging_power": 0, // min charging power in KW "v2g": false, // Is vehicle capable of vehicle to grid? - "mileage": "data/examples/energy_consumption_example.csv", // mileage in kWh/km or link to consumption.csv + "mileage": "data/examples/consumption/energy_consumption_example.csv", // mileage in kWh/km or link to consumption.csv "battery_efficiency": 0.95, // optional. default: 0.95 "idle_consumption" : 0.0 // [kWh/h] consumption while standing during a rotation }, @@ -16,7 +16,7 @@ "charging_curve": [[0, 250], [0.8, 250], [1, 25]], "min_charging_power": 0, "v2g": false, - "mileage": "data/examples/energy_consumption_example.csv", + "mileage": "data/examples/consumption/energy_consumption_example.csv", "idle_consumption" : 0.0 } }, From 80f3f317ac049accf65c12e878406d0e3a2e226a Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Apr 2025 13:09:37 +0200 Subject: [PATCH 03/17] update new examples --- data/examples/configs/basic.cfg | 112 +-------------- data/examples/configs/extensive.cfg | 14 +- data/examples/configs/market_strategy.cfg | 60 ++++++++ data/examples/configs/neg_depb_to_oppb.cfg | 49 +++++++ data/examples/configs/plw_market_strategy.cfg | 67 +++++++++ data/examples/configs/plw_strategy.cfg | 63 ++++++++ data/examples/costs/price_timeseries.csv | 134 +++++++++--------- .../electrified_stations_market.json | 23 +++ .../electrified_stations_minimal.json | 92 +----------- .../examples/vehicle_types/vehicle_types.json | 4 +- .../vehicle_types_constant_mileage.json | 8 +- simba/schedule.py | 4 + simba/util.py | 2 +- 13 files changed, 357 insertions(+), 275 deletions(-) create mode 100644 data/examples/configs/market_strategy.cfg create mode 100644 data/examples/configs/neg_depb_to_oppb.cfg create mode 100644 data/examples/configs/plw_market_strategy.cfg create mode 100644 data/examples/configs/plw_strategy.cfg create mode 100644 data/examples/electrified_stations/electrified_stations_market.json diff --git a/data/examples/configs/basic.cfg b/data/examples/configs/basic.cfg index 862d920a..fba4a57d 100644 --- a/data/examples/configs/basic.cfg +++ b/data/examples/configs/basic.cfg @@ -10,64 +10,25 @@ schedule_path = data/examples/trips/trips_example.csv # Deactivate storage of output by setting output_path = null output_path = data/sim_outputs/ # Electrified stations (required) -electrified_stations_path = data/examples/electrified_stations/electrified_stations.json +electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json # Vehicle types (defaults to: ./data/examples/vehicle_types.json) -vehicle_types_path = data/examples/vehicle_types/vehicle_types.json -# Path to station data with stations heights -# (Optional: needed if mileage in vehicle types not constant and inclination should be considered) -station_data_path = data/examples/consumption/all_stations.csv -# Path to temperature csv. data with temperatures in deg Celsius over 0-23 hours -# (Optional: needed if mileage in vehicle types not constant) -outside_temperature_over_day_path = data/examples/consumption/default_temp_winter.csv -# Path to level of loading csv. data with temperatures in deg Celsius over 0-23 hours -# (Optional: needed if mileage in vehicle types not constant) -level_of_loading_over_day_path = data/examples/consumption/default_level_of_loading_over_day.csv -# Path to configuration file for the station optimization. Only needed for mode "station_optimization" -optimizer_config_path = data/examples/configs/default_optimizer.cfg +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json # Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) cost_parameters_path = data/examples/costs/cost_params.json -# Path to rotation filter -rotation_filter_path = data/examples/rotation_filter.csv ##### Modes ##### ### Specify how you want to simulate the scenario ### # Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. # sim runs a single simulation with the given inputs. -# neg_depb_to_oppb changes negative depb-rotations to oppb charging. -# neg_oppb_to_depb changes negative oppb-rotations to depb charging. -# service_optimization finds the largest set of electrified rotations, rotations SOC<0 are removed. -# station_optimization finds the set of fewest stations to electrify all rotations. -# remove_negative removes all negative rotations. -# split_negative_depb splits and merges negative rotations to use the optimal number of busses # report generates simulation output files, including costs. mode = ["sim", "report"] -#mode = ["sim", "load_pickle", "neg_depb_to_oppb", "service_optimization", "station_optimization", "remove_negative", "split_negative_depb", "report"] ##### Flags ##### ### Activate optional functions ### # Set flag for cost calculation: (default: false) cost_calculation = true -# Check rotation assumptions when building schedule? (default: false) -check_rotation_consistency = false -# Remove rotations from schedule that violate assumptions? -# Needs check_rotation_consistency to have an effect (default: false) -skip_inconsistent_rotations = false -# Show plots for users to view, only used in mode report (default: false) -show_plots = false # generate special plots in report mode (default: false) -extended_output_plots = false -# Rotation filter variable, options: -# "include": include only the rotations from file 'rotation_filter' -# "exclude": exclude the rotations from file 'rotation_filter' from the schedule -# null: deactivate function -rotation_filter_variable = null -# Write a new trips.csv during report mode to output directory? (default: false) -create_trips_in_report = false -# Pickle current schedule and scenario during report mode -# create_pickle_in_report = false -# Load this pickle file, expects load_pickle as first mode -# load_pickle_path = "example.pkl" - +extended_output_plots = true ##### Charging strategy ##### # Preferred charging type. Options: depb, oppb (default: depb) @@ -76,10 +37,6 @@ preferred_charging_type = depb # refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html strategy_deps = balanced strategy_opps = greedy -# additional options for depot or station strategies -# refer to https://spice-ev.readthedocs.io/en/latest/simulating_with_spiceev.html#strategy-options -strategy_options_deps = {"CONCURRENCY": 1} -strategy_options_opps = {} # Cost calculation to use. Remove to use default for strategy. # Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window @@ -88,11 +45,6 @@ cost_calculation_method_opps = fixed_wo_plw ##### Physical setup of environment ##### ### Parametrization of the physical setup ### -# Default max power [kW] of grid connectors at depot and opp stations, -# Individual gc_power per gc can be defined in electrified stations -# For unlimited gc power: set very large value (default: 100000) -gc_power_opps = 100000 -gc_power_deps = 100000 # Default max power [kW] of charging station at depot and opp stations (default at opps: 300) # At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) # Individual cs_power per gc and cs type can be defined in electrified stations @@ -102,61 +54,3 @@ cs_power_deps_oppb = 150 # Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) desired_soc_deps = 1.0 desired_soc_opps = 1.0 -# Minimum fraction of capacity for recharge when leaving the depot. -# Helps calculating the minimum standing time at depot. Between 0 - 1. (default: 1) -min_recharge_deps_oppb = 1 -min_recharge_deps_depb = 1 -# Min charging time at depots and opp stations in minutes (default: 0) -min_charging_time = 0 -# Buffer time in min at opp station if no specific buffer time is given in electrified_stations.json -# Time specific buffer times can be set via a dict e.g.: {"10-22": 5, "else": 2} -# NOTE: else clause is a MUST! The buffer time is deducted off of the planned standing time. -# It may resemble things like delays and/or docking procedures (default: 0) -default_buffer_time_opps = 0 -# Buffer time in min at depot stations (default: 0). -default_buffer_time_deps = 0 - -# Assign vehicles using the "adaptive" or "fixed_recharge" algorithm (default: "adaptive"). -# "adaptive" uses vehicles with socs above the consumption of the next rotation. -# "fixed_recharge" uses vehicles for rotations if the vehicles reached the soc values defined with min_recharge_deps_oppb or depb. -assign_strategy = "adaptive" -#assign_strategy = ["adaptive", "fixed_recharge"] - -# Default voltage level for charging stations if not set in electrified_stations file -# Options: HV, HV/MV, MV, MV/LV, LV (default: MV) -default_voltage_level = "MV" -# use peak load windows from file to force lower power during times of high grid load -time_windows = data/examples/time_windows.json -# reduced power of opp/depot stations during peak load windows -peak_load_window_power_opps = 1000 -peak_load_window_power_deps = 1000 -# default values for generating new depot trips in mode split_negative_depb -# average assumed vehicle speed in km/h -default_mean_speed = 30 -# average assumed distance of any station to a depot in km -default_depot_distance = 5 - -##### LOGGING ##### -# Minimum log level. Used for console and file if not specified otherwise in "loglevel_file". -# Allowed/useful: DEBUG, INFO, WARN, ERROR (default: INFO) -# INFO includes INFO, WARN and ERROR but excludes DEBUG -loglevel = INFO -# log file name. Placed in output directory -# set to null to disable logfile creation -# leave empty to have default [timestamp].log -logfile = -# can set different log level for log file -loglevel_file = - -##### SIMULATION PARAMETERS ##### -# Maximum number of days to simulate, if not set simulate entire schedule -#days = 10 -# Set length of time step in minutes (default: 1) -interval = 1 -# Time difference between signal time and actual start time of a vehicle event in min. (default: 10) -signal_time_dif = 10 -# Show estimated time to finish simulation after each step. Not recommended for fast computations -# (default: false) -eta = false -# Save time by skipping often not needed flex_report in SpiceEV -skip_flex_report = true diff --git a/data/examples/configs/extensive.cfg b/data/examples/configs/extensive.cfg index a40b3e81..69319825 100644 --- a/data/examples/configs/extensive.cfg +++ b/data/examples/configs/extensive.cfg @@ -71,14 +71,15 @@ create_trips_in_report = false ##### Charging strategy ##### # Preferred charging type. Options: depb, oppb (default: depb) -preferred_charging_type = oppb +preferred_charging_type = depb # strategy to use at depot and electrified station +# Options: greedy, balanced, balanced_market, peak_load_window, peak_shaving, flex_window, schedule # refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html strategy_deps = balanced strategy_opps = greedy # additional options for depot or station strategies # refer to https://spice-ev.readthedocs.io/en/latest/simulating_with_spiceev.html#strategy-options -strategy_options_deps = {"CONCURRENCY": 1} +strategy_options_deps = {} strategy_options_opps = {} # Cost calculation to use. Remove to use default for strategy. @@ -125,11 +126,12 @@ assign_strategy = "adaptive" # Default voltage level for charging stations if not set in electrified_stations file # Options: HV, HV/MV, MV, MV/LV, LV (default: MV) default_voltage_level = "MV" -# use peak load windows from file to force lower power during times of high grid load +# peak load time windows: load in these times are reduced either by applying 'peak_load_window' +# strategy or by defining fixed 'peak_load_window_power' for deps and opps below (with any strategy) time_windows = data/examples/time_windows.json -# reduced power of opp/depot stations during peak load windows -peak_load_window_power_opps = 1000 +# reduced power of depot/opportunity stations during peak load windows peak_load_window_power_deps = 1000 +peak_load_window_power_opps = 1000 # default values for generating new depot trips in mode split_negative_depb # average assumed vehicle speed in km/h default_mean_speed = 30 @@ -158,5 +160,5 @@ signal_time_dif = 10 # Show estimated time to finish simulation after each step. Not recommended for fast computations # (default: false) eta = false -# Save time by skipping often not needed flex_report in SpiceEV +# Save time by skipping often not needed flex_report in SpiceEV (default: true) skip_flex_report = true diff --git a/data/examples/configs/market_strategy.cfg b/data/examples/configs/market_strategy.cfg new file mode 100644 index 00000000..fb929811 --- /dev/null +++ b/data/examples/configs/market_strategy.cfg @@ -0,0 +1,60 @@ +# general info: identifier of scenario, appended to results +scenario_name = market_example + +##### Paths ##### +### Input and output files and paths ### +# Input file containing trip information (required) +schedule_path = data/examples/trips/trips_example.csv +# Output files are stored here (defaults to: data/sim_outputs) +# Attention: In Windows the path-length is limited to 256 characters! +# Deactivate storage of output by setting output_path = null +output_path = data/sim_outputs/ +# Electrified stations (required) +electrified_stations_path = data/examples/electrified_stations/electrified_stations_market.json +# Vehicle types (defaults to: ./data/examples/vehicle_types.json) +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json +# Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) +cost_parameters_path = data/examples/costs/cost_params.json + +##### Modes ##### +### Specify how you want to simulate the scenario ### +# Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. +# sim runs a single simulation with the given inputs. +# report generates simulation output files, including costs. +mode = ["sim", "report"] + +##### Flags ##### +### Activate optional functions ### +# Set flag for cost calculation: (default: false) +cost_calculation = true +# generate special plots in report mode (default: false) +extended_output_plots = true + +##### Charging strategy ##### +# Preferred charging type. Options: depb, oppb (default: depb) +preferred_charging_type = depb +# strategy to use at depot and electrified station +# refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html +strategy_deps = balanced_market +strategy_opps = greedy +# additional options for depot or station strategies +# refer to https://spice-ev.readthedocs.io/en/latest/simulating_with_spiceev.html#strategy-options +strategy_options_deps = {"HORIZON":6} +strategy_options_opps = {"HORIZON":6} + +# Cost calculation to use. Remove to use default for strategy. +# Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window +cost_calculation_method_deps = variable_wo_plw +cost_calculation_method_opps = variable_wo_plw + +##### Physical setup of environment ##### +### Parametrization of the physical setup ### +# Default max power [kW] of charging station at depot and opp stations (default at opps: 300) +# At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) +# Individual cs_power per gc and cs type can be defined in electrified stations +cs_power_opps = 300 +cs_power_deps_depb = 150 +cs_power_deps_oppb = 150 +# Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) +desired_soc_deps = 1.0 +desired_soc_opps = 1.0 diff --git a/data/examples/configs/neg_depb_to_oppb.cfg b/data/examples/configs/neg_depb_to_oppb.cfg new file mode 100644 index 00000000..8ed86eb9 --- /dev/null +++ b/data/examples/configs/neg_depb_to_oppb.cfg @@ -0,0 +1,49 @@ +# general info: identifier of scenario, appended to results +scenario_name = neg_depb_to_oppb_example + +##### Paths ##### +### Input and output files and paths ### +# Input file containing trip information (required) +schedule_path = data/examples/trips/trips_example.csv +# Output files are stored here (defaults to: data/sim_outputs) +# Attention: In Windows the path-length is limited to 256 characters! +# Deactivate storage of output by setting output_path = null +output_path = data/sim_outputs/ +# Electrified stations (required) +electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json +# Vehicle types (defaults to: ./data/examples/vehicle_types.json) +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json + +##### Modes ##### +### Specify how you want to simulate the scenario ### +# Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. +# sim runs a single simulation with the given inputs. +# report generates simulation output files, including costs. +mode = ["sim", "report", "neg_depb_to_oppb", "report"] +#mode = ["sim", "load_pickle", "neg_depb_to_oppb", "service_optimization", "station_optimization", "remove_negative", "split_negative_depb", "report"] + + +##### Charging strategy ##### +# Preferred charging type. Options: depb, oppb (default: depb) +preferred_charging_type = depb +# strategy to use at depot and electrified station +# refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html +strategy_deps = balanced +strategy_opps = greedy + +# Cost calculation to use. Remove to use default for strategy. +# Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window +cost_calculation_method_deps = fixed_wo_plw +cost_calculation_method_opps = fixed_wo_plw + +##### Physical setup of environment ##### +### Parametrization of the physical setup ### +# Default max power [kW] of charging station at depot and opp stations (default at opps: 300) +# At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) +# Individual cs_power per gc and cs type can be defined in electrified stations +cs_power_opps = 500 +cs_power_deps_depb = 150 +cs_power_deps_oppb = 150 +# Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) +desired_soc_deps = 1.0 +desired_soc_opps = 1.0 diff --git a/data/examples/configs/plw_market_strategy.cfg b/data/examples/configs/plw_market_strategy.cfg new file mode 100644 index 00000000..12c3fc2a --- /dev/null +++ b/data/examples/configs/plw_market_strategy.cfg @@ -0,0 +1,67 @@ +# general info: identifier of scenario, appended to results +scenario_name = plw_market_example + +##### Paths ##### +### Input and output files and paths ### +# Input file containing trip information (required) +schedule_path = data/examples/trips/trips_example.csv +# Output files are stored here (defaults to: data/sim_outputs) +# Attention: In Windows the path-length is limited to 256 characters! +# Deactivate storage of output by setting output_path = null +output_path = data/sim_outputs/ +# Electrified stations (required) +electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json +# Vehicle types (defaults to: ./data/examples/vehicle_types.json) +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json +# Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) +cost_parameters_path = data/examples/costs/cost_params.json + +##### Modes ##### +### Specify how you want to simulate the scenario ### +# Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. +# sim runs a single simulation with the given inputs. +# report generates simulation output files, including costs. +mode = ["sim", "report"] + +##### Flags ##### +### Activate optional functions ### +# Set flag for cost calculation: (default: false) +cost_calculation = true +# generate special plots in report mode (default: false) +extended_output_plots = true + +##### Charging strategy ##### +# Preferred charging type. Options: depb, oppb (default: depb) +preferred_charging_type = depb +# strategy to use at depot and electrified station +# Options: greedy, balanced, balanced_market, peak_load_window, peak_shaving, flex_window, schedule +# refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html +strategy_deps = balanced_market +strategy_opps = balanced_market +# additional options for depot or station strategies +# refer to https://spice-ev.readthedocs.io/en/latest/simulating_with_spiceev.html#strategy-options +strategy_options_deps = {"HORIZON":6} +strategy_options_opps = {"HORIZON":6} + +# Cost calculation to use. Remove to use default for strategy. +# Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window +cost_calculation_method_deps = variable_w_plw +cost_calculation_method_opps = variable_w_plw + +##### Physical setup of environment ##### +### Parametrization of the physical setup ### +# Default max power [kW] of charging station at depot and opp stations (default at opps: 300) +# At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) +# Individual cs_power per gc and cs type can be defined in electrified stations +cs_power_opps = 300 +cs_power_deps_depb = 150 +cs_power_deps_oppb = 150 +# Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) +desired_soc_deps = 1.0 +desired_soc_opps = 1.0 +# peak load time windows: load in these times are reduced either by applying 'peak_load_window' +# strategy or by defining fixed 'peak_load_window_power' for deps and opps below (with any strategy) +time_windows = data/examples/time_windows.json +# reduced power of depot/opportunity stations during peak load windows +peak_load_window_power_deps = 0 +peak_load_window_power_opps = 0 \ No newline at end of file diff --git a/data/examples/configs/plw_strategy.cfg b/data/examples/configs/plw_strategy.cfg new file mode 100644 index 00000000..50832b30 --- /dev/null +++ b/data/examples/configs/plw_strategy.cfg @@ -0,0 +1,63 @@ +# general info: identifier of scenario, appended to results +scenario_name = plw_example + +##### Paths ##### +### Input and output files and paths ### +# Input file containing trip information (required) +schedule_path = data/examples/trips/trips_example.csv +# Output files are stored here (defaults to: data/sim_outputs) +# Attention: In Windows the path-length is limited to 256 characters! +# Deactivate storage of output by setting output_path = null +output_path = data/sim_outputs/ +# Electrified stations (required) +electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json +# Vehicle types (defaults to: ./data/examples/vehicle_types.json) +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json +# Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) +cost_parameters_path = data/examples/costs/cost_params.json + +##### Modes ##### +### Specify how you want to simulate the scenario ### +# Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. +# sim runs a single simulation with the given inputs. +# report generates simulation output files, including costs. +mode = ["sim", "report"] + +##### Flags ##### +### Activate optional functions ### +# Set flag for cost calculation: (default: false) +cost_calculation = true +# generate special plots in report mode (default: false) +extended_output_plots = true + +##### Charging strategy ##### +# Preferred charging type. Options: depb, oppb (default: depb) +preferred_charging_type = depb +# strategy to use at depot and electrified station +# Options: greedy, balanced, balanced_market, peak_load_window, peak_shaving, flex_window, schedule +# refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html +strategy_deps = peak_load_window +strategy_opps = peak_load_window + +# Cost calculation to use. Remove to use default for strategy. +# Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window +cost_calculation_method_deps = fixed_w_plw +cost_calculation_method_opps = fixed_w_plw + +##### Physical setup of environment ##### +### Parametrization of the physical setup ### +# Default max power [kW] of charging station at depot and opp stations (default at opps: 300) +# At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) +# Individual cs_power per gc and cs type can be defined in electrified stations +cs_power_opps = 300 +cs_power_deps_depb = 150 +cs_power_deps_oppb = 150 +# Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) +desired_soc_deps = 1.0 +desired_soc_opps = 1.0 +# peak load time windows: load in these times are reduced either by applying 'peak_load_window' +# strategy or by defining fixed 'peak_load_window_power' for deps and opps below (with any strategy) +time_windows = data/examples/time_windows.json +# reduced power of depot/opportunity stations during peak load windows +# peak_load_window_power_deps = 100 +# peak_load_window_power_opps = 100 \ No newline at end of file diff --git a/data/examples/costs/price_timeseries.csv b/data/examples/costs/price_timeseries.csv index c40f5908..5b594239 100644 --- a/data/examples/costs/price_timeseries.csv +++ b/data/examples/costs/price_timeseries.csv @@ -1,69 +1,69 @@ -time,price -2022-03-07 04:00:00,0.07995 -2022-03-07 05:00:00,0.09202 -2022-03-07 06:00:00,0.11746 -2022-03-07 07:00:00,0.17428 -2022-03-07 08:00:00,0.22796 -2022-03-07 09:00:00,0.22292 -2022-03-07 10:00:00,0.20196 -2022-03-07 11:00:00,0.20498 -2022-03-07 12:00:00,0.21466 -2022-03-07 13:00:00,0.22001 -2022-03-07 14:00:00,0.24007 -2022-03-07 15:00:00,0.24719 -2022-03-07 16:00:00,0.26154 -2022-03-07 17:00:00,0.292 -2022-03-07 18:00:00,0.26648 -2022-03-07 19:00:00,0.252 -2022-03-07 20:00:00,0.2107 -2022-03-07 21:00:00,0.1967 -2022-03-07 22:00:00,0.22121 -2022-03-07 23:00:00,0.17421 -2022-03-08 00:00:00,0.18968 -2022-03-08 01:00:00,0.19474 -2022-03-08 02:00:00,0.17051 -2022-03-08 03:00:00,0.18107 -2022-03-08 04:00:00,0.19496 -2022-03-08 05:00:00,0.19683 -2022-03-08 06:00:00,0.24768 -2022-03-08 07:00:00,0.3082 -2022-03-08 08:00:00,0.33829 -2022-03-08 09:00:00,0.3462 -2022-03-08 10:00:00,0.33899 +time,procurement +2022-03-07 04:00:00,0.07 +2022-03-07 05:00:00,0.09 +2022-03-07 06:00:00,0.11 +2022-03-07 07:00:00,0.17 +2022-03-07 08:00:00,0.22 +2022-03-07 09:00:00,0.22 +2022-03-07 10:00:00,0.20 +2022-03-07 11:00:00,0.20 +2022-03-07 12:00:00,0.21 +2022-03-07 13:00:00,0.22 +2022-03-07 14:00:00,0.24 +2022-03-07 15:00:00,0.24 +2022-03-07 16:00:00,0.26 +2022-03-07 17:00:00,0.29 +2022-03-07 18:00:00,0.26 +2022-03-07 19:00:00,0.25 +2022-03-07 20:00:00,0.21 +2022-03-07 21:00:00,0.19 +2022-03-07 22:00:00,0.22 +2022-03-07 23:00:00,0.17 +2022-03-08 00:00:00,0.18 +2022-03-08 01:00:00,0.19 +2022-03-08 02:00:00,0.17 +2022-03-08 03:00:00,0.18 +2022-03-08 04:00:00,0.19 +2022-03-08 05:00:00,0.19 +2022-03-08 06:00:00,0.24 +2022-03-08 07:00:00,0.30 +2022-03-08 08:00:00,0.33 +2022-03-08 09:00:00,0.34 +2022-03-08 10:00:00,0.33 2022-03-08 11:00:00,0.34 -2022-03-08 12:00:00,0.33564 -2022-03-08 13:00:00,0.33451 -2022-03-08 14:00:00,0.34219 -2022-03-08 15:00:00,0.343 -2022-03-08 16:00:00,0.34921 -2022-03-08 17:00:00,0.35569 -2022-03-08 18:00:00,0.345 -2022-03-08 19:00:00,0.3163 -2022-03-08 20:00:00,0.2606 +2022-03-08 12:00:00,0.33 +2022-03-08 13:00:00,0.33 +2022-03-08 14:00:00,0.34 +2022-03-08 15:00:00,0.34 +2022-03-08 16:00:00,0.34 +2022-03-08 17:00:00,0.35 +2022-03-08 18:00:00,0.34 +2022-03-08 19:00:00,0.31 +2022-03-08 20:00:00,0.26 2022-03-08 21:00:00,0.22 -2022-03-08 22:00:00,0.22495 -2022-03-08 23:00:00,0.19497 -2022-03-09 00:00:00,0.19797 -2022-03-09 01:00:00,0.17533 -2022-03-09 02:00:00,0.15268 -2022-03-09 03:00:00,0.14678 -2022-03-09 04:00:00,0.15501 -2022-03-09 05:00:00,0.20002 -2022-03-09 06:00:00,0.23798 -2022-03-09 07:00:00,0.28283 -2022-03-09 08:00:00,0.2995 -2022-03-09 09:00:00,0.29081 -2022-03-09 10:00:00,0.28278 -2022-03-09 11:00:00,0.26649 -2022-03-09 12:00:00,0.25079 -2022-03-09 13:00:00,0.2451 -2022-03-09 14:00:00,0.24285 -2022-03-09 15:00:00,0.25461 -2022-03-09 16:00:00,0.27476 -2022-03-09 17:00:00,0.30004 -2022-03-09 18:00:00,0.29735 -2022-03-09 19:00:00,0.26541 -2022-03-09 20:00:00,0.25457 -2022-03-09 21:00:00,0.23428 -2022-03-09 22:00:00,0.23338 -2022-03-09 23:00:00,0.21341 \ No newline at end of file +2022-03-08 22:00:00,0.22 +2022-03-08 23:00:00,0.19 +2022-03-09 00:00:00,0.19 +2022-03-09 01:00:00,0.17 +2022-03-09 02:00:00,0.15 +2022-03-09 03:00:00,0.14 +2022-03-09 04:00:00,0.15 +2022-03-09 05:00:00,0.20 +2022-03-09 06:00:00,0.23 +2022-03-09 07:00:00,0.28 +2022-03-09 08:00:00,0.29 +2022-03-09 09:00:00,0.29 +2022-03-09 10:00:00,0.28 +2022-03-09 11:00:00,0.26 +2022-03-09 12:00:00,0.25 +2022-03-09 13:00:00,0.24 +2022-03-09 14:00:00,0.24 +2022-03-09 15:00:00,0.25 +2022-03-09 16:00:00,0.27 +2022-03-09 17:00:00,0.30 +2022-03-09 18:00:00,0.29 +2022-03-09 19:00:00,0.26 +2022-03-09 20:00:00,0.25 +2022-03-09 21:00:00,0.23 +2022-03-09 22:00:00,0.23 +2022-03-09 23:00:00,0.21 \ No newline at end of file diff --git a/data/examples/electrified_stations/electrified_stations_market.json b/data/examples/electrified_stations/electrified_stations_market.json new file mode 100644 index 00000000..f7576c49 --- /dev/null +++ b/data/examples/electrified_stations/electrified_stations_market.json @@ -0,0 +1,23 @@ +{ + "Station-0": { // name of station + "type": "deps", // type: "deps" or "opps" + "n_charging_stations": null, // nr of charging stataions, "null" for unlimited + "price_csv": { + "csv_file": "data/examples/costs/price_timeseries.csv" + } + }, + "Station-3": { + "type": "opps", + "n_charging_stations": null, + "price_csv": { + "csv_file": "data/examples/costs/price_timeseries.csv" + } + }, + "Station-10": { + "type": "opps", + "n_charging_stations": null, + "price_csv": { + "csv_file": "data/examples/costs/price_timeseries.csv" + } + } +} diff --git a/data/examples/electrified_stations/electrified_stations_minimal.json b/data/examples/electrified_stations/electrified_stations_minimal.json index 8c6346ce..48ee5df9 100644 --- a/data/examples/electrified_stations/electrified_stations_minimal.json +++ b/data/examples/electrified_stations/electrified_stations_minimal.json @@ -1,97 +1,17 @@ { "Station-0": { // name of station "type": "deps", // type: "deps" or "opps" - "n_charging_stations": null, // nr of charging stataions, "null" for unlimited - "distance_to_grid": 150, // optional: distance to grid, default defined in cost_params - "gc_power": 5000, // optional: maximum gc power for this station, default defined in config - "cs_power_deps_oppb" : 50, // optional: maximum cs power for this station, default defined in config - "cs_power_deps_depb" : 120, // optional: maximum cs power for this station, default defined in config - "grid_operator" : "default_grid_operator", // optional: set grid operator for cost calculation. Default is "default_grid_operator" - "voltage_level": "MV", // optional: voltage_level for this station, default defined in config - "peak_load_window_power": 100, // optional: power during peak load window (if time_windowds file given), default defined in config - "energy_feed_in": { // optional: energy feed in e.g. by local renewables - "csv_file": "data/examples/energy_system/example_pv_feedin.csv", // path to feedin.csv - "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss (defaults to first timestamp in CSV) - "step_duration_s": 3600, // timestep in seconds - "column": "Feed-in Total (kW)", // column name in .csv - "nominal_power": 10, // nominal power in kW, needed for calculation of PV remuneration and cost of feed-in - "factor": 1 // factor to multiply column values, eg 0.001 for conversion from W to kW - }, - "external_load": { // optional: local external loads - "csv_file": "data/examples/energy_system/example_external_load.csv", // path to external_load.csv - "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss (defaults to first timestamp in CSV) - "step_duration_s": 3600, // timestep in seconds - "column": "External Load (kW)", // column name in .csv - "factor": 2 // factor to multiply column values, eg 0.001 for conversion from W to kW - }, - "price_csv": { // optional: price timeseries for this station - "csv_file": "data/examples/costs/price_timeseries_extended.csv", // path to price csv - "start_time": "2022-03-07 00:00:00", // optional: start time as YYYY-MM-DD hh:mm:ss. If not given, use CSV timestamps (first column) - "step_duration_s": 21600, // timestep in seconds, required if start_time is given - "procurement_column": "procurement", // optional: procurement column name in .csv - "commodity_column": "commodity", // optional: commodity column name in .csv - "virtual_column": "virtual", // optional: column name for virtual costs in .csv - "factor": 0.5 // optional: factor to multiply column values, default 1. Simulation expects €/kWh - }, - "battery": { // optional: local stationary battery - "charging_curve": [[0,50], [1,50]], // piecewise linear function that maps SoC to power, from 0 to 1, required - "capacity": 300, // kWh, assumed to be infinite if not given - "min_charging_power": 0, // kW, optional - "soc": 0, // initial state of charge [0-1], optional - "efficiency": 0.95, // optional - "discharge_curve": null // optional, same as charging curve - } + "n_charging_stations": null // nr of charging stataions, "null" for unlimited }, "Station-3": { "type": "opps", - "n_charging_stations": 3, - "energy_feed_in": { - "csv_file": "data/examples/energy_system/example_pv_feedin.csv", - "column": "Feed-in Total (kW)", - "nominal_power": 2, - "factor": 0.5 - }, - "price_csv": { - "csv_file": "data/examples/costs/price_timeseries.csv" - } - }, - "Station-10": { - "type": "opps", - "n_charging_stations": 1, - "gc_power": 250, // optional: maximum gc power can be defined per station - "cs_power_opps" : 140, // optional: maximum cs power can be defined per station - "voltage_level": "LV" // optional: voltage_level can be defined per station, influences cost - }, - "Station-21": { - "type": "opps", - "n_charging_stations": 2 - }, - "Station-22": { - "type": "deps", "n_charging_stations": null }, - "Station-26": { - "type": "opps", - "n_charging_stations": 5 - }, - "Station-28": { - "type": "opps", - "n_charging_stations": 4 - }, - "Station-30": { - "type": "opps", - "n_charging_stations": 4 - }, - "Station-32": { - "type": "opps", - "n_charging_stations": 3 - }, - "Station-39": { + "Station-10": { "type": "opps", - "n_charging_stations": 5 - }, - "Station-42": { - "type": "deps", - "n_charging_stations": null + "n_charging_stations": null, + "price_csv": { + "csv_file": "data/examples/costs/price_timeseries.csv" + } } } diff --git a/data/examples/vehicle_types/vehicle_types.json b/data/examples/vehicle_types/vehicle_types.json index 59eb3a01..d68ba99c 100644 --- a/data/examples/vehicle_types/vehicle_types.json +++ b/data/examples/vehicle_types/vehicle_types.json @@ -13,7 +13,7 @@ "oppb": { "name": "articulated bus - opportunity charging", "capacity": 150, - "charging_curve": [[0, 250], [0.8, 250], [1, 25]], + "charging_curve": [[0, 500], [0.8, 500], [1, 25]], "min_charging_power": 0, "v2g": false, "mileage": "data/examples/consumption/energy_consumption_example.csv", @@ -33,7 +33,7 @@ "oppb": { "name": "solo bus - opportunity charging", "capacity": 150, - "charging_curve": [[0, 250], [0.8, 250], [1, 25]], + "charging_curve": [[0, 500], [0.8, 500], [1, 25]], "min_charging_power": 0, "v2g": false, "mileage": 1.1, diff --git a/data/examples/vehicle_types/vehicle_types_constant_mileage.json b/data/examples/vehicle_types/vehicle_types_constant_mileage.json index decaccde..3bab938b 100644 --- a/data/examples/vehicle_types/vehicle_types_constant_mileage.json +++ b/data/examples/vehicle_types/vehicle_types_constant_mileage.json @@ -6,17 +6,17 @@ "charging_curve": [[0, 150], [0.8, 150], [1, 15]], // charging curve [SoC, kW] "min_charging_power": 0, // min charging power in KW "v2g": false, // Is vehicle capable of vehicle to grid? - "mileage": 1.0, // mileage in kWh/km or link to consumption.csv + "mileage": 1.8, // mileage in kWh/km or link to consumption.csv "battery_efficiency": 0.95, // optional. default: 0.95 "idle_consumption" : 0.0 // [kWh/h] consumption while standing during a rotation }, "oppb": { "name": "articulated bus - opportunity charging", "capacity": 150, - "charging_curve": [[0, 250], [0.8, 250], [1, 25]], + "charging_curve": [[0, 500], [0.8, 500], [1, 25]], "min_charging_power": 0, "v2g": false, - "mileage": 1.0, + "mileage": 1.7, "idle_consumption" : 0.0 } }, @@ -33,7 +33,7 @@ "oppb": { "name": "solo bus - opportunity charging", "capacity": 150, - "charging_curve": [[0, 250], [0.8, 250], [1, 25]], + "charging_curve": [[0, 500], [0.8, 500], [1, 25]], "min_charging_power": 0, "v2g": false, "mileage": 1.1, diff --git a/simba/schedule.py b/simba/schedule.py index 3e82dc75..f33b3dd7 100644 --- a/simba/schedule.py +++ b/simba/schedule.py @@ -1332,6 +1332,10 @@ def get_price_list_from_csv(price_csv_dict, gc_name=None): # backup: if neither procurement_column nor commodity_column was given, # use values from last column in CSV as commodity prices use_last_column = procurement_column is None and commodity_column is None + if use_last_column: + logging.warning(f'Price CSV for {gc_name}: Please specify procurement_column and/or' + f' commodity_column. Now, the last column in csv was interpreted as ' + f'commodity price') with csv_path.open('r', newline='', encoding='utf-8') as csvfile: reader = csv.DictReader(csvfile, delimiter=',', quotechar='"') diff --git a/simba/util.py b/simba/util.py index fa44ff70..fe4f8924 100644 --- a/simba/util.py +++ b/simba/util.py @@ -611,7 +611,7 @@ def get_parser(): parser.add_argument('--eta', action='store_true', help='Show estimated time to finish simulation after each step, ' 'instead of progress bar. Not recommended for fast computations.') - parser.add_argument('--skip-flex-report', action='store_true', + parser.add_argument('--skip-flex-report', action='store_false', help='Skip flex band creation when generating reports.') # #### LOGGING PARAMETERS #### # From eef60db1a09a4381b5fc86a12b054c0cf3d02636 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Apr 2025 13:36:38 +0200 Subject: [PATCH 04/17] add split trips example --- data/examples/configs/extensive.cfg | 2 +- data/examples/configs/split_neg_depb.cfg | 52 ++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 data/examples/configs/split_neg_depb.cfg diff --git a/data/examples/configs/extensive.cfg b/data/examples/configs/extensive.cfg index 69319825..8f32422e 100644 --- a/data/examples/configs/extensive.cfg +++ b/data/examples/configs/extensive.cfg @@ -97,7 +97,7 @@ gc_power_deps = 100000 # Default max power [kW] of charging station at depot and opp stations (default at opps: 300) # At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) # Individual cs_power per gc and cs type can be defined in electrified stations -cs_power_opps = 300 +cs_power_opps = 500 cs_power_deps_depb = 150 cs_power_deps_oppb = 150 # Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) diff --git a/data/examples/configs/split_neg_depb.cfg b/data/examples/configs/split_neg_depb.cfg new file mode 100644 index 00000000..b1d8a64b --- /dev/null +++ b/data/examples/configs/split_neg_depb.cfg @@ -0,0 +1,52 @@ +# general info: identifier of scenario, appended to results +scenario_name = split_neg_depb_example + +##### Paths ##### +### Input and output files and paths ### +# Input file containing trip information (required) +schedule_path = data/examples/trips/trips_example.csv +# Output files are stored here (defaults to: data/sim_outputs) +# Attention: In Windows the path-length is limited to 256 characters! +# Deactivate storage of output by setting output_path = null +output_path = data/sim_outputs/ +# Electrified stations (required) +electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json +# Vehicle types (defaults to: ./data/examples/vehicle_types.json) +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json + +##### Modes ##### +### Specify how you want to simulate the scenario ### +# Options: sim, neg_depb_to_oppb, neg_oppb_to_depb, service_optimization. +# sim runs a single simulation with the given inputs. +# report generates simulation output files, including costs. +mode = ["sim", "report", "split_negative_depb", "report"] +#mode = ["sim", "load_pickle", "neg_depb_to_oppb", "service_optimization", "station_optimization", "remove_negative", "split_negative_depb", "report"] + +##### Flags ##### +# Write a new trips.csv during report mode to output directory? (default: false) +create_trips_in_report = true + +##### Charging strategy ##### +# Preferred charging type. Options: depb, oppb (default: depb) +preferred_charging_type = depb +# strategy to use at depot and electrified station +# refer to https://spice-ev.readthedocs.io/en/latest/charging_strategies_incentives.html +strategy_deps = balanced +strategy_opps = greedy + +# Cost calculation to use. Remove to use default for strategy. +# Options: fixed_wo_plw, fixed_w_plw, variable_wo_plw, variable_w_plw, balanced_market, flex_window +cost_calculation_method_deps = fixed_wo_plw +cost_calculation_method_opps = fixed_wo_plw + +##### Physical setup of environment ##### +### Parametrization of the physical setup ### +# Default max power [kW] of charging station at depot and opp stations (default at opps: 300) +# At depot stations opp and depot busses have distinct charging stations (all deps default to: 150) +# Individual cs_power per gc and cs type can be defined in electrified stations +cs_power_opps = 500 +cs_power_deps_depb = 150 +cs_power_deps_oppb = 150 +# Set minimum allowed state of charge when leaving depot and opportunity stations (both default: 1) +desired_soc_deps = 1.0 +desired_soc_opps = 1.0 From 040ca877bd4d8c183026b1c32f802e23037162dd Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Wed, 9 Apr 2025 13:15:43 +0200 Subject: [PATCH 05/17] fix tests - adjusted file paths to new structure - fix neg_depb_to_oppb vehicle assignment - update rtd with new example directory structure --- data/examples/configs/basic.cfg | 2 +- data/examples/configs/minimal.cfg | 6 +- data/examples/configs/minimal_pickle.cfg | 2 +- docs/source/getting_started.rst | 8 +- docs/source/modes.rst | 4 +- docs/source/simulation_parameters.rst | 2 +- simba/schedule.py | 14 +-- simba/simulate.py | 1 + simba/util.py | 3 +- tests/conftest.py | 6 +- tests/helpers.py | 24 ++--- tests/test_consumption.py | 2 +- tests/test_cost_calculation.py | 11 +-- tests/test_data_container.py | 2 +- tests/test_example.py | 51 +++++++--- tests/test_schedule.py | 119 +++++------------------ tests/test_simulate.py | 91 +++++++++-------- tests/test_soc_dispatcher.py | 2 +- tests/test_station_optimization.py | 9 +- 19 files changed, 160 insertions(+), 199 deletions(-) diff --git a/data/examples/configs/basic.cfg b/data/examples/configs/basic.cfg index fba4a57d..65f07a1f 100644 --- a/data/examples/configs/basic.cfg +++ b/data/examples/configs/basic.cfg @@ -10,7 +10,7 @@ schedule_path = data/examples/trips/trips_example.csv # Deactivate storage of output by setting output_path = null output_path = data/sim_outputs/ # Electrified stations (required) -electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json +electrified_stations_path = data/examples/electrified_stations/electrified_stations.json # Vehicle types (defaults to: ./data/examples/vehicle_types.json) vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json # Cost parameters (needed if cost_calculation flag is set to true, see Flag section below) diff --git a/data/examples/configs/minimal.cfg b/data/examples/configs/minimal.cfg index fdc1d90f..bf636e50 100644 --- a/data/examples/configs/minimal.cfg +++ b/data/examples/configs/minimal.cfg @@ -1,9 +1,9 @@ ### Input and output files and paths ### # Input file containing trip information -schedule_path = data/examples/trips_example.csv +schedule_path = data/examples/trips_example_small.csv # Electrified stations -electrified_stations_path = data/examples/electrified_stations.json +electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json # Vehicle types # Not strictly needed (defaults to: ./data/examples/vehicle_types.json), # but if vehicle types have constant mileage, no other mileage files are needed -vehicle_types_path = data/examples/vehicle_types_constant_mileage.json +vehicle_types_path = data/examples/vehicle_types/vehicle_types_constant_mileage.json diff --git a/data/examples/configs/minimal_pickle.cfg b/data/examples/configs/minimal_pickle.cfg index fe277db1..195822cb 100644 --- a/data/examples/configs/minimal_pickle.cfg +++ b/data/examples/configs/minimal_pickle.cfg @@ -1,5 +1,5 @@ mode = ["load_pickle", "report"] # Load this pickle file, expects load_pickle as first mode -# to try this mode, first create a pickle file with another exmple using +# to try this mode, first create a pickle file with another example using # "create_pickle_in_report = true", then copy link to pickle file here load_pickle_path = scenario.pkl diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index e3bf5f3b..04f287a1 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -14,9 +14,9 @@ To try it out, first clone `this repository = 3.7) environment and clone `t Now add a new "run/debug configuration" with the following information: | module name: ``simba`` -| Parameters: ``--config data/examples/simba.cfg`` +| Parameters: ``--config data/examples/configs/basic.cfg`` | Working directory: ``path/to/local/simba_repo`` | Run with Python Console: true diff --git a/docs/source/modes.rst b/docs/source/modes.rst index c29df445..f5e5cce7 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -20,7 +20,7 @@ different modes support the user in finding optimal solutions for their eBus-Sys Chained Modes ------------- -While the default mode of SimBA is the simple simulation together with a report, modes can be chained together differently to achieve the desired results. The chain of modes is defined in the config file (default: simba.cfg) under the keyword *mode*: +While the default mode of SimBA is the simple simulation together with a report, modes can be chained together differently to achieve the desired results. The chain of modes is defined in the config file under the keyword *mode*: :: @@ -227,7 +227,7 @@ To make use of this feature the parameters in the optimizer.cfg have to be set. Optimizer Configuration ################################### -The functionality of the optimizer is controlled through the optimizer.cfg specified in the simba.cfg used for calling SimBA. +The functionality of the optimizer is controlled through the optimizer.cfg specified in the config file used for calling SimBA. .. list-table:: Optimizer.cfg parameters :header-rows: 1 diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 6b1820da..0945aa59 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -19,7 +19,7 @@ The configuration file config.cfg is provided as example in ./examples/ and prov | Physical setup of environment: Here, the physical setup is characterized | Simulation Parameters: The simulation can be adjusted using these parameters -The example (data/simba.cfg) contains parameter descriptions which are explained here in more detail: +The example configurations in `data/examples/configs/` contain parameter descriptions which are explained here in more detail: .. list-table:: config.cfg parameters :header-rows: 1 diff --git a/simba/schedule.py b/simba/schedule.py index f33b3dd7..6964419a 100644 --- a/simba/schedule.py +++ b/simba/schedule.py @@ -505,10 +505,11 @@ def assign_vehicles_w_adaptive_soc(self, args): all_standing_vehicles)) # join standing vehicles with their expected soc and sort by soc - socs = list(map(lambda v_id_deps: soc_at_departure_time(v_id_deps[0], v_id_deps[1], - departure_time, vehicle_data, - self.stations, charge_curves, - args), standing_vehicles)) + socs = list(map( + lambda v_id_deps: soc_at_departure_time( + v_id_deps[0], v_id_deps[1], departure_time, vehicle_data, + self.stations, charge_curves, args + ), standing_vehicles)) # pair with socs standing_vehicles_w_soc = [(*v, rot_idx) for v, rot_idx in zip(standing_vehicles, socs)] @@ -1578,7 +1579,6 @@ def soc_at_departure_time(v_id, deps, departure_time, vehicle_data, stations, ch if ct == "oppb": # for opportunity chargers assume a minimal soc>=0 start_soc = max(start_soc, 0) - charge_delta_soc = \ - get_charge_delta_soc(charge_curves, vt, ct, station_power, duration_in_m, - start_soc) + charge_delta_soc = get_charge_delta_soc( + charge_curves, vt, ct, station_power, duration_in_m, start_soc) return min(start_soc + charge_delta_soc, args.desired_soc_deps) diff --git a/simba/simulate.py b/simba/simulate.py index 6c474b62..db6edd32 100644 --- a/simba/simulate.py +++ b/simba/simulate.py @@ -191,6 +191,7 @@ def switch_type(schedule, scenario, args, from_type, to_type): f'Changing charging type from {from_type} to {to_type} for rotations ' + ', '.join(sorted(relevant_rotations))) schedule.set_charging_type(to_type, relevant_rotations) + schedule.assign_vehicles(args) # simulate again scenario = schedule.run(args) neg_rot = schedule.get_negative_rotations(scenario) diff --git a/simba/util.py b/simba/util.py index fe4f8924..c33476e0 100644 --- a/simba/util.py +++ b/simba/util.py @@ -474,7 +474,8 @@ def get_parser(): parser.add_argument('--output-path', default="data/sim_outputs", help='Location where all simulation outputs are stored') parser.add_argument('--electrified-stations-path', help='include electrified_stations json') - parser.add_argument('--vehicle-types-path', default="data/examples/vehicle_types.json", + parser.add_argument('--vehicle-types-path', + default="data/examples/vehicle_types/vehicle_types.json", help='location of vehicle type definitions') parser.add_argument('--station-data-path', default=None, help='Use station data to back calculation of consumption with height\ diff --git a/tests/conftest.py b/tests/conftest.py index 03c03cb8..87287de0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,5 @@ -import pathlib +from pathlib import Path -test_root = pathlib.Path(__file__).parent +test_root = Path(__file__).parent file_root = test_root / "test_input_files" -example_root = pathlib.Path(__file__).parent.parent / "data/examples" +example_root = Path(__file__).parent.parent / "data/examples" diff --git a/tests/helpers.py b/tests/helpers.py index fccb8b16..909a6236 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -7,20 +7,22 @@ from tests.conftest import example_root +MANDATORY_ARGS = { + "min_recharge_deps_oppb": 0, + "min_recharge_deps_depb": 0, + "gc_power_opps": 1000, + "gc_power_deps": 1000, + "cs_power_opps": 100, + "cs_power_deps_depb": 50, + "cs_power_deps_oppb": 150, +} + + def generate_basic_schedule(): - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() args.preferred_charging_type = "oppb" - mandatory_args = { - "min_recharge_deps_oppb": 0, - "min_recharge_deps_depb": 0, - "gc_power_opps": 1000, - "gc_power_deps": 1000, - "cs_power_opps": 100, - "cs_power_deps_depb": 50, - "cs_power_deps_oppb": 150, - } - vars(args).update(mandatory_args) + vars(args).update(MANDATORY_ARGS) data_container = DataContainer().fill_with_args(args) generated_schedule, args = pre_simulation(args, data_container) return generated_schedule, args diff --git a/tests/test_consumption.py b/tests/test_consumption.py index 229e631d..50e2ad69 100644 --- a/tests/test_consumption.py +++ b/tests/test_consumption.py @@ -7,7 +7,7 @@ class TestConsumption: """Class to test Consumption functionality""" - consumption_path = example_root / "energy_consumption_example.csv" + consumption_path = example_root / "consumption/energy_consumption_example.csv" def test_calculate_idle_consumption(self, tmp_path): """Various tests to trigger errors and check if behaviour is as expected diff --git a/tests/test_cost_calculation.py b/tests/test_cost_calculation.py index d15b170d..b4810869 100644 --- a/tests/test_cost_calculation.py +++ b/tests/test_cost_calculation.py @@ -36,14 +36,11 @@ def test_cost_calculation(self): args.cost_calculation_method_deps = "balanced_market" args.cost_calculation_method_opps = "balanced_market" costs_with_other_strat = calculate_costs(cost_params, scenario, schedule, args) - print(costs_vanilla.costs_per_gc["cumulated"]["c_total_annual"]) - print(costs_with_other_strat.costs_per_gc["cumulated"]["c_total_annual"]) station = "cumulated" - for key in costs_vanilla.costs_per_gc[station]: - if "el_energy" not in key: - continue - assert (costs_vanilla.costs_per_gc[station][key] != - costs_with_other_strat.costs_per_gc[station][key]), key + cost_vanilla = costs_vanilla.costs_per_gc[station] + cost_other = costs_with_other_strat.costs_per_gc[station] + assert cost_vanilla["c_el_power_price_annual"] != cost_other["c_el_power_price_annual"], ( + "electric power costs should differ") # PLW: will create window time series before cost calculation args.cost_calculation_method_deps = "fixed_w_plw" diff --git a/tests/test_data_container.py b/tests/test_data_container.py index d9709fcf..c9e42af8 100644 --- a/tests/test_data_container.py +++ b/tests/test_data_container.py @@ -14,6 +14,6 @@ def test_get_values_from_nested_key(self): def test_data_container(self): data_container = simba.data_container.DataContainer() - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() data_container.fill_with_args(args) diff --git a/tests/test_example.py b/tests/test_example.py index cfa1ca1a..5f52bd7d 100644 --- a/tests/test_example.py +++ b/tests/test_example.py @@ -1,4 +1,5 @@ from pathlib import Path +import pytest import re import subprocess @@ -6,28 +7,48 @@ EXAMPLE_PATH = ROOT_PATH / "data/examples" +def adjust_paths(cfg_text, tmp_path): + # adjust paths in config text to use absolute paths + # provide path to input data + cfg_text = cfg_text.replace("data/examples", str(EXAMPLE_PATH)) + # write output to tmp + cfg_text = re.sub(r"output_path.+", f"output_path = {str(tmp_path.as_posix())}", cfg_text) + # reduce horizon + cfg_text = re.sub(r"HORIZON\":\d+", "HORIZON\":1", cfg_text) + # don't show plots. spaces are optional, so use regex + cfg_text = re.sub(r"show_plots\s*=\s*true", "show_plots = false", cfg_text) + return cfg_text + + class TestExampleConfigs: - def test_example_cfg(self, tmp_path): + # create own test for every example config (can run tests in parallel) + @pytest.mark.parametrize("cfg_path", (EXAMPLE_PATH / "configs").glob("*.cfg")) + def test_eval(self, cfg_path, tmp_path): + # test single example config: does it run successfully? + if cfg_path.stem == "minimal_pickle": + # no example pickle file: skip this + return # copy cfg to tmp, adjust paths - src = EXAMPLE_PATH / "simba.cfg" - src_text = src.read_text() - # provide path to input data - src_text = src_text.replace("data/examples", str(EXAMPLE_PATH)) - # write output to tmp - src_text = re.sub(r"output_path.+", f"output_path = {str(tmp_path.as_posix())}", - src_text) + src_text = cfg_path.read_text() + dst = tmp_path / "simba.cfg" + dst.write_text(adjust_paths(src_text, tmp_path)) + + assert subprocess.call(["python", "-m", "simba", "--config", dst]) == 0, ( + cfg_path.stem + " failed") + + def test_required_files(self, tmp_path): + # test if all necessary / expected files are copied into output folder + # copy cfg to tmp, adjust paths + src = EXAMPLE_PATH / "configs/extensive.cfg" dst = tmp_path / "simba.cfg" - # don't show plots. spaces are optional, so use regex - src_text = re.sub(r"show_plots\s*=\s*true", "show_plots = false", src_text) - dst.write_text(src_text) + src_text = src.read_text() + dst.write_text(adjust_paths(src_text, tmp_path)) # call toolbox from shell - assert subprocess.call([ - "python", "-m", "simba", "--config", dst - ]) == 0 + subprocess.call(["python", "-m", "simba", "--config", dst]) - # make sure all required files have been copied to output folder + # make sure all required input files have been copied to output folder expected = [ 'simba.cfg', 'program_version.txt', diff --git a/tests/test_schedule.py b/tests/test_schedule.py index 5ad98770..40809575 100644 --- a/tests/test_schedule.py +++ b/tests/test_schedule.py @@ -12,34 +12,25 @@ from simba.data_container import DataContainer from simba.simulate import pre_simulation from tests.conftest import example_root, file_root -from tests.helpers import generate_basic_schedule - -mandatory_args = { - "min_recharge_deps_oppb": 1, - "min_recharge_deps_depb": 1, - "gc_power_opps": 1000, - "gc_power_deps": 1000, - "cs_power_opps": 100, - "cs_power_deps_depb": 50, - "cs_power_deps_oppb": 150, -} +from tests.helpers import generate_basic_schedule, mandatory_args class BasicSchedule: - temperature_path = example_root / 'default_temp_winter.csv' - lol_path = example_root / 'default_level_of_loading_over_day.csv' - vehicle_types_path = example_root / "vehicle_types.json" - electrified_stations_path = example_root / "electrified_stations.json" - path_to_all_station_data = example_root / "all_stations.csv" + temperature_path = example_root / 'consumption/default_temp_winter.csv' + lol_path = example_root / 'consumption/default_level_of_loading_over_day.csv' + vehicle_types_path = example_root / "vehicle_types/vehicle_types.json" + electrified_stations_path = example_root / "electrified_stations/electrified_stations.json" + path_to_all_station_data = example_root / "consumption/all_stations.csv" @pytest.fixture def default_schedule_arguments(self): - arguments = {"vehicle_types_path": self.vehicle_types_path, - "electrified_stations_path": self.electrified_stations_path, - "station_data_path": self.path_to_all_station_data, - "outside_temperature_over_day_path": self.temperature_path, - "level_of_loading_over_day_path": self.lol_path - } + arguments = { + "vehicle_types_path": self.vehicle_types_path, + "electrified_stations_path": self.electrified_stations_path, + "station_data_path": self.path_to_all_station_data, + "outside_temperature_over_day_path": self.temperature_path, + "level_of_loading_over_day_path": self.lol_path + } return arguments def basic_run(self): @@ -48,7 +39,7 @@ def basic_run(self): """ # set the system variables to imitate the console call with the config argument. # first element has to be set to something or error is thrown - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() data_container = DataContainer().fill_with_args(args) @@ -90,7 +81,7 @@ def test_allow_opp_charging(self): def test_optional_timeseries(self): # Test if simulation runs if level of loading and temperature timeseries is not given - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() data_container = DataContainer().fill_with_args(args) vehicle_mileage_path = None @@ -130,7 +121,7 @@ def test_optional_timeseries(self): def test_timestep(self): # Get the parser from util. This way the test is directly coupled to the parser arguments - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() data_container = DataContainer().fill_with_args(args) @@ -178,7 +169,7 @@ def test_mandatory_options_exit(self): """ Check if the schedule creation properly throws an error in case of missing mandatory options """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() data_container = DataContainer().fill_with_args(args) @@ -195,7 +186,7 @@ def test_station_data_reading(self, caplog): :param caplog: pytest fixture to capture logging """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() data_container = DataContainer().fill_with_args(args) @@ -221,7 +212,7 @@ def test_assign_vehicles_fixed_recharge(self): """ Test if assigning vehicles works as intended using the fixed_recharge strategy """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() args.min_recharge_deps_oppb = 1 args.min_recharge_deps_depb = 1 @@ -267,14 +258,14 @@ def test_assign_vehicles_fixed_recharge(self): def test_assign_vehicles_adaptive(self): """ Test if assigning vehicles works as intended using the adaptive strategy """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() args.schedule_path = file_root / "trips_assign_vehicles_extended.csv" data_container = DataContainer().fill_with_args(args) generated_schedule, args = pre_simulation(args, data_container) - args = Namespace(**{"desired_soc_deps": 1}) + args.desired_soc_deps = 1 args.assign_strategy = None generated_schedule.assign_vehicles(args) gen_rotations = generated_schedule.rotations @@ -319,7 +310,7 @@ def test_calculate_consumption(self, default_schedule_arguments): """ Test if calling the consumption calculation works :param default_schedule_arguments: basic arguments the schedule needs for creation """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() args.schedule_path = file_root / "trips_assign_vehicles.csv" data_container = DataContainer().fill_with_args(args) @@ -345,7 +336,7 @@ def test_get_common_stations(self, default_schedule_arguments): :param default_schedule_arguments: basic arguments the schedule needs for creation """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() args.schedule_path = file_root / "trips_assign_vehicles.csv" data_container = DataContainer().fill_with_args(args) @@ -372,7 +363,7 @@ def test_get_negative_rotations(self): assert ['1'] == neg_rots def test_rotation_filter(self, tmp_path): - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] args = util.get_args() args.schedule_path = file_root / "trips_assign_vehicles.csv" data_container = DataContainer().fill_with_args(args) @@ -438,13 +429,11 @@ def test_rotation_filter(self, tmp_path): s.rotation_filter(args, rf_list=[]) assert not s.rotations - def test_scenario_with_feed_in(self, default_schedule_arguments): + def test_scenario_with_feed_in(self): """ Check if running a example with an extended electrified stations file with feed in, external load and battery works and if a scenario object is returned - - :param default_schedule_arguments: basic arguments the schedule needs for creation """ - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() data_container = DataContainer().fill_with_args(args) generated_schedule, args = pre_simulation(args, data_container) @@ -617,62 +606,6 @@ def count_max_power_events(scenario): sum_grid_power_with_red = -sum(timeseries_with_reduction["grid supply [kW]"][idx_slice]) assert sum_grid_power_no_red > sum_grid_power_with_red - def test_generate_price_lists(self): - # setup basic schedule - generated_schedule, args = generate_basic_schedule() - - # only test individual price CSV and random price generation - args.include_price_csv = None - # Station-0: all options - generated_schedule.stations["Station-0"]["price_csv"] = { - "csv_file": example_root / "price_timeseries.csv", - "start_time": "2022-03-07 00:00:00", - "step_duration_s": 86400, - "column": "price", - "factor": 2 - } - # Station-3: minimal options (only CSV path) - generated_schedule.stations["Station-3"]["price_csv"] = { - "csv_file": example_root / "price_timeseries.csv" - } - # Station-10: wrong option (wrong CSV file) - generated_schedule.stations["Station-10"]["price_csv"] = { - "csv_file": example_root / "does-not-exist.csv" - } - # Station-21: start after end of schedule - generated_schedule.stations["Station-21"]["price_csv"] = { - "csv_file": example_root / "price_timeseries.csv", - "start_time": "3333-03-03 00:00:00", - "step_duration_s": 3600 - } - scenario = generated_schedule.generate_scenario(args) - events = [e for e in scenario.events.grid_operator_signals if e.cost is not None] - events_by_gc = { - gc: [e for e in events if e.grid_connector_id == gc] - for gc in generated_schedule.stations.keys()} - assert len(events_by_gc["Station-0"]) > 0 - # first entry is 0.07995, factor is 2 - assert events_by_gc["Station-0"][0].cost["value"] == 0.1599 - assert len(events_by_gc["Station-3"]) > 0 - # default factor of 1, price at 20:00 (example scenario start) - assert events_by_gc["Station-3"][0].cost["value"] == 0.2107 - # wrong file: no events - assert len(events_by_gc["Station-10"]) == 0 - # after scenario: no events - assert len(events_by_gc["Station-21"]) == 0 - - # run schedule and check prices - # example scenario covers 2022-03-07 20:15 - 2022-03-09 04:59 - scenario = generated_schedule.run(args) - # Station-0: price change every 24h, starting midnight => two price changes at midnight - assert set(scenario.prices["Station-0"]) == {0.1599, 0.18404, 0.23492} - assert scenario.prices["Station-0"][224:226] == [0.1599, 0.18404] - # Station-3: price change every hour, starting 04:00 (from csv timestamp) - # => 32 price changes - assert len(set(scenario.prices["Station-3"])) == 33 - # same price for last 59 minutes - assert set(scenario.prices["Station-3"][-59:]) == {0.15501} - def test_get_price_list_from_csv(self, tmp_path): # wrong file given assert len(schedule.get_price_list_from_csv({'csv_file': 'does-not-exist'})) == 0 diff --git a/tests/test_simulate.py b/tests/test_simulate.py index 61fc453a..def171f1 100644 --- a/tests/test_simulate.py +++ b/tests/test_simulate.py @@ -16,48 +16,21 @@ class TestSimulate: # Add propagate_mode_errors as developer setting to raise Exceptions. NON_DEFAULT_VALUES = { - "vehicle_types_path": example_path / "vehicle_types.json", - "electrified_stations_path": example_path / "electrified_stations.json", - "station_data_path": example_path / "all_stations.csv", - "cost_parameters_path": example_path / "cost_params.json", - "outside_temperature_over_day_path": example_path / "default_temp_summer.csv", - "level_of_loading_over_day_path": example_path / "default_level_of_loading_over_day.csv", - "schedule_path": example_path / "trips_example.csv", + "vehicle_types_path": example_path / "vehicle_types/vehicle_types.json", + "electrified_stations_path": + example_path / "electrified_stations/electrified_stations.json", + "station_data_path": example_path / "consumption/all_stations.csv", + "cost_parameters_path": example_path / "costs/cost_params.json", + "outside_temperature_over_day_path": example_path / "consumption/default_temp_summer.csv", + "level_of_loading_over_day_path": + example_path / "consumption/default_level_of_loading_over_day.csv", + "schedule_path": example_path / "trips/trips_example.csv", "mode": [], "interval": 15, "propagate_mode_errors": True, "preferred_charging_type": "oppb" } - MANDATORY_ARGS = { - "vehicle_types_path": example_path / "vehicle_types.json", - "electrified_stations_path": example_path / "electrified_stations.json", - "cost_parameters_path": example_path / "cost_params.json", - "outside_temperature_over_day_path": example_path / "default_temp_summer.csv", - "level_of_loading_over_day_path": example_path / "default_level_of_loading_over_day.csv", - "schedule_path": example_path / "trips_example.csv", - "mode": [], - "min_recharge_deps_oppb": 1, - "min_recharge_deps_depb": 1, - "gc_power_opps": 100000, - "gc_power_deps": 100000, - "cs_power_opps": 300, - "cs_power_deps_depb": 150, - "cs_power_deps_oppb": 150, - "interval": 15, - "days": None, - "signal_time_dif": 10, - "include_price_csv": None, - "rotation_filter_variable": None, - "seed": 1, - "default_buffer_time_opps": 0, - "default_buffer_time_deps": 0, - "desired_soc_opps": 1, - "desired_soc_deps": 1, - "min_charging_time": 0, - "default_voltage_level": "MV", - } - def get_args(self): # try to run a mode that does not exist # Get the parser from util. This way the test is directly coupled to the parser arguments @@ -77,9 +50,40 @@ def test_basic(self): simulate(args) def test_mandatory_missing(self): - values = self.MANDATORY_ARGS.copy() - - for k, v in self.MANDATORY_ARGS.items(): + mandatory_args = { + "vehicle_types_path": example_path / "vehicle_types/vehicle_types.json", + "electrified_stations_path": + example_path / "electrified_stations/electrified_stations.json", + "cost_parameters_path": example_path / "costs/cost_params.json", + "outside_temperature_over_day_path": + example_path / "consumption/default_temp_summer.csv", + "level_of_loading_over_day_path": + example_path / "consumption/default_level_of_loading_over_day.csv", + "schedule_path": example_path / "trips/trips_example.csv", + "mode": [], + "min_recharge_deps_oppb": 1, + "min_recharge_deps_depb": 1, + "gc_power_opps": 100000, + "gc_power_deps": 100000, + "cs_power_opps": 300, + "cs_power_deps_depb": 150, + "cs_power_deps_oppb": 150, + "interval": 15, + "days": None, + "signal_time_dif": 10, + "include_price_csv": None, + "rotation_filter_variable": None, + "seed": 1, + "default_buffer_time_opps": 0, + "default_buffer_time_deps": 0, + "desired_soc_opps": 1, + "desired_soc_deps": 1, + "min_charging_time": 0, + "default_voltage_level": "MV", + } + + values = mandatory_args.copy() + for k, v in mandatory_args.items(): del values[k] with pytest.raises(Exception): simulate(Namespace(**values)) @@ -92,7 +96,7 @@ def test_mandatory_missing(self): with pytest.raises(Exception): simulate(Namespace(**values)) # reset - values[fpath] = self.MANDATORY_ARGS[fpath] + values[fpath] = mandatory_args[fpath] def test_unknown_mode(self, caplog): # try to run a mode that does not exist @@ -110,8 +114,8 @@ def test_late_sim(self, caplog): args.mode = ["sim", "sim"] with caplog.at_level(logging.INFO): simulate(args) - # also captures INFO about running SpiceEV, so only compare second element - assert caplog.record_tuples[1] == ('root', logging.INFO, 'Intermediate sim ignored') + # also captures INFO about running SpiceEV, so only compare last element + assert caplog.record_tuples[-1] == ('root', logging.INFO, 'Intermediate sim ignored') def test_error_handling_in_modes(self, caplog): args = self.get_args() @@ -146,7 +150,8 @@ def test_modes(self, caplog, tmp_path): args.mode = ["station_optimization"] modes_simulation(schedule, scenario, args) - assert len(caplog.record_tuples) == 0 + # warning: no column for Station-3 price CSV + assert len(caplog.record_tuples) == 1 def test_mode_service_opt(self): # basic run diff --git a/tests/test_soc_dispatcher.py b/tests/test_soc_dispatcher.py index 4c19c72f..6f2bb923 100644 --- a/tests/test_soc_dispatcher.py +++ b/tests/test_soc_dispatcher.py @@ -17,7 +17,7 @@ def basic_run(self): """ # set the system variables to imitate the console call with the config argument. # first element has to be set to something or error is thrown - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() args.seed = 5 args.attach_vehicle_soc = True diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index 1aa1e30c..6147dbb6 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -55,7 +55,7 @@ def setup_test(self, tmp_path): self.tmp_path = tmp_path # Create a temporary config file as copy from the example configuration. - src = example_root / "simba.cfg" + src = example_root / "configs/basic.cfg" src_text = src.read_text() # don't show plots. spaces are optional, so use regex @@ -63,7 +63,7 @@ def setup_test(self, tmp_path): vehicles_dest = tmp_path / "vehicle_types.json" # store vehicles temporarily and use them in the config file - shutil.copy(example_root / "vehicle_types.json", vehicles_dest) + shutil.copy(example_root / "vehicle_types/vehicle_types.json", vehicles_dest) # opens the vehicle type file, and adjust capacity and mileage of all vehicles self.vehicle_types = adjust_vehicle_file(vehicles_dest, capacity=50, mileage=10) @@ -77,7 +77,8 @@ def setup_test(self, tmp_path): "vehicle_types_path = " + vehicles_dest_str + r"\g<2>", src_text) # Use the default electrified stations from example folder but change some values - with open(example_root / "electrified_stations.json", "r", encoding='utf-8') as file: + stations_path = example_root / "electrified_stations/electrified_stations.json" + with open(stations_path, "r", encoding='utf-8') as file: self.electrified_stations = util.uncomment_json_file(file) # only keep Station-0 electrified and remove the other staitons self.electrified_stations = {"Station-0": self.electrified_stations["Station-0"]} @@ -113,7 +114,7 @@ def generate_datacontainer_args(self, trips_file_name="trips.csv"): :type trips_file_name: str :return: data_container, args""" - sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() args.output_path = self.tmp_path args.results_directory = self.tmp_path From f33f301c095d1bb41e40cd9636b87abcda165f1f Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Thu, 10 Apr 2025 16:57:03 +0200 Subject: [PATCH 06/17] fix tests --- tests/test_schedule.py | 4 +- tests/test_station_optimization.py | 81 +++++++++++++++++++----------- 2 files changed, 55 insertions(+), 30 deletions(-) diff --git a/tests/test_schedule.py b/tests/test_schedule.py index 40809575..ca3e3f1f 100644 --- a/tests/test_schedule.py +++ b/tests/test_schedule.py @@ -12,7 +12,7 @@ from simba.data_container import DataContainer from simba.simulate import pre_simulation from tests.conftest import example_root, file_root -from tests.helpers import generate_basic_schedule, mandatory_args +from tests.helpers import generate_basic_schedule, MANDATORY_ARGS class BasicSchedule: @@ -173,7 +173,7 @@ def test_mandatory_options_exit(self): args = util.get_args() data_container = DataContainer().fill_with_args(args) - for key in mandatory_args.keys(): + for key in MANDATORY_ARGS.keys(): args = util.get_args() args.__delattr__(key) with pytest.raises(Exception): diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index 6147dbb6..3e88ef2f 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -253,23 +253,50 @@ def test_schedule_consistency(self): opt_sched, opt_scen = run_optimization(conf, sched=deepcopy(sched), scen=scen, args=args) assert len(opt_sched.rotations) == amount_rotations - def test_deep_optimization(self): - """ Check if deep analysis finds the prepared optimal solution for the test case. - - The Test case is a a 3 star like network with two rotations which are negative without - electrification. - Rotation 1: - Depot --> Station-1 ---> Station-2 -->Station-1-->Depot - Rotation 2: - Depot --> Station-1 ---> Station-3 -->Station-1-->Depot - - Greedy optimization will electrify Station-1 first since it is helpful for both rotations. - Since electrifying Station-1 is not enough to electrify either rotations, greedy - optimization will electrify Station-2 and Station-3 as well. Deep Analysis will expand - the checked nodes --> It should find that electrifying Station-2 and Station-3 is enough - without electrifying Station-1 - - """ + # def test_deep_optimization(self): + # """ Check if deep analysis finds the prepared optimal solution for the test case. + + # The Test case is a a 3 star like network with two rotations which are negative without + # electrification. + # Rotation 1: + # Depot --> Station-1 ---> Station-2 -->Station-1-->Depot + # Rotation 2: + # Depot --> Station-1 ---> Station-3 -->Station-1-->Depot + + # Greedy optimization will electrify Station-1 first since it is helpful for both rotations. + # Since electrifying Station-1 is not enough to electrify either rotations, greedy + # optimization will electrify Station-2 and Station-3 as well. Deep Analysis will expand + # the checked nodes --> It should find that electrifying Station-2 and Station-3 is enough + # without electrifying Station-1 + + # """ + # trips_file_name = "trips_for_optimizer_deep.csv" + # data_container, args = self.generate_datacontainer_args(trips_file_name) + # data_container.stations_data = {} + # args.preferred_charging_type = "oppb" + # for trip_d in data_container.trip_data: + # trip_d["distance"] *= 15 + # sched, scen = self.generate_schedule_scenario(args, data_container) + # config_path = example_root / "default_optimizer.cfg" + # conf = opt_util.read_config(config_path) + + # assert len(sched.get_negative_rotations(scen)) == 2 + + # solvers = ["quick", "spiceev"] + # node_choices = ["step-by-step", "brute"] + # conf.opt_type = "deep" + # for solver in solvers: + # for node_choice in node_choices: + # conf.solver = solver + # conf.node_choice = node_choice + # opt_sched, opt_scen = run_optimization(conf, sched=sched, scen=scen, args=args) + # assert len(opt_sched.get_negative_rotations(opt_scen)) == 0 + # assert "Station-1" not in opt_sched.stations + # assert "Station-2" in opt_sched.stations + # assert "Station-3" in opt_sched.stations + + @pytest.mark.parametrize("solver,node_choice", [("quick", "step-by-step"), ("quick", "brute"), ("spiceev", "step-by-step"), ("spiceev", "brute")]) + def test_deep_optimization(self, solver, node_choice): trips_file_name = "trips_for_optimizer_deep.csv" data_container, args = self.generate_datacontainer_args(trips_file_name) data_container.stations_data = {} @@ -282,18 +309,16 @@ def test_deep_optimization(self): assert len(sched.get_negative_rotations(scen)) == 2 - solvers = ["quick", "spiceev"] - node_choices = ["step-by-step", "brute"] conf.opt_type = "deep" - for solver in solvers: - for node_choice in node_choices: - conf.solver = solver - conf.node_choice = node_choice - opt_sched, opt_scen = run_optimization(conf, sched=sched, scen=scen, args=args) - assert len(opt_sched.get_negative_rotations(opt_scen)) == 0 - assert "Station-1" not in opt_sched.stations - assert "Station-2" in opt_sched.stations - assert "Station-3" in opt_sched.stations + # conf.solver = "spiceev" # solver + # conf.node_choice = "brute" # node_choice + conf.solver = solver + conf.node_choice = node_choice + opt_sched, opt_scen = run_optimization(conf, sched=sched, scen=scen, args=args) + assert len(opt_sched.get_negative_rotations(opt_scen)) == 0 + assert "Station-1" not in opt_sched.stations + assert "Station-2" in opt_sched.stations + assert "Station-3" in opt_sched.stations def test_deep_optimization_extended(self): trips_file_name = "trips_extended.csv" From e076395d02885d306f7ebc2069198f14a3be0bd4 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 10 Apr 2025 17:35:59 +0200 Subject: [PATCH 07/17] Fix test for low soc event Add some comments --- tests/test_station_optimization.py | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index 3e88ef2f..a3f1b7dc 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -173,24 +173,50 @@ def test_fast_calculations_and_events(self): sopt.create_charging_curves() # remove none values from socs in the vehicle_socs sopt.replace_socs_from_none_to_value() + + # Let the optimizer approximate the socs, with the two stations which are electrified vehicle_socs_fast = sopt.timeseries_calc(list(sched.stations.keys())) for vehicle, socs in scen.vehicle_socs.items(): + # Optimizer and SpiceEV should result in approximatly the same socs assert vehicle_socs_fast[vehicle][-1] == pytest.approx(socs[-1], 0.01, abs=0.01) events = sopt.get_low_soc_events(soc_data=vehicle_socs_fast, rel_soc=True) + # The scenario was generated to create a single low soc event, e.g. lower than 0 + assert 1 == sum(min(socs)<0 for socs in scen.vehicle_socs.values()) assert len(events) == 1 e = events[0] e1 = copy(e) vehicle_socs_reduced = {vehicle: [soc - 1 for soc in socs] for vehicle, socs in scen.vehicle_socs.items()} + # The vehicle socs were reduced. Now both vehicles have socs below 0 + assert 2 == sum(min(socs)<0 for socs in vehicle_socs_reduced.values()) + + + + # Depending on the option "rel_soc" a relative soc is used or not + events = sopt.get_low_soc_events(soc_data=vehicle_socs_reduced, rel_soc=False) + # Whiout a relative soc both low socs should be found + assert len(events) == 2 + events = sopt.get_low_soc_events(soc_data=vehicle_socs_reduced, rel_soc=True) + # The optimizer should only show a single event, since the low socs which was artifically + # created would not be low, if the vehicle would start with a "full" soc. assert len(events) == 1 + + + e2 = events[0] + # This shows that the events are identical. The shift in socs does not change the times, + # where a low soc event is found. assert e1.start_idx == e2.start_idx assert e1.end_idx == e2.end_idx assert e1.min_soc == e2.min_soc - vehicle_socs_increased = {vehicle: [min(soc + abs(e1.min_soc) - 0.1, 1) for soc in socs] for + new_low_soc = -0.01 + # This increases the soc, so that only a single time step is negative with new_low_soc. + # Higher socs are increased. + # Since the soc stays at 1 for longer, the start index should change + vehicle_socs_increased = {vehicle: [min(soc + abs(e1.min_soc) +new_low_soc, 1) for soc in socs] for vehicle, socs in scen.vehicle_socs.items()} events = sopt.get_low_soc_events(soc_data=vehicle_socs_increased, rel_soc=True) e3 = events[0] From 1e3c7d2d86067aa6bbe398edfb929bf790575f07 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 10 Apr 2025 17:46:59 +0200 Subject: [PATCH 08/17] Bind combination generator to optimizer instance --- simba/station_optimizer.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/simba/station_optimizer.py b/simba/station_optimizer.py index 1f070441..f1365e58 100644 --- a/simba/station_optimizer.py +++ b/simba/station_optimizer.py @@ -36,6 +36,9 @@ def __init__(self, sched: schedule.Schedule, scen: scenario.Scenario, args, self.base_stations = self.electrified_stations.copy() self.base_electrified_station_set = set() + # Generator for producing combinations for the brute force algorithm + self.brute_generator = dict() + # stations which are included can not be included again. Therefore they go into # the set of not possible stations together with excluded stations self.not_possible_stations = config.inclusion_stations.union(config.exclusion_stations) @@ -626,8 +629,7 @@ def node_to_tree(self, delta_base_energy): @opt_util.time_it def choose_station_brute(self, station_eval, - pre_optimized_set=None, missing_energy=0, - gens=dict()): + pre_optimized_set=None, missing_energy=0): """ Return a possible set of stations to electrify which has not been tried yet. Gives back a possible set of stations to electrify which shows potential and has not been @@ -648,10 +650,10 @@ def choose_station_brute(self, station_eval, station_ids = [x[0] for x in station_eval] try: - generator = gens[str(station_ids) + str(len(pre_optimized_set) - 1)] + generator = self.brute_generator[str(station_ids) + str(len(pre_optimized_set) - 1)] except KeyError: generator = opt_util.combination_generator(station_ids, len(pre_optimized_set) - 1) - gens[str(station_ids) + str(len(pre_optimized_set) - 1)] = generator + self.brute_generator[str(station_ids) + str(len(pre_optimized_set) - 1)] = generator station_eval_dict = {stat[0]: stat[1] for stat in station_eval} for comb in generator: node_name = opt_util.stations_hash(comb) From f6cfa657beb8479695686d88fe100ca4e9dede0e Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 10 Apr 2025 17:51:18 +0200 Subject: [PATCH 09/17] Make flake8 happy --- tests/test_station_optimization.py | 61 +++++------------------------- 1 file changed, 10 insertions(+), 51 deletions(-) diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index a3f1b7dc..544417e8 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -182,16 +182,14 @@ def test_fast_calculations_and_events(self): events = sopt.get_low_soc_events(soc_data=vehicle_socs_fast, rel_soc=True) # The scenario was generated to create a single low soc event, e.g. lower than 0 - assert 1 == sum(min(socs)<0 for socs in scen.vehicle_socs.values()) + assert 1 == sum(min(socs) < 0 for socs in scen.vehicle_socs.values()) assert len(events) == 1 e = events[0] e1 = copy(e) vehicle_socs_reduced = {vehicle: [soc - 1 for soc in socs] for vehicle, socs in scen.vehicle_socs.items()} # The vehicle socs were reduced. Now both vehicles have socs below 0 - assert 2 == sum(min(socs)<0 for socs in vehicle_socs_reduced.values()) - - + assert 2 == sum(min(socs) < 0 for socs in vehicle_socs_reduced.values()) # Depending on the option "rel_soc" a relative soc is used or not events = sopt.get_low_soc_events(soc_data=vehicle_socs_reduced, rel_soc=False) @@ -203,8 +201,6 @@ def test_fast_calculations_and_events(self): # created would not be low, if the vehicle would start with a "full" soc. assert len(events) == 1 - - e2 = events[0] # This shows that the events are identical. The shift in socs does not change the times, # where a low soc event is found. @@ -216,8 +212,9 @@ def test_fast_calculations_and_events(self): # This increases the soc, so that only a single time step is negative with new_low_soc. # Higher socs are increased. # Since the soc stays at 1 for longer, the start index should change - vehicle_socs_increased = {vehicle: [min(soc + abs(e1.min_soc) +new_low_soc, 1) for soc in socs] for - vehicle, socs in scen.vehicle_socs.items()} + vehicle_socs_increased = { + vehicle: [min(soc + abs(e1.min_soc) + new_low_soc, 1) for soc in socs] for + vehicle, socs in scen.vehicle_socs.items()} events = sopt.get_low_soc_events(soc_data=vehicle_socs_increased, rel_soc=True) e3 = events[0] assert e1.start_idx != e3.start_idx @@ -279,49 +276,11 @@ def test_schedule_consistency(self): opt_sched, opt_scen = run_optimization(conf, sched=deepcopy(sched), scen=scen, args=args) assert len(opt_sched.rotations) == amount_rotations - # def test_deep_optimization(self): - # """ Check if deep analysis finds the prepared optimal solution for the test case. - - # The Test case is a a 3 star like network with two rotations which are negative without - # electrification. - # Rotation 1: - # Depot --> Station-1 ---> Station-2 -->Station-1-->Depot - # Rotation 2: - # Depot --> Station-1 ---> Station-3 -->Station-1-->Depot - - # Greedy optimization will electrify Station-1 first since it is helpful for both rotations. - # Since electrifying Station-1 is not enough to electrify either rotations, greedy - # optimization will electrify Station-2 and Station-3 as well. Deep Analysis will expand - # the checked nodes --> It should find that electrifying Station-2 and Station-3 is enough - # without electrifying Station-1 - - # """ - # trips_file_name = "trips_for_optimizer_deep.csv" - # data_container, args = self.generate_datacontainer_args(trips_file_name) - # data_container.stations_data = {} - # args.preferred_charging_type = "oppb" - # for trip_d in data_container.trip_data: - # trip_d["distance"] *= 15 - # sched, scen = self.generate_schedule_scenario(args, data_container) - # config_path = example_root / "default_optimizer.cfg" - # conf = opt_util.read_config(config_path) - - # assert len(sched.get_negative_rotations(scen)) == 2 - - # solvers = ["quick", "spiceev"] - # node_choices = ["step-by-step", "brute"] - # conf.opt_type = "deep" - # for solver in solvers: - # for node_choice in node_choices: - # conf.solver = solver - # conf.node_choice = node_choice - # opt_sched, opt_scen = run_optimization(conf, sched=sched, scen=scen, args=args) - # assert len(opt_sched.get_negative_rotations(opt_scen)) == 0 - # assert "Station-1" not in opt_sched.stations - # assert "Station-2" in opt_sched.stations - # assert "Station-3" in opt_sched.stations - - @pytest.mark.parametrize("solver,node_choice", [("quick", "step-by-step"), ("quick", "brute"), ("spiceev", "step-by-step"), ("spiceev", "brute")]) + @pytest.mark.parametrize("solver,node_choice", + [("quick", "step-by-step"), + ("quick", "brute"), + ("spiceev", "step-by-step"), + ("spiceev", "brute")]) def test_deep_optimization(self, solver, node_choice): trips_file_name = "trips_for_optimizer_deep.csv" data_container, args = self.generate_datacontainer_args(trips_file_name) From 0cd16b5ac43d7224e528bf91999577be2383a93e Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 10 Apr 2025 17:53:35 +0200 Subject: [PATCH 10/17] Remove gen from docstring --- simba/station_optimizer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/simba/station_optimizer.py b/simba/station_optimizer.py index f1365e58..075d3399 100644 --- a/simba/station_optimizer.py +++ b/simba/station_optimizer.py @@ -641,8 +641,6 @@ def choose_station_brute(self, station_eval, :type pre_optimized_set: set :param missing_energy: missing energy in this branch before electrification :type missing_energy: float - :param gens: generators for brute force generation - :type gens: dict :return: combination of stations to electrify and false since this function does not support recursive calling :raises AllCombinationsCheckedException: If all combinations have been checked From df38e2489a4ce2ad99613a005bf833eed98b93b2 Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Mon, 14 Apr 2025 08:59:50 +0200 Subject: [PATCH 11/17] add smaller example trips file for minimal config --- data/examples/trips/trips_example_small.csv | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 data/examples/trips/trips_example_small.csv diff --git a/data/examples/trips/trips_example_small.csv b/data/examples/trips/trips_example_small.csv new file mode 100644 index 00000000..c930acc8 --- /dev/null +++ b/data/examples/trips/trips_example_small.csv @@ -0,0 +1,7 @@ +rotation_id,line,departure_name,departure_time,arrival_time,arrival_name,distance,vehicle_type,temperature,level_of_loading,charging_type +1,LINE_0,Station-0,2022-03-07 08:00:00,2022-03-07 09:31:00,Station-1,0.06,AB,20,0,oppb +1,LINE_0,Station-1,2022-03-07 09:31:00,2022-03-07 10:04:00,Station-2,14519,AB,-5,0.9,oppb +1,LINE_0,Station-2,2022-03-07 10:08:00,2022-03-07 10:43:00,Station-1,13541,AB,,,oppb +1,LINE_0,Station-1,2022-03-07 10:51:00,2022-03-07 11:24:00,Station-2,14519,AB,,,oppb +1,LINE_0,Station-2,2022-03-07 11:28:00,2022-03-07 12:03:00,Station-1,13541,AB,,,oppb +1,LINE_0,Station-1,2022-03-07 12:11:00,2022-03-07 12:44:00,Station-0,14519,AB,,,oppb From 3e2a345df39cd64225b6ce440b2fe15c92375597 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 6 May 2025 13:20:08 +0200 Subject: [PATCH 12/17] fix path to minimal trips --- data/examples/configs/minimal.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/examples/configs/minimal.cfg b/data/examples/configs/minimal.cfg index bf636e50..c05e901a 100644 --- a/data/examples/configs/minimal.cfg +++ b/data/examples/configs/minimal.cfg @@ -1,6 +1,6 @@ ### Input and output files and paths ### # Input file containing trip information -schedule_path = data/examples/trips_example_small.csv +schedule_path = data/examples/trips/trips_example_small.csv # Electrified stations electrified_stations_path = data/examples/electrified_stations/electrified_stations_minimal.json # Vehicle types From fac071f08b4999bbe5414c84147fbe7a2db969d7 Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Wed, 7 May 2025 10:24:54 +0200 Subject: [PATCH 13/17] fix tests - test_station_optimization: remove old test_deep_optimization, better linebreaks for parametrize (PEP8) - test_schedule: fix both test_assign_vehicles by using more extensive config --- tests/test_schedule.py | 4 +-- tests/test_station_optimization.py | 48 ++++-------------------------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/tests/test_schedule.py b/tests/test_schedule.py index ca3e3f1f..5a2d14f4 100644 --- a/tests/test_schedule.py +++ b/tests/test_schedule.py @@ -212,7 +212,7 @@ def test_assign_vehicles_fixed_recharge(self): """ Test if assigning vehicles works as intended using the fixed_recharge strategy """ - sys.argv = ["foo", "--config", str(example_root / "configs/minimal.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] args = util.get_args() args.min_recharge_deps_oppb = 1 args.min_recharge_deps_depb = 1 @@ -258,7 +258,7 @@ def test_assign_vehicles_fixed_recharge(self): def test_assign_vehicles_adaptive(self): """ Test if assigning vehicles works as intended using the adaptive strategy """ - sys.argv = ["foo", "--config", str(example_root / "configs/basic.cfg")] + sys.argv = ["foo", "--config", str(example_root / "configs/extensive.cfg")] args = util.get_args() args.schedule_path = file_root / "trips_assign_vehicles_extended.csv" data_container = DataContainer().fill_with_args(args) diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index 3e88ef2f..be4eea05 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -253,49 +253,11 @@ def test_schedule_consistency(self): opt_sched, opt_scen = run_optimization(conf, sched=deepcopy(sched), scen=scen, args=args) assert len(opt_sched.rotations) == amount_rotations - # def test_deep_optimization(self): - # """ Check if deep analysis finds the prepared optimal solution for the test case. - - # The Test case is a a 3 star like network with two rotations which are negative without - # electrification. - # Rotation 1: - # Depot --> Station-1 ---> Station-2 -->Station-1-->Depot - # Rotation 2: - # Depot --> Station-1 ---> Station-3 -->Station-1-->Depot - - # Greedy optimization will electrify Station-1 first since it is helpful for both rotations. - # Since electrifying Station-1 is not enough to electrify either rotations, greedy - # optimization will electrify Station-2 and Station-3 as well. Deep Analysis will expand - # the checked nodes --> It should find that electrifying Station-2 and Station-3 is enough - # without electrifying Station-1 - - # """ - # trips_file_name = "trips_for_optimizer_deep.csv" - # data_container, args = self.generate_datacontainer_args(trips_file_name) - # data_container.stations_data = {} - # args.preferred_charging_type = "oppb" - # for trip_d in data_container.trip_data: - # trip_d["distance"] *= 15 - # sched, scen = self.generate_schedule_scenario(args, data_container) - # config_path = example_root / "default_optimizer.cfg" - # conf = opt_util.read_config(config_path) - - # assert len(sched.get_negative_rotations(scen)) == 2 - - # solvers = ["quick", "spiceev"] - # node_choices = ["step-by-step", "brute"] - # conf.opt_type = "deep" - # for solver in solvers: - # for node_choice in node_choices: - # conf.solver = solver - # conf.node_choice = node_choice - # opt_sched, opt_scen = run_optimization(conf, sched=sched, scen=scen, args=args) - # assert len(opt_sched.get_negative_rotations(opt_scen)) == 0 - # assert "Station-1" not in opt_sched.stations - # assert "Station-2" in opt_sched.stations - # assert "Station-3" in opt_sched.stations - - @pytest.mark.parametrize("solver,node_choice", [("quick", "step-by-step"), ("quick", "brute"), ("spiceev", "step-by-step"), ("spiceev", "brute")]) + @pytest.mark.parametrize("solver,node_choice", + [("quick", "step-by-step"), + ("quick", "brute"), + ("spiceev", "step-by-step"), + ("spiceev", "brute")]) def test_deep_optimization(self, solver, node_choice): trips_file_name = "trips_for_optimizer_deep.csv" data_container, args = self.generate_datacontainer_args(trips_file_name) From c4016d2cfe36f93f056ffee37c010ba3872ffb81 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 7 May 2025 10:53:02 +0200 Subject: [PATCH 14/17] Add comment suggestions Fix some typos --- simba/station_optimizer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/simba/station_optimizer.py b/simba/station_optimizer.py index 075d3399..3df38eb8 100644 --- a/simba/station_optimizer.py +++ b/simba/station_optimizer.py @@ -648,8 +648,10 @@ def choose_station_brute(self, station_eval, station_ids = [x[0] for x in station_eval] try: + # get combination generator (reuse if possible) generator = self.brute_generator[str(station_ids) + str(len(pre_optimized_set) - 1)] except KeyError: + # create a new generator generator = opt_util.combination_generator(station_ids, len(pre_optimized_set) - 1) self.brute_generator[str(station_ids) + str(len(pre_optimized_set) - 1)] = generator station_eval_dict = {stat[0]: stat[1] for stat in station_eval} From 22a174769ade53229028eaf35ca9cdacfe8f02f9 Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Wed, 7 May 2025 11:42:47 +0200 Subject: [PATCH 15/17] change skip_flex_report to create_flex_report --- data/examples/configs/extensive.cfg | 4 ++-- docs/source/simulation_parameters.rst | 4 ++-- simba/util.py | 13 ++++++++----- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/data/examples/configs/extensive.cfg b/data/examples/configs/extensive.cfg index 8f32422e..5d95a2a9 100644 --- a/data/examples/configs/extensive.cfg +++ b/data/examples/configs/extensive.cfg @@ -160,5 +160,5 @@ signal_time_dif = 10 # Show estimated time to finish simulation after each step. Not recommended for fast computations # (default: false) eta = false -# Save time by skipping often not needed flex_report in SpiceEV (default: true) -skip_flex_report = true +# Save time by skipping often not needed flex_report in SpiceEV (default: false) +create_flex_report = false diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 0945aa59..6ebd773a 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -224,10 +224,10 @@ The example configurations in `data/examples/configs/` contain parameter descrip - false - Boolean - Show estimated time to finish simulation after each step. Not recommended for fast computations - * - skip_flex_report + * - create_flex_report - false - Boolean - - Skip generation of flex_report in SpiceEV. Activating can save time as this feature is rarely used + - Create flex band information in SpiceEV when reporting. Rarely used. Schedule diff --git a/simba/util.py b/simba/util.py index c33476e0..c3fc89e4 100644 --- a/simba/util.py +++ b/simba/util.py @@ -428,6 +428,9 @@ def mutate_args_for_spiceev(args): args.margin = 1 args.ALLOW_NEGATIVE_SOC = True args.PRICE_THRESHOLD = -100 # ignore price for charging decisions + # in SpiceEV, default is to create a flex report + # in SimBA, we usually want to skip it + args.skip_flex_report = not args.create_flex_report def get_args(): @@ -435,12 +438,12 @@ def get_args(): args = parser.parse_args() - # arguments relevant to SpiceEV, setting automatically to reduce clutter in config - mutate_args_for_spiceev(args) - # If a config is provided, the config will overwrite previously parsed arguments set_options_from_config(args, check=parser, verbose=False) + # arguments relevant to SpiceEV, setting automatically to reduce clutter in config + mutate_args_for_spiceev(args) + # Check if deprecated arguments were given and change them accordingly args = replace_deprecated_arguments(args) @@ -612,8 +615,8 @@ def get_parser(): parser.add_argument('--eta', action='store_true', help='Show estimated time to finish simulation after each step, ' 'instead of progress bar. Not recommended for fast computations.') - parser.add_argument('--skip-flex-report', action='store_false', - help='Skip flex band creation when generating reports.') + parser.add_argument('--create-flex-report', action='store_true', + help='Create a flex band when generating reports.') # #### LOGGING PARAMETERS #### # parser.add_argument('--loglevel', default='INFO', type=str.upper, From 8333c12cbdc72a1d06f227bddb537bfb3a7f5d43 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 7 May 2025 11:47:18 +0200 Subject: [PATCH 16/17] Add comments --- tests/test_station_optimization.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index 544417e8..66e76274 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -177,11 +177,11 @@ def test_fast_calculations_and_events(self): # Let the optimizer approximate the socs, with the two stations which are electrified vehicle_socs_fast = sopt.timeseries_calc(list(sched.stations.keys())) for vehicle, socs in scen.vehicle_socs.items(): - # Optimizer and SpiceEV should result in approximatly the same socs + # Optimizer and SpiceEV should result in approximately the same socs assert vehicle_socs_fast[vehicle][-1] == pytest.approx(socs[-1], 0.01, abs=0.01) events = sopt.get_low_soc_events(soc_data=vehicle_socs_fast, rel_soc=True) - # The scenario was generated to create a single low soc event, e.g. lower than 0 + # The scenario was generated to create a single low soc event, i.e. lower than 0 assert 1 == sum(min(socs) < 0 for socs in scen.vehicle_socs.values()) assert len(events) == 1 e = events[0] @@ -193,17 +193,17 @@ def test_fast_calculations_and_events(self): # Depending on the option "rel_soc" a relative soc is used or not events = sopt.get_low_soc_events(soc_data=vehicle_socs_reduced, rel_soc=False) - # Whiout a relative soc both low socs should be found + # Without a relative soc, there should be two low soc events assert len(events) == 2 events = sopt.get_low_soc_events(soc_data=vehicle_socs_reduced, rel_soc=True) - # The optimizer should only show a single event, since the low socs which was artifically - # created would not be low, if the vehicle would start with a "full" soc. + # The optimizer should only show a single event, since the low socs which was artificially + # created would not be low if the vehicle started with a "full" soc. assert len(events) == 1 e2 = events[0] - # This shows that the events are identical. The shift in socs does not change the times, - # where a low soc event is found. + # Compare events found with and without rel_soc: + # The soc shift does not change the timestep, so both events refer to the same occurrence. assert e1.start_idx == e2.start_idx assert e1.end_idx == e2.end_idx assert e1.min_soc == e2.min_soc From 17e0b2a7ba927a230293b172b395571fef47c8d1 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 7 May 2025 11:50:59 +0200 Subject: [PATCH 17/17] Create generator_key var --- simba/station_optimizer.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/simba/station_optimizer.py b/simba/station_optimizer.py index 3df38eb8..e8b1f750 100644 --- a/simba/station_optimizer.py +++ b/simba/station_optimizer.py @@ -647,13 +647,14 @@ def choose_station_brute(self, station_eval, """ station_ids = [x[0] for x in station_eval] + # get combination generator (reuse if possible) + generator_key = f"{station_ids} {len(pre_optimized_set) - 1}" try: - # get combination generator (reuse if possible) - generator = self.brute_generator[str(station_ids) + str(len(pre_optimized_set) - 1)] + generator = self.brute_generator[generator_key] except KeyError: - # create a new generator + # create new generator generator = opt_util.combination_generator(station_ids, len(pre_optimized_set) - 1) - self.brute_generator[str(station_ids) + str(len(pre_optimized_set) - 1)] = generator + self.brute_generator[generator_key] = generator station_eval_dict = {stat[0]: stat[1] for stat in station_eval} for comb in generator: node_name = opt_util.stations_hash(comb)