diff --git a/data/examples/simba.cfg b/data/examples/simba.cfg index d0dbfa9..a739a53 100644 --- a/data/examples/simba.cfg +++ b/data/examples/simba.cfg @@ -4,15 +4,15 @@ scenario_name = example ##### Paths ##### ### Input and output files and paths ### # Input file containing trip information (required) -input_schedule = data/examples/trips_example.csv +schedule_path = data/examples/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_directory = null -output_directory = data/output/ +output_path = data/output/ # Electrified stations (required) -electrified_stations = data/examples/electrified_stations.json +electrified_stations_path = data/examples/electrified_stations.json # Vehicle types (defaults to: ./data/examples/vehicle_types.json) -vehicle_types = data/examples/vehicle_types.json +vehicle_types_path = data/examples/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 @@ -23,11 +23,11 @@ outside_temperature_over_day_path = data/examples/default_temp_winter.csv # (Optional: needed if mileage in vehicle types not constant) level_of_loading_over_day_path = data/examples/default_level_of_loading_over_day.csv # Path to configuration file for the station optimization. Only needed for mode "station_optimization" -optimizer_config = data/examples/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_file = data/examples/cost_params.json +cost_parameters_path = data/examples/cost_params.json # Path to rotation filter -rotation_filter = data/examples/rotation_filter.csv +rotation_filter_path = data/examples/rotation_filter.csv ##### Modes ##### ### Specify how you want to simulate the scenario ### diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 85ed29d..a9daedf 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -212,6 +212,8 @@ To make use of this feature the parameters in the optimizer.cfg have to be set. decision_tree_path = data/last_optimization.pickle save_decision_tree = True +.. _optimizer_config: + Optimizer Configuration ################################### The functionality of the optimizer is controlled through the optimizer.cfg specified in the simba.cfg used for calling SimBA. diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 3ce450f..fb37433 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -32,11 +32,11 @@ The example (data/simba.cfg) contains parameter descriptions which are explained - Optional: no default given - string - scenario identifier, appended to output directory name and report file names - * - input_schedule + * - schedule_path - Mandatory: no default given - Path as string - Input file containing :ref:`schedule` information - * - Output_directory + * - output_path - Data/sim_outputs - Path as string - Output files are stored here; set to null to deactivate @@ -44,7 +44,7 @@ The example (data/simba.cfg) contains parameter descriptions which are explained - ./data/examples/vehicle_types.json - Path as string - Path to Electrified stations data - * - vehicle_types + * - vehicle_types_path - ./data/examples/vehicle_types.json - Path as string - Path to :ref:`vehicle_types` @@ -60,10 +60,18 @@ The example (data/simba.cfg) contains parameter descriptions which are explained - Optional: no default given - Path as string - Path to :ref:`level_of_loading` - * - cost_parameters_file + * - cost_parameters_path - Optional: no default given - Path as string - Path to :ref:`cost_params` + * - optimizer_config_path + - Optional: no default given + - Path as string + - Path to station optimizer config :ref:`optimizer_config` + * - rotation_filter_path + - Optional: no default given + - Path as string + - Path to rotation filter json * - mode - ['sim', 'report'] - List of modes is any order in range of ['sim', 'neg_depb_to_oppb', 'neg_oppb_to_depb', 'service_optimization', 'report'] diff --git a/simba/__main__.py b/simba/__main__.py index 619a2de..2beb90c 100644 --- a/simba/__main__.py +++ b/simba/__main__.py @@ -14,19 +14,19 @@ dir_name = time_str + '_' + args.scenario_name else: dir_name = time_str - if args.output_directory is not None: - args.output_directory = Path(args.output_directory) / dir_name + if args.output_path is not None: + args.output_path = Path(args.output_path) / dir_name # create subfolder for specific sim results with timestamp. # if folder doesn't exist, create folder. # needs to happen after set_options_from_config since - # args.output_directory can be overwritten by config - args.output_directory_input = args.output_directory / "input_data" + # args.output_path can be overwritten by config + args.output_directory_input = args.output_path / "input_data" try: args.output_directory_input.mkdir(parents=True, exist_ok=True) except NotADirectoryError: # can't create new directory (may be write protected): no output - args.output_directory = None - if args.output_directory is not None: + args.output_path = None + if args.output_path is not None: # copy input files to output to ensure reproducibility copy_list = [args.config, args.electrified_stations_path, args.vehicle_types_path] if "station_optimization" in args.mode: diff --git a/simba/data_container.py b/simba/data_container.py index f41fd1d..f586971 100644 --- a/simba/data_container.py +++ b/simba/data_container.py @@ -35,14 +35,13 @@ def __init__(self): def fill_with_args(self, args: argparse.Namespace) -> 'DataContainer': """ Fill DataContainer with data from file_paths defined in args. - :param args: Arguments containing paths for input_schedule, vehicle_types_path, + :param args: Arguments containing paths for schedule_path, vehicle_types_path, electrified_stations_path, cost_parameters_path, outside_temperature_over_day_path, level_of_loading_over_day_path, station_data_path :return: self """ - return self.fill_with_paths( - trips_file_path=args.input_schedule, + trips_file_path=args.schedule_path, vehicle_types_path=args.vehicle_types_path, electrified_stations_path=args.electrified_stations_path, cost_parameters_path=args.cost_parameters_path, diff --git a/simba/schedule.py b/simba/schedule.py index 26afc58..69e15f7 100644 --- a/simba/schedule.py +++ b/simba/schedule.py @@ -152,9 +152,9 @@ def from_datacontainer(cls, data: DataContainer, args): if vars(args).get("check_rotation_consistency"): # check rotation expectations inconsistent_rotations = cls.check_consistency(schedule) - if inconsistent_rotations and args.output_directory is not None: + if inconsistent_rotations and args.output_path is not None: # write errors to file - filepath = args.output_directory / "inconsistent_rotations.csv" + filepath = args.output_path / "inconsistent_rotations.csv" with open(filepath, "w", encoding='utf-8') as f: for rot_id, e in inconsistent_rotations.items(): f.write(f"Rotation {rot_id}: {e}\n") @@ -223,7 +223,7 @@ def run(self, args, mode="distributed"): For external usage the core run functionality is accessible through this function. It allows for defining a custom-made assign_vehicles method for the schedule. - :param args: used arguments are rotation_filter, path to rotation ids, + :param args: used arguments are rotation_filter_path, path to rotation ids, and rotation_filter_variable that sets mode (options: include, exclude) :type args: argparse.Namespace :param mode: SpiceEV strategy name @@ -800,7 +800,7 @@ def get_total_distance(self): 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, + :param args: used arguments are rotation_filter_path, path to rotation ids, and rotation_filter_variable that sets mode (options: include, exclude) :type args: argparse.Namespace :param rf_list: rotation filter list with strings of rotation ids (default is None) @@ -812,18 +812,18 @@ def rotation_filter(self, args, rf_list=[]): # 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: + if args.rotation_filter_path 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: + if args.rotation_filter_path: # read out rotations from file (one rotation ID per line) try: - with open(args.rotation_filter, encoding='utf-8') as f: + with open(args.rotation_filter_path, 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.") + warnings.warn(f"Path to rotation filter {args.rotation_filter_path} is invalid.") # no file, no change return # filter out rotations in self.rotations diff --git a/simba/simulate.py b/simba/simulate.py index 01139e8..c05dbaf 100644 --- a/simba/simulate.py +++ b/simba/simulate.py @@ -117,7 +117,7 @@ def modes_simulation(schedule, scenario, args): if scenario is not None and scenario.step_i > 0: # generate plot of failed scenario args.mode = args.mode[:i] + ["ABORTED"] - if args.output_directory is None: + if args.output_path is None: create_results_directory(args, i+1) if not args.skip_plots: report.generate_plots(scenario, args) @@ -260,7 +260,7 @@ def split_negative_depb(schedule, scenario, args, _i): @staticmethod def report(schedule, scenario, args, i): - if args.output_directory is None: + if args.output_path is None: return schedule, scenario # create report based on all previous modes @@ -288,12 +288,12 @@ def create_results_directory(args, i): :type i: int """ - if args.output_directory is None: + if args.output_path is None: return prior_reports = sum([m.count('report') for m in args.mode[:i]]) report_name = f"report_{prior_reports+1}" - args.results_directory = args.output_directory.joinpath(report_name) + args.results_directory = args.output_path.joinpath(report_name) args.results_directory.mkdir(parents=True, exist_ok=True) # save used modes in report version used_modes = ['sim'] + [m for m in args.mode[:i] if m not in ['sim', 'report']] diff --git a/simba/util.py b/simba/util.py index 161cba5..706350a 100644 --- a/simba/util.py +++ b/simba/util.py @@ -262,7 +262,7 @@ def cast_float_or_none(val: any) -> any: def setup_logging(args, time_str): """ Setup logging. - :param args: command line arguments. Used: logfile, loglevel, output_directory + :param args: command line arguments. Used: logfile, loglevel, output_path :type args: argparse.Namespace :param time_str: log file name if args.logfile is not given :type time_str: str @@ -272,13 +272,14 @@ def setup_logging(args, time_str): console = logging.StreamHandler() console.setLevel(log_level) log_handlers = [console] - if args.logfile is not None and args.output_directory is not None: + + if args.logfile is not None and args.output_path is not None: # optionally to file in output dir if args.logfile: log_name = args.logfile else: log_name = f"{time_str}.log" - log_path = args.output_directory / log_name + log_path = args.output_path / log_name print(f"Writing log to {log_path}") file_logger = logging.FileHandler(log_path, encoding='utf-8') log_level_file = vars(logging).get((args.loglevel_file or args.loglevel).upper()) @@ -340,28 +341,41 @@ def get_buffer_time(trip, default=0): def replace_deprecated_arguments(args): - if args.electrified_stations is not None: - assert args.electrified_stations_path is None, \ - "Multiple electrified stations are not supported." - logging.warning("The parameter 'electrified_stations' is deprecated. " - "Use 'electrified_stations_path 'instead.") - args.electrified_stations_path = args.electrified_stations - del args.electrified_stations - - if args.vehicle_types is not None: - logging.warning("The parameter 'vehicle_types' is deprecated. " - "Use 'vehicle_types_path 'instead. The value of args.vehicle_types_path " - f"{args.vehicle_types_path} is replaced with {args.vehicle_types}.") - args.vehicle_types_path = args.vehicle_types - del args.vehicle_types - - if args.cost_parameters_file is not None: - assert args.cost_parameters_path is None, \ - "Multiple cost parameters files are not supported." - logging.warning("The parameter 'cost_parameters_file' is deprecated. " - "Use 'cost_parameters_path 'instead.") - args.cost_parameters_path = args.cost_parameters_file - del args.cost_parameters_file + # handling of args with default values + # Pairs of deprecated names and new names + deprecated_names = [ + ("input_schedule", "schedule_path"), + ("vehicle_types", "vehicle_types_path"), + ("output_directory", "output_path"), + ] + for old, new in deprecated_names: + if vars(args)[old] is not None: + logging.warning( + f"Parameter '{old}' is deprecated. Use '{new}' instead. The value of args.{new}: " + f"{args.__getattribute__(new)} is replaced with {args.__getattribute__(old)} .") + # Replace value of current name with value of deprecated name + args.__setattr__(new, args.__getattribute__(old)) + # delete deprecated name + args.__delattr__(old) + + # Pairs of deprecated names and new names and verbose name + deprecated_names = [ + ("electrified_stations", "electrified_stations_path", "electrified stations paths"), + ("cost_parameters_file", "cost_parameters_path", "costs parameter paths"), + ("rotation_filter", "rotation_filter_path", "rotation filter paths"), + ("optimizer_config", "optimizer_config_path", "station optimizer config paths"), + ] + + for old, new, description in deprecated_names: + if vars(args)[old] is not None: + assert vars(args)[new] is None, \ + f"Multiple {description} are not supported. Found values for {old} and {new}." + logging.warning(f"The parameter '{old}' is deprecated. " + f"Use '{new}' instead.") + # Replace value of current name with value of deprecated name + args.__setattr__(new, args.__getattribute__(old)) + # delete deprecated name + args.__delattr__(old) return args @@ -389,7 +403,7 @@ def get_args(): # rename special options args.timing = args.eta - mandatory_arguments = ["input_schedule", "electrified_stations_path"] + mandatory_arguments = ["schedule_path", "electrified_stations_path"] missing = [a for a in mandatory_arguments if vars(args).get(a) is None] if missing: raise Exception("The following arguments are required: {}".format(", ".join(missing))) @@ -403,9 +417,9 @@ def get_parser(): parser.add_argument('--scenario-name', help='Identifier of scenario, appended to results') # #### Paths ##### - parser.add_argument('--input-schedule', + parser.add_argument('--schedule-path', help='Path to CSV file containing all trips of schedule to be analyzed') - parser.add_argument('--output-directory', default="data/sim_outputs", + 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", @@ -421,7 +435,7 @@ def get_parser(): level of loading in case they are not in trips.csv") parser.add_argument('--cost-parameters-path', default=None, help='include cost parameters json, needed if cost_calculation==True') - parser.add_argument('--rotation-filter', default=None, + parser.add_argument('--rotation-filter-path', default=None, help='Use json data with rotation ids') # #### Modes ##### @@ -456,6 +470,9 @@ def get_parser(): parser.add_argument('--create-scenario-file', help='Write scenario.json to file') parser.add_argument('--create-trips-in-report', action='store_true', help='Write a trips.csv during report mode') + parser.add_argument('--optimizer-config-path', default=None, + help="For station_optimization an optimizer_config is needed. \ + Input a path to an .cfg file or use the default_optimizer.cfg") parser.add_argument('--rotation-filter-variable', default=None, choices=[None, 'include', 'exclude'], help='set mode for filtering schedule rotations') @@ -553,19 +570,25 @@ def get_parser(): parser.add_argument('--include-price-csv-option', '-po', metavar=('KEY', 'VALUE'), nargs=2, default=[], action='append', help='append additional argument to price signals') - parser.add_argument('--optimizer_config', default=None, - help="For station_optimization an optimizer_config is needed. \ - Input a path to an .cfg file or use the default_optimizer.cfg") parser.add_argument('--time-windows', metavar='FILE', help='use peak load windows to force lower power ' 'during times of high grid load') + # Deprecated options for downwards compatibility + parser.add_argument('--input-schedule', default=None, + help='Deprecated use "schedule-path" instead') parser.add_argument('--electrified-stations', default=None, help='Deprecated use "electrified-stations-path" instead') parser.add_argument('--vehicle-types', default=None, help='Deprecated use "vehicle-types-path" instead') parser.add_argument('--cost-parameters-file', default=None, help='Deprecated use "cost-parameters-path" instead') + parser.add_argument('--rotation-filter', default=None, + help='Deprecated use "rotation-filter-path" instead') + parser.add_argument('--output-directory', default=None, + help='Deprecated use "output-path" instead') + parser.add_argument('--optimizer_config', default=None, + help='Deprecated use "optimizer-config-path" instead') parser.add_argument('--config', help='Use config file to set arguments') return parser diff --git a/tests/test_example.py b/tests/test_example.py index 170f634..1241bee 100644 --- a/tests/test_example.py +++ b/tests/test_example.py @@ -15,7 +15,7 @@ def test_example_cfg(self, tmp_path): # 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_directory.+", f"output_directory = {str(tmp_path.as_posix())}", + src_text = re.sub(r"output_path.+", f"output_path = {str(tmp_path.as_posix())}", src_text) dst = tmp_path / "simba.cfg" # don't show plots. spaces are optional, so use regex diff --git a/tests/test_schedule.py b/tests/test_schedule.py index e5848f9..532cebf 100644 --- a/tests/test_schedule.py +++ b/tests/test_schedule.py @@ -198,7 +198,7 @@ def test_assign_vehicles_fixed_recharge(self): args = util.get_args() args.min_recharge_deps_oppb = 1 args.min_recharge_deps_depb = 1 - args.input_schedule = file_root / "trips_assign_vehicles_extended.csv" + 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) @@ -242,7 +242,7 @@ def test_assign_vehicles_adaptive(self): """ sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] args = util.get_args() - args.input_schedule = file_root / "trips_assign_vehicles_extended.csv" + 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) @@ -295,7 +295,7 @@ def test_calculate_consumption(self, default_schedule_arguments): """ sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] args = util.get_args() - args.input_schedule = file_root / "trips_assign_vehicles.csv" + args.schedule_path = file_root / "trips_assign_vehicles.csv" data_container = DataContainer().fill_with_args(args) generated_schedule, args = pre_simulation(args, data_container) @@ -321,7 +321,7 @@ def test_get_common_stations(self, default_schedule_arguments): """ sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] args = util.get_args() - args.input_schedule = file_root / "trips_assign_vehicles.csv" + args.schedule_path = file_root / "trips_assign_vehicles.csv" data_container = DataContainer().fill_with_args(args) generated_schedule, args = pre_simulation(args, data_container) @@ -348,14 +348,14 @@ def test_get_negative_rotations(self): def test_rotation_filter(self, tmp_path): sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] args = util.get_args() - args.input_schedule = file_root / "trips_assign_vehicles.csv" + args.schedule_path = file_root / "trips_assign_vehicles.csv" data_container = DataContainer().fill_with_args(args) s, args = pre_simulation(args, data_container) args = Namespace(**{ "rotation_filter_variable": None, - "rotation_filter": None, + "rotation_filter_path": None, }) # add dummy rotations s.rotations = { @@ -370,25 +370,25 @@ def test_rotation_filter(self, tmp_path): # filtering not disabled, but neither file nor list given -> warning args.rotation_filter_variable = "include" - args.rotation_filter = None + args.rotation_filter_path = 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" + args.rotation_filter_path = 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") + args.rotation_filter_path.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 + args.rotation_filter_path = None s.rotations = deepcopy(s.original_rotations) s.rotation_filter(args, rf_list=['3', '4']) assert sorted(s.rotations.keys()) == ['0', '1', '2', '5'] @@ -401,8 +401,8 @@ def test_rotation_filter(self, tmp_path): # filter nothing s.rotations = deepcopy(s.original_rotations) - args.rotation_filter = tmp_path / "filter.txt" - args.rotation_filter.write_text('') + args.rotation_filter_path = tmp_path / "filter.txt" + args.rotation_filter_path.write_text('') args.rotation_filter_variable = "exclude" s.rotation_filter(args, rf_list=[]) assert s.rotations.keys() == s.original_rotations.keys() diff --git a/tests/test_simulate.py b/tests/test_simulate.py index fb8228c..37519c7 100644 --- a/tests/test_simulate.py +++ b/tests/test_simulate.py @@ -21,7 +21,7 @@ class TestSimulate: "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", - "input_schedule": example_path / "trips_example.csv", + "schedule_path": example_path / "trips_example.csv", "mode": [], "interval": 15, "propagate_mode_errors": True, @@ -34,7 +34,7 @@ class TestSimulate: "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", - "input_schedule": example_path / "trips_example.csv", + "schedule_path": example_path / "trips_example.csv", "mode": [], "min_recharge_deps_oppb": 1, "min_recharge_deps_depb": 1, @@ -144,7 +144,7 @@ def test_mode_report(self, tmp_path): args = self.get_args() args.mode = "report" args.cost_calculation = True - args.output_directory = tmp_path + args.output_path = tmp_path args.strategy_deps = "balanced" args.strategy_opps = "greedy" args.show_plots = False @@ -162,7 +162,7 @@ def test_empty_report(self, tmp_path): args.desired_soc_deps = 0 args.ALLOW_NEGATIVE_SOC = True args.cost_calculation = True - args.output_directory = tmp_path + args.output_path = tmp_path args.show_plots = False with warnings.catch_warnings(): warnings.simplefilter("ignore") @@ -171,7 +171,7 @@ def test_empty_report(self, tmp_path): def test_extended_plot(self, tmp_path): args = self.get_args() args.mode = "report" - args.output_directory = tmp_path + args.output_path = tmp_path args.show_plots = False args.extended_output_plots = True with warnings.catch_warnings(): @@ -192,7 +192,7 @@ def test_create_trips_in_report(self, tmp_path): "desired_soc_deps": 0, "ALLOW_NEGATIVE_SOC": True, "cost_calculation": False, - "output_directory": tmp_path, + "output_path": tmp_path, "show_plots": False, "create_trips_in_report": True, } @@ -204,7 +204,7 @@ def test_create_trips_in_report(self, tmp_path): simulate(Namespace(**args_dict)) # new simulation with generated trips.csv args_dict = vars(self.get_args()) - args_dict["input_schedule"] = tmp_path / "report_1/trips.csv" + args_dict["schedule_path"] = tmp_path / "report_1/trips.csv" simulate(Namespace(**(args_dict))) def test_mode_recombination(self): diff --git a/tests/test_station_optimization.py b/tests/test_station_optimization.py index 3fa822d..66a0303 100644 --- a/tests/test_station_optimization.py +++ b/tests/test_station_optimization.py @@ -115,11 +115,11 @@ def generate_datacontainer_args(self, trips_file_name="trips.csv"): sys.argv = ["foo", "--config", str(example_root / "simba.cfg")] args = util.get_args() - args.output_directory = self.tmp_path + args.output_path = self.tmp_path args.results_directory = self.tmp_path assert self.tmp_path - args.input_schedule = file_root / trips_file_name + args.schedule_path = file_root / trips_file_name data_container = DataContainer().fill_with_args(args) return data_container, args @@ -302,7 +302,7 @@ def test_deep_optimization_extended(self): sched, scen = self.generate_schedule_scenario(args, data_container) # optimization can only be properly tested if negative rotations exist assert len(sched.get_negative_rotations(scen)) > 0 - args.input_schedule = file_root / trips_file_name + args.schedule_path = file_root / trips_file_name config_path = example_root / "default_optimizer.cfg" conf = opt_util.read_config(config_path) @@ -336,7 +336,7 @@ def test_critical_stations_optimization(self, caplog): data_container.stations_data = {} args.preferred_charging_type = "oppb" sched, scen = self.generate_schedule_scenario(args, data_container) - args.input_schedule = file_root / trips_file_name + args.schedule_path = file_root / trips_file_name config_path = example_root / "default_optimizer.cfg" conf = opt_util.read_config(config_path)