From 6e68af492346dd68fd73093b4fd0b4066d296dfd Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Wed, 31 Jul 2024 12:37:37 +0200 Subject: [PATCH] add load_pickle mode and create_pickle_in_report option --- data/examples/simba.cfg | 7 ++++++- requirements.txt | 1 + simba/report.py | 11 +++++++++++ simba/simulate.py | 42 ++++++++++++++++++++++++++++++----------- simba/util.py | 7 ++++++- 5 files changed, 55 insertions(+), 13 deletions(-) diff --git a/data/examples/simba.cfg b/data/examples/simba.cfg index 82ef0801..c6c5eb08 100644 --- a/data/examples/simba.cfg +++ b/data/examples/simba.cfg @@ -38,7 +38,7 @@ rotation_filter = data/examples/rotation_filter.csv # recombination splits and merges rotations to use the optimal number of busses # report generates simulation output files, including costs. mode = ["sim", "report"] -#mode = ["sim", "neg_depb_to_oppb", "service_optimization", "station_optimization", "remove_negative", "split_negative_depb", "report"] +#mode = ["sim", "load_pickle", "neg_depb_to_oppb", "service_optimization", "station_optimization", "remove_negative", "split_negative_depb", "report"] ##### Flags ##### ### Activate optional functions ### @@ -58,6 +58,11 @@ show_plots = false 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 = "example.pkl" + ##### Charging strategy ##### # Preferred charging type. Options: depb, oppb (default: depb) diff --git a/requirements.txt b/requirements.txt index 25e02659..6b80e00d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ numpy >= 1.12.0 matplotlib -e git+https://github.com/rl-institut/spice_ev.git@dev#egg=spice_ev pandas +dill \ No newline at end of file diff --git a/simba/report.py b/simba/report.py index f2a2a364..dc5bbc6e 100644 --- a/simba/report.py +++ b/simba/report.py @@ -2,10 +2,12 @@ import csv import datetime import logging +import dill as pickle import re from typing import Iterable import matplotlib.pyplot as plt +from simba.trip import Trip from spice_ev.report import aggregate_global_results, plot, generate_reports @@ -294,6 +296,15 @@ def generate(schedule, scenario, args): file_path = args.results_directory / "trips.csv" write_csv(generate_trips_timeseries_data(schedule), file_path) + if vars(args).get('create_pickle_in_report', False): + file_path = args.results_directory / "scenario.pkl" + with file_path.open('wb') as f: + pickle.dump({ + "schedule": schedule, + "scenario": scenario, + "consumption": Trip.consumption, + }, f) + # summary of used vehicle types and all costs if args.cost_calculation: file_path = args.results_directory / "summary_vehicles_costs.csv" diff --git a/simba/simulate.py b/simba/simulate.py index 67092284..2d590e47 100644 --- a/simba/simulate.py +++ b/simba/simulate.py @@ -1,4 +1,5 @@ import logging +import dill as pickle import traceback from simba import report, optimization, util @@ -22,8 +23,16 @@ def simulate(args): :return: final schedule and scenario :rtype: tuple """ - schedule = pre_simulation(args) - scenario = schedule.run(args) + args.cost_parameters = load_cost_parameters_file(args.cost_parameters_file) + if vars(args).get("load_pickle"): + # load pickle file: skip pre_simulation + assert args.mode[0] == "load_pickle", "Load pickle: first mode must be load_pickle" + # schedule and scenario read out from pickle file in first mode + schedule = None + scenario = "pickle" # must not be None + else: + schedule = pre_simulation(args) + scenario = schedule.run(args) return modes_simulation(schedule, scenario, args) @@ -54,15 +63,6 @@ def pre_simulation(args): raise Exception(f"Path to electrified stations ({args.electrified_stations}) " "does not exist. Exiting...") - # load cost parameters - if args.cost_parameters_file is not None: - try: - with open(args.cost_parameters_file, encoding='utf-8') as f: - args.cost_parameters = util.uncomment_json_file(f) - except FileNotFoundError: - raise Exception(f"Path to cost parameters ({args.cost_parameters_file}) " - "does not exist. Exiting...") - # setup consumption calculator that can be accessed by all trips Trip.consumption = Consumption( vehicle_types, @@ -81,6 +81,18 @@ def pre_simulation(args): return schedule +def load_cost_parameters_file(file_path): + # load cost parameters + # needed for both normal simulation and load_pickle + if file_path is None: + return None + try: + with open(file_path, encoding='utf-8') as f: + return util.uncomment_json_file(f) + except FileNotFoundError: + raise Exception(f"Path to cost parameters ({file_path}) does not exist. Exiting...") + + def modes_simulation(schedule, scenario, args): """ Run the mode(s) specified in config. @@ -226,6 +238,14 @@ def split_negative_depb(schedule, scenario, args, _i): scenario = recombined_schedule.run(args) return recombined_schedule, scenario + def load_pickle(_schedule=None, _scenario=None, args=None, _i=None): + with open(args.load_pickle, 'rb') as f: + unpickle = pickle.load(f) + schedule = unpickle["schedule"] + scenario = unpickle["scenario"] + Trip.consumption = unpickle["consumption"] + return schedule, scenario + def report(schedule, scenario, args, i): if args.output_directory is None: return schedule, scenario diff --git a/simba/util.py b/simba/util.py index 2c2ffe61..10e7ce5a 100644 --- a/simba/util.py +++ b/simba/util.py @@ -279,12 +279,13 @@ def get_args(): # #### Modes ##### mode_choices = [ - 'sim', 'neg_depb_to_oppb', 'neg_oppb_to_depb', 'service_optimization', + 'sim', 'load_pickle', 'neg_depb_to_oppb', 'neg_oppb_to_depb', 'service_optimization', 'station_optimization', 'remove_negative', 'split_negative_depb', 'report'] parser.add_argument('--mode', default=['sim', 'report'], nargs='*', choices=mode_choices, help=f"Specify what you want to do. Choose one or more from \ {', '.join(mode_choices)}. \ sim runs a single simulation with the given inputs. \ + load_pickle loads files specified in load_pickle argument. \ neg_depb_to_oppb changes charging type of negative depb rotations. \ neg_oppb_to_depb changes charging type of negative oppb rotations. \ service optimization finds the largest set of electrified rotations. \ @@ -307,6 +308,10 @@ def get_args(): 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('--create-pickle-in-report', action='store_true', + help='Pickle current schedule and scenario during report mode') + parser.add_argument('--load-pickle', + help='Load given pickle file, expects load_pickle as first mode') parser.add_argument('--rotation-filter-variable', default=None, choices=[None, 'include', 'exclude'], help='set mode for filtering schedule rotations')