From 416f6d1b5684b7e77e7afd3806c1ac348180ed56 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 7 Jun 2023 10:57:52 +0200 Subject: [PATCH 1/2] this should be our new dev --- ebus_toolbox/consumption.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/ebus_toolbox/consumption.py b/ebus_toolbox/consumption.py index 63e3f182..1d9b3d4b 100644 --- a/ebus_toolbox/consumption.py +++ b/ebus_toolbox/consumption.py @@ -109,10 +109,8 @@ def calculate_consumption(self, time, distance, vehicle_type, charging_type, tem consumption_function = vehicle_type+"_from_"+consumption_path try: mileage = self.consumption_files[consumption_function]( - this_incline=height_diff / distance, - this_temp=temp, - this_lol=level_of_loading, - this_speed=mean_speed) + this_incline=height_diff / distance, this_temp=temp, + this_lol=level_of_loading, this_speed=mean_speed) except KeyError: # creating the interpol function from csv file. delim = util.get_csv_delim(consumption_path) @@ -135,10 +133,8 @@ def interpol_function(this_incline, this_temp, this_lol, this_speed): self.consumption_files.update({consumption_function: interpol_function}) mileage = self.consumption_files[consumption_function]( - this_incline=height_diff / distance, - this_temp=temp, - this_lol=level_of_loading, - this_speed=mean_speed) + this_incline=height_diff / distance, this_temp=temp, + this_lol=level_of_loading, this_speed=mean_speed) consumed_energy = mileage * distance / 1000 # kWh delta_soc = -1 * (consumed_energy / vehicle_info["capacity"]) From 20849d56148484198b501cc40b0282cbd1e164a9 Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Wed, 7 Jun 2023 15:48:28 +0200 Subject: [PATCH 2/2] rotation filter: restructure, fixes, add tests --- ebus_toolbox/schedule.py | 18 ++++++---- tests/test_schedule.py | 75 +++++++++++++++++++++++++++++++++++++--- tests/test_simulate.py | 1 + 3 files changed, 84 insertions(+), 10 deletions(-) diff --git a/ebus_toolbox/schedule.py b/ebus_toolbox/schedule.py index 27d2b6a1..6a18baa2 100644 --- a/ebus_toolbox/schedule.py +++ b/ebus_toolbox/schedule.py @@ -385,7 +385,7 @@ def get_negative_rotations(self, scenario): return list(negative_rotations) - def rotation_filter(self, args, rf_list=None): + def rotation_filter(self, args, rf_list=[]): """Edits rotations according to args.rotation_filter_variable. :param args: used arguments are rotation_filter, path to rotation ids, @@ -394,20 +394,26 @@ def rotation_filter(self, args, rf_list=None): :param rf_list: rotation filter list with strings of rotation ids (default is None) :type rf_list: list """ - rf_list = rf_list or [] - rf_list = [str(i) for i in rf_list] - if not args.rotation_filter_variable: + if args.rotation_filter_variable is None: + # filtering disabled return - if args.rotation_filter_variable and not args.rotation_filter and not rf_list: - warnings.warn("Rotation filter variable is enabled but json and list are not used.") + # cast rotations in filter to string + rf_list = [str(i) for i in rf_list] + + if args.rotation_filter is None and not rf_list: + warnings.warn("Rotation filter variable is enabled but file and list are not used.") return + if args.rotation_filter: + # read out rotations from file (one rotation ID per line) try: with open(args.rotation_filter, encoding='utf-8') as f: for line in f: rf_list.append(line.strip()) except FileNotFoundError: warnings.warn(f"Path to rotation filter {args.rotation_filter} is invalid.") + # no file, no change + return # filter out rotations in self.rotations if args.rotation_filter_variable == "exclude": self.rotations = {k: v for k, v in self.rotations.items() if k not in rf_list} diff --git a/tests/test_schedule.py b/tests/test_schedule.py index bf19627d..0d114dea 100644 --- a/tests/test_schedule.py +++ b/tests/test_schedule.py @@ -1,3 +1,5 @@ +from argparse import Namespace +from copy import deepcopy from datetime import timedelta import pytest import sys @@ -6,7 +8,7 @@ from tests.conftest import example_root, file_root from tests.helpers import generate_basic_schedule -from ebus_toolbox import schedule, trip, consumption, util +from ebus_toolbox import consumption, rotation, schedule, trip, util mandatory_args = { @@ -63,9 +65,13 @@ def test_mandatory_options_exit(self): """ Check if the schedule creation properly throws an error in case of missing mandatory options """ - with pytest.raises(Exception): - # schedule creation without mandatory args - schedule.Schedule(self.vehicle_types, self.electrified_stations) + args = mandatory_args.copy() + for key in mandatory_args.keys(): + value = args.pop(key) + with pytest.raises(Exception): + # schedule creation without mandatory arg + schedule.Schedule(self.vehicle_types, self.electrified_stations, **args) + args[key] = value def test_station_data_reading(self): """ Test if the reading of the geo station data works and outputs warnings in @@ -173,6 +179,67 @@ def test_get_negative_rotations(self): neg_rots = sched.get_negative_rotations(scen) assert '1' in neg_rots + def test_rotation_filter(self, tmp_path): + s = schedule.Schedule(self.vehicle_types, self.electrified_stations, **mandatory_args) + args = Namespace(**{ + "rotation_filter_variable": None, + "rotation_filter": None, + }) + # add dummy rotations + s.rotations = { + str(i): rotation.Rotation(id=str(i), vehicle_type="", schedule=None) + for i in range(6) + } + s.original_rotations = deepcopy(s.rotations) + # filtering disabled + args.rotation_filter_variable = None + s.rotation_filter(args) + assert s.rotations.keys() == s.original_rotations.keys() + + # filtering not disabled, but neither file nor list given -> warning + args.rotation_filter_variable = "include" + args.rotation_filter = None + with pytest.warns(UserWarning): + s.rotation_filter(args) + assert s.rotations.keys() == s.original_rotations.keys() + + # filter file not found -> warning + args.rotation_filter = tmp_path / "filter.txt" + with pytest.warns(UserWarning): + s.rotation_filter(args) + assert s.rotations.keys() == s.original_rotations.keys() + + # filter (include) from JSON file + args.rotation_filter.write_text("3 \n 4\n16") + s.rotation_filter(args) + assert sorted(s.rotations.keys()) == ['3', '4'] + + # filter (exclude) from given list + args.rotation_filter_variable = "exclude" + args.rotation_filter = None + s.rotations = deepcopy(s.original_rotations) + s.rotation_filter(args, rf_list=['3', '4']) + assert sorted(s.rotations.keys()) == ['0', '1', '2', '5'] + + # filter (include) from integer list + s.rotations = deepcopy(s.original_rotations) + args.rotation_filter_variable = "include" + s.rotation_filter(args, rf_list=[3, 4]) + assert sorted(s.rotations.keys()) == ['3', '4'] + + # filter nothing + s.rotations = deepcopy(s.original_rotations) + args.rotation_filter = tmp_path / "filter.txt" + args.rotation_filter.write_text('') + args.rotation_filter_variable = "exclude" + s.rotation_filter(args, rf_list=[]) + assert s.rotations.keys() == s.original_rotations.keys() + + # filter all (is this intended?) + args.rotation_filter_variable = "include" + s.rotation_filter(args, rf_list=[]) + assert not s.rotations + 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""" diff --git a/tests/test_simulate.py b/tests/test_simulate.py index 0b23871a..ea7659c7 100644 --- a/tests/test_simulate.py +++ b/tests/test_simulate.py @@ -31,6 +31,7 @@ class TestSimulate: "days": None, "signal_time_dif": 10, "include_price_csv": None, + "rotation_filter_variable": None, "seed": None, "default_buffer_time_opps": 0, "desired_soc_opps": 1,