From cc8fe19260507034945f282b9cc75d98e8afd3a4 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 18 Jan 2023 11:32:14 +0100 Subject: [PATCH 01/58] First basic running version of geoplotting --- ebus_toolbox/plot_geoposition.py | 317 +++++++++++++++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 ebus_toolbox/plot_geoposition.py diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py new file mode 100644 index 00000000..7124d34d --- /dev/null +++ b/ebus_toolbox/plot_geoposition.py @@ -0,0 +1,317 @@ +""" Module to implement plotting functionality of busses with georeferences""" +import datetime + +import ebus_toolbox.util as util +import pickle +import csv +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import ebus_toolbox.trip + import ebus_toolbox.schedule + import spiceev.scenario + +import requests +import json +from time import sleep +import io + +import matplotlib.pyplot as plt +import pandas as pd +from matplotlib.colors import LinearSegmentedColormap +import numpy as np +import matplotlib.pyplot as plt +import pandas as pd + +import math + +# Mathematical function we need to plot +from matplotlib.colors import LinearSegmentedColormap +import matplotlib +import matplotlib.animation as animation +matplotlib.use("TkAgg") +import os +shared_axis=None +FIGSIZE=(14,5) +LINEWIDTH=2 +DELIMITER = ';' +FRAMEALPHA=0.8 +ALPHA_POINTS=0.1 + + +### +rli_dblue =(0, 46 / 255, 80 / 255) +rli_green=(68 / 255, 175 / 255, 105 / 255) +rli_orange=(254 / 255, 127 / 255, 45 / 255) +rli_yellow=(241 / 255, 196 / 255, 15 / 255) +rli_lblue=(34/ 255, 116 / 255, 165 / 255) +rli_dgrey=(51 / 255, 88 / 255, 115 / 255) +### Not from official coperate design +rli_red =(192/255,0,0) +rli_green2 =(0, 176/255,80/255) +rli_brown = (132 / 255, 60 / 255, 12 / 255) +rli_black=(0,0,0) +rli_colors = [rli_dblue, rli_green, rli_orange, rli_yellow,rli_lblue, rli_dgrey,rli_black,rli_red, rli_brown,rli_green2] +### + +cdict = {'red': [[0.0, 0, 0], + [0.2, 34/255, 34/255], + [0.4, 68/255, 68/255], + [0.6, 254/255, 254/255], + [0.8, 241/255, 241/255], + [1.0, 255/255, 255/255]], + 'green': [[0.0, 46/255, 46/255], + [0.2, 116/255, 116/255], + [0.4, 175/255, 175/255], + [0.6, 127/255, 127/255], + [0.8, 196/255, 196/255], + [1.0, 255/255, 255/255]], + 'blue': [[0.0, 80/255, 80/255], + [0.2, 165/255, 165/255], + [0.4, 105/255, 105/255], + [0.6, 45/255, 45/255], + [0.8, 15/255, 15/255], + [1.0, 255/255, 255/255]]} +rli_rainbow_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) + +cdict = {'red': [[0.0, 0, 0], + [0.33, 0, 0], + [0.66, 34/255, 34/255], + [1, 255/255, 255/255]], + 'green': [[0.0, 0, 0], + [0.33, 46/255, 46/255], + [0.66, 116/255, 116/255], + [1, 255/255, 255/255]], + 'blue': [[0.0, 0, 0], + [0.33, 80/255, 80/255], + [0.66, 165/255, 165/255], + [1, 255/255, 45/255]]} +rli_blue_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) + +with open("schedule_opt.pickle", "rb") as file: + schedule = pickle.load(file) + +with open("scenario_opt.pickle", "rb") as file: + scenario = pickle.load(file) + +with open("args_buffered_all_depb.pickle", "rb") as file: + args = pickle.load(file) + +args.station_data_path= "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/data/buffered_all_stations.csv" + +class station: + def __init__(self, name, lat, lon, elevation): + self.name = name + self.lat = lat + self.lon = lon + self.elevation = elevation + + def get_lat_lon(self, next_station, rel_pos): + lat_pos= (next_station.lat-self.lat)*rel_pos+self.lat + lon_pos = (next_station.lon - self.lon) * rel_pos + self.lon + return lat_pos, lon_pos + + +with open(str(args.station_data_path), "r", encoding='utf-8') as f: + delim = util.get_csv_delim(args.station_data_path) + reader = csv.DictReader(f, delimiter=delim) + stations = dict() + for row in reader: + elevation = float(row['elevation']) + name = str(row['Endhaltestelle']) + lon = float(row['lon']) + lat = float(row['lat']) + stations[name]=station(name, lat, lon, elevation) + +def get_sorted_rotations(v_id, schedule): + rots=[] + for rot in schedule.rotations.values(): + if rot.vehicle_id==v_id: + rots.append(rot) + return sorted(rots, key= lambda x: x.departure_time) + + +def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, + save=False, repeat=True, vehicle_black=False, track_black=True): + v_max=1 + v_min=0 + fig = plt.figure(figsize=(14, 8)) + + fig.suptitle('Vehicle Tracking', fontsize=14) + + sub2 = fig.add_subplot(111) + ax = plt.gca() + data.xs("lat", level="Data", axis=1) + lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(),data.xs("lat", level="Data", axis=1).max().max()) + lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(),data.xs("lon", level="Data", axis=1).max().max()) + + # Get all the vehicle ids from data + vehicles = list(data.columns.levels[0]) + data_rounded = data.copy() + + round_decimals = 3 #4 decimals approx 110m in germany + all_lats=[] + all_lons=[] + # for v_id in vehicles: + # data_rounded.loc[:, (v_id, "lat")] = data_rounded[v_id]["lat"].round(round_decimals) + # data_rounded.loc[:, (v_id, "lon")]= data_rounded[v_id]["lon"].round(round_decimals) + # all_lats.extend(data_rounded[v_id]["lat"]) + # all_lons.extend(data_rounded[v_id]["lon"]) + # + # all_geos=np.array((all_lats, all_lons)) + # all_geos_unique=np.unique(all_geos, axis=1) + # # Plot track on the canvas + # if track_black: + # plot_dict = dict(color=(0, 0, 0), alpha=0.1) + # else: + # plot_dict = dict(c=data[v_id]['soc'] * 100, alpha=0.01) + # + # lns2_1 = sub2.scatter(all_geos_unique[0,:],all_geos_unique[1,:], + # **plot_dict, linestyle='-', + # linewidth=0, vmin=v_min, vmax=v_max) + # lns2_1.set_clim(vmin=v_min, vmax=v_max) + + + for v_id in vehicles: + if track_black: + plot_dict = dict(color=(0.9, 0.9, 0.9), alpha=1) + # lns2_1 = sub2.plot(data[v_id]['lat'], data[v_id]['lon'], + # **plot_dict, linestyle='-', + # linewidth=2) + lns2_1 = sub2.scatter(data[v_id]['lat'], data[v_id]['lon'], + **plot_dict, linestyle='-', + linewidth=2, s=0, vmin=v_min, vmax=v_max) + else: + plot_dict = dict(c=data[v_id]['soc'] * 100, alpha=0.01) + lns2_1 = sub2.scatter(data[v_id]['lat'], data[v_id]['lon'], + **plot_dict, linestyle='-', + linewidth=0, vmin=v_min, vmax=v_max) + lns2_1.set_clim(vmin=v_min, vmax=v_max) + + # Helper plot so we can plot a colorbar aftwards, not possible with only line plot + # lns2_1 = sub2.scatter([], [], + # **plot_dict, linestyle='-', + # linewidth=0, vmin=v_min, vmax=v_max) + + + cbar = fig.colorbar(lns2_1, ax=ax, pad=0.0) + cbar.set_alpha(1) + cbar.draw_all() + cbar.set_label("SOC") + + sub2.set_ylabel('Position') + sub2.set_xlabel('Position') + + artist_objects=[] + for _ in vehicles: + lns2_1 = sub2.scatter([0, 0], [0, 0], [0, 100]) + artist_objects.append(lns2_1) + + d_bound=0.001 + sub2.set_ylim((lon_boundary[0]-d_bound, lon_boundary[1]+d_bound)) + sub2.set_xlim((lat_boundary[0]-d_bound, lat_boundary[1]+d_bound)) + + def animate(i, data , counter=[]): + roll_v = 3 + len_v = 5 + vehicles = list(data.columns.levels[0]) + if not counter: + counter.append(i) + else: + counter[0] +=1 + i =counter[0] + start_index=i*roll_v + end_index=start_index+len_v + + for k, v_id in enumerate(vehicles): + artist_objects[k].remove() + if vehicle_black: + plot_dict = dict(color=(0, 0, 0)) + else: + mean_soc = data[v_id]["soc"][start_index:end_index].mean() + l = len(data[v_id]["lat"][start_index:end_index]) + plot_dict = dict(c=mean_soc * np.ones(l)) + artist_objects[k] = sub2.scatter(data[v_id]["lat"][start_index:end_index], + data[v_id]["lon"][start_index:end_index], + **plot_dict, + vmin=0, vmax=1, + linestyle='-', + linewidth=0) + if end_index >= len(data[v_id]["soc"]): + counter[0]=0 + + return artist_objects + + ax.axis('off') + # create animation using the animate() function + myAnimation = animation.FuncAnimation(fig, + lambda i: animate(i, data), + frames=10, + interval=50, blit=False, repeat=repeat) + # + sub2.set_ylabel('Position') + sub2.set_xlabel('Position') + + # y_d = (y_max - y_min) * 0.02 + # x_d = (x_max - x_min) * 0.02 + # sub2.set_ylim((y_min - y_d, y_max + y_d)) + # sub2.set_xlim((x_min - x_d, x_max + x_d)) + + # Toggle Comment of for saving + if save: + myAnimation.save('SOC_Animation_all_OLIA_w_locations.gif', writer='imagemagick') + + fig.tight_layout() + + plt.show() + +def find_current_trip(trips, current_time): + for i, trip in enumerate(trips): + try: + next_trip = trips[i + 1] + if next_trip.departure_time>current_time: + return trip, i + except IndexError: + return trip, i + else: + raise Exception("no trip found for time: " + str(current_time)) + +def get_rel_time_of_trip(current_time: datetime.datetime, current_trip: 'ebus_toolbox.trip.Trip'): + rel_time=(current_time-current_trip.departure_time)/\ + (current_trip.arrival_time-current_trip.departure_time) + return min(1,max(rel_time,0)) + +start_time=scenario.start_time +time_step = datetime.timedelta(hours=1/scenario.stepsPerHour) + +vehicle_data_frames=pd.DataFrame() +c = 0 +for v_id, soc_data in scenario.vehicle_socs.items(): + rotations=get_sorted_rotations(v_id, schedule) + trips = [trip for rot in rotations for trip in rot.trips ] + lats = [] + lons = [] + trip_nr=0 + for counter, soc in enumerate(soc_data): + try: + current_time=start_time+counter*time_step + current_trip, found_trip_index = find_current_trip(trips[trip_nr:],current_time) + trip_nr += found_trip_index + rel_time_of_trip=get_rel_time_of_trip(current_time, current_trip) + current_station = stations[current_trip.departure_name] + next_station = stations[current_trip.arrival_name] + lat, lon = current_station.get_lat_lon(next_station,rel_time_of_trip) + lats.append(lat) + lons.append(lon) + except IndexError: + pass + columns=[(v_id, "soc"), (v_id, "lat") , (v_id, "lon")] + data = np.array([soc_data, lats, lons]).transpose() + vehicle_data_frames=pd.concat((vehicle_data_frames, pd.DataFrame(data ,columns=columns)),axis=1) + c +=1 + if c>4: + break + + +vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, names=['Vehicle_id','Data']) +plot_merge_animate_battery(vehicle_data_frames) From bf70a3054da7e8ac9ae23407c46d7ecc56e5973c Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 18 Jan 2023 17:24:59 +0100 Subject: [PATCH 02/58] Track as line, annotations and more --- ebus_toolbox/plot_geoposition.py | 337 ++++++++++++++++--------------- 1 file changed, 175 insertions(+), 162 deletions(-) diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py index 7124d34d..e486eab3 100644 --- a/ebus_toolbox/plot_geoposition.py +++ b/ebus_toolbox/plot_geoposition.py @@ -1,6 +1,8 @@ """ Module to implement plotting functionality of busses with georeferences""" import datetime +from matplotlib.offsetbox import TextArea, AnnotationBbox + import ebus_toolbox.util as util import pickle import csv @@ -29,63 +31,65 @@ from matplotlib.colors import LinearSegmentedColormap import matplotlib import matplotlib.animation as animation + matplotlib.use("TkAgg") import os -shared_axis=None -FIGSIZE=(14,5) -LINEWIDTH=2 -DELIMITER = ';' -FRAMEALPHA=0.8 -ALPHA_POINTS=0.1 +shared_axis = None +FIGSIZE = (14, 5) +LINEWIDTH = 2 +DELIMITER = ';' +FRAMEALPHA = 0.8 +ALPHA_POINTS = 0.1 ### -rli_dblue =(0, 46 / 255, 80 / 255) -rli_green=(68 / 255, 175 / 255, 105 / 255) -rli_orange=(254 / 255, 127 / 255, 45 / 255) -rli_yellow=(241 / 255, 196 / 255, 15 / 255) -rli_lblue=(34/ 255, 116 / 255, 165 / 255) -rli_dgrey=(51 / 255, 88 / 255, 115 / 255) +rli_dblue = (0, 46 / 255, 80 / 255) +rli_green = (68 / 255, 175 / 255, 105 / 255) +rli_orange = (254 / 255, 127 / 255, 45 / 255) +rli_yellow = (241 / 255, 196 / 255, 15 / 255) +rli_lblue = (34 / 255, 116 / 255, 165 / 255) +rli_dgrey = (51 / 255, 88 / 255, 115 / 255) ### Not from official coperate design -rli_red =(192/255,0,0) -rli_green2 =(0, 176/255,80/255) +rli_red = (192 / 255, 0, 0) +rli_green2 = (0, 176 / 255, 80 / 255) rli_brown = (132 / 255, 60 / 255, 12 / 255) -rli_black=(0,0,0) -rli_colors = [rli_dblue, rli_green, rli_orange, rli_yellow,rli_lblue, rli_dgrey,rli_black,rli_red, rli_brown,rli_green2] +rli_black = (0, 0, 0) +rli_colors = [rli_dblue, rli_green, rli_orange, rli_yellow, rli_lblue, rli_dgrey, rli_black, + rli_red, rli_brown, rli_green2] ### -cdict = {'red': [[0.0, 0, 0], - [0.2, 34/255, 34/255], - [0.4, 68/255, 68/255], - [0.6, 254/255, 254/255], - [0.8, 241/255, 241/255], - [1.0, 255/255, 255/255]], - 'green': [[0.0, 46/255, 46/255], - [0.2, 116/255, 116/255], - [0.4, 175/255, 175/255], - [0.6, 127/255, 127/255], - [0.8, 196/255, 196/255], - [1.0, 255/255, 255/255]], - 'blue': [[0.0, 80/255, 80/255], - [0.2, 165/255, 165/255], - [0.4, 105/255, 105/255], - [0.6, 45/255, 45/255], - [0.8, 15/255, 15/255], - [1.0, 255/255, 255/255]]} +cdict = {'red': [[0.0, 0, 0], + [0.2, 34 / 255, 34 / 255], + [0.4, 68 / 255, 68 / 255], + [0.6, 254 / 255, 254 / 255], + [0.8, 241 / 255, 241 / 255], + [1.0, 255 / 255, 255 / 255]], + 'green': [[0.0, 46 / 255, 46 / 255], + [0.2, 116 / 255, 116 / 255], + [0.4, 175 / 255, 175 / 255], + [0.6, 127 / 255, 127 / 255], + [0.8, 196 / 255, 196 / 255], + [1.0, 255 / 255, 255 / 255]], + 'blue': [[0.0, 80 / 255, 80 / 255], + [0.2, 165 / 255, 165 / 255], + [0.4, 105 / 255, 105 / 255], + [0.6, 45 / 255, 45 / 255], + [0.8, 15 / 255, 15 / 255], + [1.0, 255 / 255, 255 / 255]]} rli_rainbow_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) -cdict = {'red': [[0.0, 0, 0], - [0.33, 0, 0], - [0.66, 34/255, 34/255], - [1, 255/255, 255/255]], - 'green': [[0.0, 0, 0], - [0.33, 46/255, 46/255], - [0.66, 116/255, 116/255], - [1, 255/255, 255/255]], - 'blue': [[0.0, 0, 0], - [0.33, 80/255, 80/255], - [0.66, 165/255, 165/255], - [1, 255/255, 45/255]]} +cdict = {'red': [[0.0, 0, 0], + [0.33, 0, 0], + [0.66, 34 / 255, 34 / 255], + [1, 255 / 255, 255 / 255]], + 'green': [[0.0, 0, 0], + [0.33, 46 / 255, 46 / 255], + [0.66, 116 / 255, 116 / 255], + [1, 255 / 255, 255 / 255]], + 'blue': [[0.0, 0, 0], + [0.33, 80 / 255, 80 / 255], + [0.66, 165 / 255, 165 / 255], + [1, 255 / 255, 45 / 255]]} rli_blue_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) with open("schedule_opt.pickle", "rb") as file: @@ -97,7 +101,63 @@ with open("args_buffered_all_depb.pickle", "rb") as file: args = pickle.load(file) -args.station_data_path= "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/data/buffered_all_stations.csv" +args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/data/buffered_all_stations.csv" + + +def main(): + with open(str(args.station_data_path), "r", encoding='utf-8') as f: + delim = util.get_csv_delim(args.station_data_path) + reader = csv.DictReader(f, delimiter=delim) + stations = dict() + for row in reader: + elevation = float(row['elevation']) + name = str(row['Endhaltestelle']) + lon = float(row['lon']) + lat = float(row['lat']) + stations[name] = station(name, lat, lon, elevation) + + start_time = scenario.start_time + time_step = datetime.timedelta(hours=1 / scenario.stepsPerHour) + + vehicle_data_frames = pd.DataFrame() + c = 0 + for v_id, soc_data in scenario.vehicle_socs.items(): + rotations = get_sorted_rotations(v_id, schedule) + trips = [trip for rot in rotations for trip in rot.trips] + lats = [] + lons = [] + trip_nr = 0 + for counter, soc in enumerate(soc_data): + try: + current_time = start_time + counter * time_step + current_trip, found_trip_index = find_current_trip(trips[trip_nr:], current_time) + trip_nr += found_trip_index + rel_time_of_trip = get_rel_time_of_trip(current_time, current_trip) + current_station = stations[current_trip.departure_name] + next_station = stations[current_trip.arrival_name] + lat, lon = current_station.get_lat_lon(next_station, rel_time_of_trip) + lats.append(lat) + lons.append(lon) + except IndexError: + pass + columns = [(v_id, "soc"), (v_id, "lat"), (v_id, "lon")] + data = np.array([soc_data, lats, lons]).transpose() + vehicle_data_frames = pd.concat((vehicle_data_frames, pd.DataFrame(data, columns=columns)), + axis=1) + # c += 1 + # if c > 2: + # break + + vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, + names=['Vehicle_id', 'Data']) + + vehicle_data_frames.index = np.arange(start_time, start_time + + len(vehicle_data_frames) * time_step, time_step) + + stations_to_annotate = {name: stat for name, stat in stations.items() if + name in schedule.stations} + plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, save=True, repeat=False) + class station: def __init__(self, name, lat, lon, elevation): @@ -107,34 +167,23 @@ def __init__(self, name, lat, lon, elevation): self.elevation = elevation def get_lat_lon(self, next_station, rel_pos): - lat_pos= (next_station.lat-self.lat)*rel_pos+self.lat + lat_pos = (next_station.lat - self.lat) * rel_pos + self.lat lon_pos = (next_station.lon - self.lon) * rel_pos + self.lon return lat_pos, lon_pos -with open(str(args.station_data_path), "r", encoding='utf-8') as f: - delim = util.get_csv_delim(args.station_data_path) - reader = csv.DictReader(f, delimiter=delim) - stations = dict() - for row in reader: - elevation = float(row['elevation']) - name = str(row['Endhaltestelle']) - lon = float(row['lon']) - lat = float(row['lat']) - stations[name]=station(name, lat, lon, elevation) - def get_sorted_rotations(v_id, schedule): - rots=[] + rots = [] for rot in schedule.rotations.values(): - if rot.vehicle_id==v_id: + if rot.vehicle_id == v_id: rots.append(rot) - return sorted(rots, key= lambda x: x.departure_time) + return sorted(rots, key=lambda x: x.departure_time) -def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, +def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, station_data=None, save=False, repeat=True, vehicle_black=False, track_black=True): - v_max=1 - v_min=0 + v_max = 1 + v_min = 0 fig = plt.figure(figsize=(14, 8)) fig.suptitle('Vehicle Tracking', fontsize=14) @@ -142,86 +191,83 @@ def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, sub2 = fig.add_subplot(111) ax = plt.gca() data.xs("lat", level="Data", axis=1) - lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(),data.xs("lat", level="Data", axis=1).max().max()) - lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(),data.xs("lon", level="Data", axis=1).max().max()) + lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(), + data.xs("lat", level="Data", axis=1).max().max()) + lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(), + data.xs("lon", level="Data", axis=1).max().max()) # Get all the vehicle ids from data - vehicles = list(data.columns.levels[0]) - data_rounded = data.copy() - - round_decimals = 3 #4 decimals approx 110m in germany - all_lats=[] - all_lons=[] - # for v_id in vehicles: - # data_rounded.loc[:, (v_id, "lat")] = data_rounded[v_id]["lat"].round(round_decimals) - # data_rounded.loc[:, (v_id, "lon")]= data_rounded[v_id]["lon"].round(round_decimals) - # all_lats.extend(data_rounded[v_id]["lat"]) - # all_lons.extend(data_rounded[v_id]["lon"]) - # - # all_geos=np.array((all_lats, all_lons)) - # all_geos_unique=np.unique(all_geos, axis=1) - # # Plot track on the canvas - # if track_black: - # plot_dict = dict(color=(0, 0, 0), alpha=0.1) - # else: - # plot_dict = dict(c=data[v_id]['soc'] * 100, alpha=0.01) - # - # lns2_1 = sub2.scatter(all_geos_unique[0,:],all_geos_unique[1,:], - # **plot_dict, linestyle='-', - # linewidth=0, vmin=v_min, vmax=v_max) - # lns2_1.set_clim(vmin=v_min, vmax=v_max) - + vehicles = list(data.columns.levels[0]) + # Plot track onto canvas via line which doesnt allow soc printing + # or via scatter plot. With a scatter plot the points can take the color of the soc which drove + # above the position. + # ToDo for soc printing soc handling needs to be implemented so for every position only a + # single soc is printed for v_id in vehicles: if track_black: plot_dict = dict(color=(0.9, 0.9, 0.9), alpha=1) - # lns2_1 = sub2.plot(data[v_id]['lat'], data[v_id]['lon'], - # **plot_dict, linestyle='-', - # linewidth=2) - lns2_1 = sub2.scatter(data[v_id]['lat'], data[v_id]['lon'], + lns2_1 = sub2.plot(data[v_id]['lat'], data[v_id]['lon'], **plot_dict, linestyle='-', - linewidth=2, s=0, vmin=v_min, vmax=v_max) + linewidth=2) else: plot_dict = dict(c=data[v_id]['soc'] * 100, alpha=0.01) lns2_1 = sub2.scatter(data[v_id]['lat'], data[v_id]['lon'], - **plot_dict, linestyle='-', - linewidth=0, vmin=v_min, vmax=v_max) + **plot_dict, linestyle='-', + linewidth=0, vmin=v_min, vmax=v_max) lns2_1.set_clim(vmin=v_min, vmax=v_max) # Helper plot so we can plot a colorbar aftwards, not possible with only line plot - # lns2_1 = sub2.scatter([], [], - # **plot_dict, linestyle='-', - # linewidth=0, vmin=v_min, vmax=v_max) - + lns2_1 = sub2.scatter([], [], + **plot_dict, linestyle='-', + linewidth=0, vmin=v_min, vmax=v_max) cbar = fig.colorbar(lns2_1, ax=ax, pad=0.0) cbar.set_alpha(1) cbar.draw_all() cbar.set_label("SOC") - sub2.set_ylabel('Position') - sub2.set_xlabel('Position') + # Plot Station Names + if station_data: + for station in station_data.values(): + ax.annotate(station.name, + xy=(station.lat, station.lon), xycoords='data', fontsize=8, ha='center') + ax.plot(station.lat, station.lon, 'bo') - artist_objects=[] + artist_objects = [] for _ in vehicles: lns2_1 = sub2.scatter([0, 0], [0, 0], [0, 100]) artist_objects.append(lns2_1) - d_bound=0.001 - sub2.set_ylim((lon_boundary[0]-d_bound, lon_boundary[1]+d_bound)) - sub2.set_xlim((lat_boundary[0]-d_bound, lat_boundary[1]+d_bound)) + d_bound = 0.005 + sub2.set_ylim((lon_boundary[0] - d_bound, lon_boundary[1] + d_bound)) + sub2.set_xlim((lat_boundary[0] - d_bound, lat_boundary[1] + d_bound)) + sub2.set_ylabel('Position') + sub2.set_xlabel('Position') + + text_box = TextArea(data.index[0]) + time_annotation_box = [AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', + fontsize=15)] + ax.add_artist(time_annotation_box[0]) - def animate(i, data , counter=[]): - roll_v = 3 - len_v = 5 + def animate(i, data, counter=[]): + roll_v = 1 + len_v = 2 + ax = plt.gca() vehicles = list(data.columns.levels[0]) if not counter: counter.append(i) else: - counter[0] +=1 - i =counter[0] - start_index=i*roll_v - end_index=start_index+len_v + counter[0] += 1 + i = counter[0] + start_index = i * roll_v + end_index = start_index + len_v + + ax.artists.remove(time_annotation_box[0]) + text_box = TextArea(data.index[start_index]) + time_annotation_box[0] = AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', + fontsize=15) + ax.add_artist(time_annotation_box[0]) for k, v_id in enumerate(vehicles): artist_objects[k].remove() @@ -236,9 +282,10 @@ def animate(i, data , counter=[]): **plot_dict, vmin=0, vmax=1, linestyle='-', - linewidth=0) + linewidth=0, zorder=50) + if end_index >= len(data[v_id]["soc"]): - counter[0]=0 + counter[0] = 0 return artist_objects @@ -252,66 +299,32 @@ def animate(i, data , counter=[]): sub2.set_ylabel('Position') sub2.set_xlabel('Position') - # y_d = (y_max - y_min) * 0.02 - # x_d = (x_max - x_min) * 0.02 - # sub2.set_ylim((y_min - y_d, y_max + y_d)) - # sub2.set_xlim((x_min - x_d, x_max + x_d)) - - # Toggle Comment of for saving + # Toggle save for saving if save: - myAnimation.save('SOC_Animation_all_OLIA_w_locations.gif', writer='imagemagick') + myAnimation.save('SOC_animation.gif', writer='imagemagick') fig.tight_layout() plt.show() + def find_current_trip(trips, current_time): for i, trip in enumerate(trips): try: next_trip = trips[i + 1] - if next_trip.departure_time>current_time: + if next_trip.departure_time > current_time: return trip, i except IndexError: return trip, i else: raise Exception("no trip found for time: " + str(current_time)) + def get_rel_time_of_trip(current_time: datetime.datetime, current_trip: 'ebus_toolbox.trip.Trip'): - rel_time=(current_time-current_trip.departure_time)/\ - (current_trip.arrival_time-current_trip.departure_time) - return min(1,max(rel_time,0)) - -start_time=scenario.start_time -time_step = datetime.timedelta(hours=1/scenario.stepsPerHour) - -vehicle_data_frames=pd.DataFrame() -c = 0 -for v_id, soc_data in scenario.vehicle_socs.items(): - rotations=get_sorted_rotations(v_id, schedule) - trips = [trip for rot in rotations for trip in rot.trips ] - lats = [] - lons = [] - trip_nr=0 - for counter, soc in enumerate(soc_data): - try: - current_time=start_time+counter*time_step - current_trip, found_trip_index = find_current_trip(trips[trip_nr:],current_time) - trip_nr += found_trip_index - rel_time_of_trip=get_rel_time_of_trip(current_time, current_trip) - current_station = stations[current_trip.departure_name] - next_station = stations[current_trip.arrival_name] - lat, lon = current_station.get_lat_lon(next_station,rel_time_of_trip) - lats.append(lat) - lons.append(lon) - except IndexError: - pass - columns=[(v_id, "soc"), (v_id, "lat") , (v_id, "lon")] - data = np.array([soc_data, lats, lons]).transpose() - vehicle_data_frames=pd.concat((vehicle_data_frames, pd.DataFrame(data ,columns=columns)),axis=1) - c +=1 - if c>4: - break + rel_time = (current_time - current_trip.departure_time) / \ + (current_trip.arrival_time - current_trip.departure_time) + return min(1, max(rel_time, 0)) -vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, names=['Vehicle_id','Data']) -plot_merge_animate_battery(vehicle_data_frames) +if __name__ == "__main__": + main() From 5af6899d1c2cf3482ca0726583024718ac5f7abf Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 19 Jan 2023 16:45:20 +0100 Subject: [PATCH 03/58] Add hover to plot --- ebus_toolbox/plot_geoposition.py | 137 ++++++++++++++++++++++--------- 1 file changed, 96 insertions(+), 41 deletions(-) diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py index e486eab3..8b9f5fa8 100644 --- a/ebus_toolbox/plot_geoposition.py +++ b/ebus_toolbox/plot_geoposition.py @@ -1,5 +1,6 @@ """ Module to implement plotting functionality of busses with georeferences""" import datetime +import typing from matplotlib.offsetbox import TextArea, AnnotationBbox @@ -103,8 +104,9 @@ args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/data/buffered_all_stations.csv" - +ANIMATION_DURATION_MIN = 480 def main(): + pickle_path="vehicle_data_frames.pickle" with open(str(args.station_data_path), "r", encoding='utf-8') as f: delim = util.get_csv_delim(args.station_data_path) reader = csv.DictReader(f, delimiter=delim) @@ -119,44 +121,51 @@ def main(): start_time = scenario.start_time time_step = datetime.timedelta(hours=1 / scenario.stepsPerHour) - vehicle_data_frames = pd.DataFrame() - c = 0 - for v_id, soc_data in scenario.vehicle_socs.items(): - rotations = get_sorted_rotations(v_id, schedule) - trips = [trip for rot in rotations for trip in rot.trips] - lats = [] - lons = [] - trip_nr = 0 - for counter, soc in enumerate(soc_data): - try: - current_time = start_time + counter * time_step - current_trip, found_trip_index = find_current_trip(trips[trip_nr:], current_time) - trip_nr += found_trip_index - rel_time_of_trip = get_rel_time_of_trip(current_time, current_trip) - current_station = stations[current_trip.departure_name] - next_station = stations[current_trip.arrival_name] - lat, lon = current_station.get_lat_lon(next_station, rel_time_of_trip) - lats.append(lat) - lons.append(lon) - except IndexError: - pass - columns = [(v_id, "soc"), (v_id, "lat"), (v_id, "lon")] - data = np.array([soc_data, lats, lons]).transpose() - vehicle_data_frames = pd.concat((vehicle_data_frames, pd.DataFrame(data, columns=columns)), - axis=1) - # c += 1 - # if c > 2: - # break - - vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, - names=['Vehicle_id', 'Data']) - - vehicle_data_frames.index = np.arange(start_time, start_time + - len(vehicle_data_frames) * time_step, time_step) + if not pickle_path: + vehicle_data_frames = pd.DataFrame() + c = 0 + + for v_id, soc_data in scenario.vehicle_socs.items(): + rotations = get_sorted_rotations(v_id, schedule) + trips = [trip for rot in rotations for trip in rot.trips] + lats = [] + lons = [] + trip_nr = 0 + for counter, soc in enumerate(soc_data): + try: + current_time = start_time + counter * time_step + current_trip, found_trip_index = find_current_trip(trips[trip_nr:], current_time) + trip_nr += found_trip_index + rel_time_of_trip = get_rel_time_of_trip(current_time, current_trip) + current_station = stations[current_trip.departure_name] + next_station = stations[current_trip.arrival_name] + lat, lon = current_station.get_lat_lon(next_station, rel_time_of_trip) + lats.append(lat) + lons.append(lon) + except IndexError: + pass + columns = [(v_id, "soc"), (v_id, "lat"), (v_id, "lon")] + data = np.array([soc_data, lats, lons]).transpose() + vehicle_data_frames = pd.concat((vehicle_data_frames, pd.DataFrame(data, columns=columns)), + axis=1) + # c += 1 + # if c > 2: + # break + + vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, + names=['Vehicle_id', 'Data']) + + vehicle_data_frames.index = np.arange(start_time, start_time + + len(vehicle_data_frames) * time_step, time_step) + else: + with open(pickle_path, "rb") as f: + print("depickeling") + vehicle_data_frames= pickle.load(f) stations_to_annotate = {name: stat for name, stat in stations.items() if name in schedule.stations} - plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, save=True, repeat=False) + vehicle_data_frames = vehicle_data_frames.iloc[:24*60,:] + plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, save=False, repeat=False) class station: @@ -180,7 +189,7 @@ def get_sorted_rotations(v_id, schedule): return sorted(rots, key=lambda x: x.departure_time) -def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, station_data=None, +def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, save=False, repeat=True, vehicle_black=False, track_black=True): v_max = 1 v_min = 0 @@ -232,7 +241,7 @@ def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, station_data=None, for station in station_data.values(): ax.annotate(station.name, xy=(station.lat, station.lon), xycoords='data', fontsize=8, ha='center') - ax.plot(station.lat, station.lon, 'bo') + ax.plot(station.lat, station.lon, 'ko') artist_objects = [] for _ in vehicles: @@ -249,7 +258,7 @@ def plot_merge_animate_battery(data: pd.DataFrame, z_ax=None, station_data=None, time_annotation_box = [AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', fontsize=15)] ax.add_artist(time_annotation_box[0]) - + hover_texts= [str(v_id) for v_id in vehicles] def animate(i, data, counter=[]): roll_v = 1 len_v = 2 @@ -260,7 +269,7 @@ def animate(i, data, counter=[]): else: counter[0] += 1 i = counter[0] - start_index = i * roll_v + start_index = i * roll_v+8*60 end_index = start_index + len_v ax.artists.remove(time_annotation_box[0]) @@ -270,7 +279,9 @@ def animate(i, data, counter=[]): ax.add_artist(time_annotation_box[0]) for k, v_id in enumerate(vehicles): + artist_objects[k].remove() + mean_soc = 0 if vehicle_black: plot_dict = dict(color=(0, 0, 0)) else: @@ -283,6 +294,7 @@ def animate(i, data, counter=[]): vmin=0, vmax=1, linestyle='-', linewidth=0, zorder=50) + hover_texts[k] = (v_id, str(round(mean_soc, 3))) if end_index >= len(data[v_id]["soc"]): counter[0] = 0 @@ -293,12 +305,14 @@ def animate(i, data, counter=[]): # create animation using the animate() function myAnimation = animation.FuncAnimation(fig, lambda i: animate(i, data), - frames=10, + frames=ANIMATION_DURATION_MIN, interval=50, blit=False, repeat=repeat) # sub2.set_ylabel('Position') sub2.set_xlabel('Position') + fig.canvas.mpl_connect("motion_notify_event",lambda event: hover_for_scatter( + event, fig,ax, artist_objects, hover_texts)) # Toggle save for saving if save: myAnimation.save('SOC_animation.gif', writer='imagemagick') @@ -307,6 +321,47 @@ def animate(i, data, counter=[]): plt.show() +def hover_for_scatter(event, fig, ax, plot_points: typing.Iterable[matplotlib.lines.Line2D], hover_texts: typing.Iterable[str], annotations=[]): + """Called when user hovers over plot. + Checks if user hovers over point. If so, delete old annotation and + create new one with relevant info from the hover_texts list. + If user does not hover over point, remove annotation, if any. + """ + if len(annotations)==0: + annotations.append(None) + for i,points in enumerate(plot_points): + if points and event.inaxes == ax: + # results shown, mouse within plot: get event info + # cont: any points hovered? + # ind: list of points hovered + cont, ind = points.contains(event) + + if cont and "ind" in ind: + ind = ind["ind"] + # points hovered + # get all point coordinates + xy = points.get_offsets().data + text = hover_texts[i] + + # # remove old annotation + if annotations and annotations[0]: + annotations[0].remove() + annotations[0]=None + + # create new annotation + annotations[0]= ax.annotate( + text, + xy=(xy[ind[0]][0], xy[ind[0]][1]), + xytext=(-20, 20), + textcoords="offset points", + bbox=dict(boxstyle="round", fc="w"), + arrowprops={'arrowstyle': "-"}, + annotation_clip=False) + fig.canvas.draw() + + + + def find_current_trip(trips, current_time): for i, trip in enumerate(trips): From 197c0c03eb35fe7efc2694e7328dfebd6c096a9c Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Mon, 30 Jan 2023 10:09:12 +0100 Subject: [PATCH 04/58] Add various track plotting elements --- ebus_toolbox/plot_geoposition.py | 180 ++++++++++++++++++++------- ebus_toolbox/station_optimization.py | 4 +- 2 files changed, 139 insertions(+), 45 deletions(-) diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py index 8b9f5fa8..2aee7543 100644 --- a/ebus_toolbox/plot_geoposition.py +++ b/ebus_toolbox/plot_geoposition.py @@ -105,8 +105,10 @@ args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/data/buffered_all_stations.csv" ANIMATION_DURATION_MIN = 480 + + def main(): - pickle_path="vehicle_data_frames.pickle" + pickle_path = "vehicle_data_frames.pickle" with open(str(args.station_data_path), "r", encoding='utf-8') as f: delim = util.get_csv_delim(args.station_data_path) reader = csv.DictReader(f, delimiter=delim) @@ -134,7 +136,8 @@ def main(): for counter, soc in enumerate(soc_data): try: current_time = start_time + counter * time_step - current_trip, found_trip_index = find_current_trip(trips[trip_nr:], current_time) + current_trip, found_trip_index = find_current_trip(trips[trip_nr:], + current_time) trip_nr += found_trip_index rel_time_of_trip = get_rel_time_of_trip(current_time, current_trip) current_station = stations[current_trip.departure_name] @@ -146,11 +149,9 @@ def main(): pass columns = [(v_id, "soc"), (v_id, "lat"), (v_id, "lon")] data = np.array([soc_data, lats, lons]).transpose() - vehicle_data_frames = pd.concat((vehicle_data_frames, pd.DataFrame(data, columns=columns)), - axis=1) - # c += 1 - # if c > 2: - # break + vehicle_data_frames = pd.concat( + (vehicle_data_frames, pd.DataFrame(data, columns=columns)), + axis=1) vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, names=['Vehicle_id', 'Data']) @@ -160,12 +161,13 @@ def main(): else: with open(pickle_path, "rb") as f: print("depickeling") - vehicle_data_frames= pickle.load(f) + vehicle_data_frames = pickle.load(f) stations_to_annotate = {name: stat for name, stat in stations.items() if name in schedule.stations} - vehicle_data_frames = vehicle_data_frames.iloc[:24*60,:] - plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, save=False, repeat=False) + vehicle_data_frames = vehicle_data_frames.iloc[:24 * 60, :] + plot_merge_animate_battery(vehicle_data_frames, vehicle_black=True, track_black=False, + station_data=stations_to_annotate, save=False, repeat=False) class station: @@ -190,7 +192,14 @@ def get_sorted_rotations(v_id, schedule): def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, - save=False, repeat=True, vehicle_black=False, track_black=True): + save=False, repeat=True, vehicle_black=False, track_black=True, + track_method="min"): + data.xs("lat", level="Data", axis=1) + lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(), + data.xs("lat", level="Data", axis=1).max().max()) + lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(), + data.xs("lon", level="Data", axis=1).max().max()) + v_max = 1 v_min = 0 fig = plt.figure(figsize=(14, 8)) @@ -199,11 +208,6 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, sub2 = fig.add_subplot(111) ax = plt.gca() - data.xs("lat", level="Data", axis=1) - lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(), - data.xs("lat", level="Data", axis=1).max().max()) - lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(), - data.xs("lon", level="Data", axis=1).max().max()) # Get all the vehicle ids from data vehicles = list(data.columns.levels[0]) @@ -213,20 +217,75 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, # above the position. # ToDo for soc printing soc handling needs to be implemented so for every position only a # single soc is printed - for v_id in vehicles: - if track_black: + round_nr = 3 + stacked_array_unique = make_unique_data(vehicles, data, track_black, track_method) + x_org= stacked_array_unique[0, :].copy() + y_org= stacked_array_unique[1, :].copy() + + stacked_array_unique[0, :] = stacked_array_unique[0, :] - min(stacked_array_unique[0, :]) + stacked_array_unique[1, :] = stacked_array_unique[1, :] - min(stacked_array_unique[1, :]) + stacked_array_unique[0, :] = stacked_array_unique[0, :] + stacked_array_unique[0, :] = stacked_array_unique[0, :] * 10 ** round_nr + stacked_array_unique[1, :] = stacked_array_unique[1, :] * 10 ** round_nr + ############## + # from scipy.ndimage import gaussian_filter as gauss + # fig = plt.figure(figsize=(8, 8)) + # + # fig.suptitle('Vehicle Tracking', fontsize=14) + # sub2 = fig.add_subplot(111) + # ax = plt.gca() + # + # stacked_array_pic = make_unique_data(vehicles, data, track_black, track_method, + # round_nr=round_nr) + # + # x = (stacked_array_pic[0, :] * 10 ** round_nr).astype(int) + # X = x - np.min(x) + # y = (stacked_array_pic[1, :] * 10 ** round_nr).astype(int) + # Y = y - np.min(y) + # z = stacked_array_pic[2, :] + # idx1 = X + # idx2 = Y + # grid_data = z + # grid = np.ones((np.max(Y) + 1, np.max(X) + 1)) + # grid[idx2, idx1] = grid_data + # ax.imshow(gauss(grid, 10)) + # ############################# + # fig = plt.figure(figsize=(14, 8)) + # + # fig.suptitle('Vehicle Tracking', fontsize=14) + # + # sub2 = fig.add_subplot(111) + # ax = plt.gca() + # + # x=stacked_array_unique[0,:] + # y=stacked_array_unique[1,:] + # z=stacked_array_unique[2,:] + # + # steps=500 + # X = np.linspace(stacked_array_unique[0, :].min(), stacked_array_unique[0, :].max(), steps) + # Y = np.linspace(stacked_array_unique[1, :].min(), stacked_array_unique[1, :].max(), steps) + # from scipy.interpolate import griddata + # Z = griddata((x, y), z,((X[None, :], Y[:, None])), method='linear') + # contour = sub2.contourf(X, Y, Z) + # ######################## + # ax.imshow(Z) + # ######################## + + if track_black: + for v_id in vehicles: plot_dict = dict(color=(0.9, 0.9, 0.9), alpha=1) lns2_1 = sub2.plot(data[v_id]['lat'], data[v_id]['lon'], **plot_dict, linestyle='-', linewidth=2) - else: - plot_dict = dict(c=data[v_id]['soc'] * 100, alpha=0.01) - lns2_1 = sub2.scatter(data[v_id]['lat'], data[v_id]['lon'], - **plot_dict, linestyle='-', - linewidth=0, vmin=v_min, vmax=v_max) - lns2_1.set_clim(vmin=v_min, vmax=v_max) + else: + plot_dict = dict(c=stacked_array_unique[2, :] * 1, alpha=0.1) + lns2_1 = sub2.scatter(stacked_array_unique[0, :], stacked_array_unique[1, :], + **plot_dict, linestyle='-', + linewidth=0, vmin=v_min, vmax=v_max) + lns2_1.set_clim(vmin=v_min, vmax=v_max) # Helper plot so we can plot a colorbar aftwards, not possible with only line plot + plot_dict = dict() lns2_1 = sub2.scatter([], [], **plot_dict, linestyle='-', linewidth=0, vmin=v_min, vmax=v_max) @@ -239,9 +298,10 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, # Plot Station Names if station_data: for station in station_data.values(): + xy=((station.lat-np.min(x_org))*10**round_nr, (station.lon-np.min(y_org))*10**round_nr) ax.annotate(station.name, - xy=(station.lat, station.lon), xycoords='data', fontsize=8, ha='center') - ax.plot(station.lat, station.lon, 'ko') + xy=xy, xycoords='data', fontsize=8, ha='center') + ax.plot(xy[0], xy[1], 'ko', zorder=100) artist_objects = [] for _ in vehicles: @@ -258,10 +318,11 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, time_annotation_box = [AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', fontsize=15)] ax.add_artist(time_annotation_box[0]) - hover_texts= [str(v_id) for v_id in vehicles] + hover_texts = [str(v_id) for v_id in vehicles] + def animate(i, data, counter=[]): roll_v = 1 - len_v = 2 + len_v = 1 ax = plt.gca() vehicles = list(data.columns.levels[0]) if not counter: @@ -269,7 +330,7 @@ def animate(i, data, counter=[]): else: counter[0] += 1 i = counter[0] - start_index = i * roll_v+8*60 + start_index = i * roll_v + 8 * 60 end_index = start_index + len_v ax.artists.remove(time_annotation_box[0]) @@ -279,13 +340,11 @@ def animate(i, data, counter=[]): ax.add_artist(time_annotation_box[0]) for k, v_id in enumerate(vehicles): - artist_objects[k].remove() - mean_soc = 0 + mean_soc = data[v_id]["soc"][start_index:end_index].mean() if vehicle_black: plot_dict = dict(color=(0, 0, 0)) else: - mean_soc = data[v_id]["soc"][start_index:end_index].mean() l = len(data[v_id]["lat"][start_index:end_index]) plot_dict = dict(c=mean_soc * np.ones(l)) artist_objects[k] = sub2.scatter(data[v_id]["lat"][start_index:end_index], @@ -311,8 +370,8 @@ def animate(i, data, counter=[]): sub2.set_ylabel('Position') sub2.set_xlabel('Position') - fig.canvas.mpl_connect("motion_notify_event",lambda event: hover_for_scatter( - event, fig,ax, artist_objects, hover_texts)) + fig.canvas.mpl_connect("motion_notify_event", lambda event: hover_for_scatter( + event, fig, ax, artist_objects, hover_texts)) # Toggle save for saving if save: myAnimation.save('SOC_animation.gif', writer='imagemagick') @@ -321,15 +380,53 @@ def animate(i, data, counter=[]): plt.show() -def hover_for_scatter(event, fig, ax, plot_points: typing.Iterable[matplotlib.lines.Line2D], hover_texts: typing.Iterable[str], annotations=[]): + +def make_unique_data(vehicles, data, track_black, track_method, round_nr=None): + v_iter = iter(vehicles) + v_id = next(v_iter) + data = pd.DataFrame(data) + if not round_nr: + r = lambda x: x + else: + r = lambda i: round(i, round_nr) + stacked_array = np.array((r(data[v_id]['lat']), r(data[v_id]['lon']), data[v_id]['soc'])) + for v_id in v_iter: + stacked_array = np.hstack( + (stacked_array, (r(data[v_id]['lat']), r(data[v_id]['lon']), data[v_id]['soc']))) + # stacked_array has all vehicle socs and geo positions in + unique_mask = np.unique(stacked_array[0:2, :], axis=1, return_index=True)[1] + stacked_array_unique = stacked_array[:, unique_mask] + + # find soc data for stacked array depending on method. Since its only needed if the track is not black check this as well + + if not track_black: + apply_function = None + if track_method == "mean": + apply_function = np.mean + elif track_method == "max": + apply_function = np.max + else: + apply_function = np.min + + for geo_index in range(len(stacked_array_unique)): + geo_loc = stacked_array_unique[0:2, geo_index] + found_positions = np.all([stacked_array[0:2, :].T == geo_loc], axis=0)[:, 0] + fill_value = apply_function(stacked_array[2, found_positions]) + stacked_array_unique[2, geo_index] = fill_value + + return stacked_array_unique + + +def hover_for_scatter(event, fig, ax, plot_points: typing.Iterable[matplotlib.lines.Line2D], + hover_texts: typing.Iterable[str], annotations=[]): """Called when user hovers over plot. Checks if user hovers over point. If so, delete old annotation and create new one with relevant info from the hover_texts list. If user does not hover over point, remove annotation, if any. """ - if len(annotations)==0: + if len(annotations) == 0: annotations.append(None) - for i,points in enumerate(plot_points): + for i, points in enumerate(plot_points): if points and event.inaxes == ax: # results shown, mouse within plot: get event info # cont: any points hovered? @@ -344,12 +441,12 @@ def hover_for_scatter(event, fig, ax, plot_points: typing.Iterable[matplotlib.li text = hover_texts[i] # # remove old annotation - if annotations and annotations[0]: + if annotations and annotations[0]: annotations[0].remove() - annotations[0]=None + annotations[0] = None # create new annotation - annotations[0]= ax.annotate( + annotations[0] = ax.annotate( text, xy=(xy[ind[0]][0], xy[ind[0]][1]), xytext=(-20, 20), @@ -360,9 +457,6 @@ def hover_for_scatter(event, fig, ax, plot_points: typing.Iterable[matplotlib.li fig.canvas.draw() - - - def find_current_trip(trips, current_time): for i, trip in enumerate(trips): try: diff --git a/ebus_toolbox/station_optimization.py b/ebus_toolbox/station_optimization.py index 757c1a87..276b5603 100644 --- a/ebus_toolbox/station_optimization.py +++ b/ebus_toolbox/station_optimization.py @@ -177,8 +177,8 @@ def run_optimization(config_path, sched=None, scen=None, this_args=None): logger.debug("Still not electrified with abs. soc with fast calc") for event in new_events: logger.debug(event.rotation.id) - with open(new_ele_stations_path, "w", encoding="utf-8", ) as file: - json.dump(ele_stations, file, indent=2) + with open(new_ele_stations_path, "w", encoding="utf-8") as file: + json.dump(ele_stations, file,ensure_ascii=False, indent=2) util.print_time() logger.debug("Spice EV is calculating optimized case as a complete scenario") _, __ = optimizer.preprocessing_scenario( From e02dca17dd0997a9fd0a421063a05b75284ff10f Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Mon, 30 Jan 2023 10:44:19 +0100 Subject: [PATCH 05/58] Bring base case to working condition --- ebus_toolbox/plot_geoposition.py | 83 ++++++++++++++++---------------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py index 2aee7543..4a902988 100644 --- a/ebus_toolbox/plot_geoposition.py +++ b/ebus_toolbox/plot_geoposition.py @@ -14,20 +14,10 @@ import ebus_toolbox.schedule import spiceev.scenario -import requests -import json -from time import sleep -import io - -import matplotlib.pyplot as plt -import pandas as pd -from matplotlib.colors import LinearSegmentedColormap import numpy as np import matplotlib.pyplot as plt import pandas as pd -import math - # Mathematical function we need to plot from matplotlib.colors import LinearSegmentedColormap import matplotlib @@ -165,9 +155,11 @@ def main(): stations_to_annotate = {name: stat for name, stat in stations.items() if name in schedule.stations} - vehicle_data_frames = vehicle_data_frames.iloc[:24 * 60, :] - plot_merge_animate_battery(vehicle_data_frames, vehicle_black=True, track_black=False, - station_data=stations_to_annotate, save=False, repeat=False) + + vehicle_data_frames = vehicle_data_frames.iloc[:24*60,:] + plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, + soc_threshold=0.2,track_black=False, vehicle_black=True, + save=False, repeat=False) class station: @@ -193,13 +185,15 @@ def get_sorted_rotations(v_id, schedule): def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, save=False, repeat=True, vehicle_black=False, track_black=True, - track_method="min"): + track_method="min", soc_threshold=1.0): + data.xs("lat", level="Data", axis=1) lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(), data.xs("lat", level="Data", axis=1).max().max()) lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(), data.xs("lon", level="Data", axis=1).max().max()) + v_max = 1 v_min = 0 fig = plt.figure(figsize=(14, 8)) @@ -212,21 +206,28 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, # Get all the vehicle ids from data vehicles = list(data.columns.levels[0]) + # Filter data for relevant SOCs + for v_id in vehicles: + if data[v_id]['soc'].min()>soc_threshold: + data=data.drop(v_id,axis=1) + data.columns = data.columns.remove_unused_levels() + vehicles = list(data.columns.levels[0]) + # Plot track onto canvas via line which doesnt allow soc printing # or via scatter plot. With a scatter plot the points can take the color of the soc which drove # above the position. - # ToDo for soc printing soc handling needs to be implemented so for every position only a - # single soc is printed + + round_nr = 3 - stacked_array_unique = make_unique_data(vehicles, data, track_black, track_method) + stacked_array_unique = make_unique_data(vehicles, data, track_method) x_org= stacked_array_unique[0, :].copy() y_org= stacked_array_unique[1, :].copy() - - stacked_array_unique[0, :] = stacked_array_unique[0, :] - min(stacked_array_unique[0, :]) - stacked_array_unique[1, :] = stacked_array_unique[1, :] - min(stacked_array_unique[1, :]) - stacked_array_unique[0, :] = stacked_array_unique[0, :] - stacked_array_unique[0, :] = stacked_array_unique[0, :] * 10 ** round_nr - stacked_array_unique[1, :] = stacked_array_unique[1, :] * 10 ** round_nr + # + # stacked_array_unique[0, :] = stacked_array_unique[0, :] - min(stacked_array_unique[0, :]) + # stacked_array_unique[1, :] = stacked_array_unique[1, :] - min(stacked_array_unique[1, :]) + # stacked_array_unique[0, :] = stacked_array_unique[0, :] + # stacked_array_unique[0, :] = stacked_array_unique[0, :] * 10 ** round_nr + # stacked_array_unique[1, :] = stacked_array_unique[1, :] * 10 ** round_nr ############## # from scipy.ndimage import gaussian_filter as gauss # fig = plt.figure(figsize=(8, 8)) @@ -278,7 +279,7 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, **plot_dict, linestyle='-', linewidth=2) else: - plot_dict = dict(c=stacked_array_unique[2, :] * 1, alpha=0.1) + plot_dict = dict(c=stacked_array_unique[2, :] * 1, alpha=0.2) lns2_1 = sub2.scatter(stacked_array_unique[0, :], stacked_array_unique[1, :], **plot_dict, linestyle='-', linewidth=0, vmin=v_min, vmax=v_max) @@ -298,7 +299,8 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, # Plot Station Names if station_data: for station in station_data.values(): - xy=((station.lat-np.min(x_org))*10**round_nr, (station.lon-np.min(y_org))*10**round_nr) + # xy=((station.lat-np.min(x_org))*10**round_nr, (station.lon-np.min(y_org))*10**round_nr) + xy=(station.lat, station.lon) ax.annotate(station.name, xy=xy, xycoords='data', fontsize=8, ha='center') ax.plot(xy[0], xy[1], 'ko', zorder=100) @@ -362,7 +364,7 @@ def animate(i, data, counter=[]): ax.axis('off') # create animation using the animate() function - myAnimation = animation.FuncAnimation(fig, + my_animation = animation.FuncAnimation(fig, lambda i: animate(i, data), frames=ANIMATION_DURATION_MIN, interval=50, blit=False, repeat=repeat) @@ -374,14 +376,14 @@ def animate(i, data, counter=[]): event, fig, ax, artist_objects, hover_texts)) # Toggle save for saving if save: - myAnimation.save('SOC_animation.gif', writer='imagemagick') + my_animation.save('SOC_animation.gif', writer='imagemagick') fig.tight_layout() plt.show() -def make_unique_data(vehicles, data, track_black, track_method, round_nr=None): +def make_unique_data(vehicles, data, track_method, round_nr=None): v_iter = iter(vehicles) v_id = next(v_iter) data = pd.DataFrame(data) @@ -399,20 +401,19 @@ def make_unique_data(vehicles, data, track_black, track_method, round_nr=None): # find soc data for stacked array depending on method. Since its only needed if the track is not black check this as well - if not track_black: - apply_function = None - if track_method == "mean": - apply_function = np.mean - elif track_method == "max": - apply_function = np.max - else: - apply_function = np.min + apply_function = None + if track_method == "mean": + apply_function = np.mean + elif track_method == "max": + apply_function = np.max + else: + apply_function = np.min - for geo_index in range(len(stacked_array_unique)): - geo_loc = stacked_array_unique[0:2, geo_index] - found_positions = np.all([stacked_array[0:2, :].T == geo_loc], axis=0)[:, 0] - fill_value = apply_function(stacked_array[2, found_positions]) - stacked_array_unique[2, geo_index] = fill_value + for geo_index in range(len(stacked_array_unique)): + geo_loc = stacked_array_unique[0:2, geo_index] + found_positions = np.all([stacked_array[0:2, :].T == geo_loc], axis=0)[:, 0] + fill_value = apply_function(stacked_array[2, found_positions]) + stacked_array_unique[2, geo_index] = fill_value return stacked_array_unique From e42ebbdef63399198db5e9df03febd4dd135c389 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 1 Feb 2023 10:52:34 +0100 Subject: [PATCH 06/58] Change for Berlin data --- ebus_toolbox/plot_geoposition.py | 110 ++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 37 deletions(-) diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py index 4a902988..4b101334 100644 --- a/ebus_toolbox/plot_geoposition.py +++ b/ebus_toolbox/plot_geoposition.py @@ -83,22 +83,22 @@ [1, 255 / 255, 45 / 255]]} rli_blue_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) -with open("schedule_opt.pickle", "rb") as file: +with open("schedule_rebased_BVG_BFI.pickle", "rb") as file: schedule = pickle.load(file) -with open("scenario_opt.pickle", "rb") as file: +with open("scenario_rebased_BVG_BFI.pickle", "rb") as file: scenario = pickle.load(file) -with open("args_buffered_all_depb.pickle", "rb") as file: +with open("args_rebased_BVG_BFI.pickle", "rb") as file: args = pickle.load(file) -args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/data/buffered_all_stations.csv" +args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/Haltestellen.csv" ANIMATION_DURATION_MIN = 480 def main(): - pickle_path = "vehicle_data_frames.pickle" + pickle_path = None #"vehicle_data_frames.pickle" with open(str(args.station_data_path), "r", encoding='utf-8') as f: delim = util.get_csv_delim(args.station_data_path) reader = csv.DictReader(f, delimiter=delim) @@ -115,8 +115,6 @@ def main(): if not pickle_path: vehicle_data_frames = pd.DataFrame() - c = 0 - for v_id, soc_data in scenario.vehicle_socs.items(): rotations = get_sorted_rotations(v_id, schedule) trips = [trip for rot in rotations for trip in rot.trips] @@ -130,8 +128,15 @@ def main(): current_time) trip_nr += found_trip_index rel_time_of_trip = get_rel_time_of_trip(current_time, current_trip) - current_station = stations[current_trip.departure_name] - next_station = stations[current_trip.arrival_name] + try: + current_station = stations[current_trip.departure_name] + except: + current_station = last_station + try: + next_station = stations[current_trip.arrival_name] + except: + next_station = current_station + last_station=current_station lat, lon = current_station.get_lat_lon(next_station, rel_time_of_trip) lats.append(lat) lons.append(lon) @@ -158,8 +163,8 @@ def main(): vehicle_data_frames = vehicle_data_frames.iloc[:24*60,:] plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, - soc_threshold=0.2,track_black=False, vehicle_black=True, - save=False, repeat=False) + soc_threshold=1,track_black=False, vehicle_black=True, + save=False, repeat=True) class station: @@ -279,7 +284,7 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, **plot_dict, linestyle='-', linewidth=2) else: - plot_dict = dict(c=stacked_array_unique[2, :] * 1, alpha=0.2) + plot_dict = dict(c=stacked_array_unique[2, :] * 1, alpha=0.8) lns2_1 = sub2.scatter(stacked_array_unique[0, :], stacked_array_unique[1, :], **plot_dict, linestyle='-', linewidth=0, vmin=v_min, vmax=v_max) @@ -302,7 +307,7 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, # xy=((station.lat-np.min(x_org))*10**round_nr, (station.lon-np.min(y_org))*10**round_nr) xy=(station.lat, station.lon) ax.annotate(station.name, - xy=xy, xycoords='data', fontsize=8, ha='center') + xy=xy, xycoords='data', xytext=(0, 5), textcoords='offset points', fontsize=8, ha='center') ax.plot(xy[0], xy[1], 'ko', zorder=100) artist_objects = [] @@ -317,6 +322,7 @@ def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, sub2.set_xlabel('Position') text_box = TextArea(data.index[0]) + time_annotation_box = [AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', fontsize=15)] ax.add_artist(time_annotation_box[0]) @@ -334,40 +340,64 @@ def animate(i, data, counter=[]): i = counter[0] start_index = i * roll_v + 8 * 60 end_index = start_index + len_v - - ax.artists.remove(time_annotation_box[0]) + try: + ax.artists.remove(time_annotation_box[0]) + except: + return artist_objects text_box = TextArea(data.index[start_index]) time_annotation_box[0] = AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', fontsize=15) ax.add_artist(time_annotation_box[0]) - - for k, v_id in enumerate(vehicles): - artist_objects[k].remove() - mean_soc = data[v_id]["soc"][start_index:end_index].mean() - if vehicle_black: - plot_dict = dict(color=(0, 0, 0)) - else: - l = len(data[v_id]["lat"][start_index:end_index]) - plot_dict = dict(c=mean_soc * np.ones(l)) - artist_objects[k] = sub2.scatter(data[v_id]["lat"][start_index:end_index], - data[v_id]["lon"][start_index:end_index], - **plot_dict, - vmin=0, vmax=1, - linestyle='-', - linewidth=0, zorder=50) - hover_texts[k] = (v_id, str(round(mean_soc, 3))) - - if end_index >= len(data[v_id]["soc"]): + # + # + + plot_dict = dict(color=(0, 0, 0)) + artist_objects[0].remove() + lat_data=data.xs("lat", level="Data", axis=1).iloc[start_index:end_index].values + lon_data=data.xs("lon", level="Data", axis=1).iloc[start_index:end_index].values + soc_data=data.xs("soc", level="Data", axis=1).iloc[start_index:end_index].mean().values + if vehicle_black: + plot_dict = dict(color=(0, 0, 0)) + else: + plot_dict = dict(c=soc_data) + artist_objects[0] = sub2.scatter(lat_data, + lon_data, + **plot_dict, + vmin=0, vmax=1, + linestyle='-', + linewidth=0, zorder=50) + + # + # + # for k, v_id in enumerate(vehicles): + # artist_objects[k].remove() + # mean_soc = data[v_id]["soc"][start_index:end_index].mean() + # if vehicle_black: + # plot_dict = dict(color=(0, 0, 0)) + # else: + # l = len(data[v_id]["lat"][start_index:end_index]) + # plot_dict = dict(c=mean_soc * np.ones(l)) + # artist_objects[k] = sub2.scatter(data[v_id]["lat"][start_index:end_index], + # data[v_id]["lon"][start_index:end_index], + # **plot_dict, + # vmin=0, vmax=1, + # linestyle='-', + # linewidth=0, zorder=50) + # hover_texts[k] = (v_id, str(round(mean_soc, 3))) + + if end_index >= len(data): counter[0] = 0 return artist_objects ax.axis('off') # create animation using the animate() function + my_animation = animation.FuncAnimation(fig, lambda i: animate(i, data), frames=ANIMATION_DURATION_MIN, - interval=50, blit=False, repeat=repeat) + interval=15, blit=False, repeat=repeat) + # sub2.set_ylabel('Position') sub2.set_xlabel('Position') @@ -380,8 +410,12 @@ def animate(i, data, counter=[]): fig.tight_layout() - plt.show() - + def on_close(event): + plt.close() + print('Closed Figure!') + fig.canvas.mpl_connect('close_event',lambda event:on_close(event)) + plt.show(block=True) + print("stopped") def make_unique_data(vehicles, data, track_method, round_nr=None): v_iter = iter(vehicles) @@ -395,6 +429,7 @@ def make_unique_data(vehicles, data, track_method, round_nr=None): for v_id in v_iter: stacked_array = np.hstack( (stacked_array, (r(data[v_id]['lat']), r(data[v_id]['lon']), data[v_id]['soc']))) + stacked_array = stacked_array.astype(float) # stacked_array has all vehicle socs and geo positions in unique_mask = np.unique(stacked_array[0:2, :], axis=1, return_index=True)[1] stacked_array_unique = stacked_array[:, unique_mask] @@ -471,8 +506,9 @@ def find_current_trip(trips, current_time): def get_rel_time_of_trip(current_time: datetime.datetime, current_trip: 'ebus_toolbox.trip.Trip'): + trip_time= (current_trip.arrival_time - current_trip.departure_time) rel_time = (current_time - current_trip.departure_time) / \ - (current_trip.arrival_time - current_trip.departure_time) + max(trip_time,datetime.timedelta(minutes=1)) return min(1, max(rel_time, 0)) From 5f83824a4ca4a02d955289c33f749b199f0788f0 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 1 Feb 2023 17:21:44 +0100 Subject: [PATCH 07/58] Change import calls to include ebus_toolbox package name, so sphinx doc works properly --- docs/source/conf.py | 16 ++++++++++++++-- ebus_toolbox/optimizer_config.py | 0 ebus_toolbox/plot_geoposition.py | 9 +++++---- ebus_toolbox/station_optimizer.py | 5 ++--- 4 files changed, 21 insertions(+), 9 deletions(-) delete mode 100644 ebus_toolbox/optimizer_config.py diff --git a/docs/source/conf.py b/docs/source/conf.py index 7e98ff01..5d427e1e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -9,11 +9,23 @@ # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. +# for example + + +#If conf.py is located in this directory, +# +#D:\\Projects\MyProject\Docs\source # +#and the project's Python modules are in +# +#D:\\Projects\MyProject\SourceCode, + import os import sys -sys.path.insert(0, os.path.abspath('..')) - +import pathlib +sys.path.insert(0, os.path.abspath('../../')) +sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix()) +sys.path.insert(0, os.path.abspath('C:/Users/paul.scheer/Python/spiceev')) # -- Project information ----------------------------------------------------- diff --git a/ebus_toolbox/optimizer_config.py b/ebus_toolbox/optimizer_config.py deleted file mode 100644 index e69de29b..00000000 diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py index 4b101334..cb13cab6 100644 --- a/ebus_toolbox/plot_geoposition.py +++ b/ebus_toolbox/plot_geoposition.py @@ -1,7 +1,7 @@ """ Module to implement plotting functionality of busses with georeferences""" import datetime import typing - +import pathlib from matplotlib.offsetbox import TextArea, AnnotationBbox import ebus_toolbox.util as util @@ -83,13 +83,14 @@ [1, 255 / 255, 45 / 255]]} rli_blue_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) -with open("schedule_rebased_BVG_BFI.pickle", "rb") as file: +f_path=pathlib.Path(__file__).parent.parent +with open(f_path / "schedule_rebased_BVG_BFI.pickle", "rb") as file: schedule = pickle.load(file) -with open("scenario_rebased_BVG_BFI.pickle", "rb") as file: +with open(f_path / "scenario_rebased_BVG_BFI.pickle", "rb") as file: scenario = pickle.load(file) -with open("args_rebased_BVG_BFI.pickle", "rb") as file: +with open(f_path / "args_rebased_BVG_BFI.pickle", "rb") as file: args = pickle.load(file) args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/Haltestellen.csv" diff --git a/ebus_toolbox/station_optimizer.py b/ebus_toolbox/station_optimizer.py index c37a6137..b3aae32a 100644 --- a/ebus_toolbox/station_optimizer.py +++ b/ebus_toolbox/station_optimizer.py @@ -9,10 +9,9 @@ import numpy as np -import optimizer_util as util +import ebus_toolbox.optimizer_util as util from src import scenario -import schedule -from ebus_toolbox import report, rotation +from ebus_toolbox import report, rotation, schedule class StationOptimizer: From 555aa477a9bf8b94098d0c7ff29c69088ca00876 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Fri, 3 Feb 2023 12:08:44 +0100 Subject: [PATCH 08/58] Add first rst files to docs source --- docs/_static/style.css | 16 ++++ docs/source/conf.py | 4 +- docs/source/ebus_toolbox.rst | 117 ++++++++++++++++++++++++++ docs/source/getting_started.rst | 31 +++++++ docs/source/index.rst | 9 +- docs/source/modes.rst | 24 ++++++ docs/source/modules.rst | 7 ++ docs/source/simulation_parameters.rst | 73 ++++++++++++++++ 8 files changed, 276 insertions(+), 5 deletions(-) create mode 100644 docs/source/ebus_toolbox.rst create mode 100644 docs/source/getting_started.rst create mode 100644 docs/source/modes.rst create mode 100644 docs/source/modules.rst create mode 100644 docs/source/simulation_parameters.rst diff --git a/docs/_static/style.css b/docs/_static/style.css index b07bdb1b..0f9e565d 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -1,3 +1,19 @@ .wy-nav-content { max-width: none; } + +/* override table width restrictions */ +.wy-table-responsive table td, .wy-table-responsive table th { + /* !important prevents the common CSS stylesheets from + overriding this as on RTD they are loaded after this stylesheet */ + white-space: normal !important; +} + +.wy-table-responsive { + overflow: visible !important; +} + +table { + table-layout: auto; + width: 800px; +} \ No newline at end of file diff --git a/docs/source/conf.py b/docs/source/conf.py index 5d427e1e..56dbe2a0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -42,7 +42,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary','sphinx.ext.autosectionlabel'] # Add any paths that contain templates here, relative to this directory. templates_path = [] @@ -67,5 +67,5 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ['../_static'] html_css_files = ['style.css'] diff --git a/docs/source/ebus_toolbox.rst b/docs/source/ebus_toolbox.rst new file mode 100644 index 00000000..cef1ada6 --- /dev/null +++ b/docs/source/ebus_toolbox.rst @@ -0,0 +1,117 @@ +ebus\_toolbox package +===================== + +Submodules +---------- + +ebus\_toolbox.consumption module +-------------------------------- + +.. automodule:: ebus_toolbox.consumption + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.costs module +-------------------------- + +.. automodule:: ebus_toolbox.costs + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.optimization module +--------------------------------- + +.. automodule:: ebus_toolbox.optimization + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.optimizer\_util module +------------------------------------ + +.. automodule:: ebus_toolbox.optimizer_util + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.plot\_geoposition module +-------------------------------------- + +.. automodule:: ebus_toolbox.plot_geoposition + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.report module +--------------------------- + +.. automodule:: ebus_toolbox.report + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.rotation module +----------------------------- + +.. automodule:: ebus_toolbox.rotation + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.schedule module +----------------------------- + +.. automodule:: ebus_toolbox.schedule + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.simulate module +----------------------------- + +.. automodule:: ebus_toolbox.simulate + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.station\_optimization module +------------------------------------------ + +.. automodule:: ebus_toolbox.station_optimization + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.station\_optimizer module +--------------------------------------- + +.. automodule:: ebus_toolbox.station_optimizer + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.trip module +------------------------- + +.. automodule:: ebus_toolbox.trip + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.util module +------------------------- + +.. automodule:: ebus_toolbox.util + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ebus_toolbox + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst new file mode 100644 index 00000000..70d51474 --- /dev/null +++ b/docs/source/getting_started.rst @@ -0,0 +1,31 @@ +Getting Started +=============== + +The eBus-Toolbox assists the user in analysing and optimising electrified bus fleets and schedules. + +.. _installation: + +Installation +------------ + +At the current stage, only a single functionality is implemented, which is processing a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and run it through a module called SpiceEV for an in-depth SOC analysis. + +To try it out, first clone this repository and then install the required packages to your current environment by running + +`pip install -r requirements.txt` + +Now you can start the eBus Toolbox module with all configurations stored at `data/configs/ebus_toolbox.cfg` via the command + +``python -m ebus_toolbox --config data/configs/ebus_toolbox.cfg`` + +The repo provides an example for each necessary input file, so the example case can be executed without the need for the user to provide any data themselves. + +To run the eBus Toolbox with your own `schedule.csv` (see details [below](#input-data)) file and default configurations run + +`python -m ebus_toolbox --input_schedule path/to/schedule.csv` + +Default configurations are detailed at `data/configs/ebus_toolbox.cfg`. + + +General Concept +--------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 8a3e2313..1e0da5f5 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,15 +4,18 @@ contain the root `toctree` directive. Welcome to the eBus-Toolbox's documentation! -======================================== +============================================ -This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies. +This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies. .. toctree:: - :maxdepth: 2 + :maxdepth: 3 :caption: Contents: + getting_started + modes + simulation_parameters Indices and tables diff --git a/docs/source/modes.rst b/docs/source/modes.rst new file mode 100644 index 00000000..7458fcc8 --- /dev/null +++ b/docs/source/modes.rst @@ -0,0 +1,24 @@ +Modes of the eBus-Toolbox +========================= + +The eBus-Toolbox assists the user in analysing and optimising electrified bus fleets and schedules. Besides a simple simulation run, several +different modes support the user in finding optimal solutions for their eBus-System. Supported Modes are + +* simple simulation +* negative depot to opportunity charger +* negative opportunity to depot charger +* station optimization + + +simple simulation +----------------- +The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started` + +negative depot to opportunity charger +------------------------------------- + +negative opportunity to depot charger +------------------------------------- + +station optimization +-------------------- \ No newline at end of file diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 00000000..8278aeee --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,7 @@ +ebus_toolbox +============ + +.. toctree:: + :maxdepth: 4 + + ebus_toolbox diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst new file mode 100644 index 00000000..f5db05bd --- /dev/null +++ b/docs/source/simulation_parameters.rst @@ -0,0 +1,73 @@ +Simulation Parameters +===================== + +The simulation of an eBus-Sytem relies on a variety of simulation parameters. +The eBus-Toolbox provides most of them as default values. Depending on specific needs adjusting +these values can increase the accuracy of the simulation outputs. The eBus-Toolbox input files are described +in detail in the following subsections as well as their default parameters. +When providing the user defined input files, the user should make sure the files are either 'utf-8' +encoded or not contain regional characters. + +Configuration +------------- + +Schedule +-------- + +To analyze your own electric bus schedule, the data needs to be provided as a .csv file where each row contains the details of a single trip of that schedule. Find the details about the various columns in this file below. The first table lists the **mandatory** columns while the second one (tbd) lists optional parameters. Refer to `data/examples/trips.csv` for an example. + +.. list-table:: schedule mandatory input + :widths: 150 300 150 + :header-rows: 1 + + * - Column Name + - Description + - Example + * - rotation_id + - Unique alphanumeric ID to identify rotations + - 27312 + * - departure_name + - Name of the station the trip starts at + - Warschauer Straße + * - departure_time + - Date and Time at which bus starts trip + - 2022-03-13T10:25 + * - arrival_name + - Name of the station the trip ends at + - Ostbahnhof Berlin + * - arrival_time + - Date and Time at which bus completes trip (e.g. yyyy-mm-ddThh:mm[:ss]) + - 2022-03-13T10:30 + * - distance + - Distance traveled in **m** + - 1340 + * - vehicle_type + - | ID of vehicle type defined in vehicle types file. Set path of this file in config + | (see default for reference: `data/examples/vehicle_types.json`) + - some_bus_type + +.. list-table:: schedule optional input + :widths: 150 300 150 + :header-rows: 1 + + * - Column Name + - Description + - Example + * - line + - The bus line + - 512, M10, X11 etc. + * - charging_type + - | The preferred charging type for this trip. + | NOTE: All trips of a rotation need to have the same charging type. + | If omitted, charging type is set according to preferred charging type provided in the config file. + - Options: **depb**, **oppb** + * - temperature + - Temperature of the trip in **degC** + - 25 + * - level_of_loading + - The level of loading of the bus on this trip in between 0 and 1 + - 0.5. + + + + From de4259f319c4867f889e94534d632ed4a9a9c4e7 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Tue, 7 Feb 2023 12:23:07 +0100 Subject: [PATCH 09/58] Extend doc and add figures --- docs/source/getting_started.rst | 27 ++++++++++++--- docs/source/index.rst | 7 +++- docs/source/modes.rst | 32 +++++++++++++++-- docs/source/simulation_parameters.rst | 49 ++++++++++++++++++++++++++- 4 files changed, 105 insertions(+), 10 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 70d51474..5c3810ec 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -1,16 +1,18 @@ +.. image:: https://user-images.githubusercontent.com/104760879/217226792-4297d3c8-8a7c-45ad-894f-5efd03031f49.png + :alt: ebus_toolbox_logo + Getting Started =============== The eBus-Toolbox assists the user in analysing and optimising electrified bus fleets and schedules. -.. _installation: +.. Without creating links like in the line below, subpages go missing from the sidebar + +.. _installation_label: Installation ------------ - -At the current stage, only a single functionality is implemented, which is processing a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and run it through a module called SpiceEV for an in-depth SOC analysis. - -To try it out, first clone this repository and then install the required packages to your current environment by running +To try it out, first clone `this repository `_ and then install the required packages to your current environment by running `pip install -r requirements.txt` @@ -29,3 +31,18 @@ Default configurations are detailed at `data/configs/ebus_toolbox.cfg`. General Concept --------------- +At the current stage, only a single functionality is implemented, which is processing a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and run it through a module called SpiceEV for an in-depth SOC analysis. + +.. figure:: https://user-images.githubusercontent.com/104760879/217225545-5e6858c1-d056-4519-beea-6274d06533c7.png + :alt: ebus_toolbox_modules + :width: 800 + + Modules of the eBus-Toolbox + +.. figure:: https://user-images.githubusercontent.com/104760879/217226800-647956c5-9d63-4988-a710-f3326a8304d5.png + :alt: ebus_toolbox_default_plot + :width: 800 + + Default output plot for a single simulation. + +More text diff --git a/docs/source/index.rst b/docs/source/index.rst index 1e0da5f5..64c27c84 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,10 +3,15 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. +.. image:: https://user-images.githubusercontent.com/104760879/217226792-4297d3c8-8a7c-45ad-894f-5efd03031f49.png + :alt: ebus_toolbox_logo + Welcome to the eBus-Toolbox's documentation! ============================================ -This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies. +This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies in Python. + + .. toctree:: diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 7458fcc8..d59b4240 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -1,3 +1,7 @@ +# Without creating links like in the line below, subpages go missing from the sidebar + +.. _sim_modes: + Modes of the eBus-Toolbox ========================= @@ -10,15 +14,37 @@ different modes support the user in finding optimal solutions for their eBus-Sys * station optimization -simple simulation +Single simulation ----------------- -The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started` +The single simulation case is the default mode. Its usage is explained in :ref:`Getting Started` negative depot to opportunity charger ------------------------------------- +| This mode is the first kind of optimization provided by the eBus-Toolbox. It takes a scenario and uses the provided depot charger vehicle data to check if the scenario can run with only depot charger vehicles without socs falling below 0. Vehicles with a soc below 0 are changed to opportunity chargers with the provided opportunity charger vehicle data and the simulation is run again. +| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type exists. +| TBC + + negative opportunity to depot charger ------------------------------------- +| This mode is the similar to the previous optimization. It takes a scenario and uses the provided opportunity charger vehicle data to check if the scenario can run with only opportunity charger vehicles without socs falling below 0. Vehicles with a soc below 0 are changed to opportunity chargers with the provided depot charger vehicle data and the simulation is run again. +| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type exists. +| TBC + + +service optimization +-------------------- +This mode optimizes a scenario by creating sub-scenarios, so the given sub-scenario runs without socs falling below 0. The sub-scenario has the same input has the scenario but only consists of a sub-sets of rotations. These sub-sets are are optimized to be as big as possible. Previous negative rotations can become positive since effects like blocked charging points by other rotations can be reduced. station optimization --------------------- \ No newline at end of file +-------------------- +.. figure:: https://user-images.githubusercontent.com/104760879/217225177-66201146-d31a-4127-9ca0-4d6e6e5a3cc4.png + :alt: optimization_loop + + Caption + +.. figure:: https://user-images.githubusercontent.com/104760879/217225588-abfad83d-9d2a-463a-8597-584e29f5f885.png + :alt: below_0_soc_event + + Caption diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index f5db05bd..296d8fab 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -1,7 +1,9 @@ +.. _simulation_parameters: + Simulation Parameters ===================== -The simulation of an eBus-Sytem relies on a variety of simulation parameters. +The simulation of an eBus-System relies on a variety of simulation parameters. The eBus-Toolbox provides most of them as default values. Depending on specific needs adjusting these values can increase the accuracy of the simulation outputs. The eBus-Toolbox input files are described in detail in the following subsections as well as their default parameters. @@ -10,6 +12,9 @@ encoded or not contain regional characters. Configuration ------------- +The configuration file config.cfg is provided as example in ./examples/ and provides the user with most of the functionality surrounding the settings and boundary conditions of a simulation. The example contains parameter descriptions which are explained here in more detail: + +.. _schedule: Schedule -------- @@ -69,5 +74,47 @@ To analyze your own electric bus schedule, the data needs to be provided as a .c - 0.5. +.. _vehicle_types: + +Vehicle types +------------- +vehicle_type.json +tbc + +Electrified stations +-------------------- +Stations which are electrified. TBC + +Cost parameters +--------------- +TBC + + + +TBC + +.. _station_geo_data: + +Station data +------------ +Geodata. TBV + + +.. _level_of_loading: + +Level of loading +---------------- +TBC + +.. _temperature_data: + +Temperatures +------------ + +TBC +.. _consumption_table: +Consumption table +----------------- +The consumption table can be referenced in the :ref:`vehicle_types` file. Instead of constant consumption the eBus-Toolbox uses provided temperatures, level of loadings, mean speeds, average inclines and the vehicle type to interpolate the consumption value from this data table. Level of loading and temperatures are read from the :ref:`schedule` if the trips provide them. If they are missing from the schedule, they are looked up from the files :ref:`level_of_loading` and :ref:`temperature_data`. The average incline is calculated from :ref:`station_geo_data` and the mean speed is calculated by using the departure and arrival time and distance provided by the schedule. \ No newline at end of file From 30a667f8baf00a3a0c793381a04833761dd672f5 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Tue, 7 Feb 2023 12:25:50 +0100 Subject: [PATCH 10/58] Remove geopositons from this branch --- ebus_toolbox/plot_geoposition.py | 517 ------------------------------ ebus_toolbox/station_optimizer.py | 7 +- 2 files changed, 3 insertions(+), 521 deletions(-) delete mode 100644 ebus_toolbox/plot_geoposition.py diff --git a/ebus_toolbox/plot_geoposition.py b/ebus_toolbox/plot_geoposition.py deleted file mode 100644 index cb13cab6..00000000 --- a/ebus_toolbox/plot_geoposition.py +++ /dev/null @@ -1,517 +0,0 @@ -""" Module to implement plotting functionality of busses with georeferences""" -import datetime -import typing -import pathlib -from matplotlib.offsetbox import TextArea, AnnotationBbox - -import ebus_toolbox.util as util -import pickle -import csv -from typing import TYPE_CHECKING - -if TYPE_CHECKING: - import ebus_toolbox.trip - import ebus_toolbox.schedule - import spiceev.scenario - -import numpy as np -import matplotlib.pyplot as plt -import pandas as pd - -# Mathematical function we need to plot -from matplotlib.colors import LinearSegmentedColormap -import matplotlib -import matplotlib.animation as animation - -matplotlib.use("TkAgg") -import os - -shared_axis = None -FIGSIZE = (14, 5) -LINEWIDTH = 2 -DELIMITER = ';' -FRAMEALPHA = 0.8 -ALPHA_POINTS = 0.1 - -### -rli_dblue = (0, 46 / 255, 80 / 255) -rli_green = (68 / 255, 175 / 255, 105 / 255) -rli_orange = (254 / 255, 127 / 255, 45 / 255) -rli_yellow = (241 / 255, 196 / 255, 15 / 255) -rli_lblue = (34 / 255, 116 / 255, 165 / 255) -rli_dgrey = (51 / 255, 88 / 255, 115 / 255) -### Not from official coperate design -rli_red = (192 / 255, 0, 0) -rli_green2 = (0, 176 / 255, 80 / 255) -rli_brown = (132 / 255, 60 / 255, 12 / 255) -rli_black = (0, 0, 0) -rli_colors = [rli_dblue, rli_green, rli_orange, rli_yellow, rli_lblue, rli_dgrey, rli_black, - rli_red, rli_brown, rli_green2] -### - -cdict = {'red': [[0.0, 0, 0], - [0.2, 34 / 255, 34 / 255], - [0.4, 68 / 255, 68 / 255], - [0.6, 254 / 255, 254 / 255], - [0.8, 241 / 255, 241 / 255], - [1.0, 255 / 255, 255 / 255]], - 'green': [[0.0, 46 / 255, 46 / 255], - [0.2, 116 / 255, 116 / 255], - [0.4, 175 / 255, 175 / 255], - [0.6, 127 / 255, 127 / 255], - [0.8, 196 / 255, 196 / 255], - [1.0, 255 / 255, 255 / 255]], - 'blue': [[0.0, 80 / 255, 80 / 255], - [0.2, 165 / 255, 165 / 255], - [0.4, 105 / 255, 105 / 255], - [0.6, 45 / 255, 45 / 255], - [0.8, 15 / 255, 15 / 255], - [1.0, 255 / 255, 255 / 255]]} -rli_rainbow_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) - -cdict = {'red': [[0.0, 0, 0], - [0.33, 0, 0], - [0.66, 34 / 255, 34 / 255], - [1, 255 / 255, 255 / 255]], - 'green': [[0.0, 0, 0], - [0.33, 46 / 255, 46 / 255], - [0.66, 116 / 255, 116 / 255], - [1, 255 / 255, 255 / 255]], - 'blue': [[0.0, 0, 0], - [0.33, 80 / 255, 80 / 255], - [0.66, 165 / 255, 165 / 255], - [1, 255 / 255, 45 / 255]]} -rli_blue_cmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) - -f_path=pathlib.Path(__file__).parent.parent -with open(f_path / "schedule_rebased_BVG_BFI.pickle", "rb") as file: - schedule = pickle.load(file) - -with open(f_path / "scenario_rebased_BVG_BFI.pickle", "rb") as file: - scenario = pickle.load(file) - -with open(f_path / "args_rebased_BVG_BFI.pickle", "rb") as file: - args = pickle.load(file) - -args.station_data_path = "C:/Users/paul.scheer/Python/bus_toolbox/eBus-Toolbox/Haltestellen.csv" - -ANIMATION_DURATION_MIN = 480 - - -def main(): - pickle_path = None #"vehicle_data_frames.pickle" - with open(str(args.station_data_path), "r", encoding='utf-8') as f: - delim = util.get_csv_delim(args.station_data_path) - reader = csv.DictReader(f, delimiter=delim) - stations = dict() - for row in reader: - elevation = float(row['elevation']) - name = str(row['Endhaltestelle']) - lon = float(row['lon']) - lat = float(row['lat']) - stations[name] = station(name, lat, lon, elevation) - - start_time = scenario.start_time - time_step = datetime.timedelta(hours=1 / scenario.stepsPerHour) - - if not pickle_path: - vehicle_data_frames = pd.DataFrame() - for v_id, soc_data in scenario.vehicle_socs.items(): - rotations = get_sorted_rotations(v_id, schedule) - trips = [trip for rot in rotations for trip in rot.trips] - lats = [] - lons = [] - trip_nr = 0 - for counter, soc in enumerate(soc_data): - try: - current_time = start_time + counter * time_step - current_trip, found_trip_index = find_current_trip(trips[trip_nr:], - current_time) - trip_nr += found_trip_index - rel_time_of_trip = get_rel_time_of_trip(current_time, current_trip) - try: - current_station = stations[current_trip.departure_name] - except: - current_station = last_station - try: - next_station = stations[current_trip.arrival_name] - except: - next_station = current_station - last_station=current_station - lat, lon = current_station.get_lat_lon(next_station, rel_time_of_trip) - lats.append(lat) - lons.append(lon) - except IndexError: - pass - columns = [(v_id, "soc"), (v_id, "lat"), (v_id, "lon")] - data = np.array([soc_data, lats, lons]).transpose() - vehicle_data_frames = pd.concat( - (vehicle_data_frames, pd.DataFrame(data, columns=columns)), - axis=1) - - vehicle_data_frames.columns = pd.MultiIndex.from_tuples(vehicle_data_frames.columns, - names=['Vehicle_id', 'Data']) - - vehicle_data_frames.index = np.arange(start_time, start_time + - len(vehicle_data_frames) * time_step, time_step) - else: - with open(pickle_path, "rb") as f: - print("depickeling") - vehicle_data_frames = pickle.load(f) - - stations_to_annotate = {name: stat for name, stat in stations.items() if - name in schedule.stations} - - vehicle_data_frames = vehicle_data_frames.iloc[:24*60,:] - plot_merge_animate_battery(vehicle_data_frames, station_data=stations_to_annotate, - soc_threshold=1,track_black=False, vehicle_black=True, - save=False, repeat=True) - - -class station: - def __init__(self, name, lat, lon, elevation): - self.name = name - self.lat = lat - self.lon = lon - self.elevation = elevation - - def get_lat_lon(self, next_station, rel_pos): - lat_pos = (next_station.lat - self.lat) * rel_pos + self.lat - lon_pos = (next_station.lon - self.lon) * rel_pos + self.lon - return lat_pos, lon_pos - - -def get_sorted_rotations(v_id, schedule): - rots = [] - for rot in schedule.rotations.values(): - if rot.vehicle_id == v_id: - rots.append(rot) - return sorted(rots, key=lambda x: x.departure_time) - - -def plot_merge_animate_battery(data: pd.DataFrame, station_data=None, - save=False, repeat=True, vehicle_black=False, track_black=True, - track_method="min", soc_threshold=1.0): - - data.xs("lat", level="Data", axis=1) - lat_boundary = (data.xs("lat", level="Data", axis=1).min().min(), - data.xs("lat", level="Data", axis=1).max().max()) - lon_boundary = (data.xs("lon", level="Data", axis=1).min().min(), - data.xs("lon", level="Data", axis=1).max().max()) - - - v_max = 1 - v_min = 0 - fig = plt.figure(figsize=(14, 8)) - - fig.suptitle('Vehicle Tracking', fontsize=14) - - sub2 = fig.add_subplot(111) - ax = plt.gca() - - # Get all the vehicle ids from data - vehicles = list(data.columns.levels[0]) - - # Filter data for relevant SOCs - for v_id in vehicles: - if data[v_id]['soc'].min()>soc_threshold: - data=data.drop(v_id,axis=1) - data.columns = data.columns.remove_unused_levels() - vehicles = list(data.columns.levels[0]) - - # Plot track onto canvas via line which doesnt allow soc printing - # or via scatter plot. With a scatter plot the points can take the color of the soc which drove - # above the position. - - - round_nr = 3 - stacked_array_unique = make_unique_data(vehicles, data, track_method) - x_org= stacked_array_unique[0, :].copy() - y_org= stacked_array_unique[1, :].copy() - # - # stacked_array_unique[0, :] = stacked_array_unique[0, :] - min(stacked_array_unique[0, :]) - # stacked_array_unique[1, :] = stacked_array_unique[1, :] - min(stacked_array_unique[1, :]) - # stacked_array_unique[0, :] = stacked_array_unique[0, :] - # stacked_array_unique[0, :] = stacked_array_unique[0, :] * 10 ** round_nr - # stacked_array_unique[1, :] = stacked_array_unique[1, :] * 10 ** round_nr - ############## - # from scipy.ndimage import gaussian_filter as gauss - # fig = plt.figure(figsize=(8, 8)) - # - # fig.suptitle('Vehicle Tracking', fontsize=14) - # sub2 = fig.add_subplot(111) - # ax = plt.gca() - # - # stacked_array_pic = make_unique_data(vehicles, data, track_black, track_method, - # round_nr=round_nr) - # - # x = (stacked_array_pic[0, :] * 10 ** round_nr).astype(int) - # X = x - np.min(x) - # y = (stacked_array_pic[1, :] * 10 ** round_nr).astype(int) - # Y = y - np.min(y) - # z = stacked_array_pic[2, :] - # idx1 = X - # idx2 = Y - # grid_data = z - # grid = np.ones((np.max(Y) + 1, np.max(X) + 1)) - # grid[idx2, idx1] = grid_data - # ax.imshow(gauss(grid, 10)) - # ############################# - # fig = plt.figure(figsize=(14, 8)) - # - # fig.suptitle('Vehicle Tracking', fontsize=14) - # - # sub2 = fig.add_subplot(111) - # ax = plt.gca() - # - # x=stacked_array_unique[0,:] - # y=stacked_array_unique[1,:] - # z=stacked_array_unique[2,:] - # - # steps=500 - # X = np.linspace(stacked_array_unique[0, :].min(), stacked_array_unique[0, :].max(), steps) - # Y = np.linspace(stacked_array_unique[1, :].min(), stacked_array_unique[1, :].max(), steps) - # from scipy.interpolate import griddata - # Z = griddata((x, y), z,((X[None, :], Y[:, None])), method='linear') - # contour = sub2.contourf(X, Y, Z) - # ######################## - # ax.imshow(Z) - # ######################## - - if track_black: - for v_id in vehicles: - plot_dict = dict(color=(0.9, 0.9, 0.9), alpha=1) - lns2_1 = sub2.plot(data[v_id]['lat'], data[v_id]['lon'], - **plot_dict, linestyle='-', - linewidth=2) - else: - plot_dict = dict(c=stacked_array_unique[2, :] * 1, alpha=0.8) - lns2_1 = sub2.scatter(stacked_array_unique[0, :], stacked_array_unique[1, :], - **plot_dict, linestyle='-', - linewidth=0, vmin=v_min, vmax=v_max) - lns2_1.set_clim(vmin=v_min, vmax=v_max) - - # Helper plot so we can plot a colorbar aftwards, not possible with only line plot - plot_dict = dict() - lns2_1 = sub2.scatter([], [], - **plot_dict, linestyle='-', - linewidth=0, vmin=v_min, vmax=v_max) - - cbar = fig.colorbar(lns2_1, ax=ax, pad=0.0) - cbar.set_alpha(1) - cbar.draw_all() - cbar.set_label("SOC") - - # Plot Station Names - if station_data: - for station in station_data.values(): - # xy=((station.lat-np.min(x_org))*10**round_nr, (station.lon-np.min(y_org))*10**round_nr) - xy=(station.lat, station.lon) - ax.annotate(station.name, - xy=xy, xycoords='data', xytext=(0, 5), textcoords='offset points', fontsize=8, ha='center') - ax.plot(xy[0], xy[1], 'ko', zorder=100) - - artist_objects = [] - for _ in vehicles: - lns2_1 = sub2.scatter([0, 0], [0, 0], [0, 100]) - artist_objects.append(lns2_1) - - d_bound = 0.005 - sub2.set_ylim((lon_boundary[0] - d_bound, lon_boundary[1] + d_bound)) - sub2.set_xlim((lat_boundary[0] - d_bound, lat_boundary[1] + d_bound)) - sub2.set_ylabel('Position') - sub2.set_xlabel('Position') - - text_box = TextArea(data.index[0]) - - time_annotation_box = [AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', - fontsize=15)] - ax.add_artist(time_annotation_box[0]) - hover_texts = [str(v_id) for v_id in vehicles] - - def animate(i, data, counter=[]): - roll_v = 1 - len_v = 1 - ax = plt.gca() - vehicles = list(data.columns.levels[0]) - if not counter: - counter.append(i) - else: - counter[0] += 1 - i = counter[0] - start_index = i * roll_v + 8 * 60 - end_index = start_index + len_v - try: - ax.artists.remove(time_annotation_box[0]) - except: - return artist_objects - text_box = TextArea(data.index[start_index]) - time_annotation_box[0] = AnnotationBbox(text_box, xy=(0.1, 0.1), xycoords='axes fraction', - fontsize=15) - ax.add_artist(time_annotation_box[0]) - # - # - - plot_dict = dict(color=(0, 0, 0)) - artist_objects[0].remove() - lat_data=data.xs("lat", level="Data", axis=1).iloc[start_index:end_index].values - lon_data=data.xs("lon", level="Data", axis=1).iloc[start_index:end_index].values - soc_data=data.xs("soc", level="Data", axis=1).iloc[start_index:end_index].mean().values - if vehicle_black: - plot_dict = dict(color=(0, 0, 0)) - else: - plot_dict = dict(c=soc_data) - artist_objects[0] = sub2.scatter(lat_data, - lon_data, - **plot_dict, - vmin=0, vmax=1, - linestyle='-', - linewidth=0, zorder=50) - - # - # - # for k, v_id in enumerate(vehicles): - # artist_objects[k].remove() - # mean_soc = data[v_id]["soc"][start_index:end_index].mean() - # if vehicle_black: - # plot_dict = dict(color=(0, 0, 0)) - # else: - # l = len(data[v_id]["lat"][start_index:end_index]) - # plot_dict = dict(c=mean_soc * np.ones(l)) - # artist_objects[k] = sub2.scatter(data[v_id]["lat"][start_index:end_index], - # data[v_id]["lon"][start_index:end_index], - # **plot_dict, - # vmin=0, vmax=1, - # linestyle='-', - # linewidth=0, zorder=50) - # hover_texts[k] = (v_id, str(round(mean_soc, 3))) - - if end_index >= len(data): - counter[0] = 0 - - return artist_objects - - ax.axis('off') - # create animation using the animate() function - - my_animation = animation.FuncAnimation(fig, - lambda i: animate(i, data), - frames=ANIMATION_DURATION_MIN, - interval=15, blit=False, repeat=repeat) - - # - sub2.set_ylabel('Position') - sub2.set_xlabel('Position') - - fig.canvas.mpl_connect("motion_notify_event", lambda event: hover_for_scatter( - event, fig, ax, artist_objects, hover_texts)) - # Toggle save for saving - if save: - my_animation.save('SOC_animation.gif', writer='imagemagick') - - fig.tight_layout() - - def on_close(event): - plt.close() - print('Closed Figure!') - fig.canvas.mpl_connect('close_event',lambda event:on_close(event)) - plt.show(block=True) - print("stopped") - -def make_unique_data(vehicles, data, track_method, round_nr=None): - v_iter = iter(vehicles) - v_id = next(v_iter) - data = pd.DataFrame(data) - if not round_nr: - r = lambda x: x - else: - r = lambda i: round(i, round_nr) - stacked_array = np.array((r(data[v_id]['lat']), r(data[v_id]['lon']), data[v_id]['soc'])) - for v_id in v_iter: - stacked_array = np.hstack( - (stacked_array, (r(data[v_id]['lat']), r(data[v_id]['lon']), data[v_id]['soc']))) - stacked_array = stacked_array.astype(float) - # stacked_array has all vehicle socs and geo positions in - unique_mask = np.unique(stacked_array[0:2, :], axis=1, return_index=True)[1] - stacked_array_unique = stacked_array[:, unique_mask] - - # find soc data for stacked array depending on method. Since its only needed if the track is not black check this as well - - apply_function = None - if track_method == "mean": - apply_function = np.mean - elif track_method == "max": - apply_function = np.max - else: - apply_function = np.min - - for geo_index in range(len(stacked_array_unique)): - geo_loc = stacked_array_unique[0:2, geo_index] - found_positions = np.all([stacked_array[0:2, :].T == geo_loc], axis=0)[:, 0] - fill_value = apply_function(stacked_array[2, found_positions]) - stacked_array_unique[2, geo_index] = fill_value - - return stacked_array_unique - - -def hover_for_scatter(event, fig, ax, plot_points: typing.Iterable[matplotlib.lines.Line2D], - hover_texts: typing.Iterable[str], annotations=[]): - """Called when user hovers over plot. - Checks if user hovers over point. If so, delete old annotation and - create new one with relevant info from the hover_texts list. - If user does not hover over point, remove annotation, if any. - """ - if len(annotations) == 0: - annotations.append(None) - for i, points in enumerate(plot_points): - if points and event.inaxes == ax: - # results shown, mouse within plot: get event info - # cont: any points hovered? - # ind: list of points hovered - cont, ind = points.contains(event) - - if cont and "ind" in ind: - ind = ind["ind"] - # points hovered - # get all point coordinates - xy = points.get_offsets().data - text = hover_texts[i] - - # # remove old annotation - if annotations and annotations[0]: - annotations[0].remove() - annotations[0] = None - - # create new annotation - annotations[0] = ax.annotate( - text, - xy=(xy[ind[0]][0], xy[ind[0]][1]), - xytext=(-20, 20), - textcoords="offset points", - bbox=dict(boxstyle="round", fc="w"), - arrowprops={'arrowstyle': "-"}, - annotation_clip=False) - fig.canvas.draw() - - -def find_current_trip(trips, current_time): - for i, trip in enumerate(trips): - try: - next_trip = trips[i + 1] - if next_trip.departure_time > current_time: - return trip, i - except IndexError: - return trip, i - else: - raise Exception("no trip found for time: " + str(current_time)) - - -def get_rel_time_of_trip(current_time: datetime.datetime, current_trip: 'ebus_toolbox.trip.Trip'): - trip_time= (current_trip.arrival_time - current_trip.departure_time) - rel_time = (current_time - current_trip.departure_time) / \ - max(trip_time,datetime.timedelta(minutes=1)) - return min(1, max(rel_time, 0)) - - -if __name__ == "__main__": - main() diff --git a/ebus_toolbox/station_optimizer.py b/ebus_toolbox/station_optimizer.py index b3aae32a..e96c98f1 100644 --- a/ebus_toolbox/station_optimizer.py +++ b/ebus_toolbox/station_optimizer.py @@ -439,7 +439,7 @@ def get_charge_events_per_station(self, station_name, rotations=None): warnings.warn("Station to be checked has no following trip. Final destinations" "can not offer lift to the soc and are therefore discarded") continue - arrival_time= trip.arrival_time + arrival_time = trip.arrival_time start_idx = self.get_index_by_time(charging_event_start_time) end_time = rot.trips[i+1].departure_time buffer_time = util.get_buffer_time(trip, self.args.default_buffer_time_opps) @@ -447,7 +447,7 @@ def get_charge_events_per_station(self, station_name, rotations=None): cht = rot.vehicle_id.find("depb") ch_type = (cht > 0) * "depb" + (cht <= 0) * "oppb" v_type = rot.vehicle_id.split("_" + ch_type)[0] - event = util.ChargingEvent(start_idx=start_idx,end_idx=end_idx, + event = util.ChargingEvent(start_idx=start_idx, end_idx=end_idx, arrival_time=arrival_time, start_time=charging_event_start_time, end_time=end_time, buffer_time=buffer_time, vehicle_id=rot.vehicle_id, @@ -457,7 +457,6 @@ def get_charge_events_per_station(self, station_name, rotations=None): charging_events.append(event) return charging_events - def sort_station_events(self, charge_events_single_station): return sorted(charge_events_single_station, key=lambda x: x.arrival_time) @@ -885,7 +884,7 @@ def get_must_stations_and_rebase(self, relative_soc=False): ############### must_stations = {'Heppenheim Graben', 'Wahlen Grundschule', 'Erbach Gesundheiszentrum', - 'Heppenheim Vogelsbergstraße', 'Rimbach Kirche', 'Hirschhorn Grundschule', + 'Heppenheim Vogelsbergstraße', 'Rimbach Kirche', 'Hirschhorn Grundschule', 'Bensheim Geschw.-Scholl-Schule', 'Lindenfels Poststraße', 'Heppenheim Bahnhof', 'Zotzenbach Schule', 'Heppenheim Kreiskrankenhaus', 'Weinheim Hauptbahnhof', 'Worms Hauptbahnhof', From 65ab842d07d9f0d412a9faa170ddb97b93a44058 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Tue, 7 Feb 2023 12:27:17 +0100 Subject: [PATCH 11/58] Make flake8 happy --- ebus_toolbox/optimizer_util.py | 5 +++-- ebus_toolbox/station_optimization.py | 8 ++++---- ebus_toolbox/station_optimizer.py | 2 -- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ebus_toolbox/optimizer_util.py b/ebus_toolbox/optimizer_util.py index b0cf2a83..7cfefd0e 100644 --- a/ebus_toolbox/optimizer_util.py +++ b/ebus_toolbox/optimizer_util.py @@ -25,7 +25,7 @@ class ChargingEvent: """ Class to gather information about a charging event""" - def __init__(self, start_idx, end_idx,arrival_time, start_time, end_time, buffer_time, + def __init__(self, start_idx, end_idx, arrival_time, start_time, end_time, buffer_time, vehicle_id, capacity, station_name, rotation): self.start_idx = start_idx @@ -213,9 +213,9 @@ def get_charging_time(trip1, trip2, args): return 0 return max(0, standing_time_min) + def get_charging_start(trip1, args): """ Returns the possible start of charging consindering buffer times - :param trip1: First trip :param args: arguments Namespace with default buffer time :return: First possible charging time as datetime object @@ -223,6 +223,7 @@ def get_charging_start(trip1, args): buffer_time = get_buffer_time(trip1, args.default_buffer_time_opps) return trip1.arrival_time+buffer_time + def get_buffer_time(trip, default_buffer_time_opps): """ Return the buffer time as timedelta object :param trip: trip object diff --git a/ebus_toolbox/station_optimization.py b/ebus_toolbox/station_optimization.py index 276b5603..02163f6b 100644 --- a/ebus_toolbox/station_optimization.py +++ b/ebus_toolbox/station_optimization.py @@ -54,7 +54,7 @@ def main(): """ main call""" util.print_time() config_path = "./data/examples/optimizer.cfg" - opt_sched, opt_scen= run_optimization(config_path) + opt_sched, opt_scen = run_optimization(config_path) util.print_time() import pickle with open("schedule_opt.pickle", "wb") as f: @@ -121,8 +121,8 @@ def run_optimization(config_path, sched=None, scen=None, this_args=None): logger = setup_logger(args, conf) - # remove those args, since they lead to file creation, which is not - # needed. + # remove those args, since they lead to file creation, which is not + # needed. if not conf.save_all_results: del args.save_timeseries del args.save_results @@ -178,7 +178,7 @@ def run_optimization(config_path, sched=None, scen=None, this_args=None): for event in new_events: logger.debug(event.rotation.id) with open(new_ele_stations_path, "w", encoding="utf-8") as file: - json.dump(ele_stations, file,ensure_ascii=False, indent=2) + json.dump(ele_stations, file, ensure_ascii=False, indent=2) util.print_time() logger.debug("Spice EV is calculating optimized case as a complete scenario") _, __ = optimizer.preprocessing_scenario( diff --git a/ebus_toolbox/station_optimizer.py b/ebus_toolbox/station_optimizer.py index e96c98f1..a39cac8a 100644 --- a/ebus_toolbox/station_optimizer.py +++ b/ebus_toolbox/station_optimizer.py @@ -429,8 +429,6 @@ def get_charge_events_per_station(self, station_name, rotations=None): try: charging_event_start_time = util.get_charging_start(trip, self.args) end_time = rot.trips[i + 1].departure_time - - # Do not add the event if there is charging time of at least the defined # min charging time if charging_event_start_time + self.args.min_charging_time >= end_time: From 8bdf7a72756b4c83e8c2df36f4a2d0ae3e95eb4b Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 8 Feb 2023 14:25:15 +0100 Subject: [PATCH 12/58] Add more doc --- docs/source/conf.py | 2 +- docs/source/getting_started.rst | 19 +++++++++++++------ docs/source/index.rst | 6 ++---- docs/source/modes.rst | 10 ++++++++++ docs/source/simulation_parameters.rst | 18 ++++++++++++++++-- 5 files changed, 42 insertions(+), 13 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 56dbe2a0..3daca017 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -43,7 +43,7 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary','sphinx.ext.autosectionlabel'] - +numfig = True # Add any paths that contain templates here, relative to this directory. templates_path = [] diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 5c3810ec..53d1d8d8 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -14,7 +14,9 @@ Installation ------------ To try it out, first clone `this repository `_ and then install the required packages to your current environment by running -`pip install -r requirements.txt` + + +``pip install -r requirements.txt`` Now you can start the eBus Toolbox module with all configurations stored at `data/configs/ebus_toolbox.cfg` via the command @@ -22,26 +24,31 @@ Now you can start the eBus Toolbox module with all configurations stored at `dat The repo provides an example for each necessary input file, so the example case can be executed without the need for the user to provide any data themselves. -To run the eBus Toolbox with your own `schedule.csv` (see details [below](#input-data)) file and default configurations run +To run the eBus-Toolbox with your own `schedule.csv` (see :ref:`schedule`)) file and default configurations run -`python -m ebus_toolbox --input_schedule path/to/schedule.csv` +``python -m ebus_toolbox --input_schedule path/to/schedule.csv`` Default configurations are detailed at `data/configs/ebus_toolbox.cfg`. General Concept --------------- -At the current stage, only a single functionality is implemented, which is processing a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and run it through a module called SpiceEV for an in-depth SOC analysis. +At the current stage several functionalities are implemented. The base simulation processes a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and runs it through a module called SpiceEV for an in-depth SOC analysis. +Other modes can alter bus types from depot to opportunity chargers, optimize sets of rotations to increase electrification or suggest stations for electrification by minimizing the amount of stations needed. You can learn more about the modes :ref:`here ` +.. _figure_ebus_toolbox_modules: .. figure:: https://user-images.githubusercontent.com/104760879/217225545-5e6858c1-d056-4519-beea-6274d06533c7.png :alt: ebus_toolbox_modules - :width: 800 + :width: 600 Modules of the eBus-Toolbox +:numref:`figure_ebus_toolbox_modules` shows how the different modules work together to calculate the scenario. Optionally different optimizations can be used or even chained together. The output of the simulation is locally saved and consists of the vehicle socs, summaries for each rotation, estimated costs for vehicles, infrastructure and operation as well as station specific electric loads, utilization rates and other key performance indicators. Some of them can be plotted automatically and can be seen in :numref:`ebus_toolbox_default_plot` + +.. _ebus_toolbox_default_plot: .. figure:: https://user-images.githubusercontent.com/104760879/217226800-647956c5-9d63-4988-a710-f3326a8304d5.png :alt: ebus_toolbox_default_plot - :width: 800 + :width: 600 Default output plot for a single simulation. diff --git a/docs/source/index.rst b/docs/source/index.rst index 64c27c84..b1a0ac92 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -12,8 +12,6 @@ Welcome to the eBus-Toolbox's documentation! This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies in Python. - - .. toctree:: :maxdepth: 3 :caption: Contents: @@ -21,11 +19,11 @@ This toolbox extends the functionality of the Open Source simulation tool SpiceE getting_started modes simulation_parameters - + modindex Indices and tables ================== * :ref:`genindex` * :ref:`modindex` -* :ref:`search` + diff --git a/docs/source/modes.rst b/docs/source/modes.rst index d59b4240..c6563bbd 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -39,12 +39,22 @@ This mode optimizes a scenario by creating sub-scenarios, so the given sub-scena station optimization -------------------- +.. _optimization_loop: .. figure:: https://user-images.githubusercontent.com/104760879/217225177-66201146-d31a-4127-9ca0-4d6e6e5a3cc4.png + :width: 600 :alt: optimization_loop Caption +:numref:`optimization_loop` shows xxxxxxxxxxxxxxxxxxx + .. figure:: https://user-images.githubusercontent.com/104760879/217225588-abfad83d-9d2a-463a-8597-584e29f5f885.png + :width: 600 :alt: below_0_soc_event Caption + + +chained modes +------------- +Lorem ipsum ... \ No newline at end of file diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 296d8fab..6e4ab315 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -35,13 +35,13 @@ To analyze your own electric bus schedule, the data needs to be provided as a .c - Name of the station the trip starts at - Warschauer Straße * - departure_time - - Date and Time at which bus starts trip + - Date and time at which bus starts trip (ISO-Format) - 2022-03-13T10:25 * - arrival_name - Name of the station the trip ends at - Ostbahnhof Berlin * - arrival_time - - Date and Time at which bus completes trip (e.g. yyyy-mm-ddThh:mm[:ss]) + - Date and Time at which bus completes trip (ISO-Format) (e.g. yyyy-mm-ddThh:mm[:ss]) - 2022-03-13T10:30 * - distance - Distance traveled in **m** @@ -73,6 +73,20 @@ To analyze your own electric bus schedule, the data needs to be provided as a .c - The level of loading of the bus on this trip in between 0 and 1 - 0.5. +This is how a schedule file might look like. + ++--------+----------------+---------------------+---------------------+--------------+----------+-------------+--------------+-------------+------------------+ +| line | departure_name | departure_time | arrival_time | arrival_name | distance | rotation_id | vehicle_type | temperature | level_of_loading | ++========+================+=====================+=====================+==============+==========+=============+==============+=============+==================+ +| LINE_0 | Station-0 | 2022-03-07 21:28:00 | 2022-03-07 21:31:00 | Station-1 | 1530 | 1 | 12m_bus | 20 | 0 | ++--------+----------------+---------------------+---------------------+--------------+----------+-------------+--------------+-------------+------------------+ +| LINE_0 | Station-1 | 2022-03-07 21:31:00 | 2022-03-07 22:04:00 | Station-3 | 14519 | 1 | 12m_bus | -5 | 0.9 | ++--------+----------------+---------------------+---------------------+--------------+----------+-------------+--------------+-------------+------------------+ +| LINE_0 | Station-3 | 2022-03-07 22:08:00 | 2022-03-07 22:43:00 | Station-1 | 13541 | 1 | 12m_bus | | | ++--------+----------------+---------------------+---------------------+--------------+----------+-------------+--------------+-------------+------------------+ +| LINE_0 | Station-1 | 2022-03-07 22:51:00 | 2022-03-07 23:24:00 | Station-2 | 14519 | 1 | 12m_bus | | | ++--------+----------------+---------------------+---------------------+--------------+----------+-------------+--------------+-------------+------------------+ + .. _vehicle_types: From dc7bdcfbfe072821c1782db9769378f7eabe3c26 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Fri, 24 Feb 2023 10:45:53 +0100 Subject: [PATCH 13/58] Extend modes --- docs/source/modes.rst | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index c6563bbd..86a50882 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -11,12 +11,24 @@ different modes support the user in finding optimal solutions for their eBus-Sys * simple simulation * negative depot to opportunity charger * negative opportunity to depot charger +* service optimization * station optimization +* report +While the default mode is the simple simulation modes can be chained together to achieve the desired results. The chain of modes is defined in the config file (default: ebus_toolbox.cfg) under the keyword *mode*: +:: + mode = ["sim", "report"] -Single simulation +This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. An extended simple use case would be + mode = ["sim", "report" ,"neg_depb_to_oppb", "report] + + + + +simple simulation ----------------- -The single simulation case is the default mode. Its usage is explained in :ref:`Getting Started` +The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data + negative depot to opportunity charger ------------------------------------- From 510389a884aa4c1022da9d82e20b86d20799f639 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Fri, 24 Feb 2023 11:45:35 +0100 Subject: [PATCH 14/58] Extend modes --- docs/source/modes.rst | 47 ++++++++++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 86a50882..71487357 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -15,34 +15,43 @@ different modes support the user in finding optimal solutions for their eBus-Sys * station optimization * report -While the default mode is the simple simulation modes can be chained together to achieve the desired results. The chain of modes is defined in the config file (default: ebus_toolbox.cfg) under the keyword *mode*: +chained modes +------------- +While the default mode of the ebus-toolbox 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: ebus_toolbox.cfg) under the keyword *mode*: :: mode = ["sim", "report"] -This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. An extended simple use case would be +This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. Their output describes the simulation outcome of this mutated schedule. An extended simple use case would be +:: mode = ["sim", "report" ,"neg_depb_to_oppb", "report] - - +Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. The description what the modes do +can be found below. simple simulation ----------------- -The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data +The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. Every chain of modes starts with a simple simulation, even if it is not explicitly called. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The charging type for each rotation is read from the trips.csv if this data is included. If not the *preferred_charging_type* from the config file is used, as long as the provided vehicles data provides the preferred_charging_type for the specified vehicle type. negative depot to opportunity charger ------------------------------------- -| This mode is the first kind of optimization provided by the eBus-Toolbox. It takes a scenario and uses the provided depot charger vehicle data to check if the scenario can run with only depot charger vehicles without socs falling below 0. Vehicles with a soc below 0 are changed to opportunity chargers with the provided opportunity charger vehicle data and the simulation is run again. -| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type exists. -| TBC + +This mode is the first kind of optimization provided by the eBus-Toolbox and is called by +:: + mode = ["neg_depb_to_oppb"] +It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. +| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. negative opportunity to depot charger ------------------------------------- -| This mode is the similar to the previous optimization. It takes a scenario and uses the provided opportunity charger vehicle data to check if the scenario can run with only opportunity charger vehicles without socs falling below 0. Vehicles with a soc below 0 are changed to opportunity chargers with the provided depot charger vehicle data and the simulation is run again. -| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type exists. -| TBC +|This mode is analogous to *neg_depb_to_oppb* +This mode is the second kind of optimization provided by the eBus-Toolbox and is called by +:: + mode = ["neg_oppb_to_depb"] +It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to opportunity chargers. +| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as opportunity charger exists in the provided vehicles_data.json. service optimization @@ -67,6 +76,20 @@ station optimization Caption +report +----------------- +The The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. + + chained modes ------------- -Lorem ipsum ... \ No newline at end of file +While the default mode of the ebus-toolbox is the simple simulation, modes can be chained together to achieve the desired results. The chain of modes is defined in the config file (default: ebus_toolbox.cfg) under the keyword *mode*: +:: + mode = ["sim", "report"] + +This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. An extended simple use case would be +:: + mode = ["sim", "report" ,"neg_depb_to_oppb", "report] + +Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. The description what the modes do +can be found below. \ No newline at end of file From 462409d1149d826e505cfd37ab1d670d153bd4ff Mon Sep 17 00:00:00 2001 From: Jakob Gemassmer Date: Thu, 6 Apr 2023 13:28:21 +0200 Subject: [PATCH 15/58] explanation of cost calculation in rtd --- docs/source/modes.rst | 97 ++++++++++++++++++++++++++++++++++++++++++- ebus_toolbox/costs.py | 1 + 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index c6563bbd..204411a2 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -12,6 +12,7 @@ different modes support the user in finding optimal solutions for their eBus-Sys * negative depot to opportunity charger * negative opportunity to depot charger * station optimization +* report Single simulation @@ -57,4 +58,98 @@ station optimization chained modes ------------- -Lorem ipsum ... \ No newline at end of file +Lorem ipsum ... + + +Report +------------- +Cost calculation +~~~~~~~~~~~~~ + +This mode calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. +The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV `_ for the calculation of electricity costs. + +* Investment + * **Busses**: Costs for all busses used in the simulation. Costs include battery swaps, depending on the lifetime of both busses and batteries. + * **Charging infrastructure**: Costs for all depot and opportunity charging stations, depending on the number of actually used charging stations at each grid connector. + * **Grid connectors**: Costs for grid connectors and transformers, depending on the voltage level and the distance to the grid. + * **Garages**: Costs for workstations and charging infrastructure at garages. + * **Stationary storages**: Costs for stationary batteries at depot and opportunity stations, depending on its capacity. +* Maintenance + * Depending on the lifetime of each component maintenance costs are calculated for busses, charging infrastructure, grid connectors and stationary storages. +* Electricity + * **Power procurement**: Costs for the procurement of energy. + * **Grid fees**: Costs for power and energy price, depending on the voltage level and the utilization time per year. + * **Taxes**: Taxes like electricity taxes, depending on given taxes by price sheet. + * **Feed-in remuneration**: Remuneration for electricity fed into the grid. + +As result the following table is saved as CSV: + ++---------------------------------+----------+-----------------------------------------------------------------------+ +|**parameter** | **unit** | **description** | ++=================================+==========+=======================================================================+ +|c_vehicles | EUR | Investment costs of all busses | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_gcs | EUR | Investment costs of all grid connectors | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_cs | EUR | Investment costs of all charging stations | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage_cs | EUR | Investment costs of charging stations at garages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage | EUR | Investment costs of garages itself | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage_workstations | EUR | Investment costs of working stations at garages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_stat_storage | EUR | Investment costs of stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_invest | EUR | Sum of all investment costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_vehicles_annual | EUR/year | Annual investment costs of all busses | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_gcs_annual | EUR/year | Annual investment costs of all grid connectors | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_cs_annual | EUR/year | Annual investment costs of all charging stations | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage_annual | EUR/year | Sum of annual investment costs of garages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_stat_storage_annual | EUR/year | Annual investment costs of all stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_invest_annual | EUR/year | Sum of all annual investment costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_gc_annual | EUR/year | Annual maintenance costs of grid connectors | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_infrastructure_annual | EUR/year | Annual maintenance costs of charging stations and stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_vehicles_annual | EUR/year | Annual maintenance costs of busses | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_stat_storage_annual | EUR/year | Annual maintenance costs of stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_annual | EUR/year | Sum of annual maintenance costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_procurement_annual | EUR/year | Annual costs of power procurement | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_power_price_annual | EUR/year | Annual grid fee for highest load peak | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_energy_price_annual | EUR/year | Annual grid fee for drawn energy | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_taxes_annual | EUR/year | Annual costs for all electricity related taxes | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_feed_in_remuneration_annual | EUR/year | Annual feed-in remuneration | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_annual | EUR/year | Sum of all annual electricity costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ + + + + + + + + + + + + diff --git a/ebus_toolbox/costs.py b/ebus_toolbox/costs.py index e89b11c8..e2dc65dd 100644 --- a/ebus_toolbox/costs.py +++ b/ebus_toolbox/costs.py @@ -150,6 +150,7 @@ def calculate_costs(c_params, scenario, schedule, args): costs["c_maint_annual"] = (costs["c_maint_infrastructure_annual"] + costs["c_maint_vehicles_annual"]) costs["c_invest"] = costs["c_vehicles"] + costs["c_cs"] + costs["c_gcs"] + costs["c_garage"] + # ToDo: add stat storages to investment costs (also annual)? costs["c_invest_annual"] = (costs["c_vehicles_annual"] + costs["c_cs_annual"] + costs["c_gcs_annual"] + costs["c_garage_annual"]) From 48653934a2fe452d990f6a4c47302e8e5200892b Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Tue, 25 Apr 2023 14:19:16 +0200 Subject: [PATCH 16/58] Fix several issues with doc string formatting, e.g. blank lines and identation --- docs/source/ebus_toolbox.rst | 8 -------- docs/source/modes.rst | 27 +++------------------------ ebus_toolbox/consumption.py | 1 + ebus_toolbox/optimizer_util.py | 4 +++- ebus_toolbox/schedule.py | 3 +++ ebus_toolbox/util.py | 6 ++++-- 6 files changed, 14 insertions(+), 35 deletions(-) diff --git a/docs/source/ebus_toolbox.rst b/docs/source/ebus_toolbox.rst index cef1ada6..e7a1a296 100644 --- a/docs/source/ebus_toolbox.rst +++ b/docs/source/ebus_toolbox.rst @@ -36,14 +36,6 @@ ebus\_toolbox.optimizer\_util module :undoc-members: :show-inheritance: -ebus\_toolbox.plot\_geoposition module --------------------------------------- - -.. automodule:: ebus_toolbox.plot_geoposition - :members: - :undoc-members: - :show-inheritance: - ebus\_toolbox.report module --------------------------- diff --git a/docs/source/modes.rst b/docs/source/modes.rst index d02b55af..53762fc8 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -19,7 +19,7 @@ chained modes ------------- While the default mode of the ebus-toolbox 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: ebus_toolbox.cfg) under the keyword *mode*: :: - mode = ["sim", "report"] + mode = ["sim", "report"] This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. Their output describes the simulation outcome of this mutated schedule. An extended simple use case would be :: @@ -39,8 +39,7 @@ negative depot to opportunity charger This mode is the first kind of optimization provided by the eBus-Toolbox and is called by :: mode = ["neg_depb_to_oppb"] -It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. -| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. +It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. | NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. @@ -76,29 +75,9 @@ station optimization Caption -report ------------------ -The The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. - - -chained modes -------------- -While the default mode of the ebus-toolbox is the simple simulation, modes can be chained together to achieve the desired results. The chain of modes is defined in the config file (default: ebus_toolbox.cfg) under the keyword *mode*: -:: - mode = ["sim", "report"] - -This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. An extended simple use case would be -:: - mode = ["sim", "report" ,"neg_depb_to_oppb", "report] - -Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. The description what the modes do -can be found below. -======= -Lorem ipsum ... - - Report ------------- +The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Cost calculation ~~~~~~~~~~~~~ diff --git a/ebus_toolbox/consumption.py b/ebus_toolbox/consumption.py index 7857abf0..f66cc0f5 100644 --- a/ebus_toolbox/consumption.py +++ b/ebus_toolbox/consumption.py @@ -33,6 +33,7 @@ def __init__(self, vehicle_types, **kwargs) -> None: def calculate_consumption(self, time, distance, vehicle_type, charging_type, temp=None, height_diff=0, level_of_loading=None, mean_speed=18): """ Calculates consumed amount of energy for a given distance. + :param time: The date and time at which the trip ends :type time: datetime.datetime :param distance: Distance travelled [m] diff --git a/ebus_toolbox/optimizer_util.py b/ebus_toolbox/optimizer_util.py index 7cfefd0e..9c01e25c 100644 --- a/ebus_toolbox/optimizer_util.py +++ b/ebus_toolbox/optimizer_util.py @@ -584,7 +584,8 @@ def combs_unordered_no_putting_back(n: int, k: int): def run_schedule(this_sched, this_args, electrified_stations=None, cost_calc=False): - """Run a given schedule and electrify stations if need be + """Run a given schedule and electrify stations if need be. + :param this_sched: schedule object :param this_args: args namespace object :param electrified_stations: dict of electrified stations. Default value None means no further @@ -593,6 +594,7 @@ def run_schedule(this_sched, this_args, electrified_stations=None, cost_calc=Fal :raises SystemExit: in case of wrong cost calculation file :return: schedule and scenario objects after spiceev simulation """ + this_sched2 = copy(this_sched) this_sched2.stations = electrified_stations this_sched2, new_scen = preprocess_schedule(this_sched2, this_args, diff --git a/ebus_toolbox/schedule.py b/ebus_toolbox/schedule.py index 88fb6382..80b127cd 100644 --- a/ebus_toolbox/schedule.py +++ b/ebus_toolbox/schedule.py @@ -63,6 +63,7 @@ def from_csv(cls, path_to_csv, vehicle_types, stations, **kwargs): :return: Returns a new instance of Schedule with all trips from csv loaded. :rtype: Schedule """ + schedule = cls(vehicle_types, stations, **kwargs) station_data = dict() @@ -190,12 +191,14 @@ def run(self, args): def set_charging_type(self, ct, rotation_ids=None): """ Change charging type of either all or specified rotations. Adjust minimum standing time at depot after completion of rotation. + :param ct: Choose this charging type wheneever possible. Either 'depb' or 'oppb'. :type ct: str :param rotation_ids: IDs of rotations for which to set charging type. If None set charging charging type for all rotations. :type rotation_ids: list """ + assert ct in ["oppb", "depb"], f"Invalid charging type: {ct}" for id, rot in self.rotations.items(): diff --git a/ebus_toolbox/util.py b/ebus_toolbox/util.py index 1885bb87..9a9c386a 100644 --- a/ebus_toolbox/util.py +++ b/ebus_toolbox/util.py @@ -17,8 +17,9 @@ def save_version(file_path): def get_buffer_time(trip, default=0): """ Get buffer time at arrival station of a trip. - Buffer_time is an abstraction of delays like docking procedures and - is added to the planned arrival time + + Buffer_time is an abstraction of delays like docking procedures and is added to the planned + arrival time. :param trip: The of buffer time of this trips arrival is returned. :type trip: ebus_toolbox.Trip @@ -39,6 +40,7 @@ def get_buffer_time(trip, default=0): "else": 1 } """ + schedule = trip.rotation.schedule buffer_time = schedule.stations.get(trip.arrival_name, {}).get('buffer_time', default) From 054a526eff8906df65700e029cbd230476f4df34 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Tue, 25 Apr 2023 16:42:40 +0200 Subject: [PATCH 17/58] Add to the station optimizer --- docs/source/modes.rst | 55 +++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 53762fc8..78a5aae6 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -1,4 +1,5 @@ -# Without creating links like in the line below, subpages go missing from the sidebar +.. + # Without creating links like in the line below, subpages go missing from the sidebar .. _sim_modes: @@ -15,58 +16,77 @@ different modes support the user in finding optimal solutions for their eBus-Sys * station optimization * report -chained modes +Chained Modes ------------- While the default mode of the ebus-toolbox 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: ebus_toolbox.cfg) under the keyword *mode*: + :: + mode = ["sim", "report"] -This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. Their output describes the simulation outcome of this mutated schedule. An extended simple use case would be +This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. Their output describes the simulation outcome of this mutated schedule. An extended simple use case would be: + :: + mode = ["sim", "report" ,"neg_depb_to_oppb", "report] Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. The description what the modes do can be found below. -simple simulation +Simple Simulation ----------------- -The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. Every chain of modes starts with a simple simulation, even if it is not explicitly called. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The charging type for each rotation is read from the trips.csv if this data is included. If not the *preferred_charging_type* from the config file is used, as long as the provided vehicles data provides the preferred_charging_type for the specified vehicle type. +The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. Every chain of modes starts with a simple simulation, even if it is not explicitly listed in the modes. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The charging type for each vehicle is read from the rotation information from the trips.csv if this data is included. If the data is not included *preferred_charging_type* from the config file is used, as long as the provided vehicles data provides the preferred_charging_type for the specified vehicle type. -negative depot to opportunity charger +Negative Depot to Opportunity Charger ------------------------------------- +This mode is the first kind of optimization provided by the eBus-Toolbox and is called by: -This mode is the first kind of optimization provided by the eBus-Toolbox and is called by :: + mode = ["neg_depb_to_oppb"] -It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. | NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. +It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. + +.. note:: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. -negative opportunity to depot charger + +Negative Opportunity to Depot Charger ------------------------------------- -|This mode is analogous to *neg_depb_to_oppb* +This mode is analogous to *neg_depb_to_oppb*. This mode is the second kind of optimization provided by the eBus-Toolbox and is called by + :: + mode = ["neg_oppb_to_depb"] + It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to opportunity chargers. -| NOTE: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as opportunity charger exists in the provided vehicles_data.json. +.. note:: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as opportunity charger exists in the provided vehicles_data.json. -service optimization +Service Optimization -------------------- This mode optimizes a scenario by creating sub-scenarios, so the given sub-scenario runs without socs falling below 0. The sub-scenario has the same input has the scenario but only consists of a sub-sets of rotations. These sub-sets are are optimized to be as big as possible. Previous negative rotations can become positive since effects like blocked charging points by other rotations can be reduced. -station optimization +Station Optimization -------------------- +This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. The network with no opportunity charging station is first analyzed to find rotations which fail at the current stage and to estimate the potential of electrifying each station by its own. *Step-by-step* new opportunity stations are electrified until full electrification is reached. The optimization assumes that at every electrified station unlimited charging points exist, i.e. the number of simultaneously charging buses is not limited. In between each electrification a simulation is run and the network is analyzed again. The first run called the **base optimization** leads to a scenario which often times is better than extensively optimizing the scenario by hand. Since a greedy approach can not guarantee a global optimum a second extensive optimization can be chained to this base optimization. This *deep* optimization can make use of a *step-by-step* decision tree expansion which evaluates new combinations of electrified stations starting with the most promising combinations **OR** use a *brute* force approach trying to reduce the amount of electrified stations by one in comparison the the base optimization. The step-by-step process of the optimization follows :numref:`optimization_loop` + .. _optimization_loop: .. figure:: https://user-images.githubusercontent.com/104760879/217225177-66201146-d31a-4127-9ca0-4d6e6e5a3cc4.png :width: 600 :alt: optimization_loop - Caption + Steps of the optimization loop until full electrification is reached. + +To speed up the optimization process the scenario is divided into groups of independent systems. Each system is solved on its own and further divided whenever possible. + +The functionality of the optimizer is controlled through the optimizer.config + + + -:numref:`optimization_loop` shows xxxxxxxxxxxxxxxxxxx .. figure:: https://user-images.githubusercontent.com/104760879/217225588-abfad83d-9d2a-463a-8597-584e29f5f885.png :width: 600 @@ -75,6 +95,11 @@ station optimization Caption +At the current stage the scenario to be optimized needs depot charging stations at the start and end of each rotation. The scenario should not contain any opportunity charging stations. If for a given scenario opportunity charging stations are predefined, i.e. the scenario should contain a specific electrification and is set in the *electrified_station.json* the solver type *spice_ev* should be used in the *optimizer.cfg*. If the *quick* solver is supposed to be used the station can be listed in *must_stations* while the *electrified_stations.json* should only contain depot stations + + + + Report ------------- The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. From 9308767aecab4e532b9a003dbf3af4a91d2bedaf Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 27 Apr 2023 13:40:14 +0200 Subject: [PATCH 18/58] Add to station optimization --- docs/source/modes.rst | 230 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 221 insertions(+), 9 deletions(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 78a5aae6..cc0dc39d 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -1,12 +1,13 @@ .. # Without creating links like in the line below, subpages go missing from the sidebar + this is a comment by the way .. _sim_modes: Modes of the eBus-Toolbox ========================= -The eBus-Toolbox assists the user in analysing and optimising electrified bus fleets and schedules. Besides a simple simulation run, several +The eBus-Toolbox assists the user in analyzing and optimising electrified bus fleets and schedules. Besides a simple simulation run, several different modes support the user in finding optimal solutions for their eBus-System. Supported Modes are * simple simulation @@ -71,7 +72,23 @@ This mode optimizes a scenario by creating sub-scenarios, so the given sub-scena Station Optimization -------------------- -This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. The network with no opportunity charging station is first analyzed to find rotations which fail at the current stage and to estimate the potential of electrifying each station by its own. *Step-by-step* new opportunity stations are electrified until full electrification is reached. The optimization assumes that at every electrified station unlimited charging points exist, i.e. the number of simultaneously charging buses is not limited. In between each electrification a simulation is run and the network is analyzed again. The first run called the **base optimization** leads to a scenario which often times is better than extensively optimizing the scenario by hand. Since a greedy approach can not guarantee a global optimum a second extensive optimization can be chained to this base optimization. This *deep* optimization can make use of a *step-by-step* decision tree expansion which evaluates new combinations of electrified stations starting with the most promising combinations **OR** use a *brute* force approach trying to reduce the amount of electrified stations by one in comparison the the base optimization. The step-by-step process of the optimization follows :numref:`optimization_loop` +Greedy Optimization +#################### +This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. Two basic approaches to use the optimization module are setting the mode in the ebus_toolbox configuration file to + +:: + + mode = ["sim", "station_optimization", "report"] + + +or + +:: + + mode = ["sim","neg_depb_to_oppb", "station_optimization", "report"] + +While the first call optimizes the scenario straight away trying to electrify all opportunity chargers, the second call, changes depot chargers to opportunity chargers, if they were not able to finish their rotations in the first simulation run. This way the second approach can lead to a higher degree of electrification for the system. +The network with no opportunity charging station is first analyzed to find rotations which fail at the current stage and to estimate the potential of electrifying each station by its own. *Step-by-step* new opportunity stations are electrified until full electrification is reached. The optimization assumes that at every electrified station unlimited charging points exist, i.e. the number of simultaneously charging buses is not limited. In between each electrification a simulation is run and the network is analyzed again. The first run called the **base optimization** leads to a scenario which often times is better than extensively optimizing the scenario by hand. Since a greedy approach can not guarantee a global optimum a second extensive optimization can be chained to this base optimization. This *deep* optimization can make use of a *step-by-step* decision tree expansion which evaluates new combinations of electrified stations starting with the most promising combinations **OR** use a *brute* force approach trying to reduce the amount of electrified stations by one in comparison to the base optimization. The step-by-step process of the optimization follows :numref:`optimization_loop` .. _optimization_loop: .. figure:: https://user-images.githubusercontent.com/104760879/217225177-66201146-d31a-4127-9ca0-4d6e6e5a3cc4.png @@ -80,25 +97,220 @@ This mode optimizes a scenario by electrifying as few opportunity stations as po Steps of the optimization loop until full electrification is reached. -To speed up the optimization process the scenario is divided into groups of independent systems. Each system is solved on its own and further divided whenever possible. +After a single simulation is run the rotations are analyzed. Any time a vehicle goes below an soc of zero (or a self defined value) a low soc event is triggered. This event saves information about when the soc reached its minimal value and the history before that up to a point of an upper soc threshold, with the default value being 1. Stations inside of this time span are potentially able to mitigate the low soc and are stored with other information about the event. :numref:`low_soc_event` shows a possible soc history with a low soc event. -The functionality of the optimizer is controlled through the optimizer.config +.. _low_soc_event: +.. figure:: https://user-images.githubusercontent.com/104760879/217225588-abfad83d-9d2a-463a-8597-584e29f5f885.png + :width: 600 + :alt: below_0_soc_event + Low soc event and classification of stations. +The next step groups low soc events based on the stations which were found earlier. Events which share at least one station could possibly interact with each other, e.g. vehicles could share a charging station. Therefore groups are build which do not share any stations in between groups. This speeds up the optimization process since for every electrification and simulation only rotations are calculated which could be impacted by the change. +Since greedy approaches execute the step which seems most promising in the current situation an evaluation function is needed. One possible approach could be to simulate each scenario, meaning simulating every case in which one of all possible stations is electrified and continuing with the best case. The optimizer does not use this approach. Instead an approximation function is used to evaluate the potential of electrifying a station. This approximation function analyzes the duration at each stop, the possible charging time, the soc and resulting possible charging power (battery with high socs are charged at a lower rate) as well as the upper soc threshold and minimal soc of the event. While this methodology is not accurate in all cases, e.g. a station could exist multiple times inside of a low soc event, therefore charging the first time at this station would alter the soc and charging power the vehicle has the second time it reaches the station, it seems well suited as heuristic for choosing the most promising station. The objective function of choosing what the *best* station is, is the mitigation of missing charge, i.e. what is the minimal amount of energy that needs to be inserted into the battery, so that no soc is below 0. +After the evaluation selected a station to be electrified the scenario input data is altered so that vehicles at this station are charged without limitation of charging points. This is followed up by a detailed simulation which can make use of a highly accurate solver for charging events called *SpiceEV* or a less accurate but faster solver. Now the resulting system has less missing charge and the potentials of stations might be decreased. Also a single group might have been split up into several smaller groups which can be analyzed even quicker. Therefore the loop repeats up until the point the missing charge in the system is zero or in other words the system is fully electrified. -.. figure:: https://user-images.githubusercontent.com/104760879/217225588-abfad83d-9d2a-463a-8597-584e29f5f885.png - :width: 600 - :alt: below_0_soc_event +At the current stage the scenario to be optimized needs depot charging stations at the start and end of each rotation. The scenario should not contain any opportunity charging stations. If for a given scenario opportunity charging stations are predefined, i.e. the scenario should contain a specific electrification and is set in the *electrified_station.json* the solver type *spice_ev* should be used in the *optimizer.cfg*. If the *quick* solver is supposed to be used the station can be listed in *inclusion_stations* while the *electrified_stations.json* should only contain depot stations. Stations can be also excluded from optimization by adding their name to *exclusion_stations*. + +Deep Optimization +#################### +The greedy algorithm in the base optimization can not guarantee that the solution is the global optimum. This is why the use of the *deep* mode is recommended for systems with high requirements. After the first run, instead of electrifying the station with the highest potential the second best station is electrified. This is similar to a decision tree, where every node is a set of electrified stations, with the first node being zero stations electrified and the last node being all stations electrified. The nodes in between correlate with every possible state of electrification. Each branch therefore represents an additional electrification of a single station. . The algorithm continues electrifying the best station, as long as this node has not been evaluated yet. This way gradually all possible nodes are checked. The search stops whenever the number of stations surpasses the number of the current optimal solution. If several options with the same optimal number of stations arise, they can be found in the log file of the optimizer, but only one file with optimized stations is produced. + +**Pruning** is used to stop evaluation of branches, whenever foresight predicts that no better solution will be reached. This is done through the simple heuristic of checking the sum of potential of the n remaining stations with the highest potentials, with n being the number until the number of stations of the current optimal solution is reached. - Caption +| **Example:** +| The base optimization found a set of 5 stations to fully electrify the scenario. These stations are *A*, *B*, *C*, *D* and *E* which were chosen in the same order. The whole scenario consists of the whole alphabet of stations. The deep optimization starts with evaluating a scenario without any electrified opportunity stations. Depot stations are electrified. The first evaluation gives a sorted list of potentials by +======== ===== +Station Potential +======== ===== +*A* 85 +*X* 75 +*B* 30 +*E* 25 +... ... +======== ===== -At the current stage the scenario to be optimized needs depot charging stations at the start and end of each rotation. The scenario should not contain any opportunity charging stations. If for a given scenario opportunity charging stations are predefined, i.e. the scenario should contain a specific electrification and is set in the *electrified_station.json* the solver type *spice_ev* should be used in the *optimizer.cfg*. If the *quick* solver is supposed to be used the station can be listed in *must_stations* while the *electrified_stations.json* should only contain depot stations +In the base optimization Station *A* was chosen since it showed the highest potential. The deep optimization ignores this node since it has been evaluated already and chooses station *X* instead. After a detailed simulation with *X* electrified, the remaining stations are evaluated again. +======== ===== +Station Potential +======== ===== +*B* 28 +*E* 25 +*C* 20 +*G* 18 +... ... +======== ===== +For every vehicle the amount of missing energy is calculated and summed up. In this example case the missing energy is 85. Since 4 stations are remaining until the current optimum of 5 stations is reached, the 4 stations with the highest potential are evaluated in this case + +.. math:: + + Pot = Pot_B + Pot_E + Pot_C + Pot_G = 28 + 25 + 20 +18 = 91 + +In this case the potential is high enough to continue the exploration of this branch. If the potential would have been below 85 the branch would have been pruned, meaning it would not be explored any further and labeled as *not promising*. It is not promising since it will not lead to a better solution than the current one. This is the case since on one hand the evaluation by approximation tends to overestimate the potential while the missing energy is accurately calculated and on the other hand electrification of stations can reduce the potential of other stations, for example if 2 stations charge the same rotation, electrifying one station might fully electrify the rotation meaning the potential of the other station drops to zero. +This concept can reduce the amount of nodes which have to be checked. + +Other Optimization Functionality +################################### +**Mandatory stations** can be attained to increase the optimization process. Mandatory stations are defined by being stations which are needed for a fully electrified system. To check if a station *Y* is a mandatory station can be easily attained by simulating the network with every station electrified except *Y*. If the system has vehicle socs which drop below the minimal soc (default value is 0) in this scenario, the station is mandatory. In the later exploration of best combinations of stations this station will be included in any case. + +**Impossible rotations** are rotations which given the settings are not possible to be run as opportunity chargers, given the vehicle properties, even when every station is electrified. Before starting an optimization it is recommended to remove these rotations from the optimization, since the optimizer will not reach the goal of full electrification. + +**Quick solver** +Instead of using the regular SpiceEV solver for optimization the user can also choose the *quick* solver. This approximates the soc history of a vehicle by straight manipulation of the soc data and numeric approximations of the charged energy. Therefore small differences between solving a scenario with SpiceEV and the quick solver exist. For the quick solver to work, some assumptions have to be met as well + +* Depots charge the vehicles to 100% soc +* Station electrification leads to unlimited charging points +* Base scenario has no electrified opportunity stations +* No grid connection power restrictions + +At the end of each optimization the optimized scenario will run using SpiceEV. This guarantees that the proposed solution works. If this is not the case, using SpicEV as solver is recommended + +**Continuing optimizations** can be useful in cases where simulation of the base case is slow or considerable effort was put into optimization before. The user might want to continue the optimization from the state where they left off. To speed up multiple optimizations or split up a big optimization in multiple smaller calculations two features are in early development. Experienced users can use these features on their own accord with a few minor implementation steps. To skip a potentially long simulation, with the simulation of the scenario being the first step of every ebus-toolbox run, the optimizer.config allows for using pickle files for the three major objects args, schedule and scenario. After pickling the resulting objects, the optimizer can be prompted to use them instead of using whatever other input is fed into the optimizer. This is done by giving the paths to the pickle files in the optimizer.cfg. + +:: + + args = data/args.pickle + schedule = data/schedule.pickle + scenario = data/scenario.pickle + +If they are provided they are used automatically. All three pickle files need to be set. + +If a deep optimization takes to long to run it in one go, it is possible to save the state of the decision tree as pickle file as well. Reloading of the state is possible and will lead to a continuation of the previous optimization. This feature is still in development and needs further testing. +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 Configuration +################################### +The functionality of the optimizer is controlled through the optimizer.cfg specified in the ebus_toolbox.cfg used for calling the eBus_Toolbox. + +.. list-table:: Optimizer.cfg parameters + :header-rows: 1 + + * - Parameter + - Default value + - Expected values + - Description + * - debug_level + - 1 + - 1 to 99 + - Level of debugging information that is printed to the .log file between. debug_level = 1 prints everything + * - console_level + - 99 + - 1 to 99 + - "Level of debugging information that is printed in the console. console_level = 99 only prints critical information." + * - exclusion_rots + - [] + - ["rotation_id1", "rotation_id2" ..] + - Rotations which shall not be optimized + * - exclusion_stations + - [] + - ["station_id1", "station_id2" ..] + - Stations which shall not be electrified + * - inclusion_stations + - [] + - ["station_id1", "station_id2" ..] + - Station which shall be electrified. *Note:* If using inclusion stations, rebasing is recommended + * - standard_opp_station + - {"type": "opps", "n_charging_stations": 200, "distance_transformer": 50} + - dict() + - Description of the charging station using the syntax of electrified_stations.json + * - charge_eff + - 0.95 + - 0 to 1 + - Charging efficiency between charging station and vehicle battery. Only needed for solver=quick + * - battery_capacity + - 0 + - positive float value + - Optimizer overwrites vehicle battery capacities with this value. If the line is commented out or the value is 0, no overwriting takes place + * - charging_curve + - [] + - [[soc1, power1], [soc2, power2] ….] with soc between 0-1 and power as positive float value + - Optimizer overwrites vehicle charging curve with this value. If the line is commented out or the value is [], no overwriting takes place + * - charging_power + - 0 + - positive float value + - Optimizer overwrites vehicle charging power with this value. If the line is commented out or the value is 0, no overwriting takes place + * - min_soc + - 0 + - 0 to 1 + - Optimizer uses this value as lower SOC threshold, meaning vehicles with socs below this value need further electrification + * - solver + - spiceev + - [quick, spiceev] + - Should an accurate solver or a quick solver be used. At the end of each optimization the solution is always validated with the accurate (spiceev) solver + * - rebase_scenario + - False + - [True, False] + - If scenario settings are set, the optimizer might need rebasing for proper functionality. For example in case of changing the battery capacity or other vehicle data through this config or setting inclusion stations this should be set to True + * - pickle_rebased + - False + - [True, False] + - Should the rebased case be saved as pickle files + * - pickle_rebased_name + - rebased + - file_name as string + - Name of the pickle files of the rebased case + * - run_only_neg + - False + - [True, False] + - Should all rotations be rebased or can rotations which stay above the soc threshold be skipped? + * - run_only_oppb + - False + - [True, False] + - Filter out depot chargers during optimization + * - pruning_threshold + - 3 + - positive integer value + - Number of stations left until number of stations in optimal solution is reached,where pruning is activated. Calculation time of checking for pruning is not negligible, meaning that a lot of pruning checks (high pruning threshold, e.g. 99) lead to slower optimization. Low values will rarely check for pruning but also pruning will be rarely achieved + * - opt_type + - greedy + - [greedy, deep] + - Deep will lead to a deep optimization after a greedy one. Greedy will only run a single optimization case. + * - node_choice + - step-by-step + - [step-by-step, brute] + - How should the deep optimization choose the nodes. Brute is only recommended in smaller systems + * - max_brute_loop + - 20 + - positive integer value + - How many combinations is the brute force method allowed to check + * - estimation_threshold + - 0.8 + - 0 to 1 + - Factor with which the potential evaluation is multiplied before comparing it to the missing energy. A low estimation threshold will lead to a more conservative approach in dismissing branches. + * - remove_impossible_rotations + - False + - [True, False] + - Discard rotations which have socs below the threshold, even when every station is electrified + * - check_for_must_stations + - True + - [True, False] + - Check stations if they are mandatory for a fully electrified system. If they are, include them + * - decision_tree_path + - "" + - file_name as string + - Optional and in development: Path to pickle file of decision_tree. + * - save_decision_tree + - False + - [True, False] + - Optional and in development: Should the decision tree be saved? + * - reduce_rotations + - False + - [True, False] + - Should the optimizer only optimize a subset of rotations? + * - rotations + - [] + - ["rotation_id1", "rotation_id2" ..] + - If reduce_rotations is True, only the list of these rotations is optimized. Report ------------- From 206614e5e69a9a703ac524b7d15cd384ea40a141 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 27 Apr 2023 14:19:35 +0200 Subject: [PATCH 19/58] Add to report description --- docs/source/modes.rst | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index cc0dc39d..028c6b3d 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -314,9 +314,35 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci Report ------------- -The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. +The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Default outputs are + +| **Grid Connector Overview (gc_overview.csv)** +| Contains information about charging stations, including their names, types, maximum power, maximum number of charging stations, total energy usage, and use factors for the least, second least, and third least utilized charging stations. + +| **Grid Connector Time Series (gc_power_overview_timeseries.csv)** +| Time series of power flow in kW for every grid connector + +| **Rotation SoC Data (rotation_socs.csv)** +| Time series of soc for each rotation. + +| **Vehicle SoC Data (vehicle_socs.csv)** +| Time series of soc for each vehicle. + +| **Rotation Summary (rotation_summary.csv)** +| Contains data related to the rotation of vehicles, including the start and end times of each rotation, the type and ID of the vehicle, the depot name, the lines the vehicle traveled, total energy consumption in kWh, distance traveled in m, and various charging-related metrics such as charging type and soc at arrival, minimum soc and if the rotation had negative soc values. + +| **Overview Plots (run_overview.pdf and run_overview.png)** +| Contains plots for socs for every vehicle, power at each charging station, batteries, external loads and feed-ins as well as price time series for each station. + +| **Station Data Summary (simulation_station_xy.json)** +| Contains information about the simulation interval, grid connector, photovoltaics, charging strategy, average flexible power range per time window, total drawn energy from the grid, average duration of standing events, maximum drawn power, total energy fed into the grid, maximum stored energy in each battery, number of load cycles for stationary batteries and vehicles, and number of times vehicle soc was below the desired soc on departure. + +| **Station Data Time Series (simulation_timeseries_station_xy.csv)** +| Contains station specific time series including price of electricity, grid supply, fixed loads, battery power, energy stored in battery, flex band boundaries, battery feed, charging station power use, occupied charging stations and charging stations in use as well as vehicles which are at the station. + + Cost calculation -~~~~~~~~~~~~~ +~~~~~~~~~~~~~~~~~~ This mode calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV `_ for the calculation of electricity costs. From 61f3d249cff0efabd57516a3b4a02c11fbe0f973 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 27 Apr 2023 14:35:08 +0200 Subject: [PATCH 20/58] Add overview png and files folder --- docs/build/html/_files/run_overview.png | Bin 0 -> 149685 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/build/html/_files/run_overview.png diff --git a/docs/build/html/_files/run_overview.png b/docs/build/html/_files/run_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..a975f3c731d27cb50d9090dec4db1f1cb1677ade GIT binary patch literal 149685 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 literal 0 HcmV?d00001 From 8a477d6588a3633bb68f2a974ea08c082495c58f Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 27 Apr 2023 14:39:12 +0200 Subject: [PATCH 21/58] Add overview png and files folder --- docs/source/getting_started.rst | 2 +- docs/source/modes.rst | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 53d1d8d8..18b00261 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -46,7 +46,7 @@ Other modes can alter bus types from depot to opportunity chargers, optimize set :numref:`figure_ebus_toolbox_modules` shows how the different modules work together to calculate the scenario. Optionally different optimizations can be used or even chained together. The output of the simulation is locally saved and consists of the vehicle socs, summaries for each rotation, estimated costs for vehicles, infrastructure and operation as well as station specific electric loads, utilization rates and other key performance indicators. Some of them can be plotted automatically and can be seen in :numref:`ebus_toolbox_default_plot` .. _ebus_toolbox_default_plot: -.. figure:: https://user-images.githubusercontent.com/104760879/217226800-647956c5-9d63-4988-a710-f3326a8304d5.png +.. figure:: _files/run_overview.png :alt: ebus_toolbox_default_plot :width: 600 diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 028c6b3d..5b18848c 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -314,7 +314,10 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci Report ------------- -The report will include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Default outputs are +The report will generate several files which include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. + +Default outputs +################################### | **Grid Connector Overview (gc_overview.csv)** | Contains information about charging stations, including their names, types, maximum power, maximum number of charging stations, total energy usage, and use factors for the least, second least, and third least utilized charging stations. @@ -340,12 +343,12 @@ The report will include information about the expected socs, power loads at the | **Station Data Time Series (simulation_timeseries_station_xy.csv)** | Contains station specific time series including price of electricity, grid supply, fixed loads, battery power, energy stored in battery, flex band boundaries, battery feed, charging station power use, occupied charging stations and charging stations in use as well as vehicles which are at the station. - +.. _cost_calculation: Cost calculation -~~~~~~~~~~~~~~~~~~ - -This mode calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. -The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV `_ for the calculation of electricity costs. +################################### +| **Cost calculation (summary_vehicles_costs.csv)** +| This is an optional output which calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. +| The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV `_ for the calculation of electricity costs. * Investment * **Busses**: Costs for all busses used in the simulation. Costs include battery swaps, depending on the lifetime of both busses and batteries. From f4ab5c47c860468bdfd31aa09d8ee5df96cb7324 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 9 May 2023 12:12:08 +0200 Subject: [PATCH 22/58] make make html possible and restructure doc directories for images --- docs/make.bat | 4 ++-- .../html/_files => source/_static}/run_overview.png | Bin docs/source/getting_started.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename docs/{build/html/_files => source/_static}/run_overview.png (100%) diff --git a/docs/make.bat b/docs/make.bat index 2119f510..6247f7e2 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -7,8 +7,8 @@ REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) -set SOURCEDIR=. -set BUILDDIR=_build +set SOURCEDIR=source +set BUILDDIR=build if "%1" == "" goto help diff --git a/docs/build/html/_files/run_overview.png b/docs/source/_static/run_overview.png similarity index 100% rename from docs/build/html/_files/run_overview.png rename to docs/source/_static/run_overview.png diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 18b00261..6137a578 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -46,7 +46,7 @@ Other modes can alter bus types from depot to opportunity chargers, optimize set :numref:`figure_ebus_toolbox_modules` shows how the different modules work together to calculate the scenario. Optionally different optimizations can be used or even chained together. The output of the simulation is locally saved and consists of the vehicle socs, summaries for each rotation, estimated costs for vehicles, infrastructure and operation as well as station specific electric loads, utilization rates and other key performance indicators. Some of them can be plotted automatically and can be seen in :numref:`ebus_toolbox_default_plot` .. _ebus_toolbox_default_plot: -.. figure:: _files/run_overview.png +.. figure:: _static/run_overview.png :alt: ebus_toolbox_default_plot :width: 600 From 6dbe2037895789cb8e11d2a73a878063e1630ed5 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Thu, 25 May 2023 09:38:30 +0200 Subject: [PATCH 23/58] add methodology_overview.png --- docs/source/_static/methodology_overview.png | Bin 0 -> 64639 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/source/_static/methodology_overview.png diff --git a/docs/source/_static/methodology_overview.png b/docs/source/_static/methodology_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..af8dc284019cfaed1c585b0811d80470e89b5616 GIT binary patch literal 64639 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 literal 0 HcmV?d00001 From 398b34a65b1bfb11663ceea0f2339d438f50ff44 Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Fri, 26 May 2023 08:49:30 +0200 Subject: [PATCH 24/58] change RTD mode description of service opt --- docs/source/modes.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 5b18848c..49124e61 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -68,7 +68,9 @@ It takes the results of the previous simulation, attains all rotations which had Service Optimization -------------------- -This mode optimizes a scenario by creating sub-scenarios, so the given sub-scenario runs without socs falling below 0. The sub-scenario has the same input has the scenario but only consists of a sub-sets of rotations. These sub-sets are are optimized to be as big as possible. Previous negative rotations can become positive since effects like blocked charging points by other rotations can be reduced. +This mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. +Now, only rotations are left that are non-negative when viewed alone, but might beome negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. +In the end, the largest number of rotations that produce a non-negative result when taken together is returned as the optimized scenario. Station Optimization -------------------- From c3cf91c6c9de8a87d42d5b27823a061b1b91111c Mon Sep 17 00:00:00 2001 From: "stefan.schirmeister" Date: Wed, 7 Jun 2023 09:48:03 +0200 Subject: [PATCH 25/58] fix typo --- docs/source/modes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 49124e61..8239a366 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -69,7 +69,7 @@ It takes the results of the previous simulation, attains all rotations which had Service Optimization -------------------- This mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. -Now, only rotations are left that are non-negative when viewed alone, but might beome negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. +Now, only rotations are left that are non-negative when viewed alone, but might become negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. In the end, the largest number of rotations that produce a non-negative result when taken together is returned as the optimized scenario. Station Optimization From 1c9f5081bb60a90d2a52ff78be23285d9061dc2a Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Aug 2023 08:28:38 +0200 Subject: [PATCH 26/58] change name to SimBA in rtd text --- docs/source/getting_started.rst | 6 +++--- docs/source/index.rst | 2 +- docs/source/modes.rst | 20 ++++++++++---------- docs/source/simulation_parameters.rst | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 6137a578..46f5e9d5 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -4,7 +4,7 @@ Getting Started =============== -The eBus-Toolbox assists the user in analysing and optimising electrified bus fleets and schedules. +SimBA assists the user in analysing and optimising electrified bus fleets and schedules. .. Without creating links like in the line below, subpages go missing from the sidebar @@ -24,7 +24,7 @@ Now you can start the eBus Toolbox module with all configurations stored at `dat The repo provides an example for each necessary input file, so the example case can be executed without the need for the user to provide any data themselves. -To run the eBus-Toolbox with your own `schedule.csv` (see :ref:`schedule`)) file and default configurations run +To run SimBA with your own `schedule.csv` (see :ref:`schedule`)) file and default configurations run ``python -m ebus_toolbox --input_schedule path/to/schedule.csv`` @@ -41,7 +41,7 @@ Other modes can alter bus types from depot to opportunity chargers, optimize set :alt: ebus_toolbox_modules :width: 600 - Modules of the eBus-Toolbox + Modules of the SimBA :numref:`figure_ebus_toolbox_modules` shows how the different modules work together to calculate the scenario. Optionally different optimizations can be used or even chained together. The output of the simulation is locally saved and consists of the vehicle socs, summaries for each rotation, estimated costs for vehicles, infrastructure and operation as well as station specific electric loads, utilization rates and other key performance indicators. Some of them can be plotted automatically and can be seen in :numref:`ebus_toolbox_default_plot` diff --git a/docs/source/index.rst b/docs/source/index.rst index b1a0ac92..bdbf7818 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,7 +6,7 @@ .. image:: https://user-images.githubusercontent.com/104760879/217226792-4297d3c8-8a7c-45ad-894f-5efd03031f49.png :alt: ebus_toolbox_logo -Welcome to the eBus-Toolbox's documentation! +Welcome to SimBA's documentation! ============================================ This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies in Python. diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 8239a366..dc053336 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -4,10 +4,10 @@ .. _sim_modes: -Modes of the eBus-Toolbox -========================= +Modes of SimBA +============== -The eBus-Toolbox assists the user in analyzing and optimising electrified bus fleets and schedules. Besides a simple simulation run, several +SimBA assists the user in analyzing and optimising electrified bus fleets and schedules. Besides a simple simulation run, several different modes support the user in finding optimal solutions for their eBus-System. Supported Modes are * simple simulation @@ -19,13 +19,13 @@ different modes support the user in finding optimal solutions for their eBus-Sys Chained Modes ------------- -While the default mode of the ebus-toolbox 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: ebus_toolbox.cfg) under the keyword *mode*: +While the default mode of the 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: ebus_toolbox.cfg) under the keyword *mode*: :: mode = ["sim", "report"] -This results in a simple simulation with a following report. To run a simulation the ebus-toolbox creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. Their output describes the simulation outcome of this mutated schedule. An extended simple use case would be: +This results in a simple simulation with a following report. To run a simulation SimBA creates a schedule which contains all information about how the bus system is supposed to run. Some modes are allowed to mutate the schedule in some way, which makes chaining of modes especially useful. Their output describes the simulation outcome of this mutated schedule. An extended simple use case would be: :: @@ -41,7 +41,7 @@ The simple simulation case is the default mode. Its usage is explained in :ref:` Negative Depot to Opportunity Charger ------------------------------------- -This mode is the first kind of optimization provided by the eBus-Toolbox and is called by: +This mode is the first kind of optimization provided by SimBA and is called by: :: @@ -49,14 +49,14 @@ This mode is the first kind of optimization provided by the eBus-Toolbox and is It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. -.. note:: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. +.. note:: Charging types are only switched by SimBA if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. Negative Opportunity to Depot Charger ------------------------------------- This mode is analogous to *neg_depb_to_oppb*. -This mode is the second kind of optimization provided by the eBus-Toolbox and is called by +This mode is the second kind of optimization provided by SimBA and is called by :: @@ -64,7 +64,7 @@ This mode is the second kind of optimization provided by the eBus-Toolbox and is It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to opportunity chargers. -.. note:: Charging types are only switched by the eBus-Toolbox if the corresponding vehicle type as opportunity charger exists in the provided vehicles_data.json. +.. note:: Charging types are only switched by SimBA if the corresponding vehicle type as opportunity charger exists in the provided vehicles_data.json. Service Optimization -------------------- @@ -172,7 +172,7 @@ Instead of using the regular SpiceEV solver for optimization the user can also c At the end of each optimization the optimized scenario will run using SpiceEV. This guarantees that the proposed solution works. If this is not the case, using SpicEV as solver is recommended -**Continuing optimizations** can be useful in cases where simulation of the base case is slow or considerable effort was put into optimization before. The user might want to continue the optimization from the state where they left off. To speed up multiple optimizations or split up a big optimization in multiple smaller calculations two features are in early development. Experienced users can use these features on their own accord with a few minor implementation steps. To skip a potentially long simulation, with the simulation of the scenario being the first step of every ebus-toolbox run, the optimizer.config allows for using pickle files for the three major objects args, schedule and scenario. After pickling the resulting objects, the optimizer can be prompted to use them instead of using whatever other input is fed into the optimizer. This is done by giving the paths to the pickle files in the optimizer.cfg. +**Continuing optimizations** can be useful in cases where simulation of the base case is slow or considerable effort was put into optimization before. The user might want to continue the optimization from the state where they left off. To speed up multiple optimizations or split up a big optimization in multiple smaller calculations two features are in early development. Experienced users can use these features on their own accord with a few minor implementation steps. To skip a potentially long simulation, with the simulation of the scenario being the first step of every SimBA run, the optimizer.config allows for using pickle files for the three major objects args, schedule and scenario. After pickling the resulting objects, the optimizer can be prompted to use them instead of using whatever other input is fed into the optimizer. This is done by giving the paths to the pickle files in the optimizer.cfg. :: diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 6e4ab315..7e4399b4 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -4,8 +4,8 @@ Simulation Parameters ===================== The simulation of an eBus-System relies on a variety of simulation parameters. -The eBus-Toolbox provides most of them as default values. Depending on specific needs adjusting -these values can increase the accuracy of the simulation outputs. The eBus-Toolbox input files are described +SimBA provides most of them as default values. Depending on specific needs adjusting +these values can increase the accuracy of the simulation outputs. The SimBA input files are described in detail in the following subsections as well as their default parameters. When providing the user defined input files, the user should make sure the files are either 'utf-8' encoded or not contain regional characters. @@ -131,4 +131,4 @@ TBC Consumption table ----------------- -The consumption table can be referenced in the :ref:`vehicle_types` file. Instead of constant consumption the eBus-Toolbox uses provided temperatures, level of loadings, mean speeds, average inclines and the vehicle type to interpolate the consumption value from this data table. Level of loading and temperatures are read from the :ref:`schedule` if the trips provide them. If they are missing from the schedule, they are looked up from the files :ref:`level_of_loading` and :ref:`temperature_data`. The average incline is calculated from :ref:`station_geo_data` and the mean speed is calculated by using the departure and arrival time and distance provided by the schedule. \ No newline at end of file +The consumption table can be referenced in the :ref:`vehicle_types` file. Instead of constant consumption SimBA uses provided temperatures, level of loadings, mean speeds, average inclines and the vehicle type to interpolate the consumption value from this data table. Level of loading and temperatures are read from the :ref:`schedule` if the trips provide them. If they are missing from the schedule, they are looked up from the files :ref:`level_of_loading` and :ref:`temperature_data`. The average incline is calculated from :ref:`station_geo_data` and the mean speed is calculated by using the departure and arrival time and distance provided by the schedule. \ No newline at end of file From 79f52a85721ccfa618205d75d67ae4dd2bbaf86f Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Aug 2023 08:32:24 +0200 Subject: [PATCH 27/58] solve stashed merge conflicts --- docs/source/getting_started.rst | 4 ++-- docs/source/index.rst | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 46f5e9d5..d27ad025 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -4,7 +4,7 @@ Getting Started =============== -SimBA assists the user in analysing and optimising electrified bus fleets and schedules. +This toolbox was designed to analyze and optimize electrified bus fleets. .. Without creating links like in the line below, subpages go missing from the sidebar @@ -37,7 +37,7 @@ At the current stage several functionalities are implemented. The base simulatio Other modes can alter bus types from depot to opportunity chargers, optimize sets of rotations to increase electrification or suggest stations for electrification by minimizing the amount of stations needed. You can learn more about the modes :ref:`here ` .. _figure_ebus_toolbox_modules: -.. figure:: https://user-images.githubusercontent.com/104760879/217225545-5e6858c1-d056-4519-beea-6274d06533c7.png +.. figure:: _static/methodology_overview.png :alt: ebus_toolbox_modules :width: 600 diff --git a/docs/source/index.rst b/docs/source/index.rst index bdbf7818..fcec2e16 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,8 +9,7 @@ Welcome to SimBA's documentation! ============================================ -This toolbox extends the functionality of the Open Source simulation tool SpiceEV to facilitate eBus feasibility studies in Python. - +This toolbox was designed to analyze and optimize electrified bus fleets. .. toctree:: :maxdepth: 3 From 9eb687c1865a23420e95a899c3bc2afcd0e737a2 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Aug 2023 08:36:23 +0200 Subject: [PATCH 28/58] change logo to SimBA --- .../_static/2023_06_08_eBus-Toolbox Logo.png | Bin 0 -> 19658 bytes docs/source/index.rst | 6 ++++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 docs/source/_static/2023_06_08_eBus-Toolbox Logo.png diff --git a/docs/source/_static/2023_06_08_eBus-Toolbox Logo.png b/docs/source/_static/2023_06_08_eBus-Toolbox Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5836edba45b10fbea9487d5eec670c4ff1632003 GIT binary patch literal 19658 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 literal 0 HcmV?d00001 diff --git a/docs/source/index.rst b/docs/source/index.rst index fcec2e16..c7f22957 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -3,8 +3,10 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -.. image:: https://user-images.githubusercontent.com/104760879/217226792-4297d3c8-8a7c-45ad-894f-5efd03031f49.png - :alt: ebus_toolbox_logo +.. _figure_SimBA_logo: +.. figure:: _static/2023_06_08_eBus-Toolbox Logo.png + :alt: ebus_toolbox_logo + :width: 600 Welcome to SimBA's documentation! ============================================ From 0f715eab587f6941ca1a6070879ce3181f80b5ce Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Aug 2023 16:54:13 +0200 Subject: [PATCH 29/58] update rtd pictures, config and getting_started --- data/examples/ebus_toolbox.cfg | 2 +- docs/source/_static/PyCharm_Configuration.png | Bin 0 -> 69829 bytes ...8_eBus-Toolbox Logo.png => SimBA_logo.png} | Bin docs/source/_static/SimBA_module_overview.png | Bin 0 -> 59991 bytes docs/source/_static/methodology_overview.png | Bin 64639 -> 0 bytes docs/source/getting_started.rst | 77 +++++++-- docs/source/index.rst | 8 +- docs/source/modes.rst | 58 +++---- docs/source/simulation_parameters.rst | 147 +++++++++++++++++- 9 files changed, 243 insertions(+), 49 deletions(-) create mode 100644 docs/source/_static/PyCharm_Configuration.png rename docs/source/_static/{2023_06_08_eBus-Toolbox Logo.png => SimBA_logo.png} (100%) create mode 100644 docs/source/_static/SimBA_module_overview.png delete mode 100644 docs/source/_static/methodology_overview.png diff --git a/data/examples/ebus_toolbox.cfg b/data/examples/ebus_toolbox.cfg index d9f83b72..3325442b 100644 --- a/data/examples/ebus_toolbox.cfg +++ b/data/examples/ebus_toolbox.cfg @@ -76,7 +76,7 @@ default_buffer_time_opps = 0 # Options: HV, HV/MV, MV, MV/LV, LV (default: MV) default_voltage_level = "MV" -##### SIMULATION PARAMETERS ##### +##### Simulation Parameters ##### # Maximum number of days to simulate, if not set simulate entire schedule #days = 10 # Set length of timestep in minutes (default: 1) diff --git a/docs/source/_static/PyCharm_Configuration.png b/docs/source/_static/PyCharm_Configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..8d42e3651376d5a8944eba4511a97ae7ae36c510 GIT binary patch literal 69829 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

U1IdyzvZDDQ85CRz#JIXVKlR5t9KmC`rDa| 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 From d3437521a448fff81cad8a448ba454207569b2ee Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 9 Aug 2023 08:29:05 +0200 Subject: [PATCH 48/58] revert charging_type in trips_example but add new trips_example_ct --- data/examples/trips_example.csv | 130 ++++++++++++++--------------- data/examples/trips_example_ct.csv | 65 +++++++++++++++ 2 files changed, 130 insertions(+), 65 deletions(-) create mode 100644 data/examples/trips_example_ct.csv diff --git a/data/examples/trips_example.csv b/data/examples/trips_example.csv index a08c3e83..055034de 100644 --- a/data/examples/trips_example.csv +++ b/data/examples/trips_example.csv @@ -1,65 +1,65 @@ -line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading,charging_type -LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0,oppb -LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9,oppb -LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,,,oppb -LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,,,oppb -LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,,,oppb -LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,,,oppb -LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,,,oppb -LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,,,oppb -LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,,,oppb -LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,,,oppb -LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,,, -LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,,, -LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,,, -LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,,, -LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,,, -LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,,, -LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,,, -LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,,, -LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,,, -LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,,, -LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,,, -LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,,, -LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,,, -LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,,, -LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,,, -LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,,, -LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,,, -LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,,, -LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,,, -LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,,, -LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,,, -LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,,, -LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,,, -LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,,, -LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,,, -LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,,, -LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,,, -LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,,, -LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,,, -LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,,, -LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,,, -LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,,, -LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,,, -LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,,, -LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,,, -LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,,, -LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,,, -LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,,, \ No newline at end of file +line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading +LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0 +LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9 +LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,, +LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,, +LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,, +LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,, +LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,, +LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,, +LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,, +LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,, +LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,, +LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,, +LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,, +LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,, +LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,, +LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,, +LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,, +LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,, +LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,, +LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,, +LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,, +LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,, +LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,, +LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,, +LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,, +LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,, +LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,, +LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,, +LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,, +LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,, +LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,, +LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,, +LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,, +LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,, +LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,, +LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,, +LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,, +LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,, +LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,, +LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,, +LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,, +LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,, +LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,, +LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,, +LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,, +LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,, +LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,, +LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,, +LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,, +LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,, +LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,, +LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,, +LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,, +LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,, +LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,, +LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,, +LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,, +LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,, +LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,, +LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,, +LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,, +LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,, +LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,, +LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,, \ No newline at end of file diff --git a/data/examples/trips_example_ct.csv b/data/examples/trips_example_ct.csv new file mode 100644 index 00000000..04f03929 --- /dev/null +++ b/data/examples/trips_example_ct.csv @@ -0,0 +1,65 @@ +line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading,charging_type +LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0,oppb +LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9,oppb +LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,,,oppb +LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,,,oppb +LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,,,oppb +LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,,,oppb +LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,,,oppb +LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,,, +LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,,, +LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,,, +LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,,, +LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,,, +LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,,, +LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,,, +LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,,, +LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,,, +LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,,, +LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,,, +LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,,, +LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,,, +LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,,, +LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,,, +LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,,, +LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,,, +LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,,, +LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,,, +LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,,, +LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,,, +LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,,, +LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,,, +LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,,, +LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,,, +LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,,, +LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,,, +LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,,, +LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,,, \ No newline at end of file From 1ffa555d6d2572924c4854ed09b38a6dccafa449 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 9 Aug 2023 08:50:45 +0200 Subject: [PATCH 49/58] still WIP: rtd --- data/examples/electrified_stations.json | 16 +++++++++------- docs/source/simulation_parameters.rst | 8 +++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/data/examples/electrified_stations.json b/data/examples/electrified_stations.json index c8755001..a43730f7 100644 --- a/data/examples/electrified_stations.json +++ b/data/examples/electrified_stations.json @@ -2,8 +2,12 @@ "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, // distance to grid, needed for cost calculation - "energy_feed_in": { // energy feed in e.g. by local renewables + "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 + "voltage_level": "MV", // optional: voltage_level for this station, 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 "start_time": "2022-03-07T00:00:00", // start time as YYYY-MM-DDThh:mm:ss "step_duration_s": 3600, // timestep in seconds @@ -11,23 +15,21 @@ "nominal_power": 10, // nominal power in kW, needed for PV remuneration "factor": 1 // factor to multiply column values, eg 0.001 for conversion from W to kW }, - "external_load": { // local external loads + "external_load": { // optional: local external loads "csv_file": "data/examples/example_external_load.csv", // path to feedin.csv "start_time": "2022-03-07T00:00:00", // start time as YYYY-MM-DDThh:mm:ss "step_duration_s": 900, // 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 }, - "battery": { // local stationary battery + "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 - }, - "cs_power_deps_oppb" : 50, // optional: maximum cs power can be defined per station - "cs_power_deps_depb" : 120 // optional: maximum cs power can be defined per station + } }, "Station-3": { "type": "opps", diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index abcbba77..884a55d9 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -276,14 +276,11 @@ Cost parameters TBC - -TBC - .. _station_geo_data: Station data ------------ -Geodata. TBV +TBC .. _level_of_loading: @@ -292,13 +289,14 @@ Level of loading ---------------- TBC + .. _temperature_data: Temperatures ------------ - TBC + .. _consumption_table: Consumption table From 3606654522ebba310df5d51216d6e57bf149ee94 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 9 Aug 2023 13:57:08 +0200 Subject: [PATCH 50/58] update documentation --- data/examples/cost_params.json | 4 +- data/examples/electrified_stations.json | 8 +-- docs/source/simba_features.rst | 4 +- docs/source/simulation_parameters.rst | 74 +++++++++++++++++++++---- 4 files changed, 71 insertions(+), 19 deletions(-) diff --git a/data/examples/cost_params.json b/data/examples/cost_params.json index 4cd4efa5..38359dff 100644 --- a/data/examples/cost_params.json +++ b/data/examples/cost_params.json @@ -28,7 +28,7 @@ "gc": { "LV": { "default_distance": 50, - "capex_gc_fix": 16.85, + "capex_gc_fix": 100, "capex_gc_per_meter": 16.85, "capex_gc_per_kW": 24.14, "capex_transformer_fix": 0, @@ -36,7 +36,7 @@ }, "MV/LV": { "default_distance": 100, - "capex_gc_fix": 16.85, + "capex_gc_fix": 100, "capex_gc_per_meter": 16.85, "capex_gc_per_kW": 24.14, "capex_transformer_fix": 0, diff --git a/data/examples/electrified_stations.json b/data/examples/electrified_stations.json index a43730f7..40d4ffa9 100644 --- a/data/examples/electrified_stations.json +++ b/data/examples/electrified_stations.json @@ -12,13 +12,13 @@ "start_time": "2022-03-07T00:00:00", // start time as YYYY-MM-DDThh:mm:ss "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 PV remuneration + "nominal_power": 10, // nominal power in kW, needed calculation of for PV remuneration "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 feedin.csv + "csv_file": "data/examples/example_external_load.csv", // path to external_load.csv "start_time": "2022-03-07T00:00:00", // start time as YYYY-MM-DDThh:mm:ss - "step_duration_s": 900, // timestep in seconds + "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 }, @@ -49,7 +49,7 @@ "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 diff --git a/docs/source/simba_features.rst b/docs/source/simba_features.rst index a1515f69..248a7d95 100644 --- a/docs/source/simba_features.rst +++ b/docs/source/simba_features.rst @@ -4,6 +4,8 @@ Features of SimBA ================= +.. _consumption_analysis: + Consumption analysis -------------------- @@ -70,7 +72,7 @@ Default outputs Cost calculation ################ | **Cost calculation (summary_vehicles_costs.csv)** -| This is an optional output which calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. +| This is an optional output which calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the :ref:`cost_params`. | The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV documentation `_ for the calculation of electricity costs. * Investment diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 884a55d9..a06fe64c 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -5,10 +5,7 @@ Simulation Parameters The simulation of an eBus-System relies on a variety of simulation parameters. SimBA provides most of them as default values. Depending on specific needs adjusting -these values can increase the accuracy of the simulation outputs. The SimBA input files are described -in detail in the following subsections as well as their default parameters. -When providing the user defined input files, the user should make sure the files are either 'utf-8' -encoded or not contain regional characters. +these values can increase the accuracy of the simulation outputs. The SimBA input files are described in detail in the following subsections as well as their default parameters. When providing the user defined input files, the user should make sure the files are either 'utf-8' encoded or not contain regional characters. Except for the ``electrified_stations.json``, all .json files can be enriched with in-line comments starting with :code:`\\\\`. .. _config: @@ -232,7 +229,7 @@ This is how a schedule file might look like. Vehicle types ------------- -The vehicle types that can be used are defined in the "vehicle_type.json". The path to this file has to be defined in the :ref:`config` and an example is given at `data/examples/vehicle_types.json`. +The vehicle types that can be used are defined in the "vehicle_type.json". The path to this file has to be defined in the :ref:`config` and an example is given at "data/examples/vehicle_types.json". The data is structured as a .json where the top level key represents the vehicle_type, that needs to correspont to the "vehicle_type" defined in the :ref:`schedule`. The next level key defines the charging_type ("oppb" or "depb"). For one vehicle type either one or both charging types can be defined and for each given charging type the specifications in the third level of the .json have to be given. In this level, the parameters for the specified vehicle are be defined. The specification of one vehicle with the vehicle_type "AB" and the charging_types "depb" and "oppb" is given as follows: @@ -265,37 +262,90 @@ The data is structured as a .json where the top level key represents the vehicle Electrified stations -------------------- -All stations, that are or could be equipped with charging infrastructure have to be parameterized in the "electrified_stations.json" together with their grid connection, charging infrastructure and local energy systems. The path to this file has to be defined in the :ref:`config` and an example is given at `data/examples/electrified_stations.json`. +All stations, that are or could be equipped with charging infrastructure have to be parameterized in the "electrified_stations.json" together with their grid connection, charging infrastructure and local energy systems. The path to this file has to be defined in the :ref:`config`. + +The data is structured as a .json where the top level key represents the station name, that needs to correspont to the "departure_name", respectively "arrival_name" defined in the :ref:`schedule`. Each station has two mandatory arguments: "type" defines if a station is a depot ("deps") or a opportunity charging station ("opps") and "n_charging_stations" limits the amount of vehicles, that can simulataniously charge at one station. + +Furthermore the energy system at each station can be characterized in terms of local power generation ("energy_feed_in"), local external loads ("external_load") or local stationary electric power storage ("battery"). An example that displays all further parameters and the specification of the local energy systems is given at "data/examples/electrified_stations.json". -TODO: HIER WEITER .. _cost_params: Cost parameters --------------- -TBC +In order to run the :ref:`cost_calculation`, all cost parameters are to be defined in the ``cost_params.json``. The file is used as input for both, SimBA and SpiceEV, as both tools do part of the cost calculation and therefore no comments are allowed here. If not otherwise specified the investments/costs are gross prices. A commented example is given below, for a working example please refer to "data/examples/cost_params.json". + +.. code-block:: json + + { + "vehicles": { // all vehicles and charging types have to be defined here + "SB_debp": { // all combinations of vehicle types and charging types have a separate cost definition, the name is to be given as [vehicle_type]_[charging_type] + "capex": 500000, // investment cost for one vehicle without vehicle battery + "c_maint_per_km": 0.24, // maintanance cost per km + "lifetime": 14 // lifetime of the vehicle in years + } + }, + "batteries": { // vehicle battery + "lifetime_battery": 7, // lifetime of the vehicle battery in years + "cost_per_kWh": 250 // investment cost for vehicle battery per kWh + }, + "gc": { // grid connection + "LV": { // grid connection in specific volatege level. Options are "HV", "HV/MV", "MV", "MV/LV", "LV" and all relevant voltage levels have to be defined here + "default_distance": 50, // Used if not specified individually in electrified_stations.json + "capex_gc_fix": 100, // fix investment cost for establishing a grid connection + "capex_gc_per_meter": 16.85, // investment cost per meter + "capex_gc_per_kW": 24.14, // investment cost per kW + "capex_transformer_fix": 0, // fix investment cost for a transformer + "capex_transformer_per_kW": 0 // fix investment cost for a transformer per kW + }, + "lifetime_gc": 50, // lifetime of the grid connection in years + "c_maint_transformer_per_year": 0.02, // annual maintanance costs in % of capex + "lifetime_transformer": 20 // lifetime in years + }, + "stationary_storage": { // stationary electric energy storage + "capex_fix": 1, // fix investment cost for stationary storage + "capex_per_kWh": 1, // investment cost for stationary storage per kWh + "c_maint_stat_storage_per_year": 0.02, // annual maintanance costs in % of capex + "lifetime_stat_storage": 20 // lifetime in years + }, + "cs":{ // charging stations + "capex_opps_per_kW": 877.5, // investment cost for opportunity charging stations per kW + "capex_deps_per_kW": 1000, // investment cost for depot charging stations per kW + "lifetime_cs": 20, // lifetime of charging stations in years + "c_maint_cs_per_year": 0.02 // annual maintanance costs in % of capex + }, + "garage": { + "n_charging_stations": 1, // number of charging stations for the garage + "power_cs": 50, // power of the charging stations for the garage + "vehicles_per_workstation": 20, // how many vehicles share one workstation + "cost_per_workstation": 245000, // investment cost for one workstation + "lifetime_workstations": 20 // lifetime in years + } + } + +all remaining parameters are described in the example file. .. _station_geo_data: Station data ------------ -TBC +The file "all_stations.csv" contains information that is relevant for all stations regardless of their status of electrification. At this stage of development this reduces to the information of station height that is relevant only if a trip specific :ref:`consumption_analysis` is employed. See the example at "data/examples/all_stations.csv" for the required structure. .. _level_of_loading: Level of loading ---------------- -TBC + +If a trip specific :ref:`consumption_analysis` is employed, the level of loading for each trip is required. This information can be detailed in the :ref:`schedule`. If not specified there, a default value for every hour of the day can be specified in this file. See the example at "data/examples/default_level_of_loading_over_day.csv" for the required structure. .. _temperature_data: Temperatures ------------ -TBC - +If a trip specific :ref:`consumption_analysis` is employed, the temperature for each trip is required. This information can be detailed in the :ref:`schedule`. If not specified there, a default value for every hour of the day can be specified in this file. See the example at "data/examples/default_temp_summer.csv" for the required structure. .. _consumption_table: From 1025eabe92bbbdd38f21ede318af98314647f0ca Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 9 Aug 2023 14:44:15 +0200 Subject: [PATCH 51/58] Fix typos --- docs/source/simulation_parameters.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index a06fe64c..fea77604 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -231,7 +231,7 @@ Vehicle types The vehicle types that can be used are defined in the "vehicle_type.json". The path to this file has to be defined in the :ref:`config` and an example is given at "data/examples/vehicle_types.json". -The data is structured as a .json where the top level key represents the vehicle_type, that needs to correspont to the "vehicle_type" defined in the :ref:`schedule`. The next level key defines the charging_type ("oppb" or "depb"). For one vehicle type either one or both charging types can be defined and for each given charging type the specifications in the third level of the .json have to be given. In this level, the parameters for the specified vehicle are be defined. The specification of one vehicle with the vehicle_type "AB" and the charging_types "depb" and "oppb" is given as follows: +The data is structured as a .json where the top level key represents the vehicle_type, that needs to correspond to the "vehicle_type" defined in the :ref:`schedule`. The next level key defines the charging_type ("oppb" or "depb"). For one vehicle type either one or both charging types can be defined and for each given charging type the specifications in the third level of the .json have to be given. In this level, the parameters for the specified vehicle are be defined. The specification of one vehicle with the vehicle_type "AB" and the charging_types "depb" and "oppb" is given as follows: .. code-block:: json @@ -264,7 +264,7 @@ Electrified stations All stations, that are or could be equipped with charging infrastructure have to be parameterized in the "electrified_stations.json" together with their grid connection, charging infrastructure and local energy systems. The path to this file has to be defined in the :ref:`config`. -The data is structured as a .json where the top level key represents the station name, that needs to correspont to the "departure_name", respectively "arrival_name" defined in the :ref:`schedule`. Each station has two mandatory arguments: "type" defines if a station is a depot ("deps") or a opportunity charging station ("opps") and "n_charging_stations" limits the amount of vehicles, that can simulataniously charge at one station. +The data is structured as a .json where the top level key represents the station name, that needs to correspond to the "departure_name", respectively "arrival_name" defined in the :ref:`schedule`. Each station has two mandatory arguments: "type" defines if a station is a depot ("deps") or a opportunity charging station ("opps") and "n_charging_stations" limits the amount of vehicles, that can simultaneously charge at one station. Furthermore the energy system at each station can be characterized in terms of local power generation ("energy_feed_in"), local external loads ("external_load") or local stationary electric power storage ("battery"). An example that displays all further parameters and the specification of the local energy systems is given at "data/examples/electrified_stations.json". @@ -281,7 +281,7 @@ In order to run the :ref:`cost_calculation`, all cost parameters are to be defin "vehicles": { // all vehicles and charging types have to be defined here "SB_debp": { // all combinations of vehicle types and charging types have a separate cost definition, the name is to be given as [vehicle_type]_[charging_type] "capex": 500000, // investment cost for one vehicle without vehicle battery - "c_maint_per_km": 0.24, // maintanance cost per km + "c_maint_per_km": 0.24, // maintenance cost per km "lifetime": 14 // lifetime of the vehicle in years } }, @@ -290,7 +290,7 @@ In order to run the :ref:`cost_calculation`, all cost parameters are to be defin "cost_per_kWh": 250 // investment cost for vehicle battery per kWh }, "gc": { // grid connection - "LV": { // grid connection in specific volatege level. Options are "HV", "HV/MV", "MV", "MV/LV", "LV" and all relevant voltage levels have to be defined here + "LV": { // grid connection in specific voltage level. Options are "HV", "HV/MV", "MV", "MV/LV", "LV" and all relevant voltage levels have to be defined here "default_distance": 50, // Used if not specified individually in electrified_stations.json "capex_gc_fix": 100, // fix investment cost for establishing a grid connection "capex_gc_per_meter": 16.85, // investment cost per meter @@ -299,20 +299,20 @@ In order to run the :ref:`cost_calculation`, all cost parameters are to be defin "capex_transformer_per_kW": 0 // fix investment cost for a transformer per kW }, "lifetime_gc": 50, // lifetime of the grid connection in years - "c_maint_transformer_per_year": 0.02, // annual maintanance costs in % of capex + "c_maint_transformer_per_year": 0.02, // annual maintenance costs in % of capex "lifetime_transformer": 20 // lifetime in years }, "stationary_storage": { // stationary electric energy storage "capex_fix": 1, // fix investment cost for stationary storage "capex_per_kWh": 1, // investment cost for stationary storage per kWh - "c_maint_stat_storage_per_year": 0.02, // annual maintanance costs in % of capex + "c_maint_stat_storage_per_year": 0.02, // annual maintenance costs in % of capex "lifetime_stat_storage": 20 // lifetime in years }, "cs":{ // charging stations "capex_opps_per_kW": 877.5, // investment cost for opportunity charging stations per kW "capex_deps_per_kW": 1000, // investment cost for depot charging stations per kW "lifetime_cs": 20, // lifetime of charging stations in years - "c_maint_cs_per_year": 0.02 // annual maintanance costs in % of capex + "c_maint_cs_per_year": 0.02 // annual maintenance costs in % of capex }, "garage": { "n_charging_stations": 1, // number of charging stations for the garage From b599b31d153fb0a1f5b95d2b12dc136a7fb2d3b3 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 9 Aug 2023 16:19:00 +0200 Subject: [PATCH 52/58] Fix more typos --- docs/source/getting_started.rst | 6 ++++-- docs/source/simba_features.rst | 8 ++++---- docs/source/simulation_parameters.rst | 4 ++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index ad08e6eb..9a71cce1 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -3,6 +3,7 @@ Getting Started SimBA - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. It is used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and rotations, determining charging strategies, and calculating investments and costs. + .. Without creating links like in the line below, subpages go missing from the sidebar .. _installation_label: @@ -28,7 +29,7 @@ Default configurations are detailed at `data/configs/simba.cfg`. Usage with PyCharm ################## -To use SimBa with PyCharm, create a new python (>= 3.7) environment and clone this repository. Then go to File -> Settings -> project in PyCharm and set Python of the newly created environment as interpreter and the local SimBA repository as project root. Now install the required packages by running in the Terminal: +To use SimBa with PyCharm, create a new python (>= 3.7) environment and clone `this repository `_. Then go to File -> Settings -> project in PyCharm and set Python of the newly created environment as interpreter and the local SimBA repository as project root. Now install the required packages by running in the terminal: ``pip install -r requirements.txt`` @@ -52,7 +53,8 @@ SimBA is designed as a toolbox, so the specific use can be adapted to the users :numref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. - Modules of SimBA +Modules of SimBA +################ Depending on the given simulation parameters, the vehicles are then dispatched. In this step, every rotation – the sum of all trips between leaving the depot until return – is allocated to a specific vehicle. The vehicles can be charged at any number of :ref:`electrified_stations`. These can be classified either as depot stations (deps) or as opportunity stations (opps). Each vehicle can be charged following one of the two charging strategies: Either as opportunity charging bus (oppb) or as depot charging bus (depb). While an oppb is charged at both deps and opps, depb are only charged at deps. The charging strategy can either be defined for each rotation in the :ref:`schedule` data or for all not explicitly defined rotations using the "preferred charging type" option in the :ref:`config`. Using this information, the charging simulation is then carried out. diff --git a/docs/source/simba_features.rst b/docs/source/simba_features.rst index 248a7d95..cd959ad0 100644 --- a/docs/source/simba_features.rst +++ b/docs/source/simba_features.rst @@ -33,7 +33,7 @@ The charging simulation is carried out in the open source software `SpiceEV Date: Wed, 9 Aug 2023 16:23:44 +0200 Subject: [PATCH 53/58] Expand service_optimization text --- docs/source/modes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 54b6fd6b..008e8dd2 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -74,7 +74,7 @@ It takes the results of the previous simulation, and changes the charging type o Service Optimization -------------------- It can happen that several buses influence each other while simultaneously charging at the same charging station, e.g. due to limited grid power or limited number of charging stations, which can lead to negative SoCs due to hindered charging. In this case, this mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. -Now, only rotations are left that are non-negative when viewed alone, but might become negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. +Now, only rotations are left that are non-negative when viewed alone, but might become negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. The previous two rotation-sets will not be tried on their own from now on. In the end, the largest number of rotations that produce a non-negative result when taken together is returned as the optimized scenario. Station Optimization From 6a480c71ec3f9c5be76491961fe2221d1fd7860f Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Thu, 10 Aug 2023 06:29:12 +0200 Subject: [PATCH 54/58] include remove_negative to rtd and remove deprecated file Development progress.md --- Development Progress.md | 40 ---------------------------------------- docs/source/modes.rst | 15 ++++++++++++++- 2 files changed, 14 insertions(+), 41 deletions(-) delete mode 100644 Development Progress.md diff --git a/Development Progress.md b/Development Progress.md deleted file mode 100644 index 3d6dff6d..00000000 --- a/Development Progress.md +++ /dev/null @@ -1,40 +0,0 @@ -# SimBA: Simulation tool for Bus Applications - -## Idea - -This toolbox helps to do bus feasibility studies and answer research questions - -## Tools - -For overview and interfaces of tools see here: -https://miro.com/app/board/o9J_lu8coPI=/ - -### scedule data preparation - -* [X] from VIP to RLI scedule data format -* [ ] from eFlips to RLI scedule data format - -### scedule data analysis - -* [ ] Generate table of rotation distances -* [ ] Ranking by accumulated break time - -### Consumption analysis -* [ ] air conditioning consumption based on weather data - -### SOC analysis -Assumptions: Leave depot fully loaded - -SOC trend for each rotation based on: -* [X] charging locations (OC) -* [X] number of available charging infrastructure (OC) -* [ ] charging characteristics (OC) - -### Charge demand analysis -Generate load profile for each charging location based on SOC analysis - -### Schedule adjustment -* [X] split up rotations with negative SOC -* [X] recombine splitted rotations - -### Charging Location Tool \ No newline at end of file diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 008e8dd2..ed2e798c 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -29,7 +29,7 @@ This results in a simple simulation with a following report. To run a simulation :: - mode = ["sim", "report" ,"neg_depb_to_oppb", "report] + mode = ["sim", "report" ,"neg_depb_to_oppb", "remove_negative", "report] Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. Descriptions for the modes can be found below. @@ -322,3 +322,16 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci Report ------ The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Please refer to :ref:`generate_report` for more detailed information. + +.. _remove_negative: + +Remove negative rotations +------------------------------ + +This mode removes rotations with negative SoCs from the scenario and repeats the simulation. It is called by + +:: + + mode = ["remove_negative"] + +This can be useful as rotations with negative SoCs are not feasible for electrification. If they are included in the scenario, they are nonetheless being charged and contribute to costs, installed infrastructure and electricity demand. \ No newline at end of file From c7a1a8c61474fc9ae007d13cc10b28e0bb84df3a Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Thu, 10 Aug 2023 06:32:58 +0200 Subject: [PATCH 55/58] only include trips example with def charging type --- data/examples/trips_example.csv | 130 ++++++++++++++--------------- data/examples/trips_example_ct.csv | 65 --------------- 2 files changed, 65 insertions(+), 130 deletions(-) delete mode 100644 data/examples/trips_example_ct.csv diff --git a/data/examples/trips_example.csv b/data/examples/trips_example.csv index 055034de..04f03929 100644 --- a/data/examples/trips_example.csv +++ b/data/examples/trips_example.csv @@ -1,65 +1,65 @@ -line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading -LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0 -LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9 -LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,, -LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,, -LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,, -LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,, -LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,, -LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,, -LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,, -LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,, -LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,, -LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,, -LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,, -LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,, -LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,, -LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,, -LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,, -LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,, -LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,, -LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,, -LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,, -LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,, -LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,, -LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,, -LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,, -LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,, -LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,, -LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,, -LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,, -LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,, -LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,, -LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,, -LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,, -LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,, -LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,, -LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,, -LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,, -LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,, -LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,, -LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,, -LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,, -LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,, -LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,, -LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,, -LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,, -LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,, -LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,, -LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,, -LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,, -LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,, -LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,, -LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,, \ No newline at end of file +line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading,charging_type +LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0,oppb +LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9,oppb +LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,,,oppb +LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,,,oppb +LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,,,oppb +LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,,,oppb +LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,,,oppb +LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,,, +LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,,, +LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,,, +LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,,, +LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,,, +LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,,, +LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,,, +LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,,, +LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,,, +LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,,, +LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,,, +LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,,, +LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,,, +LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,,, +LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,,, +LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,,, +LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,,, +LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,,, +LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,,, +LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,,, +LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,,, +LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,,, +LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,,, +LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,,, +LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,,, +LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,,, +LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,,, +LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,,, +LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,,, \ No newline at end of file diff --git a/data/examples/trips_example_ct.csv b/data/examples/trips_example_ct.csv deleted file mode 100644 index 04f03929..00000000 --- a/data/examples/trips_example_ct.csv +++ /dev/null @@ -1,65 +0,0 @@ -line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading,charging_type -LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0,oppb -LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9,oppb -LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,,,oppb -LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,,,oppb -LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,,,oppb -LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,,,oppb -LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,,,oppb -LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,,,oppb -LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,,,oppb -LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,,,oppb -LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,,,oppb -LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,,, -LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,,, -LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,,, -LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,,, -LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,,, -LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,,, -LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,,, -LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,,, -LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,,, -LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,,, -LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,,, -LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,,, -LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,,, -LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,,, -LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,,, -LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,,, -LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,,, -LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,,, -LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,,, -LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,,, -LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,,, -LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,,, -LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,,, -LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,,, -LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,,, -LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,,, -LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,,, -LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,,, -LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,,, -LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,,, -LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,,, -LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,,, -LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,,, -LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,,, -LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,,, -LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,,, -LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,,, -LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,,, -LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,,, -LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,,, -LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,,, \ No newline at end of file From 449164fce7e499dcdf5beb2c74146afecd55bfca Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 10 Aug 2023 09:11:34 +0200 Subject: [PATCH 56/58] Fix cost table --- docs/source/simba_features.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/simba_features.rst b/docs/source/simba_features.rst index cd959ad0..486be7d5 100644 --- a/docs/source/simba_features.rst +++ b/docs/source/simba_features.rst @@ -94,7 +94,7 @@ As result the following table is saved as CSV: +---------------------------------+----------+-----------------------------------------------------------------------+ |**parameter** | **unit** | **description** | +=================================+==========+=======================================================================+ -|c_vehicles | EUR | Investment costs of all buses | +|c_vehicles | EUR | Investment costs of all buses | +---------------------------------+----------+-----------------------------------------------------------------------+ |c_gcs | EUR | Investment costs of all grid connectors | +---------------------------------+----------+-----------------------------------------------------------------------+ @@ -111,7 +111,7 @@ As result the following table is saved as CSV: |c_invest | EUR | Sum of all investment costs | +---------------------------------+----------+-----------------------------------------------------------------------+ +---------------------------------+----------+-----------------------------------------------------------------------+ -|c_vehicles_annual | EUR/year | Annual investment costs of all buses | +|c_vehicles_annual | EUR/year | Annual investment costs of all buses | +---------------------------------+----------+-----------------------------------------------------------------------+ |c_gcs_annual | EUR/year | Annual investment costs of all grid connectors | +---------------------------------+----------+-----------------------------------------------------------------------+ @@ -128,7 +128,7 @@ As result the following table is saved as CSV: +---------------------------------+----------+-----------------------------------------------------------------------+ |c_maint_infrastructure_annual | EUR/year | Annual maintenance costs of charging stations and stationary storages | +---------------------------------+----------+-----------------------------------------------------------------------+ -|c_maint_vehicles_annual | EUR/year | Annual maintenance costs of buses | +|c_maint_vehicles_annual | EUR/year | Annual maintenance costs of buses | +---------------------------------+----------+-----------------------------------------------------------------------+ |c_maint_stat_storage_annual | EUR/year | Annual maintenance costs of stationary storages | +---------------------------------+----------+-----------------------------------------------------------------------+ From b1d493ac7ffc37e9ab9079049eedae988c97673f Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Thu, 10 Aug 2023 11:46:03 +0200 Subject: [PATCH 57/58] adjust remove negative description --- docs/source/modes.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index ed2e798c..62268044 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -16,6 +16,7 @@ different modes support the user in finding optimal solutions for their eBus-Sys * service optimization * station optimization * report +* remove negative rotations Chained Modes ------------- @@ -328,7 +329,7 @@ The report will generate several files which include information about the expec Remove negative rotations ------------------------------ -This mode removes rotations with negative SoCs from the scenario and repeats the simulation. It is called by +This mode removes rotations with negative SoCs from the schedule and repeats the simulation. It is called by :: From 17663ebb1e515cf2557988174ee24ed3666aa63b Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Thu, 10 Aug 2023 12:23:29 +0200 Subject: [PATCH 58/58] Fix numref which was not working --- docs/source/getting_started.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 9a71cce1..2aa9c3ce 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -51,6 +51,8 @@ SimBA is designed as a toolbox, so the specific use can be adapted to the users :alt: figure_simba_modules :width: 600 + Overview of SimBA modules. + :numref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. Modules of SimBA

U1IdyzvZDDQ85CRz#JIXVKlR5t9KmC`rDa| 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 literal 0 HcmV?d00001 diff --git a/docs/source/_static/2023_06_08_eBus-Toolbox Logo.png b/docs/source/_static/SimBA_logo.png similarity index 100% rename from docs/source/_static/2023_06_08_eBus-Toolbox Logo.png rename to docs/source/_static/SimBA_logo.png diff --git a/docs/source/_static/SimBA_module_overview.png b/docs/source/_static/SimBA_module_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..5ecfaab9df4a3e92d5c226ca9d6854407f66c071 GIT binary patch literal 59991 zcmdSBbySqy+dqmTqLKoFNQ#t{0s_)4BHbO*jnvQ}C@IpN(h@@qFbG2^AsrF}!!RH% zF*FR#xzWe(`@HY@{mwdnoU_h4tVPb;``&TweSPA(iBMIRBe?V64i**`f&5Dubu27w zc`U5!Yqzcge{o(6UjV*cb5oa-!m1dgUIl)+VJ)d7iG@`igLn2C2l)N=o0ocSSXhMZ zSD)9qoIhJ&VXbb+%SdW^8E-V(dudE$ZRL12^(q(-B9I=(+ z1zV>l$0pdOlB6oLvM>%7yrR9eDslaNN0?&2ZLg{uUeNq=kEf}oZyfMD=)Y2Y<)6Gc zm*H3M7iXyeskoe-vX`GZSv5mIEaWc&vbPdGH6L0!9+x$@==)X{`kn#Z!@{CBkbq)e z{m@Mti@y4f1;MotzWV-l;~IkS>IZt?|1aMHbN~Ls?YxXYg~KS`SDW*yLs;SR-z|hS zzU5r9UAJX72PG;cfyZOzRj`L{= z6V_WrhWrz>;Q|57qRn^l(wNE+qn8{X3H7&^wS-yZv$s%`-&>?k)-)r za!Y7UcJFLVD2@dVYGRQ3c(F4qC0u1s6eHsM#eg%WZQyLHmyd6mx@!68eAuwgepIM| z5<-KOCSQa~&_a36rBF|N4H?)S@iy5+ysmpHW+<@Rl2Ng`>QM2#urn1Ms-Pnl0yIwg zErST-*g~>E_4&YIQ@vrvQ@~$1tgf9Le|`lg%>JFqZ33FSSY;JICoDL$7T6+G)B zjjPtqE zg;L#9G8c+Dn78+Ohfp^N>up1vC4%b>_I!3>M&)NFvRT5)z~!OZuAR*W%n+^jX2MTW z?;`Q@zVo%)_hn66D=Ky!heVq+*$pB47uIl!*-YEi7yIqqED7SrOQZ^Q8By&AIAyg) zv!_2x+qB6gjj;KGP#k(E+oi!o#>A%|0*nYn_Bi0g!f;yQCd^PaLUraIWJR~m?c;2V zpA5QVT%UC&!I$oAXivXYs$8IrZ-(#uE1#CgoBgl0wjXL8Q#kz1kW2yj(?7JKb7`k_ zMjFQ_?FX(n>q#*!Pu3|dPWJ1J#2AJaW^i+m{Qk+@%E5!LrGIiZU#6L~obQd>RDBJm zhoBI1BS~%hajk*+Dqy|cjX9^ZuB(mX_6P~d@=;{`61v{IeEO>smyeTS~vx@up5U-(b6fui5>g- z0jW4b_05LvHy`keT<4$Li0RW{mZ>+o)PX(c$Rawak*PAp6~ME2`0N^PA-g7y{wJ4KTLx{B>O-C6NR3&)^ZH^B|zYnCm-io3ZIbO zY%Tba(z*goiWstDZS*+8NY@!i{*?Yy@i{nlNOsYIVhJzphDjdQODYH#5{FBRXc0yH z#QVh;h@PR=L=vvF%zKBflzobeL}PIXOshHiYgAa==@(DEi~Y{+7cM_pPo zJk1-Of?m*XkW@-)B<4K3pZ?=py5_r&YO-Q62esb+zQPSqNP}_K7aYTY6@gS}aq0AJU(R!Jquz8*m9{`TJ z)oRwmbn@ZzL4W0zk?Wdp}pj)`n^Gmt?m|ywa5%NGm|FC+7TVTNr<|?7T<+-`NG5KOW=M3pzYIf2WWlR^9Sx4fO8Fm z7x20zZUyx2^O$rV|I^LV7jdev?sW61wf0AcvVp6%cz0-qLfCV|I701R{)*;K=3)#2EQJ<3N z7*M?<(|4yiC&t9s)ZlY;-M8qb(kN`7SRYA+K2gIeAOJGQbvKGx>sV5+&tXRgItAMw zQVsK9w7obdTnqs&iydx%JNLl(>u8^1ShS{*RKUBG9b0ARVESkQ20xX%W&PR-t)Iy* zP9L@}d7o-A6Zyg{r0-|<8iHYaDoS>jQC=h$HQpyT%~Iu+Ns=$ z>95$&V>aPNgbTC^cTYa*4_-l#vi0)W_gF4XcU@t+#f9H=M%Uy5OHVHgzfLlJA3vsf zG+-GTc4__Vxt@nQ99ds-CkP|AkNYepobcL&S4y>M=lQpp=x`QE-#h*nen;#=w=IOL zh-1OhV)uhiA+zV3Bg2!7;xZ>mT7-+Muc%-Zp%xu~V}v*0Vf$5tgh%y)Dt1DR=7Xh8 zOfH?l@Fsga+>El_rP>BEa>6i09>aR2K5UF=4Z1t+QO?DaT^u2P5zLU#ZDLh)D%6kblj$WG$1P$Wk!rtzqac2i~CA8mEt%RcNo7OnN zayud7k*j#ms1N9DDAwgXaqP-bLWNA4DU}uVm;=6)^A$WIdtu|;UW_qmB zNQmkI>C1^@?S=A?128_;=u=3a>5;TZcxIecGA^^VMU4e}enUwM*i`#`rq!`JWZ0E;3~lwge5 zL{7be!{cd94!-VfiSL&AtF-v+hc$He(f?Ohc&Tm+SOYU|@ys?6U1T`8ZN1?-6Yy(1 zU!?|08N4iO!O3&KhB}Q{njN@@1sCupvFSd!&WpY8Th-t12QM30@LDwy;mv3j{qDp^ z_a0F5J1cn0a??4n{kw;(@^`kH+nYSEI+zH&W|A#d;H*bya)9O3DfO5%?W3r#T&O1e z_qCD0>kUW~czyX$>*Xzb|A(w441KFKFaQ1ela}L0{(UFFP#{GV!SQU6%$XpImzGLb z(~|!(#i1*JoqRM);xW0N@|FZo0fZTNAy%zG0XiyB#t7d8=Bq>TbNTJ7v5<9xhztH7 z{mnGDI(zobWjqtc`MI+eo_bjR%83p#+jo0L4o}fe{^XqluH>u!_r2-B?a9+adO^#j zMj3EXw^`8}5Y)!&0XBR0hpaee%)jR&R=>P>7gMYjYlk|&1wmz+{*RZ{ujplxvShF3 zHtYZ5WvTKN0!*P!tQ0hZy@z?fG2#wFdSe`!kT%x0@akIy%QU!Bz^% zV%6x8Dt*~^k-@@x|FFif@pOs*b7$wj`aA+?Fb2%}^iY+@b^kt|_OzVdYCyXl=S$RY zzU2DV*6BEDfJp3Uy0L!tqA=1`AwYi;jFx`GpOXA5cx>??{#*_!QYc#)>oDPOH{h>8 z%b$p%^^Bm_vGPiVH+Uj0v^i(e*u|f8Q)qnxw=~wG8&>$q05YY>r3YEoeADFUIj52` zUE^*U_cAw8Nt~El*+iKh8Bz`Vyqu3cz9#FgThsdhwK2YXcEU6IeqiD0=926yn2?W% z7!tki=bd^T_J9+gJv|G*c;>Wd;@Kvj*86*w^{Ka$_<)VqAAXoP9S;CpTJDLDOhWwn&14p~coDO<$R14d@~s2Ki>JuH9TF;Cq&O8`qPT`ceK)zUYr9G{ zZm!%48@0h_pC1V}-FFb6x|d!ebQ^<=Q`XINv4#n(5A40^a3|)?JwgJ~T`J`a6}d!F zo^STlY=v(RTpf8cU&9cge25j=#n~`*MU!~!pdX0GuE$_U($FIZu=+sibGKvo%F2Hz z=``!{&h4CL(I^SNmK9_P>l)x>Z%+Q~B%)EAW6G05BdODhkMW+&)F((e*zd=%%{u1d+pfh;M%7cP6ZCaclqL6owKC2aUyxt)zGJ1M|V zj;5iN6_~^j+Ly$y6P{VWhGZp*%~e|^@ip4AOKa5hZDFEwrUxT?qcMW^F;yXPNj->) zrs0k3oJU3P3NWb(H3qy!mDjLrl^BjWfZN&tNcp8qZcNE-i<@}U*FGkpgE4Lky`U9> zsmaKn;Bl)kB zDXVdGNSvnb1_`#pP$FwZ#ByJ<4nq@m!&7?07I`9~ikEWuqYaG2s=uyRA9^}vttPua zkoSo>=7q^ltfz4yu-@)7#rY+7L+7UZDcYGgy$`qdy>x>3d4j|*zGwF)U@VI3qu7xp z#rw%EZjYZ$+X`|Y`OWqtxSC#cgZ4hR8t*uNGnF&@=pd+PqCq5%Tcz4uR9VUHWvTkK*sfm2ZkdtLOwq2s+{uf;p~ZT@VF zVb-!8V=A8+0&nxbP)&ek5hhmz1wn2*3c{o);$wMMDGvp<(#4Mh^!5v zeVl{#X?dQVQ|kH28*3YN2P>=Ey3o$CRT^vHSWYMk+Z;khn?+8Av@6N*~2EY(~%}d4{CWxcVm^(9ut8c>UiyOfhS@{>| z9t|AVMnM9~_|4mjuUM?U_4!7Qm{eq9t1vkKn5k#DoQ!j9J$v~=R_+{Ezx8K6tf=@N zAb5q#ZzWG(u2(J&PIcgWp7;xHZjOIn72D2ME2n=$;8$ol3=o)Fz35YbKs6ceZchc9 zcirI^!Ayrv(|u5)MY%HuHj6x;Wh4z}M~Xu2a$44%W`NW3vQnq~3`x=Qh-yNy52PQN zCw^&@OJ1<6pJ_xNx?=%rv_I6feawjL6tM}f za@Xl$0q3nNGgfhO7WK?w zZ#?AvagT!h?e%#?^a`6lG$WUV_SmEM9I!(L5$76&$F$fD`@a*8dbQ%JsB%RWw)^>=|*t@m5 zxtr**S&wQ5pWGHgvt5hJH*N#2;P7$&XUHV7R72VcUHNPg8>^WFf>%ebhp~kVDO1c? z>>oMnl(4iPsO3=eLt-8VUv-ThSs0Gf4dNJ=|DD(IReOR6(d0JWpCaGZS}%+6_pPw) z+qBd7TM5R3LLIEXp!l=Ui)wz!8Em!@E+s{CrQzm}&1j#=$en;|mnD$8HrY~@Dk;=bS?NVtM{NZ z+`N8s#WV-|e16-A3G-Dt+f`~h7sN;0x^BzQ98}xK=M~@03tgA^UQmJWXKGp=b8{=h zd55_|OGZe*6iWR8Jp3~wf^gwgO8eW2t!AIkUYz+MG^MMjwf5h+_SmlZnHv=;nH`}U z{5cc$rx0!emoX_5HVbSU{%ATs!z^d&HS!uh*n_@`B%O&7s6KSBR!b+)lv>DhF+NTz zZz2F(>vNu)T$TlLVSZ;sr&&isu+E_<$4#ofRD%!L8egx^+aQZSYIGM!-llvN2{DS& zWcdwrd8I8wmUm1k^iy96WYN)%y zS6o($$`@df0mCnOGy`UM9$HQ8`8u9A=a6Ic4GA^OKZN@vo(UPcKaa7`JJem;C6(r{ z9O5TV{i598Gf&D_a@TEliF#v|Gy&=Dh(c%ZXFs9aJrN!J>gQ$q#7YXC)z5Y%_T%AD zCB&-nMq1Fy4}rp3TkZ<~i2T z^}{s_;alog_`RRusyS0`fYts%{CYR8SRKdBzj&MX!1c|j4ZPXF)A{*s$C z*(*Z*)eH+k7@YX;G0-C=V@dwi_aI$_Q%LU1CqM$Ix&kA_iP!(#uka+aF7KygX59Zf zH={R#phnADi=DMiL{FrzXqUQd@~Chueo6V?{#?D~gY(79S;&RmY(n{J$ftrxj$%)G zN_D-zb0g7c0h>lYSvP>M%m%*aYbH+Aj9c0#WR(7|*#a0JW@%OWB>7-Ri>S$G-xhu% zr5Z0|_2?ho_;;FOxeyhe!{yF;@`BFd9S{D{>HYwKIsRv!SL4y)M3|PosfoauBT@KG z>EWgi4&S5Xv^9(Rx&EwX>Y%k}3(K^9Ugi5h7(O$|r1PNE@bsTOGgu(9u3=fBuc zO`Cv)IxT(G9mxHw?awd|csMmfAc4KTq0&IBr_~VD9qBk@yT@4cypmV#F(~514Durz zoEH5B1o~=d>~D^#V@X&A1N%u=re6%1b|_xANDDM2v3w;F0e|B`5=^Y9L10%}RIKFH zt>Qz?3mQsI&jEBD?yzXXj+D4;TFGWo$e9G$>arKh4xJ&I$+9>7-)OxqQ$W7tHVpJ? z=Exrr_g!pI;ljVs*XcD8OfV$sRXJH%R%W1f9r1h9TvmwA;RH``O7{+Gu3 zD>?j&k%p8OKGxQ5<9T`>tb^phc*yatj{U`_-pv-5ah&?~6QT_!MpK8=Zpi3NK{pF* z9GXaJan2^a9E^&}*>1uk>u875h~(Usj6e;?HBTdiA01N`k)2GoTkSotVJW+SPJnT2 zYj7|2DGG4?`nek{deSwt9hpAP)c~2E!`sVEi)e{UE=CR1w)#l(KZN#{71@Ls@hZCo z9V9>I0IBD^2uyd&J)9SHv)5fVm@rg>c0I1$M_uPQHyvd*^I?6MN}tV?A)BQ0)j1de z%#wiCtMWz4jn&};I+3cy5>$|88W|8jx*Wi|#9CIVxT_ZuQex{I3&mMx_m&YIHZ}|{ zNBX(VMz)WtyfD()e{@y>p18u6 z9t5H}ku>3dq*tx{W=N#r;L0#mnRsOO+ZyjWWdCk3Y?r7D8z<4rD4g{#HY{JZf%&z_ z`{DvJ$p|9sg(}!sVYcC!Kd1*d3Ey^J2X=+t%~Kf`t+m+dSPYdkM6JMjX3|a|@KQWw z`t%9Y`I_Z>B?b$w2G;vn&dVCp`tiQ}jNEmbgbghAqI>JUDbtr~S$?wbwFJ(d^Uzgr z5Zty78hehyd`8RXkYL*!jCiWseULI{!TGz?7L*&LS(+u%-_4v5T;YcnSzcx;WL<#Y z!Y-TL!!=UPM=d(h3atOT-QyNr1XsDQ>O-BT--cct=*3+^8QJ*MDjPWAM!~;797g}(ZlA$DWf%P+>bcG(W<8c?J2eKP|Q|NKO)k( z8_n6}#qrk*TR6BS9BoMKV?hA=`U}A|>5<|oz5f_Qaj|a<`oRDA@1CdcGtK!`@QQ|q z+^rAfO5CC0J*9hx!7rhzzf&jPcTqqV5&bW2iSJ5K<}~Rtg%M}czTJvs6Cju&fg8W* z0R>eE?|9KJH5G{475_an-g3P2&r4wQ=+=E7QutExBbZsvKm?Ese3@>|GIF@>BrTTt zP7VydT>nLvl_7{MQ5I-17sQtqc)?%=#oJhF@!Xx!Pd}4GUmaP$Lk=sx#}JZbC^?a_ z^x6B#(f0Iq)nRHnHQ8PJ)~S8w+6<4Wms+yFbnkeNttKu%VD*vYxC`?jAo`F>PIB4k zJX>_xms^3Ewtg<2b=y*9+CQW6hVai?|Mk7c(je5`$6jN~*nfkE-uwBQ_^?m|E$Uw8 zRtKLdR9Vpk;%=m8s!ulI)y@_7DY$Ihag_NzY%9%C?y9yVWeChuPKIz=?Y$I(ygpw^ z?4$O?*tM(Ec?~_Mo$UFlqraFwQ`t24YPz1GwX~tK5~aJnH6+3st>kN5Z;7d2z7Pi! zX8;@7@msYy4pp|Vlk{ec>`s10^kU`Z%MVVj+KEg=RMFJzx|K8;_r)^U*}VSv1v@rB zBTth>w1_kP5q#TdW^_j@Y!&%)@d-6}J$fiKUSvcRc|e%nD&o)TdD;gEtog+{fm^3f zrimnPM@Gqj7&PMQx=nlSK44v)!tt@qW}}PQTFs`T;e^ki>G0xZJ5EEU@8w*-3p!3- zx6bYhc0M~;xOW%SMuBs(S9^_eDn{AHx0KR`(<|{X-o(Q|wrx%USu6QvUVt6Y5d+qb z2{2D?9|z%;Mjm-bGAUd>Hqm5!yNTiI_`XhrOH06b6oCsPp#;O|b(?b_UB%#S8vv8qRfSjyO&yx)?O}@%KSS4*gK*#;Z>qZL|b0fGrumBjSeR|%KIPp{WOA8jBdwL(zJ|=bwSjYWtK)2Fw|J--$uDMk0HHH$Vj}TO1 zALT`q(IAqj`3lhR13)CaT=u4U@*`5K_2E0fA^-`wqZh=EFY8lMD8JC&?5DXQ?tDgT zAN9~?MwZ|F`)SorBg@{6{{YCVq&l)VENo+iwg;N6=D!~tU$8v`E6>Cb{sEZ)_-PUG z2f&zE%i6W+$PjgA9xC6%=>Lw_j5ZHb4mj5VE1^x_3Z&NYPKHz9NnP8AJF+H%Prk$;-MD z+H86hkG>IX#RMUyl-C2CIUq&ft23YR=5oyi?pcaXl7Uem4ItBX~@{$IVb zFo7mSW^Id2VmJ-xf=S5IULo+_*53FJwh!NSz)Y6<4^;?fUYLzXe-6L>L_Y>)ZXbQI zKxNq{;D0)w-1o#0974~`a})7SQA+#ua-7r_%}eY5;w86+KnNE9Heuhok4f>LOD+)K z-O3+^eY(%kE~Dt>bx2si`4_|e!$^1y`}WrR6iNAG+P|bw3@C?cZ26DcKft83wMDiu z>Co=!K6tW|r}wJtvcR$2(@j@R`^s?O{h*7FP=3YSwEc}#{7k${w}wE{C9=PLL*}Li z9VgaElrAFrSeH|Y@V8Rk_}KzgJu~Q1pTV|qpnK|zSxRZqbLLts zB2``M%TbcTkt|5?S=P?GHSXeB@k~=FQcc6FqOxxZV-Sbt$?Qx(!yUvfGGh7=Qa6NI zB}2M|6{D_?kXpcw>Wa+9Ha$Hbd~AIhZp8G4i&fQ-Nagn^v0D_aXE8 zhUcJy=H~VYYvJ6Qq~tF(S-B;p%sY>`-v6do;hnK))^VDPlkZ3G69&vNlj-^8S)rc< z!%>+`86_$dSgSW6M$@Ggw0oz%PAk7C9;{U;74Rc%T{xEz6<>y_ouLM9E+RXyuXvAs z^En1sjnUKbA8Gt)H+3IpSHA-+IYui^o{TfUYq4VV$WE}ri?Ug9vjARqZ)%K12)R78 zPjJ$HXK?5)g~W(&|DkPOdJ*k`nmksosOY-|%3^>896CK+)yP`Jn7l90b)S;lV}*Oj zS!qDA=^Z7Y9}Jjq9Oos4PgS?Fo8qg~AESesZpVbd_rBl?JGEM>$_6>;oV-5&@-ebG zyM-#n!|3flx^O3`qGa&_+vn}BwE_&#rT3p7QgoLqKZoC|2;=uw%ycr;Jq{XJwzu}}~DR?3>rX_r8+ z?jF9R8#zLLt3qdnUF**PGeYnwln)zargj={Di$eGA?`34I4d@0!6E0xuB?lcUA9WT z2Ko4J^r86{@W6wNvUSXu$^B1lrUJ%2@E0&}<$3b}Qy+ekuRfZ#b;wm32a;qR>S*j) zyfeQ$J-_5TC0zGHu~0yINx&@p#dgt~p3wD#(L%;#G_*c-bF zMYZGe{iaN$mR9;8$QiEabrwC;9<;)*W|$Kd$u`)WUounhq@UH-q&p~O9XwAnk3gK_B>m3|8D1W zpiWpzHr#5-zh-miaC=EJO1=M1kpQ?-8S^zKpuS+(A!UNc(jKfK+t5knq{_C3foBqM z-F~IuoS+2@R;WGw5#*5KIlAgXcy4?z;wcO4SMZbK8dNgUk=A7Bo=3Phj5~`_ev2Df z91)8Sj?7wP3~aS)4Ioui#UIG;R`&6XLnNYsvcXvNa>0nwO4!ZX_bb&gWKI-#I>yv7 zcMZMD1t*K0z$2|gQNV7EZuY5Xvnv}x369TCWkRy}$rKJ* z+Vz9mzvWO5(sPj8IKvQVr&#E=FGjch-#6lNGU9pOv+@N@dn;5F~R3sEsqC z@TbzM!DcuAa||SYq}Cw}CFDp#430EpUo`h|SP8mDljFYlv3yp6ayJlVqhLp(H#QDV zMFBxvMcj02ZvF$`@)%A z>n>=uCd<%X$hB7rztvJ_`zU_>A5;3pOpM&h+77=CbWh~;g}USnzxgLqL?T;S07qMQ z^Sj%rKJ#i_&5F|n-IGeqxgKj<$Lal@@qEtw30Q|ySVpCP)#Y`x_i^<@A2g+n4z?Ju z#cOAXFpC|i!8q6>u8anzS}GNJWsMcjsi-bCw~kR)N5?$uA8H2rt&dE6>6(D!V0@jZ z&JbPuL7EWcuR0EL$8{`|6}7*-M2_nE?j1gGTnuZjJbxEcw)asQMY`WRt_uP;H73(= zb9N}Q&XnR@M<~bm&1_!T&>qykW`#)XQ-L}Y?sty?`py44JB)wi6g;_h!#HM~M-w8~ z$*1%!V%Bf4`sap={{1^or@iE1aStR8ypo)R#6>=THjrmqqw@& z9737xMVq-jB-ERBA6@Y4RZMhoeTp*)8N|p?3Sixv001v}f8`s8d?E`6@Qm9-3Fs&( zCsJNk(aV7b{&eUam$J~wP3T7A6D5!N+|eFVh>cu3%LH|FOUr6f?$Q3m!0Q9rqUO|Z z1?yNZ>Hgv`w}$}!f_<=0z#^<`#>_L>FSa(mUNe6R-e#F$nvw!8M1pm-Z&@Hyn z{Mb|TBQ5>hkFHUvybV>w^+dQ2hlN8%KlvID(s$A!b`mq zp0k=^v<@x8=Y#$AsoyM`uf3!Lw9eW~28Nv`z4b z>^v)#hL;HiKQqne#-YFF;ryo~!6;e22D&6k$!dGGFMzY!5>%eZ*S`lo9t63{zsK*& zOESK@{%Mv-n3YJn3c{v!F0 zIi*xJ+>t#ST_|+hAndBe@P=1*n~1^D2?~BP36Q%Ir8I4)eTmZs0hxDt3!K9CRIP?} zC>C9yy^=9V;3Z@5YOq%o#DkDpklHd`1z9dq3?f6b2f5E;}-@b_E~ z4q?`Zen?$obWj40)p`qPO^!NI|LQ$%q^$s{xdm)NJ7adj=uvi_xzFV?8F>BII+0jr z{rS}509#yphu1AOo{VDBxrv2@fGryEGZ6Iji+2;lQNa{EnpuuM_T0t2W2=6qfr@p+ zPRtom(fn-_gHK>nAN9xrX5=|NssJKz_k9eXidJsz$;;M2p?3WM-DdbdrF^Ejw}(L7 z>RIo>L%<0-zSb-)N+x`ko!om9J_?1(P+{BGY!VVaAzn9->8_3mEF!nN-Lr02>Y%5P zLA~Mh0Mj7Hv4smKiaYeRtZhWjZEU3dqQoc@5Zw4Kk!tt7vkI|kUo-(4s~Ft+!oTUZ ze^4@ldY2bZh%J&_P^3$IVC^TJ!>f?!19GDpJ@Xr%4D>zPeB`!=?FE?pO*Pk*s zvLYMM_qwKbK@$~XJPapy-sMYxrcbo-wY5$e!Oc%4)!ZR{qKCgNZ3#@f>A%MJ&NCmg;n+&w&WsZn^Z!}sFL>n)lTYrEa|kp)Wk=G{d&mt2=l zJS!p!?AJHq!?HcO->J#wOLB?&);W5ree@xac=gxT1S02G4JrzN+lD5QKTCgu&g_`G1ew+RMl>L-v?AAUx~7}kty$luD#N}QpjniBJ(lEe4kzV!#)Irk zTVp)Iqln<^w`Jz+Vq^&}NUH5FggK`7nB5#z6!<7ME)PUGSppYgb9H$;Q z{JHmiJ|rNi^^*^N=IExLHPtCPO+np~?nx+_>FS0+$3W-HC z5G#5CA*eiazF$70@8&h7OTvy^ZGR-ssdR7fvGq~6-c>QX?l#v=l>*KmkSsEz6b9qd zNxSmbp;CqC@PIsolS>3Zv$^ghZj%H)qvaq`k3;X{(w7vL6nYMy0ggUU2Oa=u$uYia0GQtmb`Zc_C8cFIBj6=t z0|byi;J5>D2k7l3p&2z6ZRU7-?U~=Ee)yF7_Rjqnq&3RfKyUez=wSplYht18_M+ z2XCvGCV=ZgNAvah&Nd%Ud`)d;h6S*tP%5^FV=)q5IgWThrS`!_V|!Tp@-0gOx9_DF zpAqYx$e|5zpzZnr%F~cmJVfxs6FoI6u)-H%{o=IWoYV6}3^jXZ`_4S_Iudm_No6;J zL5{a-h>6V~oMu7WzZrh115MD>=U1w9d;@YJa>sGbBW^`G8vl!Bs{NGf{$S^8p#XX$ z`oXWm#`HdCa8V=82F%=Z{2}rhF)rXiTX1%R++r0y7DyT9s~F%h* z0LLh;D`W&9Ji(8vT%D<8Yg@$7v)lrU7>jjG9qc^7v)$!5e$1>^nNoc8!rx_N>;5GN z@###fAoa#)(jD$pbjQO?04(K=YqgI9x9Yg|&m@!=sCbY-uiK~c8kOxSbs4bKQRRyu zJq+N7ROG~#hg5p ztYKj0{P7i+=MPG^%E!S8d{<{A?pKj3R}>BeF>A|bi0q3ELDe=5AV+_Hu#69nHZbvM zESj!}hPS9FM~7gLvI8J)e*7U2+h=bB_BE5KDOIsWrxPJB?E1sPEYIj!4?vi63d>i9 zt(PJ#PP~PM=IJUTSoTDmQdaGtOd`MK2$GwCXjG1a;Cfl>K*2dKKiOOUdQi8{@cz!R zBOE1Mm$Cu3D|eu9Yk!H@ETmc1-f5co)zt;&U*A4GVJOMs4Dl?U4gioWdBb~a;Sw5x z9K#wFAOD0bEBH{#kADIjaGbjJ0j=!4HEa^lZ1`UjxE0yWZoi#%Zg$gYjuJ<9&O9}P zBK1!L@<$gif<;XzK7!G{C;A@#UIh1&S1Y~&faYWcoxT>VaxuPXk9of(p5KXI1k6<1 zm0e#)kHq<54f9gZV*C<82CR*i@QF}Uz~x^oG0?vG_>P8=D6SL!#cO+Tu5$ky9)xAG zr?}1*&01~}dLaj$`MNy?lx{#B&^qCw9F;dtSCQYdiGi_1x?@|JG(KN-nH-|AFUT*S zLC$jDyB`T#fY+O4mcx$sJ$B;f^Q}vBAqRX@AZuiuOAgCXhp~3}Z)W><^Wrho7y)8c zUf}vmU~&y9xs(-EgZF%Jx6)@3woah%ojc>52UF+6SkNCa*t{dQ;Vrc`R4ui2mC|75 zVUN?>=*9);v}V0w5|{FG>g=x~-r3pOd%_IIA?N}d_uyNl?b4tIG| zK{HtW*#GPh$zQJo%7EInEn46}JQ|yMy2?7+NiHRIb*5r5;{S* z;K}~MqHDx^f7B|H(3UP}EfJ2aV-Q;^6VPS>Q28S%CZsAF=3Mbx*CI1IkP{Z|kZ3jU z=k{iJdi=Db_2bO!nbJa1FPUh!93;@S zoNZ%FzKExqb*bXy0gxqg~0$*NTI_CHu?9}hV;~l$2fX9UDBp?m_G91uj$y z|Fr?|#d03%yad*&c%=YH&h-9mzDv#O{y)T9)V}|xq2}Fy5pb!(f*ab#o#93Q4 z6~LbXFmQXw`!siH>ztr&y>$w+SQes!nH)t8mTTdK|f09I6 zbv`e%`0`b(&dxe2#Cybcr81cvkLy`CsD?zrBR+38!=aAuBFFs74%3U^=unj9*9gTn z73-dI@PwUfAN4Z>9kZz74*ldkhDUeiIBaDh0?FZ-501}8DBtU6uU?UeNL>qV0(?|( zj2G^J-rTon{G#%kUq#}w5QF@$jgH|e!H(eHtFYND)uVc}kU_SUNI^jcY?~htqYX_K zLBQ2?l=X2KP!sXR9e8DNAH=R5`JXl_w%4)C!2{l>4*_G)+viaHB3_S+hPFu>iU(wp zd3g^>!X#ts3(B>sAnPPDJ|_JAD4v$7Y`WepC6CcmtQun zb6-8@sD1!E^S4HG|BQ112M{_7@DJq}ORi%{dH(dU~6%EYr_VHIS?5NcLFCHn_B--e(R+5V~27lgyo zC~#`a^1BvlP%VQg(rJZ(sDt~ftt~z)XXCE%JWEmlCQ-k6`Y2xW8W#Ohff*s0zZYXk zVUHxVXso>V5U9Cz8%h5FhvHc}%$3(I?GEO_$zik3vQPu+yeId26Y+5WHBX5Nj(f;z zW=tPgf}EN2%H7a}cwTx`#}`ayfF(i&O=Of9O#!1GZdukmDj#G>cl zkH;3=k$Ca#BAihRcqCV_8&q8fG1EMaV^G=aA<=$@TgZU~H#~Q;jmk#jdrUCD;1xnH z`Ei@_JwgruMa=(Ms6^o8)>tWfQB=W4_`yrSEFd9eP`{)HB#7(FX?*!+%t6Q426TF! zmU(4-{!#&8`J;bLv^pWg2!AP)8cI|Pj;psk*Qk?|(wX#He&_6?l8NeA81rz5SKpR-$YA5#3>B_w@GwZ;rAAx+lG;%DK1GtxxAUPIHI!F%x5(s7FX!5 z_s3zEoq-9ZY)s-%EP`fjr|{8~(wVB<#sZa=^c(^^f=Cp^y!e;^XV<-ptX;+?*Vovo z*Mmjxjk~GOL^nW1UYc1C3PoAyK#>lybI9)$G%Y_8by#L)4rUksB-_55ps#`3*IC zJoA+aj)K=a`T_eYI7+>QR6jsRT4L;@T1?Y2^p*=D^=igTGxiA*omrEaycwt3hwR3o z5Nqng;j{-X&?GNrmWeB3k*r%A8zYt#^>NJl_Q^j4Y@2a}DGT6BMSE%#V^(!kz@f04 zaN@YNQ8D%MO5)VDLx-6K+bQ3<%}1##8qth3X9=lV`Z7~T7uIA%w^~}maKVBdlNNcD zmX_|6k^X`5ff}~U5MxJ0@+WU0Bs&tR(4Opjg(dIxiKBU~r+ldH8>v=BxppHau-@{UAkO*NUn~_!qXm%O4EKtNBm74!q&RK=75`Q!J?+BC!4J zMhEmU*f6b0AmM6j^BdL9x*n)mD+q1|S|Ac)V8~yd;D~yF>-waq*e%`Ab&;`^$8_%Dov9B}m4@ivF{NOJ(KpC4 zH3ZM+UDJ|5!`q1`DV2sBnDmLL`pm$~q`4BCbx~SIcTy*5POhh*rt8gIjwq{x6@bx! zepwJHU96Y^8sO%fApdB1^qeIi8r&TSV@t7a5 zAwxWte(b?yh-h)(NLSXd@n!dY#c&>WU26&lwV{n(b6C>BJ>Zk)YSF>@Hju)wGtQQJ zC8bRt_SG{$x0j6|4%Mfn_rq6zMr-$R5O4|5t<*nOZHQ61pxlHxJHcUPd4q_DhSDn? zn0Y(R1Jhp|&zdn!G|62=i_GmYm9?877AQWxEAy!4o+`N$Z>Z^IUoYb$hGJf8cleXH zkTREK3M$jQA65}YDtv_9(+qqjL(u)8mr8n!afQW=MjPJqtrcQ$>mql16Pwm==4LyE z)@g<)rM@|aC4o0JNWsVMEtWj+j%hwFm(r7(7zKuw<2mkFjjDTAs8c^LGJB`#(Qs7k zpnptmaor*2{6H-o7angg!Ojs|@vF&eDabLq{U?w`JB(10M3$7t+n#L4bnMCVbR39> zin+8<{Xt23JB=cP+JTKsGB>i)k{NYls|sDiokl#$!;1M9>U@oEXi52?sCKua)z@em zMm7zcLxlGiXSc?Wk8{mm4!*5i-nzE~yd|ZMIEomUqxud)EFZ@NRao)x@a|^vi37?5#t(*_iP#mqbSbrrCpIN5B z?zz@p)sQ{1Nf6yX((z_`PFR(KF^~NXZ)YcJM}3hQG|@|Qid@hw^u>205mUfYT>VOW2Jm`iVdR36J zHlz405X0}zDi%~om!1M^0U2JaDcAg z8Z%;7(B3iKf_2BEg(TCp(ip4&{Lgk2gr9l-Ij|_e&w36KVAa6^FFA{=Ty>iRwpZ@S zob^?He|!o5e6wtXKyuE(Gg0MJn%h@eJ_}79ua~sTo$ihZgH=X!4D;D@ii{RIl|F>~ zG?13aC2i$QkHoFu%eK;lm7*KBU#~EH zTSf+IvkoSmvx}i~4+#29%o4CL0xd~U{JoJWJ3DqZwhm~gYM<5o$2P98ZmMsEmfJ;x z0-=-SY#i`S#_i=azE-QD1lb=I1??jfPYh397Ue`4Z#Z#5h2NSV&a5WlIf%qNQIM6X zGzkha20@HU4+bYz-74;NK%GCF-MXQxKhFZFN!M7s>`zD3zRvHbH^~V%bv1o|AAfB2 zpcZ%t``#OcxfIU@)>!M}aciNs69!>i z?lsy?6_4YwRj}r`+5wecEb&-)_tkzKmh62ZAgxj&*wOcwznsP26<6LoFOmp)IC|k$ z=Pe|?{G`(7x~9HotIZ27P3}qak4TUUb~~h#ixC z_=7rzdLYc|ORz3xI?G^?8c!gP<0(vVD`CweTl+yY9@D3gyBpQ7Le!$DN>nd!~M-Y!+njC2~eRZ@*M z3vb#Fb}t6^CYuqY4h>ei9TtVfZ*lR3*GL z>pb9Nx?K)|1E(oJe;H?!Mhji$$mTv0k*KZq5!^=~+U%;-+>CciP3u%7>qn2wdvF5H ztP$TNDv><=WsId3Z)S(RCSfV%Muu{U4o!w=OJch%JCcrNTW0lX;Ny6gD%Cawh|hu& z9K>I{tUcgLeG#fPwZ4O>YGYxoH_`ePn+Y(}&%L_Q#tr$eGg3lf-SFgCP6X1E+zICW z>fsKtDyG4<)isQLa%x2*5Z zVdvtO!S|V@SO3jfd>MSz)NEjd`N@wAk7#xD3`J$!lJjB$)ZE`(VWM;6UCbMt6IgFg zQt2wY;nJKi3$bj?8xq&_x?PjC5IxG=G&ANxf0x27ZbI3W=}?F>=90FKi}NQ*-62=Q zdXYhaB{u=@?9eLT_xFs`;@U2+^>@?W*cuiwP2b6>W0%+Kw}h7)H1s$)X0wsxEeDau zJWSTcy{t6~qjap#GCJca0PiT!zti@t@Cs>Gx3nlvmf@hMgL|J#Du@Pohc5EV24#Xf z_-bcGe6K*XXRPJ6k9o?J7(7mEp5Is2*c>z>BTJGw++Ogt8owiRmzA0K=zH>LfKO)C z$vu7VDc`IJ$W7mPk2kYWa@2dVFY=G%AB~FYQQZ|%F~7Z6pG>@@155H{F1((X%ilIS zn){qq*Gh?~+C2W=Fwf`~e#~Bf?yUvS3!5=t6}utO9K`iOccSwG%g{_eeaNn;Veeu5 zS8Ifdo?(^eSnH}+g!jAT`L&Hz^mh)1G9Szd0YtHeS=9w@-{4MR!*JP=0^^%-nV~` z^Wiet_WDcZTclMy%3?XAeel5QQ6Rg6q3`Z3!~5iv4n=n#$s9r$?PgT$$^r!sYG=7ECn#>~8LEPqLY_C!1qJB+_-U+tB;4|b@j++(v0+U(F$vupK&j7oSN1%b z$Q#MZ{TjqyGxDTD+w}sjfWQ*95S$HeF{R0MXVk8)(LlI_BEuBnCE3{1X}|StO<8?G zB6VnX14U}PI&85fx+l9U7IvZ5cdG-{_KqhIn+9Dd=-rKCk;BBLXv!%a&*Y>wW#Rgm-}5mIj0&L@nWB*1ZmP*}Hm|R4J9|*I(za&WLcxx{L&_Di=L{tc-!^Y%mRue90!$OkoA+Ve6g$01G2ptS zoGNuRL%U~c-~ASwfBT=)G~`4eH-(Zz8L+&SGG>&Ik)N)=o%WzX*H6Fx+`vWEnCm~R z(+R)DD&BTM!bnt_hK;ps_}Est3jeTxFL>1NN@(wo;O#@v-X!R5qGQ2xygsrxha^7;O}Pc>gw_x|o7{MO~c7kV@%QFEdZ#L&CEfrMbT z0aLN*|8dZe67uouF2<9l$LdM0(jkapJibUVrX&wZir*vGW}hpL49tWALAc=4iG}VnrPkW zQK@~r9KNVH30w$R8;AG)?-77{l(+v3z4g%Ke;tDdG04j^y!Z!w@}K8?O5X&x}OOl70rAIJF^ouv0?DqF{tC(61|WCr@+X%~NY z-Yf&Yar%C-Z2In@Yk@$sj9eLBT>c;XfXN-%o@QAiwl#P2UxmM6vXWR;#K-yXXO4h8 zWC3O3P0Ue3cO0vXglpM6_j&)vC9II{?1v)t75idl_Ijnb2p(Ab+x)M?jXP)f;3em` zgW^m7=$UtZ8NgtuLK4eDG|zEAwK_UnEYtKM)$Wxrt8`uVJDLOCpqdK0l5FJgY)nkZ z)dT^9H&BWaZuk$t&H_Wo50@X2usC>F?bhUYDm^0`?8>&{n>069(roHx*Gk9} z)8TG#7zJ+IM)O-_|Kl!_X7Lea!pfid9AtMtRuCX9hBnPikJPKh23ZL=Th1pG4%z$& zOux&x)mF_#y;!x@prKK*IsP;-DyjIidDTGYo5ylYegQWl{Oa zI|=$LGn01lFSVvUjDqLMtN{BPI9p)AK#v{m9wdiq+JDk7O1x5v>G!`Lw!1LFb3DKXH`yibOWojyUz@ms~`c}0j?#Jf0AHr8hT0A96>=xzeU2MI8 zMKhrsreykZ7ZQP(w50lSgmQRQA-UO0rjHEdu1$}EHfc`%0FbI3g$G!@rn)GT)S4?r zY78^pE}0-(o5g|rcyj_sLRP!Sv6?Uc_#u-6Q|_=jblqk2lhw1mJ=`No8E0d@42g>5 zC(k)WlL+ND_?cMA$cbKx-y=wK}zK2bmq}|i7Hu`0Mhn!Nmr>bb`rRs zUtF}GmMbu6OouS;Q~Q0u){_5^?r0Q8B1h9RH{CHUta`M#)&!L=NNs@XW#xy@JoKv3@XF6Fe^O}(s-J>qCna3+!(Bro6tD__ zGQuxgdXlw<-Lo{Y1rV~oJqC0e~_vRtdY{JdRLyCp0}ta8W8JDSq)3>%jya$Sp8 z7-jQ4%d^V-!f6xN8quNIyQO{J)R+L%NYuUCI@>a8m$q>LFs+<`O8*V;?iGgXuWlDJ zqUmwKQTKk))UHz)x}5PnG7(LWE2w-XHk;1(CP3_m)t9%r!{VrlsrSOERFs>UiNN`` zF$XdWAi{cogm)LTh`_Swui|`?>ad|diXREL`Najd(1&@T+;JS%BA&Ncl)C-8uP-vr zH&^|&_6Ul7d7&&iN?+lXW4gCh-;`}VpmO=V>9opTFZWp)h^J&ck;~S*>+&jgvsTZF zdpVGrcVDggE|WvatNtkicgr4Y0eIef0wl7o-pt8M1BbPn$>1=TEEMx0pZ!iLf{N~V zOnd8Xlb-SoKW===(fUY@_ud3tz~Zm)1j2{*qOKVqMQ69OzZRYtIiAGT^7K(C_UYO} zHCkc)=G7(Rzh|8F6;=y$c#w*UDn%P%oEtE6gt|(B3W1PorC>VzBB!Ph9RN|v2lQoD zdsiMKQ26XZm0!@{5>6%-a^z8Qqo58?-|={mbH=%jqs(}pkB!b8<-g70kXkNe19hRq zO-Co&l&q^uE_#Ri3$eric2wGJ;G#=qqtyDMcimm(wKf&owKpuB`6)A~s-!ii zyw{ROlEv{{Px(uYMu9Mrw~fj5(fDZ=`W)$y@`1qn1^hYD>HFl#J73?dZ5mN(Rn^&j z7#-X99RKzx+Z@J9mW?fgRcWXmNZ;oUpb8c=f4s$mFU13>9dHvdN(XAm(&P{P7N#Bj|kIPFxWL*8afG+rSRndkrXb86P7* z&hGCjz<}=xLjK66->7CvwAe5R4WTof@fqTpP0w1PgftfJ!9aq6&%VFLUFvjTx=+}; zE|(&sX-a@^HBWeokPWLF`Vfzdqj_}}WE{o|+lS0y`T>9mhbye7;)ckn&nSr2%FV6} zCk~CIaHphm6pGC0*Bc3W>AKfQP*2~0D0J*#hegHO#w?FNsv2U)CA&xI+FsmT{Ms3w zSLO<7|e(kJ%;^MDeY?~Gh!=mP*@ za!o28D@6KwRc(iUrzaZ;**%;dok@W!tzEI$*tB=~E;EUMZ)6RRj6iZFg$u=_WlbkI zM(@8dI)$1IuA>^E*6i6;AJQEowKaRNN}K&=+*EYgJT#tB;&?d;<{mO34NrSdgo!XU zT->!wGnY42C;043_5&ta*Ac59|j_KMtRs7h74Cz{)D}a5UY$4GK48KY%N=+<_u>n2-8_%?R)N&>}anhB1j`;t}7 zpM;3M4S!w>i%wZ_OUqP*LN94Ka!nH+LvNF+>35ZO$8(}Kw{AGSERsChl~2v&xic7- zY;FVd+6VT&?yjv-Vc^ypTfB_QjzclDK|67lzw*0Mm|f1q!~~`YeV9J*!t6{q?ryg0 z4uKOS@<|>Lj%b81omGL7i8j4U^Xw=|2o3m!F-2y8MNG=T+*Rp@l)BZUEQy)WJi?&D zrSOaxaVKpNejjm-yi#)^Z8u)QAHE+|h}m!+$_<2g4B*?^Lk&mWc)u;9cHAP8y&KCn z)5SM%YDv3PEbPHeo-8j#Ay?_2$$yv9%&LTX|F2I0rCjpxQWB;){;6Qzj-9l3sq6*Lr(Oq1&@7%_^1X9n?g@{Sx z8)wiiFNiJ!rq8zqKKwPo<(Zb}yB72aGa zX>`^<5k`Y2^NgtZ!!C}hGdg+NB{C!Bi$%w$Om+`M`>-c5{T@~%!z|EYu_Q7QRY_K< zDKOXq0OrIk{}z$T%g?SW*FFNR_YMhgxh5EjfKeHkGfv-~xtopHy$?Uep9D|)!jVqQ zziRv*0j>(eC*WvDz|mTa+zdIYfT&8}o7}cbkwrK`9d%3~4 zNJ<24TR&&9*mt**Xog$LU84NDZLG1GMCP90xq*qh^?mBy4y&*uNCZ*33#7&YXq#$D z4uRR{0;hWSdoO*bCe)s|cPTA%->GTZ*<3euyZdoDiGt*CXWupE(49j?=!YGHIJ?yW z=Da?+SnblIC!)QNy$gwnMd#-OWs}52>)$e0E}Iy2e1K>J z|5&3Befm1?gJ%m@bsN4ulH{j4TO%!z$Dzz}g+hFNK&CRfG>E|G^?-1Qr(r)r$n;HA zB>i3H(RFI*H?=4jy;+>*NFP}Jw)o5*T0u!Q1eECti@Uh#oR5b z^rMZPl^4j7kCUlz4fi~o8IUxZuK43F;Y?AS#kzt--rx$_CPElo53brdG?VR2_V&8(F=`*qj+Sb&Rwu8Trc$L)$QNZ^sm4igLjM7^*2ro<8sV z0I^Ogt0)l`al1mVUrH?2n^JW&+l?1Z6w7?y_59R80UE|QBJZym1zgfG5Zei5KNWuD zx!>@Eg(-|~`~}vHYD5v*ilqUFAza<*LqAvFOXOW=8D{kQJ>3EuRGziKef4_4eMSGWVB<0f35pZ`NMO(mepFU47t=JLe&-?6T z(T`@B17F}o*U6W~;OT=o`cW!?KVkZzRb*8gybkPyG8cK?m*CyjjJRAD3S9ILawMpH z!niPvL9RhDnGM4hWIE3^wgc6p!%v0b>K&B`hzC&gPWF$ofm$LE&Q6mtaoumsAMBcmH)`JQarDhuyiJpSd4fVW`vTL-(VXNr-mEE}cm{ zQuPn&obMq2?VLV%yQX;trZeRM6olp-1#UXzF}S|Ebd-{4+X+zJ@YaA$DfpkmLg5+v z%IRX={u{kYx`p$vRp1SVU(GecTUbqE@2vP==KxD*fdlV?5BzSR!vq#rOb9XxL^|vg zB1jIgBhd2JzXhGn$pe&`y8AYFU_IKFMaaHJvksypHe8US=6Gs`V()dvD%1Dz2LRN2 z>AwjfJ+!@moyL3iYWUBi13qkwvWWkoU0lE*zVXMm@wb$9#;TL}@W(gnSHAcf=tyGd z$o&u51Rx`?{kH=|`+-ep{)dUBkmr(Zg@o|5NAu$Eo~urw{7hOIPH0`U6UDpH5?gOH0RP|5MOJJCiY9T(+M@ zi}^YyRvmQie(<$B_E~2iTlG1!h2Ba=;|6;!`Cv0Jz3CH=7JcVr&UDUIsm=*2E%|&|W3g|UV=5ee%YXf287+HQem}B0rV}GU zyu#ZT0kTBCCzI-DX3mfvnK<<&@K8DXMp}96J&7G5_{ID2piiot>ciC60hJ{)KB ze#?ckFX7?!KkT8^6S(hj_3qJ3x8j}sr=FTuCF8%`pinFHK6Ul~%r70ReWYF@<_t)? zD1An%?9l6h-2U|T)z4>m4rl`<0SoHf^@+^L<1m~ zqqG5B-I3S0s%X#OrGqJmrAW;7(qbg^+rbQ>XzkK1VeG54kz5^A7B_wxM%j9x)SHW$ zW~UzW`#R=--{0n_Amy0`7nVicf934w{D&nDRAK;GrhAl#PK=$oU+edAx2JorqE8ic z@P8UVnHiB4Q(zJYKvK19i$2vaSM8FrGVh;`1k|egglE6$Kb(+YUGf;-1R$ZQey7*b zAkp8@(rX#-&^H2u8|$a*vIv2Z=1oLl ztIBDFVLutCKkHfy3&NkiSK#NIP@XA@(n0)W%Kp@u|2P={y!2nvMGtZKsbT+NOZ{o` z0EC|clQ;k{)(dL8jOZ5~fTggfUWsjdI6Q6QT-(cTD(%b^Le!1_haUaURV@chgL5$g z6V0|wdZ^dfJ}k2K*mJe0e(&RK)NyWHDzEk?PEkbt)mXo;0h~v{t7V{f3IGjOiugpt zSLJ|{K)sA5B_jKmZO9BuU!v*0FVm}Hju8yhwhwtQj_)ZjA5YdCPW|=aOp4L z(fEDM%|X=5m?-hsckIgr$&L>c$D$JpESnH`L+irZ^(iET=v-yTzWA@Z3bGBmSdtHc z%|!IXhb)%}TpfY8GFY@5O}$ubBdlsixKFjw@409pn2 zc9O-rgt(<8SU~4}Ho&+Fy~7 zC*9lS9WFSOPS>70S-sTt7d6U81mpu+CY$Y z4}|0XZ3f&%W>>bTPB@R~^ADO%-fq*pI5IB9Wg{eEORBK{VmgSNFyn1?FlPF|Bg88S zP3=nW{N0gN8LJHxh1u|GYJuntHui%ox2~=IU4uww zb)$)>Sqaywo2Xx4ojp%ri*&#Iee7Fqa2x79|@6Z@5YWf%0pNv+U$ zZ^gZN;sH23^}u4x)GvX+ zpuO^UKy7d~Ez0t7#Z;0u#IY%JuZ&{kJ#I_0?n+ceG-eguST(1A_U-cRcT=W~f)!I4 z0OSpR%2}e$=RPFD07!fa3$NE?L6_uByNNzaW>rp34U8|h)V6c>jFvu&^>??>5Jd;M@!55)2o^hh>)zS=U7`}k>Vn|?7z zm#U=K@Dpso8>3^EgaP`khX{l;-lWO0kl<;@wXkTdE&J2Y^K0Iji^}aJmcrKkQ+T+B z2F>mqsc&4|f144jF@ISRv8{hv5tr(}gf1EtP(>$^`U%aK|sK(3jdf)v8v|ZkaOIN=+&}`_rk}wW@$g!X){Tsb_#HcRG zJB{?>=n&B5WW1PxU(bCp8|&UL>z|zHn|M@K2L0K={)CAu;a@sl)&o!CziDL7EphnV zd}q?|F9`T*LvYFrt#mIrq2z|7k{Y#D1Wn7znE?}9!pd5h+2;dxju7)1LIohp46s@` zcTF$9k!*RXjIGIqajTjQ0OyLEjb~JoY*ii2S*4;CpPUUJK=TuU_e4DXJH7bPt$-Kf zZo$d`nH;*&303oJn49r`|GMQ2vIsr|X1`>M{Q&PmL-&;`Op^;}y~A_mK;>jFFc|c_ z18-Cq`m0g?D_KGRb}xh>-@hui6O5eWv@`N3-LZBeJUK2n-e9}+LaObS7f9DI>jwUvS%i5n zs0?EQ&D!__I1h@0BZFwrgjUz^-EJ?XG93v@BbA2HY%`Hxh}g^GMM^8W{fUKF!Vmns zEX1T45eE#YePB0_~NY7p3Q!KIsV#8K7PL0fF~tT0x31 zYex7|ur%})V4X4bNU@(DpjUz-$6aWwxbEZc>*VDiV|&I#ipqZ*z0}p7VTOz1Y7!)7JVRi{NX4d7l#xfGK$G-$fwL-AMTG#Vxnscci*q{M zYh{l&p47v>ulUoZ_@Rd`a2jCcBT#7vs%KWXt$Q$nKfCzkv?poAd?Vt>C$ISy@ChX? z5?)-x>z{t+0i5i|8iz6uy&RgF!CTzp$j!W|8@2Cc@H%KHR`8kIDB(U-`H9HfbI{QK z+7&?m3}=f3m_@d1X7_S}oJ(hTblF26Oc#(*xq4O$bO4y4P?;ezd^RRMui-s6J+4KK z>ZkkUgOP7>7`qo4h~vXY;k)jRe0lSB!Td>WRgzwx0)WBzhP34+hFmSuz~ESovblc(SKn>o6c44X~)Vwn3k^f$-DN}KVSS| zHZ?yUr3TWb)=IZXIj8k;OjiC`Mxc6yeNjs*y@zdhVqo4}Npgj*Q?ITr{C8hIhVGxX zJgc4-*V@=Vl9YqI-5^wPV%uf?--WCeAlB|rL{ByhpFQ>4y-_s5CS8S4uX^f zMjxtudQwtmZdY@C!tvu-WgbCA7&~Jz0?@oSG@jHqw=kLbf*!hpA-5j001j#*FRmz` zj37Yn@}yLR&@a;kPB8omZUho$rIAaK5r{pt=|b z)rF<(E$J$xgKtxAp{|#%y6|k>UZ9?fE{K4TP}*mxZ3^-ti|b8xJ0>3_lcv91f!Gfl z6;vL%)(NY!t@7JZdff(jEFAD+Jr^v{1~yUH5)*nUi)$ue-D%bJ2((2yptj6$@8sOZ zm|Q(%Un_E6hdZ|RDmhQGA(fim#sS;s%uWF^pAET+*HSn0SYNTKu~zzrmwUK0McAyp zD1m7+XyI#?SQl9bFyV+J=6ZLd9ZS1E4OTGYTl47jJYQS*x#Ago$}ogcNd6lo`or#0 zf-I;Q)Mi&@^>18t=*CMDW)%Ht5xjng(t)w+x_fraeS7J;Pc>!iPH)iN`80Y?L`Y%1^)>@v{H<8!_ub(<$x3@*`mI?#%?=>NCR^ zF!d-XNOwXfqu!!tb$I%|4yB!n#_5DQ8I{)_qcND13b5q~E8(eR^?bS|mv5Vop1`nc z*B`J58_n!(%~69PTN<65dvJKj1!BodG)OBj-6D|lr@}e-RC}6pM02#&Vdx*^}om3y-f6`6u;zTVEjV`E}I}N?#UlV!|SXEE4~9D5(t( zfnM`}`J6!2;b70srf$-I#WMwATX(sFsNfe6V&VrjJpmu@-IdO?TE&xG?_cxyNRwB3l&<;xDBVpk~jF_al$PN+oa zi~Pks&P+F%82Zqew`t6Z)P9wMybPg8^vqENcpRF0$M|FSjEh-@+B!pJH-X*GdRb1P zX-IICby=;mlPBciyOQ##`gbpIoExW~#mO{V>8TygDk0kKMH{7wEz=UNwF+O(Xg-(D zet02^M{WO^l^g?-ss2F1xlo z0KY*6V}cToYR~h@H~xA52!#%Rda|;!KWynqyg?&)K^64hB|}6NpaC+30r=m~)%<@- zkyhRxCI-a_HTpl-oQ3|knRcZT9XHLGqR+-oo{I`UmF!=7BU-_R(=Fv%hAq02u?V zD<^2<`uUjSy3_wll&zxq|ImQW_qE-X*xPQ~zvb%*1soe=R?ryv2Q~?CL`UCtXuxpJ z?*&)Rq#!WB6ToDCjcft-w=?q#(HnrPQF-!SDeF&*-@jMhU|Z{yyzBZ}YG_>fWq>Qc z%}st5RR&j@&*`@2ozfNX^B1`m?(pFc51t}e0ec+AO8&&6Z&mE=rV99mSHH*S-J(t6 znvXndf$ZG8#SAup#%zpV3oq{Z*9Iz*PcVQ(*H*Fit+*eGd9({X$JDV;LjHy>Ykm7` z#g(^@f9p{_tN?AJQT4oC>kp6A4F>E=%CBe!yv?5scphgnLMEJZP3?U83xj)IY7zQ{ zaM&)jq!3;_+5Y-Q$rrFO6P(|S(;E!Jm6TvzMm#zy0i>%v_4D=zHiyp#bLpQZLI%St z_vS1d&d0=D_n#^<84Ko(1Q1HlTRyux`QaBau0{7wy#5Y@asQYQ{yj<-pL*jkg259q z(g=K_m4UxZiDEY}ZY#!F3!4F9k6IA>Oo&52vH=fC4BZfphFj`h|GDi>m5Uf5(Z>_Y z|G%L!3GI%3W$VpS&E({%-JVUfuI_OquPD&g*A8rkb&ky=k0M1LgHr z6P@JRq_pMxn(-v2KD3qQH>d?8;`kqi%63ter;~6tyqq}|W}e!-W>e#7jq00TLM+9@ zU<;H8KtYTH*=M~{KgYwWQL)ASa9Tjl0frZ_m6b|EG&=ZIkg>y_*?xbCjwVEuZ^ z+aXxz+a&cQpvMeI_!*}fpysu-yDAJ}`8KY+ClGiha{O*CVZz08RO=nI^uHl%h4`+X zEaf*#3w&Y90B<7n!&lZgmB#Gjy;D2X43OH!AQj2!eO&DbxcoW9^sGJ6;rm#eB}o(1 z?DjY96XplcxH(&H8XLH*H|*|y6#7xV=LDdHtU&*&d*a$6Joe9@^N7t3<1r+mvN^AU zmc=cfbk^jzyQ^*et93I<)o?S17r$F&^qZg5$ALFM=!U=6tN6pCo3lnJYdx!M>KZ$p5O7V3J08 zCx49c@$xe_*AS%*3xl^W#{0hyeBp2g+}&L)WQ{gbO+wb1C^`eKT%T=56r4JJ?I(Q>-Lpyjv(bQ7k0U_6nFn4m}DU zHAtRuwj5@iA6xg*_w$Tb8I7YYwEY@N z7Q9joua-cfUhB_xnXwptom2l^fz%);w%M9?Yn>D^pJeY1g+mEm!7)PYN3aA zD1zZ$MW(MMbA+y&?o7}YfNR;PMWORJQcdbs7vW9JWo8!*|u7RjGq@jdB%?kA<`YUqnSail^d` z2Na^nsjhbGoV=?Hy6q9e6O*?P^$!P>_VFELV51=5n(xoJe@bCS(&*mCBP1#NP?4-^ z)7p}>>K3zw731hofd6pN%};hL7HntpbvZjL2GyWv&z~lL||i&!oPrjX&|iQuvrk z;;(^+Je2*q4V}l(O(kN63u<(N1FXU#sEp0gaRNZ#woK=KR= zR-JynxAN@CU2MaQkx)xMhvjFYUwVP9)DwW{)`)^K((DpFHPFUqObiS1qE)~~Gl=SZ zC+cB#$Zu@X+66W9H9TE0{Mw@bJuwnkejPU^Uvy{e>ec4vD8}ncepoE3m>ShtJAQ27pb*X80CXCW0^l4mxyFKEo(I5(tiC##lQY9{@h+Gd;|PMwyqy6AFSs%< zUZ({<9nv#^*P~$v)-^6TVKqlPa?(uDEVSGI6BC}JUc>X;cUf4zLfj+aYytdaM z?%RX04JOvyvp6FgIv1`=mCC-9N=~@zzSifo@aTddUWbjzl%Ap?n*;2a5r4RM^Q6`4tf@;MJPM;|bp$5)V1)7)ZA7@9{8Higow(D%$ewk6D=` zr#jjBHt09(qPSvY{Lczvs-r@rf-nk+#t8rjQ&`3qKCVMqv2(( z%@e3tI{$W!?rn9#dz%@I9`wXD417{3$_!^4qH(Ics=A%WdS~`+Ki4ep)Zb#SbApB* z$mlCgvUgx)^yjZi!TGPfMNX*t+B*a~46Y|t{k=7rP9J+~s6l-f;ix2-BNF}iH5?-a z7*nl<;^G$m>Y&P>YH&wQ%LgYKaz2Gu(~1o2yvY$EcsA3MOhP7F6iC&mf_iQDw3C3_ z>C$J-D7SHExL(rbe$=DkWJk}{xh&)?q;Zs)>cWB-0RbUim+s+V@HZ$7&5#o<`TX+f zoV-+%lieq+D&ZotZ){L^(vhb`Gs9Vx2L%a((rngO28FOO%Y28PfMf~u@)^_Z*LP;M zkkWnKQ+Dxr!v#Qy^l-0Kav$PxB;}aY<6LhujR27C$E?Raf;9SMJPxn@Zq5{vh_oFb(bt_Aoec?oUZgLpGRPN%sQcN0iq1_C!B~@ybw_>ClQr z>vE-vxitj$Yu0Crsn|Xd2kj=&Nsq&l%w@;V@il1|e;JkhV5}VCKUCJK&L=^2SfR&W zL=c@-K||WYTNF;oRd*LT-yP<>RTp)?(h_b{J~F4a675g5HNNt^+(6tBGZE0LtKcM0 zJ#Hmc8cNzvb-{f~?I2aOn?abfd%B{+hyz9s6+nU_Mj#+6vxHvdk~vT6KbTq`WlU0&nFld$ubj(M*_I)r!%7j7QuznoHr*U}d;*>dv&M8)Pa*e=9F z=7sLVLmvB%M959L5&1Ko-{F7Z`H_INh>g=$nUIAPMO%Ye_360F?kS(}%I*hCbkN=F zOpWfWGe5?pYV!HS6%Te$bS{q97|XLpXKJ1 zX}U9`b>-KjXV>1Kp0mi<#(H!>5j~nN(>=&rG5>W7U4 z4X~5F9x863Gl+9(y*8PM?BM^w0HSYA07SsOa~kobW;?KUE$m&>G9xn9dr*ikIJv0w z%~dEZLy>~aIz@%yLFWapw?rKWX73WaeBWn<>OQQr-it_|aMa3I{&vJE(YI61C#(Bw zSP=(z(yxt6cSAjUWnuat7Mwby48%cVFw7d_P~|mO^lpzh+J)oT-V4B1`H}{cMNtIfb~K|bDG=Eo-$&>U zd8EfEc{$CJp%y%rcQKYQ(W_xLSC1E49;qz8c#nfgjAdocV!c4I zLHeae_*I)R3DZKg`@<7wJuD08N8BuEMfTtqXY=NZD7T7Sm+^6l&i*lvbi1joKB~HP zvj*3q8Am1G-5en-8|M-0iMS;zME~?yqpkVZidQ$g52YT5MWKE-G8_a_ST_(LI1E#pm{!qazree!Akn;wB_|M79V8kjSNi4@A%b-aM9M8Nocd#fiQBbj}*voN{XqZ z+Geu|dD%Vn53ha_wx^bg;w4J7EroIWQ0r&quG4;s7BzKl(@c%>2Z1;~?|VTCQR%Hx z&ODD{1m#6Yof0Fm!~#27Ys7g>u~EHo_`@gH9;~Kia&AxaU-$AVXCD;levS=7&GUps6uXW%R;a^;YsZT_sPVk;bcH#Nr zo-ljISa&)w@I225mR+oXa1d%pH;Sw@w0Utm@G`U7bI8q#!j;`fX;C<4vR&4f4Zh-E zofBH2gB@v8%^QQ8@WeKeIVxM=EjCtDvq|Z*dvN8bB}sT7=aN}tEp+qQ?tbDG5iu}! z_@ij{d!i^-D{0iLUMgaJ7GNCv=j}yuyFCnG_jG7pWiFev(yn-;v)w_C6IU@8;X}|o zZ3mAtVy=#VvIJ&k^|~64k!saL!d5?JJ6SX(qYWsHHrm#Uq$ujn9%$rx zC8AwIR@KlWx|K*D8f_iPSpc5s3qE2@=|LOcfJ>D$=Hg|Jy!jBfm=t*Q)5VQxjzhp&!Njv|kN`I;v}?bv#P%5y_)+5935G zYP{-wi>f+Ga30Rhf%=EGsVIvN<_6|QRNWlTUK@pd4sh&lBq_UuM;3*uYMwZR74TX2 zK;uhSWR^m|;`=r=6gvxrgkpLms&vH=vmzZDxzdCq>+JVd470ZBt)vfKED6GRkk>zY zZr!rMl?VsKsec(|yf8E z%@FC_oUnf2JC{Hu5q0Z6+fcAMai{=_2)JSfUN3%uQG?&Y5w%E%58R+(yzVbi!n!0h-JZr0! zGhX&F&sg2AaYs7#$rC+pJQ~uiJ0X3%#Wh?HKZLS*`Y4R1tZ$^;8tfMpa$s+AxVx=W z??p!-TdQIJ9C>$Q{3;Q#>-DO0QIr$I@Xud?P)lRB?%Kd&)y_sI8wYnVDsv&xIPq?} zi(-3$hz_l!$%}{Avu8m8|4~v-A8;mA+MOt3s}lKPzWlg)@#n<^))2v&goFf_PMh5} zFR#;#w{ZDel^I&mYbN)tAiz&lNnnHW(r3B~f*i;Naw(9!J}BY{j{Aw(K>Ak|-Y1a6 zN>lUf~l`Qu}hrm zt6E&BNQnWxnSXLa`72__$E5iHf`JYJ#jwiodli&`L5h)9?Mk=KYPKFb@6QD)tHnrf zkzY1``@@yC`Cm2*;*3>kqj0$rRKab#aPy~m*Z0Q<01c^G+lOc$j9F!i>U-CN7$1Gnl0W|kRi!_zpWZB zk+*=2Qxt*zXd0mV5+mixVg-hO+O#2JiD=hCAFYzGo$Uo~bXbxgFCdS_u% zd(8UDFZ&%au<Mm&fD1ZJ^?QM`LvI(S?(v$hgwPFU$7V zj_-2t&0tOgI5b{^MnAHD-&O_=Io=J!sJ@?H?+J|e!XT*mWWdLr$4}S!bG^x!$8VL| z9*mgS`IYxa@RF_N_7f+IqOjZ8a zq~Jp!#t!s)m*xo&?-}q%+nxu>#hN|8+H&{z=@sLTH=m5DYTqyLd;b^vRPC3( zZ*4!20PNw=yYb4!R4eB65{=yh5O58~t-dDflVN>?N&xBHp&`_pgWhjZz_E20S+Y>j zYb9u)Elu0g$yxucdl_0&(Y3NS(dE_^52PKMX8=jG1Q+LX5%US|LxJ*Em9`S}eJQrW zUM#FmEALhzuHo)}TGXHkXp;VfSzb;{^m_TPlT1ObRZZ&$mVwscu(I2CdHgJ-Rn~y7kh?+n5kg4|yUoS8 z+eapzMqG>&<1}vQ@P=a{t195JP9YWW?SV`H={=M*ab?C16Be@l?K$U;#u-p596N1R zj`z~1MLih4+th_>Q8b#3p87~@pGi_^&yrJ&*DS7Gnc1m+Tc4MOShwBGj`Pd42fcfL zg&uJ5>)!z0yMGBp+87)Sq;o-(k0U9cKL?9fOZ)F;qWN4)KgRc6j`Td{u-q8kn_W zOfj3iM7W=)%sTD9(N4NqYD3UCIXxsIUwHVJTqBV8PY%)r9Bd0`tRF>nlq4qkh92GidJ zN}%RSV}1Jh{4I;S`IovOMttV%uXp$_8e;);zpZOyiQ?;6NU8}32JFbNMmEJ38y=?naTuIhh^=vm;W&ie^~^S+4=$P0Lf4AFOk3qd*GFPT-Id4 z0D4Kz%!)zh@;O|^lU2dk;jPdoP+3TRuCs5!jb>EdlO^1Mkn}_$$?RCX883)?ocnlKhj$4idd-bG_W&_FphptpZQcA8vWkph&hyKJ$t$p6O9ehd%j zk)5tlo_BXohV(La6>OBn-EJXNP?_B%B+h)XL$3wb*9qyqUKy-P!%R+_WTFAxYgs5i zLTCo*LNG`ILP!y#)lZWmHv?tLN7zj69_;y@p+nM2{kDQ*XH1HDF7--)4ys``48+@d z>9cO9!S;Ses`Y}8eyWlZ3kxWdw3jaH&w!?=Ry}KA(J=P#h3fwE`E|G<|2sZRU@%VHY; z{^0Qc0Ls9uCnDY<*TIe6uVew` z49O|895%}N#dU8@AO$oO-R#Y+Bb@negsh{u4Ev3zo69P92dEgZd>5?-78|{j6OK142*K}@j=+T+ z#cxf9+)TA^#q=W&JGCL$U;Jl=t(amXCR08%qxT|=L7{7CFC(lBPeP5>j*VI@Z@;`b zhVeFF`4x5Xd;j#Qkwkak^_dIH*ak9=oSor zDl55$dWd2Jm{MrxTv~1iWE+EbOU?I7Jb!!Cu?zvFlyzZt(R61=1UO1pb4y?q@>zuB^`i zf~)EG$$UsNk|nOF&vDAn-t_IuR5Nd*@k9K=eMiEytNIB@sB!J72v);OVkOV1Zk*s8E09_9UeWzB%;-JXW@r!P#vZP zNVrfOpKS=Z@|K4fc+a+i>R;N}Mt>W$CW7DUa)2en@fXc&AdHfDzb|!EPdf>3Ha{;z ztmPwsR*A~xUbXQnBJi&Q7j$f(`SusfhQ`%UmyEM#qj1AH%n6*;c0I!+MU1V;y+wn3iLOzR$q02Z{^u=+>Z)o ziuS}WV!y;qFk-QVsRRGO0_B}x&v)>|@vS#JPm`1HQgey8pJW%0ZI=iElc>y^{oP`~ zib$`k4gDUDDEu_~teDsFETvVMj3ISB@pS@)K*P3&vq`R;Y+NL+dSSI+*9Q3=cY{@h z24ax^=T+)#IpNY9Z@^7FB0EYoZT`(uZ@((-F>JL@Ac7UXhC$;4Xo!c5V zmA-8fRuSL7H^c*s!cUh5)0XlpXf6&BrH>Dny}e_ZS7H-ki8I17883O{s4AX}>BRTR z_VU9tB(_)>+ePDs&^_jL~PDy+Cvz z4^E(IbS0MH`m!gnndW0iL~eGnX_{6&qFM2hKoBfQufdV097o}b7c-tRlCU#=mMIV# zUk=2rf%(d%-sT-KdX@l7mjCz23({L@SMtMUC5rnt9G?!0zB9-xwoRWdR7Z#JsV^9K2TCIzB^rHRursAkp!qU3)dwHJ% z{ji|srWTA^RQ}-xVglQ2baww!h};Av>R}U+KO_C>D`pvZl7}Q!fYt`uo@!rN>G7y$ z(%v*~r%pPq{7zb+o3Mzm%iK$PHtdVva9_H|j@mqW%SB0jKXvf*z9c-f(Zu@NVb9RU zX85$deqp0IIUC%{aU@6H2WN^gUS+%?ad$Z7KZYSY~)3--7O;A#Bc^T@G)MlN@|uex)zKu*%) z6Oir+DW7Yqss>szi#7UZ`p1aImOjRJgX<1g5aN+&9#SCQ3Y2<&FT}vwOHNXkgR86_ zX{+?0f=jfVC>_@BwXtxD(tD7{enod zqv=>A~w{%zhBR$D{guq zuR9F9vX@UGN2SQas>JH#jRqBza<<;1E!fEP!A@eY`%?-g2m=fadjRob6mA!Z_POU= zdZ`-TCakcEEJ9RMPe+6p-uIwU4STXgfE@hU$shD-)rN4#q3N`Ee1Q128Df4V>(goh zTU<7ga!8w937Y~up{0#HfEg6c0G;b%0W&wFq)&_c?w)r(KX$J&-!*ieiqOAS z_tR7MBJtPzff_7Xf}C6AI0BpJk}-pb`^$OwJ;qG@qW4qBAY!%7^0g+cwYC@AlB57&bP}0fR>>A(&Lkq8Ca(TuC`14m!V~MzG>(#{Hi0Xzh4Ut0|9!{+y6so8VE7qWo_P0R^53iuLTdVUXO zA$&;ux3_8q<<%R0nE$;E#%*ZAjAz?trekISQJ8U=y3XqH1d3xi#$J; z5g#R{UrRIq_f&a#Zn=2j`x>hmrZeY)^jd?`F~&7-W#!Kd$z-c<#FC01bn zo-Yu1$EevXy~)L#%xAMeY5zLLWvark1BUcJy(IrnPV3Tx=_*9LIe)?Nk(`i$G#cO& z{3n%v$Xt#9UI=7F=UWd<>dJp7#cM==r~zbtig_Sw^Ud4+J1l|8uZ+8{IF6LQ$#oQlH-lNo3}C9 zLuOfYj$7k{dHfd1rMWqa!8Sm|F{m)Fh28~vov^u zgO`*Wnj;>+6zgzlyjo!O>?w&k(Z5esG&j%jk8%JzMS-Gtp3LZIeR3IXdSm04kg~wd z0&}~}spx0@Mt9^FjO|7(5VBe#2jbdAG#J~wx27`^%Vw>>KadY8aCFXe{_CKi3RH}M z(2)S}cThEp4rTpOzlWnwB>_A^3hF5*uswh^fRrTAqJB^dYT7gNIXA<-+IWz#xuJ^5 zii^?1bbVSTrsRXa%h$jRqK*NS*^}Busw%vk8dl0+>Nh@sA|J5=MeFr4^|)K^lL0w7{1d)T0!AHzguBY_>|yaa*ZE4&O3;jy z$o3IkXWe**Zt-I3%3AL#rkdet_I?*dvj8P_Ty8z){WAnAgQx1_YWd#2Z-FL{RpoP| z6F~8BtKHlhO?;j-X0>XYet3!P+w;219DA?p78g9CT)r8V>U8!{OCmyTe^Ah*$72i| zqwOoN!4j@zl0E&NIwR`!OG_dZopMe3!ht--f=STgMJse zGpvzcoC7Jw*#c*`0^wx6M~Qip*~QQPNDBTq- z+xvJ&2x58V!RLHcXFo|ruhY~@>f6OI1#N6>?cTV8p~BVc)qG*9)=5|2-eKY5LjVUG zM`+e?U0zB)V)ya;B3L@IbfczQXxy$`zk4sOtCK_54f;^SsVGQc?1y$?fL>8f+_V;6 zAn}Pu9e*`(YDpnkeCTi~!g%v%Lz1Wb6_7RvuX+D-)RmIO0Ba61z&?OBvhnH&4vB$9 zpk;WR@Jhz>U=T}zl3qL*!^6zyn zSgJ1FeY>|M*E}NjGgzHg<~pw?QguZ`b4-F)EY*z}9hPwYX;t{_{S zkK^Ygs7Yezw25ch@>I_L)5fDt&|%90BxD&``PAXORS6Bg&2`ev&sLR~>{+6F7Y^lX z#w;9ckX6q;anjv^NJ5SNM7?#VPXFs~H_@ZT@`&)xN`tJ$X(s`SaDnr_N2TU#tG?0X z+It!HwI;cK&JA?3w9xTM){Wairoh5W;S-^P?oYWOAk8j7VTb)3md-%=1{%Lywr%kj zf`OnPc0ZbEw%4PAGV>~fcJEJ6`OCr69-e0-MzrrSdzweF_rat@C<{BPQ{+|$C&TLL zIA#S$-vmf-=SD{RDc^|CVELZ>H>qz3%E)BFyc!v4wh+mT}Q*_cEe_TNt4I z!hsIVwiLTfwy&VFtW!Hmev4V!BC}(8Q=bW0lSRG!F*?r_xY1}-W&LzF# zs_!R>W99?vzQE3?eP#o4M1N@2N;+^~X~L4KXu}kn_Z4mz-s2bp9v1eaLSd;^4S6q# zweYOj_gg408BOhzy8$HTh#x5|R!QLmH94$lPy_mx>>9x@CU|4BVuCUj?+4CPJlS(m z6cl_*rLERoP?6$fFx7{euIqRlU0ZEh?p%R?b3BYKGri--07Rk4yv{Zo$@#rlV;%Lz zvkZA4co04gt@&BRX3y5XtFN6cPTCI(AvrU+&v*B2PuSl2k4iNYi}s+M6Mt6^OB9R! z%Hy3$k2N1rryw648Cv zlw?|cs&|6N3JhYBF7F5Hc3U7MeXu9kRzQ}u%2|6nRPC)yMC{yELAdvzeuMRbgNdXE zgXAe9KAS@92MdWTB{Bb2BTc9U#4CD1mp92_=q!!hD?5{g7Nwg)=Br;o=~KBsS}{xB zs;M}iRm{mMpbG1}AiFlCMEq`=;hiCzmjFIH{?M*oH}^0oAVxI{e_>kenLHu&JjIM% ziOb{NYMHcaP8l=OL<3ywxKlbjOL)CP1u;iV%r=3q(P;SOl4wDC=eCCvn-Fi9E4)GX z{#O-VzkUe~Ayl9@2gz6^i!7Cc?#|1RaWKNo5yXv-S{%KrB-gJKiBdpv@(jC_lnjXJ#4*hnl{CraC>e%JJ_ReI8^a#mUR9etHm>5FjE$*mRVf?Rty9p1w3hZr7-HuT@`XD zwtpxsAoA~hfLk@=Xfj84@U%}*@N^l{%NVT~#}T9`h*ng|e>9JD>`_ zG^jlyAe_*z*|2epRwnQ&coNHY-HP-v;g7DMVU4?*TlXH4%+q8P*MFGeWtob&=aW*g zzYwm)D)iuXf(?Rs9lwwBnTv9de3Eqit97<{yDlOXY0(E(8#`AT2ATFef-d8Ig(m7n zqKlLV4@l8VM~xg-<3F#>7GygOX_1j6F(c@2cx|`!Py0sgYI7rp1gyOL_d>@dm+>kL zgvp(iNpqykA%)u?g-R%WI@20ddu6PzYTqNd$;N@%jWWYSgC8%;UP5S)Q*1=-7{_2s zyRO=27Zf%HX>y?q?3Tnz52ob%V|F6K&7Wn?;vFnL**o3pP^U-b*vXkAG`dfBS$A=Z zE#6fB zt+v6>0dMKYrfFt@L9}vuj zWZg8CmbPHTgJaQd%eaVECK?`g<3=xaDon zmZMDFu&y(_CAReVG@54*vLeZIu zlPkzrK;Vtzqpt?|bXh_!;*eV9XS&@ec|`nfoTY62jjPsxHhC;1GuLNXru z@7mOlQG40pykd(|U`CFO+n7udtrmSas1T*yiw4zV3G0TUThjh7AE#HW+wDz4uFgev zG3JLubZ`Cp#&{K!ufB9EsNQ1kV5fS}9@{0mqgUH-Fd;7oIei%nYf z0~VICa1q2bMRTEU@o@HV(0@51lhslyvE!ddQ=xVX2arv2&WFRGh>-Mdc&+lxc4E=m zVamY_pJLe&@6PE2%Sp*$VjnD(rMb~cquQ^H&axiw6!1|#d5u`iM{=Rah>+RUOr z40toIU^?`=g0UKAl?Hvqhw?VrQAt&#mI!-I;-)HLX|R2(M2BJliQi9bHxA}?vii=? z91Mh5gY)vZ&#d^DoFFM1KphGhAPmidS1Q2Ek?U`qb@XzV6X_B^J9W8@$hnCRyfrq4 zm!7cgzD2_;{KY&DlV`-a#dO^s{Sd(2gwwLi(DLr`Y1`y=!s==oZ>?#3nQ-i+7F@u4 zMHgA-_eGHVzTVA~2hrwUQbl@tQKZOq-zP!!<;>%=$?SYH+E329_YIGO{LZGt&*ryh zLh3JJz4)3=7#dR4txzxlty$czDJ9%h9GeMzt>4^}XjJ5Fgy@HiZwF0oxx!aoavE{p zgjK6uR9F7iSLLIpgl|O+cT<)fMx~Czy6mL#Wc7KD9En$xJ;`M8=4~DO*(HEP0bO=EaZspZVAmC z=rV$LwITi*V{~N-*EaxO^WZ=%wk;Yri^GDN0wS)2Imvcb{uniTqHg1}@!3!1ES>fA zS-07Pd-%Zby2#G-Ls7dIovWxhsEd2RZg zt)7+PxJc>4U%a!+LVsR8V=K4;R`<$kVwHhzg$0r`mwol?3$|Oque@tQ+1hx54lmP2 zei+-GZLw}ZZEGeC*F~Q`7@To(7Q;COS*TB8y|5eocgjh!lGoNHY&`JTV7C|kG_gb(xBm4Pv`^~hi_+7W1`&&jZ!YT6Xc-EerZ1@V zXU_)8<$crUroNh%ls3&)zg*~A4_012MH#ypd_v*G;B?mrx-XwFQW^z2*E+$s_r=|} zU7qMW(=jxEaIDzcS>zL3{pJ%S&ST^Fwj`CMLiEw9?E_#6zP|5r?9x6ArCZT)K^ueb zW5LWU5BLeHH-Db>loXoDerK_5Z z8(#6jn(mWt%VVP|3;d;oe0x9ejb{~@6uE#U$ENe-v(sfhBe*O`RbqPjVR(XfN{$b{ z>Z7)O)1$W|em@eWENC@0Tks^*bRzo&gp=y-a|Z&V>t8QtYH z-MCpOUfobzD!+Ne6`NNXx7!Xcw3VzH5yYMlE8nEof05;MGceZM(33Yw8m|qq4YJcJ zqc$p@JD4TcNj1w3D`N9HUfi&2cQmJ@9CJbuc+?=Dj*Rmj$!DDS;wzH;0MnfOmAmn6 zG{js{KLO4QAt{tQl3u%)dCp9+P$`W!wcIGy40?7oeyeUw{AfMSR7)fz$G}%xXHT1y z-Pkr8WPwUIb=Z&&#%&(!Tg%DE9279I{k73{B;)I6Bx?6mg;Z5lZB+e()v(EfK!W7O zsulU#_R@J)OseFb6Bb;$aPrdClv{JC>4q1Bkhw2BiQw0a&?W?~dynraD=+4(K@%_@ z*XMlaKo@H3AS#t|mJz1#X9Ss8cVq&#|U zh2TmoINKf*H%=mHrI-IK!@v}B-TcznoqFBtGG@FK#rK{@_8*T4X=&u7yl0r$sA-$l zGr^_yy7vSz*mP2fb3LT;Rn>g7TUbim<33nW$kw=J;J~H)pHjFNS2IO6rFIeeAJg8dTXrc24fYDvXNdtT+Ekf6>BGJ5!2Y!d zN0P8mo>zqtc)?x4At4H(BoqhI>aonS#=7I^@)^JUS78G;O7visqg9LPI%MXEU!5PJ zf)qd74b9?rztq5zed5A;Z``4cB_+AdCdB&ajNPHQOkm9_Cw1z1Dnb8^k_qaQ1s;-- zIdMO~xzr~hk9qIWnIbI#4^6w)11op?d}`i52jzY}@GQSaXSUJ#*e!$EpWnm`m&)^E zSS+ipE^zklI`Jp^b&u1?Cg}0 zBI(}a$qEX~rva%KXi%TSt-79|WL-zJol5`?=jxY?@YaJ=h&3KiJRreWiVg`g@RG#= z8LG~WY<&^k=i*+D9E1}s^ubUvrViLbW;_~3T{6U)!x#ki;Y8$aU`tZ{J5Xa>wjWl~dX>TFk245+N>7n+@3D%OamL!mn_$tO<6D zA4WhGrdan1WZmb*giaCV?%)Ub2S+s|=$5mR-=9*`@GObN1(U%i z*17q=Zv9>WK__LmRtO>GRov36Ry=%k-BGKg(%|sZ$OQx&_hOY*qg(SZMGSP(sElPW;`9_~V>N1+R&xmA-<#1stm>o5PEjPwdG`RhlL>dCw0n5pH>o zX)bCydcG3d$rY1(LzrG)q$`?qrhD5vP=tC$1We?Hp#)`KITu&~>%etT6G*c5Ib4>;C*n z#PQ)Va{Isz$LBhWj|WrYUCG#N*V2^r<;-s+TUC=uwPTZ~dk6w6>R-%UgnWkjSwa?w z(b=v5+dS5pv32~{-n&jcUG?9#q+d=67F0TQRfJwKNSBMan5U!WR!pC*-Y>EL>_VeZ zVBMiSwU5#Mi(B`zUE|28o{xy%7V$cqu**H70?BZGdO(K#o$io`CY&0Pyjt~4H@2sTnf z%VGiWUv!m9R$uGp{gxBMq*_mE=HKM=Q7%vJ@j;nP%7R(wO-rekbiKXSYtO)mrU7%$vD#viPw)w@na~g=6D_ z62ju$yr+Zw!XO@Z9%n$r;RX!I^Dk$MY7C{$MG(BeHzm7E{n4Y;&~EV=PDWG;d1A77 z0a;Q;Qv-TL*(Bc%32je|M?;hGWGo%*9MpS@D;8M=xBHB~w2N81ub$9=$RlAb+Yr(f3xDCq4?b+#4V>iyaPSf605}+3u+8Dz9{467E6B?+zUce3upp>NH}yDulB;i*e?(~EBXLudOpW_8b?8;!CaLFYlK&wQ>E z#^*rAT;OHvJX<~_bKeH-4H6A;-!5z>=e<9l zv#7@)aRSZF5zf|%L~BGRGQ4>C*I6j>?(chqLaiuuiCANC)!r$?)!!<)^9BCNHC~xZ zI@wlFC8q{USzf+k4;?LUnMTT)0|2Ewa5%oIuFR@L5RHjVnrcs3QRN!BZ=ks$P^*ic z$iBztzulc^P;|^0c(`Vo@P)NH7ai~+@GGN;Kqx_HzDu*Z=YX3z{4^i|SYb@pGxby4 z^%k|%DpHVnTyrZn)y|?8>1EfMX+hZ)%v-laPpae^(g7>zfHA&+#*2^{Ue9f;Bgx5D zK-(PASPR9zYGsIf?onhJ6XrYla71Vu9}CsxeN0tSBl+ra(}c_=d3T-JQz|0fob?F+4U^jll??1;u-Vj+ai$dLl~^;4hl7_*4(lGyK~#C?bN zJa9lmgpJ=~yupfa%;YvJezTg`s5qU^JTf?#?r0H}6I}FhDQPK7SQ@llNp?SHoscqd z-X*cmD62aR5l|g}>LX1-ZVuT7h_XuF*HrlRm+$XUB&b`Pgx`I0`3iC;FQ9Q~?b$wA zZ?kW6rCdE*YFx@4Up_4lub%r1Q|?5`x4jf~Yh6qqIlt#%%hBZ@Ys zs&A_`K)L2*wI!1Y5)SX}k)fTwBAQ`8(Si3^e1xR}+P<*D_J7VA@he>~qc>aOte?iR z=*GW5$?7Hh_%9!FgrxZI0n`TNt$jlpKK>ZHo`FBWCL|jY-*C|2#&zvA2&`~} zJA_x-4Vu+4fpu{H20mA%mi>_a0pnRo-_(p({3z{@(pb8jA@8#Jk_3d~hop*`s3bOv zii@G`)yZgPacir4sAc0Xyeg^VKb!V=wNj|(B)~R?4uJDm?8NY>NL4b*seibm<$Ujg zh}(x`5LILOs>#qCQ<);b)aWZKyeKs7Vf0VPT~2Wq{1bAUP~=w?3fmmN#rD@IcQb{$ zR;IwZPFtoy#QkBn4B4Nti8kC?a2l6}>t9VOEVU*M>>bgr3T{1L?7_ZA@Zk&nH30+0 zu@hz%*NZcvR$@+H^_pTkFCs$C=%MrYx--M=Cmltmgc7uPRcGb>b4*tH@@PjGq5`_$1 z%9mk6ea;caf!_wNQ{h%j#0NX`gGJP5b40UvLehD_?wX9AU}1OVNJ8su`|Q=@c0F_G zwJ&&wFG$(d+przKS^h-VvUsB8?d$pIzHKY_?Cr14>e*enIzlKG_Sl~~aBO2$OifA$ zbBK{B(B(sM#ID>LZ-p8wSN9&cc@L*|^wci6u@o>}HuZ~t)MqFWp8MmgHrM(QYv}|p z72fsgiO)}kF830K-#vDz+BOW|aVE1Ln!VvT^GW*$j$wXEM$v4+kracZxi=BRQ9Yu5QHSuMQuthDJA@hiXf!62A$LpF`G*zgWh`#H59tuR?(r~H!bQR2*#s1OV?L-;hXrNs@AwU~Rgfq0`UQZXCc{hl`WgO0@J(?FMJ z_etk}C8HO<-jXg;vHs!jym8MeH%7r~Me280uJL{FRfs6YF9;&SD`em&J$bcfO!xFq zHHYhsV+tua(5~JN5SRu1)$R}B0W$Ah2X(_1S)+@tO542D$h1VbtEIf0uw$w4NAi40 zjt;b;W#i6XiF+jP4*Vyn0O3=@uou<+$vbK$Mmh;Qmuby8>)GVCyCk_f!TvRV0e9;DyL~*uLL{+Yh z^_LB*j^48ZUuJHy;7i!N_VI<48QoAeilrpHuIpR`N4X*+xm}qA%_V+(bJvw(e$3c! zzoKnf7PiqkC`l|Q@{^l>cyFf7TD9p|46Xel0s=N;Ybp;I0 ze)Ij^j_hTR5x5%)m1EtxeA-m*i5Mfp-5=4iGzr_?>Q^|em6Tk(SWt()x zmqVqzuR{boD@Qezq^jD{P@_=T0c9(EslHZBaX1e-R`0EvFHRfb{ zVRa8*ZjlA+DP{TR{ku`q$Z{AETfEF1KG?-ozio!n{0)sz+?7TG13I9GzYHpnT}qia zUTrb<{0_^fXR{70aw+64K?@UNM3oB3d}bL^d>V$HY_W9C6-l;?i;t$+f@0#gAZ)rS zKFgqJV&Lw^h9lsoUhYH_K|67>E=T{XOx+hb&PQT>pu=9rnOoAQl*X@F+_2pWt;q+* zOhv`t7w2M#PNvXXiks+nebj_8IU)t|*ViK92!7B(Ph-!F80>#-ewARe)5!N>iPtXO z{FNyHd!3J$MbY?23h8oCS$lualSt($1t!7l(%y=x<8BZ8_|s>u50jNGfN+b%+E4v= zQxe?}^w3QEp}~;V{Z@lCuA!ejlJoDc;XmKsh+FvLi>R1fSgup~Xj9Wn9#%;TJ`umR zJ_6yZmMjGvMg;<_fQLZF-fTErgyGIaMQDo8u*AkMYm4RGE$Mfta;SFG$yOfQjk|t) z&-Q+#pzxn3q;ubs)g6JB#2dJ3$5I zV~`_$d?upq>(!sPQs7u>2r7%=M7&X06k5m+cI5FLu&tOP{LJZyTHkk;957{=1RUjo zf{?wpVJ(R;s&F&3fe$AOX^PA>lq6HW>xJR>)knoHCL#P7PRgy}>g+S_6}kHLEv7ra zUc%#|NYXXpKXzee2E12>NE@LwN6%ul?(++knZy#*$K7W<`5|=pC{o^w?!>17ayz)T zJ7dtQ4pdhsvKuov{h{&0zJfP`e>L*cGR75GYHAA`NOvW&Lx1VbY0%$>?W3d(f#gO(vG17-jbq9)%`Uqu z^`c=)YLdIml)8rBuXQ_){M3_h&i(|EKj;zkJbbzl7~VCCUXJihu{zBO3%R%~uQMC8 z`~8FQXu0gC9bY;h1u2vk|2-c)`X8=!XrFZxqmQa2qHmcj5FI*J-AN>p1pKjEJ{3a@ zZY>`l8_m@EbZod?XYN<)6kdv0zerfyeO+c_Jfg|bdVJcUJDY`MV{#iuGJ0`4Mwc{( zB)#hM3x1QuyW<#86Ttfn7*vy~PYS$k0yHS{f@HLJDkoqurGNV|@KJSlR2voV%DEi( zrq0IALL$(+i=S`37NI0&Rlsw0JJQ>0(M8U)BiSzRoAKx8K|9@3eP6gLN!i8K{T|`Q zs3yaNqzahZFLu}Xu~HSwrWaS{X!-m|t99)9L!_U-@9d)wsVbS`JTt%Zam$G z5civgeZ|7sA0fm(rfFV94G(*BFoQl;@@D{1K|Yowff<4|blDst8769nTTJ%{2TYIu z7Y^9tpCLToA{_D$8Og{@d-t(?xUJ$%sE$QIiG>urvH}yhF5%6g3xHOn@H+&(fzQ$YMkp}Y?!#8|iEVW1)L|`5XX^Q05Oh+>kF1%N zKu?NQ$R0;cB19DTchLF^3oo0EVOM%?^YMnN05qN4bjAb+Pw?>uqdcpCmaj$x1|asZ zbxwzGOhmXPfl2{m2E1NQ6?T3P$oCZDX0y4~Cwn4&UyQF3#CN?Vp^D95Rxnl?MJZJK zXzxwyol`FXu%833Pn|Jj?*cv>zY7p&i=}=aWspUJO@Yys-12HRpQ*|-X?OY=H&x$# zyab<59osYLZ#*TZNWJ&88X!R<=L|In)=friAfzv?&QD?831&A3ApH}tc3R%tc#kFX zBl42-^2YgLAx3Ox2)dicFgFUh5yoGb+1raE>(=}NayldPe{8xQxWy6T<>5|DOz@0t(;#CvlRSrOM zR*TCo?wPy8=`68N$01h#)VAglQgPQsrzPe#UpJt{4|^@pR|#fWdk*XF>bVKkcB@xhvYmcQ-d~I^9N92kSP$$;`|DNml}OXZFt};@UP|yj>ocfxHr_ zjiK0bQ1>_Opw`7+7CQO!4`52e5f{qZrk^t%SK9{1o(*>8UN4|bIxQ{rFF5f zc(7JD!Q*l07Hzif)1MkIwH|~+6^<=`!ZWyK=Oysf^9OitpS}?KU1s?f4>Sm9J`L_| z)BD<8c%f0QmFfr-0BG{dN~nOTj0WhC!@~NArK24Vz4EXC<6Vnoj8#+!@J<@d^P)F5 z*60WwFxF)~FTvl&T3v}mW66=67wP}M@idfv1u~X^P7h~bU^}p@3djgz1yA%dC&bzU z87rAUCjm4t5^Y_>@w#v2x#9mm$36#6=Qr$x%)B$C@L^f623mN)z_3KM>So^ehgxfs zw7`6i@GoE&FfeQo137cUGR>Ve<;QPN53%1@6MhCb(<}_0Z@#?2d-X>i5r&|njf-}D z-4=vCm-Q!!4d`+oVDGiTH85exQsP&DO|Sw{MZJh*^02MKvyr-am4`7&O2{b>&N+MnV#kN9wlS*Dn0M8!xtL zr&V3h)rBT17s9}cP&&3j^V?&ooYTt!wk+|`>FnJ;X0HJ03RRWSD^lhwMj+u-SH@t&(*o#waKKK;js zWRK~pwWq+wpG~j395lmE;U0+=Sh S_$J~DQtavK=d#Wzp$Pz?P0GLk literal 0 HcmV?d00001 diff --git a/docs/source/_static/methodology_overview.png b/docs/source/_static/methodology_overview.png deleted file mode 100644 index af8dc284019cfaed1c585b0811d80470e89b5616..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 64639 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 diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index d27ad025..2106313d 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -1,10 +1,8 @@ -.. image:: https://user-images.githubusercontent.com/104760879/217226792-4297d3c8-8a7c-45ad-894f-5efd03031f49.png - :alt: ebus_toolbox_logo - Getting Started =============== -This toolbox was designed to analyze and optimize electrified bus fleets. +SimBa - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. +It be used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and circulations, determining charging strategies, and calculating investments and costs. .. Without creating links like in the line below, subpages go missing from the sidebar @@ -12,15 +10,13 @@ This toolbox was designed to analyze and optimize electrified bus fleets. Installation ------------ -To try it out, first clone `this repository `_ and then install the required packages to your current environment by running - - +To try it out, first clone `this repository `_ and then install the required packages to your current python environment by running ``pip install -r requirements.txt`` Now you can start the eBus Toolbox module with all configurations stored at `data/configs/ebus_toolbox.cfg` via the command -``python -m ebus_toolbox --config data/configs/ebus_toolbox.cfg`` +``python -m ebus_toolbox --config data/examples/ebus_toolbox.cfg`` The repo provides an example for each necessary input file, so the example case can be executed without the need for the user to provide any data themselves. @@ -30,20 +26,40 @@ To run SimBA with your own `schedule.csv` (see :ref:`schedule`)) file and defaul Default configurations are detailed at `data/configs/ebus_toolbox.cfg`. +Usage with PyCharm +################## + +To use SimBa with PyCharm, create a new python (>= 3.7) environment and clone this repository. Then go to File -> Settings -> project in PyCharm and set Python of the newly created environment as interpreter and the local SimBA repository as project root. Now install the required packages by running in the Terminal: + +``pip install -r requirements.txt`` + +Now add a new "run/debug configuration" with the following information: + +| module name: ``SimBA`` +| Parameters: ``--config data/examples/ebus_toolbox.cfg`` +| Working directory: ``Path\to\local\SimBa`` +| Run with Python Console: true + +Now you can run the scenario specified in the conif usin PyCharm. General Concept --------------- -At the current stage several functionalities are implemented. The base simulation processes a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and runs it through a module called SpiceEV for an in-depth SOC analysis. -Other modes can alter bus types from depot to opportunity chargers, optimize sets of rotations to increase electrification or suggest stations for electrification by minimizing the amount of stations needed. You can learn more about the modes :ref:`here ` +SimBA is designed as a toolbox, so the specific use can be adapted to the users needs. Its core functionality is to run scenariobased simulations. A scenario is defined by a set of input files. Next to the simulation mode, several optimization modes exist, that can be linked and executed consecutively. -.. _figure_ebus_toolbox_modules: -.. figure:: _static/methodology_overview.png - :alt: ebus_toolbox_modules +.. _figure_simba_modules: +.. figure:: _static/SimBA_module_overview.png + :alt: figure_simba_modules :width: 600 - Modules of the SimBA + Modules of SimBA + +:ref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. + +Depending on the given simulation parameters, the vehicles are then dispatched. In this step, every rotation – the sum of all trips between leaving the depot until return – is allocated to a specific vehicle. The vehicles can be charged at any number of :ref:`electrified_stations`. These can be classified either as depot stations (deps) or as opportunity stations (opps). Each vehicle can be charged following one of the two charging strategies: Either as opportunity charging bus (oppb) or as depot charging bus (depb). While an oppb is charged at both deps and opps, depb are only charged at deps. The charging strategy can either be defined for each rotation in the :ref:`schedule` data or for all not explicitly defined rotations using the "preferred charging type" option in the :ref:`config`. Using this information, the charging simulation is then carried out. + +As a result of each simulation the energy demand at each electrified station, the development of vehicles SoCs (State of Charge), summaries of all rotations, estimated costs for vehicles, infrastructure and operationand further data can be displayed and saved. Some information can also be plotted, an example can be seen in :numref:`ebus_toolbox_default_plot`. -:numref:`figure_ebus_toolbox_modules` shows how the different modules work together to calculate the scenario. Optionally different optimizations can be used or even chained together. The output of the simulation is locally saved and consists of the vehicle socs, summaries for each rotation, estimated costs for vehicles, infrastructure and operation as well as station specific electric loads, utilization rates and other key performance indicators. Some of them can be plotted automatically and can be seen in :numref:`ebus_toolbox_default_plot` +In case an optimization is carried out, the results are then analyzed, the optimizer adapts the input data and parameters and starts the process again with the trip consumption analysis. In which order and for what purpose the individual modules are executed is mainly defined using the different modes. These modes can be used to manipulate the defined scenario e.g. by altering bus types from depot to opportunity chargers, optimize sets of rotations to increase electrification or suggest stations for electrification by minimizing the amount of stations needed. You can learn more about the modes :ref:`here `. .. _ebus_toolbox_default_plot: .. figure:: _static/run_overview.png @@ -52,4 +68,33 @@ Other modes can alter bus types from depot to opportunity chargers, optimize set Default output plot for a single simulation. -More text +Specific modules +---------------- + +Consumption analysis +#################### + +.. _vehicle_dispatch: + +Vehicle Dispatch +################ + +Charging simulation +################### + +Generate report +############### + +Optimization +############ + +.. _consistency_check: + +Consistency check +################# + + +.. _rotation_filter: + +Rotation filter +############### diff --git a/docs/source/index.rst b/docs/source/index.rst index c7f22957..aa48d553 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -4,14 +4,14 @@ contain the root `toctree` directive. .. _figure_SimBA_logo: -.. figure:: _static/2023_06_08_eBus-Toolbox Logo.png - :alt: ebus_toolbox_logo - :width: 600 +.. figure:: _static/SimBA_Logo.png + :alt: SimBA_Logo + :width: 200 Welcome to SimBA's documentation! ============================================ -This toolbox was designed to analyze and optimize electrified bus fleets. +SimBa - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. .. toctree:: :maxdepth: 3 diff --git a/docs/source/modes.rst b/docs/source/modes.rst index dc053336..0d818703 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -36,6 +36,11 @@ can be found below. Simple Simulation ----------------- + +:: + + mode = ["sim"] + The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. Every chain of modes starts with a simple simulation, even if it is not explicitly listed in the modes. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The charging type for each vehicle is read from the rotation information from the trips.csv if this data is included. If the data is not included *preferred_charging_type* from the config file is used, as long as the provided vehicles data provides the preferred_charging_type for the specified vehicle type. @@ -47,9 +52,9 @@ This mode is the first kind of optimization provided by SimBA and is called by: mode = ["neg_depb_to_oppb"] -It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to depot chargers. +It takes the results of the previous simulation, and changes the charging type of all rotations which had a negative SoC to opportunity chargers. -.. note:: Charging types are only switched by SimBA if the corresponding vehicle type as depot charger exists in the provided vehicles_data.json. +.. note:: Charging types are only switched by SimBA if the corresponding vehicle type as opportunity charging bus exists in the provided vehicles_data.json. @@ -62,13 +67,13 @@ This mode is the second kind of optimization provided by SimBA and is called by mode = ["neg_oppb_to_depb"] -It takes the results of the previous simulation, attains all rotations which had a negative soc, and changes their vehicle type to opportunity chargers. +It takes the results of the previous simulation, and changes the charging type of all rotations which had a negative SoC to depot charging. -.. note:: Charging types are only switched by SimBA if the corresponding vehicle type as opportunity charger exists in the provided vehicles_data.json. +.. note:: Charging types are only switched by SimBA if the corresponding vehicle type as depot charging bus exists in the provided vehicles_data.json. Service Optimization -------------------- -This mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. +It can happen that several busses influence each other while simulataiously charging at the same charging station, e.g. due to limited grid power or limited number of charging stations, which can lead to negative SoCs due to hindered charging. In this case, this mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. Now, only rotations are left that are non-negative when viewed alone, but might become negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. In the end, the largest number of rotations that produce a non-negative result when taken together is returned as the optimized scenario. @@ -99,18 +104,18 @@ The network with no opportunity charging station is first analyzed to find rotat Steps of the optimization loop until full electrification is reached. -After a single simulation is run the rotations are analyzed. Any time a vehicle goes below an soc of zero (or a self defined value) a low soc event is triggered. This event saves information about when the soc reached its minimal value and the history before that up to a point of an upper soc threshold, with the default value being 1. Stations inside of this time span are potentially able to mitigate the low soc and are stored with other information about the event. :numref:`low_soc_event` shows a possible soc history with a low soc event. +After a single simulation is run the rotations are analyzed. Any time a vehicle goes below an SoC of zero (or a self defined value) a low SoC event is triggered. This event saves information about when the SoC reached its minimal value and the history before that up to a point of an upper SoC threshold, with the default value being 1. Stations inside of this time span are potentially able to mitigate the low SoC and are stored with other information about the event. :numref:`low_soc_event` shows a possible SoC history with a low SoC event. .. _low_soc_event: .. figure:: https://user-images.githubusercontent.com/104760879/217225588-abfad83d-9d2a-463a-8597-584e29f5f885.png :width: 600 :alt: below_0_soc_event - Low soc event and classification of stations. + Low SoC event and classification of stations. -The next step groups low soc events based on the stations which were found earlier. Events which share at least one station could possibly interact with each other, e.g. vehicles could share a charging station. Therefore groups are build which do not share any stations in between groups. This speeds up the optimization process since for every electrification and simulation only rotations are calculated which could be impacted by the change. +The next step groups low SoC events based on the stations which were found earlier. Events which share at least one station could possibly interact with each other, e.g. vehicles could share a charging station. Therefore groups are build which do not share any stations in between groups. This speeds up the optimization process since for every electrification and simulation only rotations are calculated which could be impacted by the change. -Since greedy approaches execute the step which seems most promising in the current situation an evaluation function is needed. One possible approach could be to simulate each scenario, meaning simulating every case in which one of all possible stations is electrified and continuing with the best case. The optimizer does not use this approach. Instead an approximation function is used to evaluate the potential of electrifying a station. This approximation function analyzes the duration at each stop, the possible charging time, the soc and resulting possible charging power (battery with high socs are charged at a lower rate) as well as the upper soc threshold and minimal soc of the event. While this methodology is not accurate in all cases, e.g. a station could exist multiple times inside of a low soc event, therefore charging the first time at this station would alter the soc and charging power the vehicle has the second time it reaches the station, it seems well suited as heuristic for choosing the most promising station. The objective function of choosing what the *best* station is, is the mitigation of missing charge, i.e. what is the minimal amount of energy that needs to be inserted into the battery, so that no soc is below 0. +Since greedy approaches execute the step which seems most promising in the current situation an evaluation function is needed. One possible approach could be to simulate each scenario, meaning simulating every case in which one of all possible stations is electrified and continuing with the best case. The optimizer does not use this approach. Instead an approximation function is used to evaluate the potential of electrifying a station. This approximation function analyzes the duration at each stop, the possible charging time, the SoC and resulting possible charging power (battery with high SoCs are charged at a lower rate) as well as the upper SoC threshold and minimal SoC of the event. While this methodology is not accurate in all cases, e.g. a station could exist multiple times inside of a low SoC event, therefore charging the first time at this station would alter the SoC and charging power the vehicle has the second time it reaches the station, it seems well suited as heuristic for choosing the most promising station. The objective function of choosing what the *best* station is, is the mitigation of missing charge, i.e. what is the minimal amount of energy that needs to be inserted into the battery, so that no SoC is below 0. After the evaluation selected a station to be electrified the scenario input data is altered so that vehicles at this station are charged without limitation of charging points. This is followed up by a detailed simulation which can make use of a highly accurate solver for charging events called *SpiceEV* or a less accurate but faster solver. Now the resulting system has less missing charge and the potentials of stations might be decreased. Also a single group might have been split up into several smaller groups which can be analyzed even quicker. Therefore the loop repeats up until the point the missing charge in the system is zero or in other words the system is fully electrified. @@ -118,7 +123,7 @@ At the current stage the scenario to be optimized needs depot charging stations Deep Optimization #################### -The greedy algorithm in the base optimization can not guarantee that the solution is the global optimum. This is why the use of the *deep* mode is recommended for systems with high requirements. After the first run, instead of electrifying the station with the highest potential the second best station is electrified. This is similar to a decision tree, where every node is a set of electrified stations, with the first node being zero stations electrified and the last node being all stations electrified. The nodes in between correlate with every possible state of electrification. Each branch therefore represents an additional electrification of a single station. . The algorithm continues electrifying the best station, as long as this node has not been evaluated yet. This way gradually all possible nodes are checked. The search stops whenever the number of stations surpasses the number of the current optimal solution. If several options with the same optimal number of stations arise, they can be found in the log file of the optimizer, but only one file with optimized stations is produced. +The greedy algorithm in the base optimization can not guarantee that the solution is the global optimum. This is why the use of the *deep* mode is recommended for systems with high requirements. After the first run, instead of electrifying the station with the highest potential the second best station is electrified. This is similar to a decision tree, where every node is a set of electrified stations, with the first node being zero stations electrified and the last node being all stations electrified. The nodes in between correlate with every possible state of electrification. Each branch therefore represents an additional electrification of a single station. The algorithm continues electrifying the best station, as long as this node has not been evaluated yet. This way gradually all possible nodes are checked. The search stops whenever the number of stations surpasses the number of the current optimal solution. If several options with the same optimal number of stations arise, they can be found in the log file of the optimizer, but only one file with optimized stations is produced. **Pruning** is used to stop evaluation of branches, whenever foresight predicts that no better solution will be reached. This is done through the simple heuristic of checking the sum of potential of the n remaining stations with the highest potentials, with n being the number until the number of stations of the current optimal solution is reached. @@ -158,14 +163,14 @@ This concept can reduce the amount of nodes which have to be checked. Other Optimization Functionality ################################### -**Mandatory stations** can be attained to increase the optimization process. Mandatory stations are defined by being stations which are needed for a fully electrified system. To check if a station *Y* is a mandatory station can be easily attained by simulating the network with every station electrified except *Y*. If the system has vehicle socs which drop below the minimal soc (default value is 0) in this scenario, the station is mandatory. In the later exploration of best combinations of stations this station will be included in any case. +**Mandatory stations** can be attained to increase the optimization process. Mandatory stations are defined by being stations which are needed for a fully electrified system. To check if a station *Y* is a mandatory station can be easily attained by simulating the network with every station electrified except *Y*. If the system has vehicle SoCs which drop below the minimal SoC (default value is 0) in this scenario, the station is mandatory. In the later exploration of best combinations of stations this station will be included in any case. **Impossible rotations** are rotations which given the settings are not possible to be run as opportunity chargers, given the vehicle properties, even when every station is electrified. Before starting an optimization it is recommended to remove these rotations from the optimization, since the optimizer will not reach the goal of full electrification. **Quick solver** -Instead of using the regular SpiceEV solver for optimization the user can also choose the *quick* solver. This approximates the soc history of a vehicle by straight manipulation of the soc data and numeric approximations of the charged energy. Therefore small differences between solving a scenario with SpiceEV and the quick solver exist. For the quick solver to work, some assumptions have to be met as well +Instead of using the regular SpiceEV solver for optimization the user can also choose the *quick* solver. This approximates the SoC history of a vehicle by straight manipulation of the SoC data and numeric approximations of the charged energy. Therefore small differences between solving a scenario with SpiceEV and the quick solver exist. For the quick solver to work, some assumptions have to be met as well -* Depots charge the vehicles to 100% soc +* Depots charge the vehicles to 100% SoC * Station electrification leads to unlimited charging points * Base scenario has no electrified opportunity stations * No grid connection power restrictions @@ -235,7 +240,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci - Optimizer overwrites vehicle battery capacities with this value. If the line is commented out or the value is 0, no overwriting takes place * - charging_curve - [] - - [[soc1, power1], [soc2, power2] ….] with soc between 0-1 and power as positive float value + - [[soc1, power1], [soc2, power2] ….] with SoC between 0-1 and power as positive float value - Optimizer overwrites vehicle charging curve with this value. If the line is commented out or the value is [], no overwriting takes place * - charging_power - 0 @@ -244,7 +249,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci * - min_soc - 0 - 0 to 1 - - Optimizer uses this value as lower SOC threshold, meaning vehicles with socs below this value need further electrification + - Optimizer uses this value as lower SoC threshold, meaning vehicles with SoCs below this value need further electrification * - solver - spiceev - [quick, spiceev] @@ -264,7 +269,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci * - run_only_neg - False - [True, False] - - Should all rotations be rebased or can rotations which stay above the soc threshold be skipped? + - Should all rotations be rebased or can rotations which stay above the SoC threshold be skipped? * - run_only_oppb - False - [True, False] @@ -292,7 +297,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci * - remove_impossible_rotations - False - [True, False] - - Discard rotations which have socs below the threshold, even when every station is electrified + - Discard rotations which have SoCs below the threshold, even when every station is electrified * - check_for_must_stations - True - [True, False] @@ -315,11 +320,11 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci - If reduce_rotations is True, only the list of these rotations is optimized. Report -------------- -The report will generate several files which include information about the expected socs, power loads at the charging stations or depots, default plots for the scenario and other useful data. +------ +The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Default outputs -################################### +############### | **Grid Connector Overview (gc_overview.csv)** | Contains information about charging stations, including their names, types, maximum power, maximum number of charging stations, total energy usage, and use factors for the least, second least, and third least utilized charging stations. @@ -328,26 +333,27 @@ Default outputs | Time series of power flow in kW for every grid connector | **Rotation SoC Data (rotation_socs.csv)** -| Time series of soc for each rotation. +| Time series of SoC for each rotation. | **Vehicle SoC Data (vehicle_socs.csv)** -| Time series of soc for each vehicle. +| Time series of SoC for each vehicle. | **Rotation Summary (rotation_summary.csv)** -| Contains data related to the rotation of vehicles, including the start and end times of each rotation, the type and ID of the vehicle, the depot name, the lines the vehicle traveled, total energy consumption in kWh, distance traveled in m, and various charging-related metrics such as charging type and soc at arrival, minimum soc and if the rotation had negative soc values. +| Contains data related to the rotation of vehicles, including the start and end times of each rotation, the type and ID of the vehicle, the depot name, the lines the vehicle traveled, total energy consumption in kWh, distance traveled in m, and various charging-related metrics such as charging type and SoC at arrival, minimum SoC and if the rotation had negative SoC values. | **Overview Plots (run_overview.pdf and run_overview.png)** -| Contains plots for socs for every vehicle, power at each charging station, batteries, external loads and feed-ins as well as price time series for each station. +| Contains plots for SoCs for every vehicle, power at each charging station, batteries, external loads and feed-ins as well as price time series for each station. | **Station Data Summary (simulation_station_xy.json)** -| Contains information about the simulation interval, grid connector, photovoltaics, charging strategy, average flexible power range per time window, total drawn energy from the grid, average duration of standing events, maximum drawn power, total energy fed into the grid, maximum stored energy in each battery, number of load cycles for stationary batteries and vehicles, and number of times vehicle soc was below the desired soc on departure. +| Contains information about the simulation interval, grid connector, photovoltaics, charging strategy, average flexible power range per time window, total drawn energy from the grid, average duration of standing events, maximum drawn power, total energy fed into the grid, maximum stored energy in each battery, number of load cycles for stationary batteries and vehicles, and number of times vehicle SoC was below the desired SoC on departure. | **Station Data Time Series (simulation_timeseries_station_xy.csv)** | Contains station specific time series including price of electricity, grid supply, fixed loads, battery power, energy stored in battery, flex band boundaries, battery feed, charging station power use, occupied charging stations and charging stations in use as well as vehicles which are at the station. .. _cost_calculation: + Cost calculation -################################### +################ | **Cost calculation (summary_vehicles_costs.csv)** | This is an optional output which calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. | The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV `_ for the calculation of electricity costs. diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 7e4399b4..78a63d87 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -10,11 +10,150 @@ in detail in the following subsections as well as their default parameters. When providing the user defined input files, the user should make sure the files are either 'utf-8' encoded or not contain regional characters. +.. _config: + Configuration ------------- -The configuration file config.cfg is provided as example in ./examples/ and provides the user with most of the functionality surrounding the settings and boundary conditions of a simulation. The example contains parameter descriptions which are explained here in more detail: +The configuration file config.cfg is provided as example in ./examples/ and provides the user with most of the functionality surrounding the settings and boundary conditions of a simulation. The config file is divided into several sections: + +| Paths: Here all in- and output paths are defined +| Modes: Here the modes of execution can be defined +| Flags: Here, optional functionality can be activated or deactivated +| Physical setup of environment: Here, the physical setup is characterized +| Simulation Parameters: The simulation can be adjusted using these paramteres + +The example (data/simba.cfg) contains parameter descriptions which are explained here in more detail: + +.. list-table:: config.cfg parameters + :header-rows: 1 + + * - Parameter + - Default value + - Expected values + - Description + * - input_schedule + - Mandatory: no default given + - path as string + - Input file containing :ref:`schedule` information + * - output_directory + - data/sim_outputs + - path as string + - Output files are stored here + * - electrified_stations + - ./data/examples/vehicle_types.json + - path as string + - Path to Electrified stations data + * - vehicle_types + - ./data/examples/vehicle_types.json + - path as string + - Path to :ref:`vehicle_types` + * - station_data_path + - Optional: no default given + - path as string + - Path to :ref:`station_geo_data` + * - outside_temperature_over_day_path + - Optional: no default given + - path as string + - Path to :ref:`temperature_data` + * - level_of_loading_over_day_path + - Optional: no default given + - path as string + - Path to :ref:`level_of_loading` + * - cost_parameters_file + - Optional: no default given + - path as string + - Path to :ref:`cost_params` + * - mode + - ['sim', 'report'] + - List of modes is any order in range of ['sim', 'neg_depb_to_oppb', 'neg_oppb_to_depb', 'service_optimization', 'report'] + - The order of :ref:`sim_modes` is defined here + * - cost_calculation + - false + - Boolean + - Activates the :ref:`cost_calculation` + * - check_rotation_consistency + - false + - Boolean + - Activates the :ref:`consistency_check` + * - skip_inconsistent_rotations + - false + - Boolean + - If check_rotation_consistency is active, rotations that don't comply with the checked assumtions are removed from the schedule if skip_inconsistent_rotations is set true + * - show_plots + - false + - Boolean + - If activated, plots are displayed with every run of :ref:`report` mode + + * - preferred_charging_type + - depb + - depb, oppb + - All rotations that have no specification of charging type in :ref:`Schedule` are assigned the charging type defined here + * - gc_power_opps + - 100000 + - Numeric + - Default max power [kW] of grid connectors at opportunity charging stations, Individual gc_power per gc can be defined in :ref:`electrified_stations` + * - gc_power_deps + - 100000 + - Numeric + - Default max power [kW] of grid connectors at depot charging stations, Individual gc_power per gc can be defined in :ref:`electrified_stations` + * - cs_power_opps + - 300 + - Numeric + - Default max power [kW] of opportunity charging stations + * - cs_power_deps_depb + - 300 + - Numeric + - Default max power [kW] of depot charging stations for depot charging busses. Individual cs_power per gc and cs type can be defined in :ref:`electrified_stations` + * - cs_power_deps_oppb + - 300 + - Numeric + - Default max power [kW] of depot charging stations for opportunity charging busses. Individual cs_power per gc and cs type can be defined in :ref:`electrified_stations` + * - desired_soc_deps + - 1 + - 0...1 + - Minimum allowed state of charge when leaving a depot station after charging. Also used to initialize the vehicles SoCs at the beginning of the simulation. + * - desired_soc_opps + - 1 + - 0...1 + - Minimum allowed state of charge when leaving an opportunity station after charging + * - min_recharge_deps_oppb + - 1 + - 0...1 + - This value is used to calculate the minimum standing time of opportunity charging busses at the depot, which is needed for the :ref:`vehicle_dispatch` + * - min_recharge_deps_depb + - 1 + - 0...1 + - This value is used to calculate the minimum standing time of depot charging busses at the depot, which is needed for the :ref:`vehicle_dispatch` + * - min_charging_time + - 0 + - Numeric + - Only stops that are longer than the time defined here are used for charging + * - default_buffer_time_opps + - 0 + - Numeric or dict e.g. {"10-22": 5, "else": 2} (else clause is a must if using the dict definition) + - The buffer time is deducted off of the planned standing time at each opportunity station. It can be used to model things like delays and/or docking procedures. This value is used if no specific buffer is defined per station in :ref:`electrified_stations`. It can either be given as constant or depending on the time of the day using a dict. + * - default_voltage_level + - MV + - HV, HV/MV, MV, MV/LV, LV + - The default volage level is used, if no specific voltage level is defined per station in :ref:`electrified_stations`. It is used to calculate the costs. Choices describe high voltage (HV), transfomer between high and medium voltage (HV/MV), medium voltage MV, transfomer between medium and low voltage (MV/LV) and low voltage (LV) + + * - days + - Optional: no default given + - numeric + - If this value is defined only the first number of 'days' of the schedule are simulated + * - interval + - 1 + - numeric + - timestep in minutes + * - signal_time_dif + - 10 + - numeric + - Some strategies use limited foresight. E.g. priorization of vehicles at limited number of charging stations is carried out only for this time ahead of actual time step. Also used in spiceEV as time difference between signal time and actual start time of a vehicle event in min. + * - eta + - false + - boolen + - Show estimated time to finish simulation after each step. Not recommended for fast computations -.. _schedule: Schedule -------- @@ -95,10 +234,14 @@ Vehicle types vehicle_type.json tbc +.. _electrified_stations: + Electrified stations -------------------- Stations which are electrified. TBC +.. _cost_params: + Cost parameters --------------- TBC From 7a19fbdef8c5c94e0b02f801472cd699048decd2 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Aug 2023 18:34:05 +0200 Subject: [PATCH 30/58] make new flake8 6.1 happy --- ebus_toolbox/consumption.py | 2 +- ebus_toolbox/rotation.py | 6 +++--- ebus_toolbox/simulate.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ebus_toolbox/consumption.py b/ebus_toolbox/consumption.py index f66cc0f5..d8c1e6aa 100644 --- a/ebus_toolbox/consumption.py +++ b/ebus_toolbox/consumption.py @@ -60,7 +60,7 @@ def calculate_consumption(self, time, distance, vehicle_type, charging_type, tem :raises AttributeError: if there is no path to temperature or lol data provided """ - assert self.vehicle_types.get(vehicle_type, {}).get(charging_type),\ + assert self.vehicle_types.get(vehicle_type, {}).get(charging_type), \ f"Combination of vehicle type {vehicle_type} and {charging_type} not defined." vehicle_info = self.vehicle_types[vehicle_type][charging_type] diff --git a/ebus_toolbox/rotation.py b/ebus_toolbox/rotation.py index d07991f8..fa1d8c7e 100644 --- a/ebus_toolbox/rotation.py +++ b/ebus_toolbox/rotation.py @@ -58,10 +58,10 @@ def add_trip(self, trip): # set charging type if given charging_type = trip.get('charging_type') if charging_type in ['depb', 'oppb']: - assert self.charging_type is None or self.charging_type == charging_type,\ + assert self.charging_type is None or self.charging_type == charging_type, \ f"Two trips of rotation {self.id} have distinct charging types" assert self.schedule.vehicle_types.get( - self.vehicle_type, {}).get(charging_type) is not None,\ + self.vehicle_type, {}).get(charging_type) is not None, \ (f"The required vehicle type {self.vehicle_type}({charging_type}) " "is not given in the vehicle_types.json file.") self.set_charging_type(charging_type) @@ -93,7 +93,7 @@ def set_charging_type(self, ct): if ct == self.charging_type: return - assert self.schedule.vehicle_types.get(self.vehicle_type, {}).get(ct),\ + assert self.schedule.vehicle_types.get(self.vehicle_type, {}).get(ct), \ f"Combination of vehicle type {self.vehicle_type} and {ct} not defined." old_consumption = self.consumption diff --git a/ebus_toolbox/simulate.py b/ebus_toolbox/simulate.py index d6c32355..a48b44f0 100644 --- a/ebus_toolbox/simulate.py +++ b/ebus_toolbox/simulate.py @@ -56,7 +56,7 @@ def simulate(args): scenario = schedule.run(args) # run the mode(s) specified in config - if type(args.mode) != list: + if not isinstance(args.mode, list): # backwards compatibility: run single mode args.mode = [args.mode] From 230fbc60e261af842fada32eb736b59d1f3e15a9 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 1 Aug 2023 19:37:31 +0200 Subject: [PATCH 31/58] add simba_modules to rtd --- docs/source/getting_started.rst | 31 ----------------------------- docs/source/index.rst | 1 + docs/source/modules.rst | 2 ++ docs/source/simba_modules.rst | 35 +++++++++++++++++++++++++++++++++ ebus_toolbox/util.py | 29 +++++++++++++-------------- 5 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 docs/source/simba_modules.rst diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 2106313d..43c22639 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -67,34 +67,3 @@ In case an optimization is carried out, the results are then analyzed, the optim :width: 600 Default output plot for a single simulation. - -Specific modules ----------------- - -Consumption analysis -#################### - -.. _vehicle_dispatch: - -Vehicle Dispatch -################ - -Charging simulation -################### - -Generate report -############### - -Optimization -############ - -.. _consistency_check: - -Consistency check -################# - - -.. _rotation_filter: - -Rotation filter -############### diff --git a/docs/source/index.rst b/docs/source/index.rst index aa48d553..7e71b2a4 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,6 +18,7 @@ SimBa - the Simulation toolbox for Bus Applications - was designed to analyze an :caption: Contents: getting_started + simba_modules modes simulation_parameters modindex diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 8278aeee..7e007c3b 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -1,3 +1,5 @@ +:orphan: + ebus_toolbox ============ diff --git a/docs/source/simba_modules.rst b/docs/source/simba_modules.rst new file mode 100644 index 00000000..bd062964 --- /dev/null +++ b/docs/source/simba_modules.rst @@ -0,0 +1,35 @@ + +.. _simba_modules: + +SimBA modules +============= + + + +Consumption analysis +-------------------- + +.. _vehicle_dispatch: + +Vehicle Dispatch +---------------- + +Charging simulation +------------------- + +Generate report +--------------- + +Optimization +------------ + +.. _consistency_check: + +Consistency check +----------------- + + +.. _rotation_filter: + +Rotation filter +--------------- \ No newline at end of file diff --git a/ebus_toolbox/util.py b/ebus_toolbox/util.py index 53e61711..67816604 100644 --- a/ebus_toolbox/util.py +++ b/ebus_toolbox/util.py @@ -16,10 +16,21 @@ def save_version(file_path): def get_buffer_time(trip, default=0): - """ Get buffer time at arrival station of a trip. + """ + Get buffer time at arrival station of a trip. Buffer_time is an abstraction of delays like + docking procedures and is added to the planned arrival time. - Buffer_time is an abstraction of delays like docking procedures and is added to the planned - arrival time. + NOTE: Buffertime dictionaries map hours of the day to a buffer time. + Keys are ranges of hours and corresponding values provide buffer time in + minutes for that time range. + An entry with key "else" is a must if not all + hours of the day are covered. + E.g. + buffer_time = { + "10-22": 2, + "22-6": 3, + "else": 1 + } :param trip: The of buffer time of this trips arrival is returned. :type trip: ebus_toolbox.Trip @@ -27,18 +38,6 @@ def get_buffer_time(trip, default=0): :type default: dict, numeric :return: Buffer time :rtype: numeric - - NOTE: Buffertime dictionaries map hours of the day to a buffer time. - Keys are ranges of hours and corresponding values provide buffer time in - minutes for that time range. - An entry with key "else" is a must if not all - hours of the day are covered. - E.g. - buffer_time = { - "10-22": 2, - "22-6": 3, - "else": 1 - } """ schedule = trip.rotation.schedule From efefdd04fecb4e748cb5cea8d329551b1d70f6b1 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 2 Aug 2023 09:30:24 +0200 Subject: [PATCH 32/58] add content to rdt modules of SimBA --- docs/source/modes.rst | 116 +---------------------------- docs/source/simba_modules.rst | 135 +++++++++++++++++++++++++++++++++- 2 files changed, 136 insertions(+), 115 deletions(-) diff --git a/docs/source/modes.rst b/docs/source/modes.rst index 0d818703..c8548363 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -43,6 +43,7 @@ Simple Simulation The simple simulation case is the default mode. Its usage is explained in :ref:`Getting Started`. Every chain of modes starts with a simple simulation, even if it is not explicitly listed in the modes. The simulation takes the scenario as is. No parameters will be adjusted, optimized or changed in any way. The charging type for each vehicle is read from the rotation information from the trips.csv if this data is included. If the data is not included *preferred_charging_type* from the config file is used, as long as the provided vehicles data provides the preferred_charging_type for the specified vehicle type. +.. _neg_depb_to_oppb: Negative Depot to Opportunity Charger ------------------------------------- @@ -56,7 +57,7 @@ It takes the results of the previous simulation, and changes the charging type o .. note:: Charging types are only switched by SimBA if the corresponding vehicle type as opportunity charging bus exists in the provided vehicles_data.json. - +.. _neg_oppb_to_depb: Negative Opportunity to Depot Charger ------------------------------------- @@ -321,118 +322,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci Report ------ -The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. - -Default outputs -############### - -| **Grid Connector Overview (gc_overview.csv)** -| Contains information about charging stations, including their names, types, maximum power, maximum number of charging stations, total energy usage, and use factors for the least, second least, and third least utilized charging stations. - -| **Grid Connector Time Series (gc_power_overview_timeseries.csv)** -| Time series of power flow in kW for every grid connector - -| **Rotation SoC Data (rotation_socs.csv)** -| Time series of SoC for each rotation. - -| **Vehicle SoC Data (vehicle_socs.csv)** -| Time series of SoC for each vehicle. - -| **Rotation Summary (rotation_summary.csv)** -| Contains data related to the rotation of vehicles, including the start and end times of each rotation, the type and ID of the vehicle, the depot name, the lines the vehicle traveled, total energy consumption in kWh, distance traveled in m, and various charging-related metrics such as charging type and SoC at arrival, minimum SoC and if the rotation had negative SoC values. - -| **Overview Plots (run_overview.pdf and run_overview.png)** -| Contains plots for SoCs for every vehicle, power at each charging station, batteries, external loads and feed-ins as well as price time series for each station. - -| **Station Data Summary (simulation_station_xy.json)** -| Contains information about the simulation interval, grid connector, photovoltaics, charging strategy, average flexible power range per time window, total drawn energy from the grid, average duration of standing events, maximum drawn power, total energy fed into the grid, maximum stored energy in each battery, number of load cycles for stationary batteries and vehicles, and number of times vehicle SoC was below the desired SoC on departure. - -| **Station Data Time Series (simulation_timeseries_station_xy.csv)** -| Contains station specific time series including price of electricity, grid supply, fixed loads, battery power, energy stored in battery, flex band boundaries, battery feed, charging station power use, occupied charging stations and charging stations in use as well as vehicles which are at the station. - -.. _cost_calculation: - -Cost calculation -################ -| **Cost calculation (summary_vehicles_costs.csv)** -| This is an optional output which calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. -| The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV `_ for the calculation of electricity costs. - -* Investment - * **Busses**: Costs for all busses used in the simulation. Costs include battery swaps, depending on the lifetime of both busses and batteries. - * **Charging infrastructure**: Costs for all depot and opportunity charging stations, depending on the number of actually used charging stations at each grid connector. - * **Grid connectors**: Costs for grid connectors and transformers, depending on the voltage level and the distance to the grid. - * **Garages**: Costs for workstations and charging infrastructure at garages. - * **Stationary storages**: Costs for stationary batteries at depot and opportunity stations, depending on its capacity. -* Maintenance - * Depending on the lifetime of each component maintenance costs are calculated for busses, charging infrastructure, grid connectors and stationary storages. -* Electricity - * **Power procurement**: Costs for the procurement of energy. - * **Grid fees**: Costs for power and energy price, depending on the voltage level and the utilization time per year. - * **Taxes**: Taxes like electricity taxes, depending on given taxes by price sheet. - * **Feed-in remuneration**: Remuneration for electricity fed into the grid. - -As result the following table is saved as CSV: - -+---------------------------------+----------+-----------------------------------------------------------------------+ -|**parameter** | **unit** | **description** | -+=================================+==========+=======================================================================+ -|c_vehicles | EUR | Investment costs of all busses | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_gcs | EUR | Investment costs of all grid connectors | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_cs | EUR | Investment costs of all charging stations | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_garage_cs | EUR | Investment costs of charging stations at garages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_garage | EUR | Investment costs of garages itself | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_garage_workstations | EUR | Investment costs of working stations at garages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_stat_storage | EUR | Investment costs of stationary storages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_invest | EUR | Sum of all investment costs | -+---------------------------------+----------+-----------------------------------------------------------------------+ -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_vehicles_annual | EUR/year | Annual investment costs of all busses | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_gcs_annual | EUR/year | Annual investment costs of all grid connectors | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_cs_annual | EUR/year | Annual investment costs of all charging stations | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_garage_annual | EUR/year | Sum of annual investment costs of garages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_stat_storage_annual | EUR/year | Annual investment costs of all stationary storages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_invest_annual | EUR/year | Sum of all annual investment costs | -+---------------------------------+----------+-----------------------------------------------------------------------+ -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_maint_gc_annual | EUR/year | Annual maintenance costs of grid connectors | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_maint_infrastructure_annual | EUR/year | Annual maintenance costs of charging stations and stationary storages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_maint_vehicles_annual | EUR/year | Annual maintenance costs of busses | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_maint_stat_storage_annual | EUR/year | Annual maintenance costs of stationary storages | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_maint_annual | EUR/year | Sum of annual maintenance costs | -+---------------------------------+----------+-----------------------------------------------------------------------+ -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_el_procurement_annual | EUR/year | Annual costs of power procurement | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_el_power_price_annual | EUR/year | Annual grid fee for highest load peak | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_el_energy_price_annual | EUR/year | Annual grid fee for drawn energy | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_el_taxes_annual | EUR/year | Annual costs for all electricity related taxes | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_el_feed_in_remuneration_annual | EUR/year | Annual feed-in remuneration | -+---------------------------------+----------+-----------------------------------------------------------------------+ -|c_el_annual | EUR/year | Sum of all annual electricity costs | -+---------------------------------+----------+-----------------------------------------------------------------------+ - - - +The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Please refer to :ref:`generate_report` for more datailed information. diff --git a/docs/source/simba_modules.rst b/docs/source/simba_modules.rst index bd062964..1928aa18 100644 --- a/docs/source/simba_modules.rst +++ b/docs/source/simba_modules.rst @@ -4,11 +4,16 @@ SimBA modules ============= - - Consumption analysis -------------------- +The consumption can be calculated in two ways: Either with a constant average specific consumption or using a consumption table, where the consumption depends on the temperature, the incline, the level of loading and the speed profile/ average speed. + +To use a constant consumption, this value can be defined in the :ref:`vehicle_types` as "mileage" in the unit of [kWh/km]. To use the relative consumtion, a consumption table need to be created with data for each vehicle type and the path to the consumption table is assigned to the variable "mileage" in :ref:`vehicle_types`. The consumption table should have the columns "vehicle_type", "level_of_loading", "incline" ,"mean_speed_kmh", "t_amb", "consumption_kwh_per_km" and its creation is at ths point of development not part of SimBA. + +The level_of_loading describes the share between an empty vehicle (0) and a fully loaded vehicle (1) can be handed over in two ways: Either directcly as a column in :ref:`schedule` with specific values for each individual trip or as an input file "default_level_of_loading.csv" (path defined in :ref:`config`) containing values for each hour of the day. SimBA will first look into schedule and take this value and if it is not defined take the one from the .csv file. The temperature information is obtained in the same way as the level of loading and should be given in °C. In Order to calculate the consumption based on the in incline, an extra "all_stations.csv" file (path defined in :ref:`config`) has to be provided containing information on the elevation in m of each station. The incline is then calculated as the average incline between start and stop of the trip, which is an assumption that creates good results for vehicles with recuperation technology, as most electric vehicles have. The mean speed is calculated using the information provided in :ref:`schedule` about duration and length of each trip. + + .. _vehicle_dispatch: Vehicle Dispatch @@ -17,12 +22,138 @@ Vehicle Dispatch Charging simulation ------------------- +The charging simulation is carried out in the open source software `SpiceEV `_, that is included in SimBA as a package. SimBA therefore uses SpiceEVs carging strategy "distributed", that allows to sepatarte the charging strategy depending on the station type. The station types can be either depot charging station (deps) or opportunity charging station (opps). At depot charging stations vehicles are being charged using SpiceEVs strategy "balanced", which uses the whole standing time to charge with the minimal power to reach a desired SoC. At opportunity charging stations the strategy "greedy" is employed, that charges with the maximum available power due to restrictions from the grid connectoion, the charging curve of the vehicle and the charging station. + +.. _generate_report: + Generate report --------------- +The generation of the report is implemented as a mode, that can be activated with the keyword "report" in modes (:ref:`report`). The report generates most of the output files. These are saved in a subfolder of the output directory as defined in :ref:`config` named as a string with the modes executed up to the point when report is called. e.g. mode = ['sim', 'report', 'neg_oppb_to_depb', 'report'] will create two subfolders in the output directory named "sim" and "sim__neg_oppb_to_depb" containing the output files for the respective times in simulation. + +The generation of the report can be modified using the flag "cost_calculation" in :ref:`config`. If this flag is set to true, each report will also generate the file "summary_vehicles_costs.csv". + +Default outputs +############### + +| **Grid Connector Overview (gc_overview.csv)** +| Contains information about charging stations, including their names, types, maximum power, maximum number of charging stations, total energy usage, and use factors for the least, second least, and third least utilized charging stations. + +| **Grid Connector Time Series (gc_power_overview_timeseries.csv)** +| Time series of power flow in kW for every grid connector + +| **Rotation SoC Data (rotation_socs.csv)** +| Time series of SoC for each rotation. + +| **Vehicle SoC Data (vehicle_socs.csv)** +| Time series of SoC for each vehicle. + +| **Rotation Summary (rotation_summary.csv)** +| Contains data related to the rotation of vehicles, including the start and end times of each rotation, the type and ID of the vehicle, the depot name, the lines the vehicle traveled, total energy consumption in kWh, distance traveled in m, and various charging-related metrics such as charging type and SoC at arrival, minimum SoC and if the rotation had negative SoC values. + +| **Overview Plots (run_overview.pdf and run_overview.png)** +| Contains plots for SoCs for every vehicle, power at each charging station, batteries, external loads and feed-ins as well as price time series for each station. + +| **Station Data Summary (simulation_station_xy.json)** +| Contains information about the simulation interval, grid connector, photovoltaics, charging strategy, average flexible power range per time window, total drawn energy from the grid, average duration of standing events, maximum drawn power, total energy fed into the grid, maximum stored energy in each battery, number of load cycles for stationary batteries and vehicles, and number of times vehicle SoC was below the desired SoC on departure. + +| **Station Data Time Series (simulation_timeseries_station_xy.csv)** +| Contains station specific time series including price of electricity, grid supply, fixed loads, battery power, energy stored in battery, flex band boundaries, battery feed, charging station power use, occupied charging stations and charging stations in use as well as vehicles which are at the station. + +| **Overview on costs and vehicles (summary_vehicles_costs.csv)** +| If colst_caluclation is activated, this file contains the cost report as described below in :ref:`cost_calculation`. + +.. _cost_calculation: + +Cost calculation +################ +| **Cost calculation (summary_vehicles_costs.csv)** +| This is an optional output which calculates investment and maintenance costs of the infrastructure as well as energy costs in the scenario. The costs are calculated based on the price sheet, given as input in the ``costs_params.json``. +| The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV documentation `_ for the calculation of electricity costs. + +* Investment + * **Busses**: Costs for all busses used in the simulation. Costs include battery swaps, depending on the lifetime of both busses and batteries. + * **Charging infrastructure**: Costs for all depot and opportunity charging stations, depending on the number of actually used charging stations at each grid connector. + * **Grid connectors**: Costs for grid connectors and transformers, depending on the voltage level and the distance to the grid. + * **Garages**: Costs for workstations and charging infrastructure at garages. + * **Stationary storages**: Costs for stationary batteries at depot and opportunity stations, depending on its capacity. +* Maintenance + * Depending on the lifetime of each component maintenance costs are calculated for busses, charging infrastructure, grid connectors and stationary storages. +* Electricity + * **Power procurement**: Costs for the procurement of energy. + * **Grid fees**: Costs for power and energy price, depending on the voltage level and the utilization time per year. + * **Taxes**: Taxes like electricity taxes, depending on given taxes by price sheet. + * **Feed-in remuneration**: Remuneration for electricity fed into the grid. + +As result the following table is saved as CSV: + ++---------------------------------+----------+-----------------------------------------------------------------------+ +|**parameter** | **unit** | **description** | ++=================================+==========+=======================================================================+ +|c_vehicles | EUR | Investment costs of all busses | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_gcs | EUR | Investment costs of all grid connectors | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_cs | EUR | Investment costs of all charging stations | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage_cs | EUR | Investment costs of charging stations at garages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage | EUR | Investment costs of garages itself | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage_workstations | EUR | Investment costs of working stations at garages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_stat_storage | EUR | Investment costs of stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_invest | EUR | Sum of all investment costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_vehicles_annual | EUR/year | Annual investment costs of all busses | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_gcs_annual | EUR/year | Annual investment costs of all grid connectors | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_cs_annual | EUR/year | Annual investment costs of all charging stations | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_garage_annual | EUR/year | Sum of annual investment costs of garages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_stat_storage_annual | EUR/year | Annual investment costs of all stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_invest_annual | EUR/year | Sum of all annual investment costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_gc_annual | EUR/year | Annual maintenance costs of grid connectors | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_infrastructure_annual | EUR/year | Annual maintenance costs of charging stations and stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_vehicles_annual | EUR/year | Annual maintenance costs of busses | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_stat_storage_annual | EUR/year | Annual maintenance costs of stationary storages | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_maint_annual | EUR/year | Sum of annual maintenance costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_procurement_annual | EUR/year | Annual costs of power procurement | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_power_price_annual | EUR/year | Annual grid fee for highest load peak | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_energy_price_annual | EUR/year | Annual grid fee for drawn energy | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_taxes_annual | EUR/year | Annual costs for all electricity related taxes | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_feed_in_remuneration_annual | EUR/year | Annual feed-in remuneration | ++---------------------------------+----------+-----------------------------------------------------------------------+ +|c_el_annual | EUR/year | Sum of all annual electricity costs | ++---------------------------------+----------+-----------------------------------------------------------------------+ + Optimization ------------ +There are several options for optimizations that are implemented as :ref:`sim_modes`. These options are currently: + +* :ref:`neg_depb_to_oppb` +* :ref:`neg_oppb_to_depb` +* :ref:`Service Optimization` +* :ref:`Station Optimization` + .. _consistency_check: Consistency check From 6d6784513d960c9d11875f321204dae437a5069c Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 11:06:52 +0200 Subject: [PATCH 33/58] Minor changes to make flake8 and sphinx happy --- docs/source/conf.py | 1 - docs/source/ebus_toolbox.rst | 109 -------------------------------- docs/source/getting_started.rst | 2 +- docs/source/modules.rst | 9 --- ebus_toolbox/optimizer_util.py | 14 ++-- ebus_toolbox/util.py | 6 +- 6 files changed, 13 insertions(+), 128 deletions(-) delete mode 100644 docs/source/ebus_toolbox.rst delete mode 100644 docs/source/modules.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 3daca017..81cb065d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -25,7 +25,6 @@ import pathlib sys.path.insert(0, os.path.abspath('../../')) sys.path.insert(0, pathlib.Path(__file__).parents[2].resolve().as_posix()) -sys.path.insert(0, os.path.abspath('C:/Users/paul.scheer/Python/spiceev')) # -- Project information ----------------------------------------------------- diff --git a/docs/source/ebus_toolbox.rst b/docs/source/ebus_toolbox.rst deleted file mode 100644 index e7a1a296..00000000 --- a/docs/source/ebus_toolbox.rst +++ /dev/null @@ -1,109 +0,0 @@ -ebus\_toolbox package -===================== - -Submodules ----------- - -ebus\_toolbox.consumption module --------------------------------- - -.. automodule:: ebus_toolbox.consumption - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.costs module --------------------------- - -.. automodule:: ebus_toolbox.costs - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.optimization module ---------------------------------- - -.. automodule:: ebus_toolbox.optimization - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.optimizer\_util module ------------------------------------- - -.. automodule:: ebus_toolbox.optimizer_util - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.report module ---------------------------- - -.. automodule:: ebus_toolbox.report - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.rotation module ------------------------------ - -.. automodule:: ebus_toolbox.rotation - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.schedule module ------------------------------ - -.. automodule:: ebus_toolbox.schedule - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.simulate module ------------------------------ - -.. automodule:: ebus_toolbox.simulate - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.station\_optimization module ------------------------------------------- - -.. automodule:: ebus_toolbox.station_optimization - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.station\_optimizer module ---------------------------------------- - -.. automodule:: ebus_toolbox.station_optimizer - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.trip module -------------------------- - -.. automodule:: ebus_toolbox.trip - :members: - :undoc-members: - :show-inheritance: - -ebus\_toolbox.util module -------------------------- - -.. automodule:: ebus_toolbox.util - :members: - :undoc-members: - :show-inheritance: - -Module contents ---------------- - -.. automodule:: ebus_toolbox - :members: - :undoc-members: - :show-inheritance: diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 43c22639..ce5e9a94 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -53,7 +53,7 @@ SimBA is designed as a toolbox, so the specific use can be adapted to the users Modules of SimBA -:ref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. +:numref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. Depending on the given simulation parameters, the vehicles are then dispatched. In this step, every rotation – the sum of all trips between leaving the depot until return – is allocated to a specific vehicle. The vehicles can be charged at any number of :ref:`electrified_stations`. These can be classified either as depot stations (deps) or as opportunity stations (opps). Each vehicle can be charged following one of the two charging strategies: Either as opportunity charging bus (oppb) or as depot charging bus (depb). While an oppb is charged at both deps and opps, depb are only charged at deps. The charging strategy can either be defined for each rotation in the :ref:`schedule` data or for all not explicitly defined rotations using the "preferred charging type" option in the :ref:`config`. Using this information, the charging simulation is then carried out. diff --git a/docs/source/modules.rst b/docs/source/modules.rst deleted file mode 100644 index 7e007c3b..00000000 --- a/docs/source/modules.rst +++ /dev/null @@ -1,9 +0,0 @@ -:orphan: - -ebus_toolbox -============ - -.. toctree:: - :maxdepth: 4 - - ebus_toolbox diff --git a/ebus_toolbox/optimizer_util.py b/ebus_toolbox/optimizer_util.py index 4f272efa..aa8b6e3b 100644 --- a/ebus_toolbox/optimizer_util.py +++ b/ebus_toolbox/optimizer_util.py @@ -1,5 +1,4 @@ -""" Module for the minor classes LowSocEvent, ChargingEvent, OptimizerConfig -and utility functionality used by the StationOptimizer and station_optimization""" +""" Module for LowSocEvent, ChargingEvent, OptimizerConfig and utility functionality""" import logging import math import os @@ -26,7 +25,8 @@ class ChargingEvent: - """ Class to gather information about a charging event""" + """Class to gather information about a charging event""" + def __init__(self, start_idx, end_idx, arrival_time, start_time, end_time, buffer_time, vehicle_id, capacity, station_name, rotation): @@ -246,12 +246,12 @@ def get_charging_start(trip1, args): def get_buffer_time(trip, default_buffer_time_opps): - """ Return the buffer time as timedelta object + """Return the buffer time as timedelta object :param trip: trip to be checked :type trip: ebus_toolbox.trip.Trip :param default_buffer_time_opps: the default buffer time at opps charging stations - :return: buffer time + :return: buffer ti :rtype: datetime.timedelta """ return timedelta(minutes=get_buffer_time_util(trip, default_buffer_time_opps)) @@ -353,6 +353,7 @@ def evaluate(events: typing.Iterable[LowSocEvent], :param kwargs: optional overwriting of soc_lower_thresh, soc_upper_thresh or soc_data :return: sorted stations and potentials :rtype: list(str(station_id), float(potential)) + """ soc_lower_thresh = kwargs.get("soc_lower_thresh", optimizer.config.min_soc) soc_upper_thresh = kwargs.get("soc_upper_thresh", optimizer.args.desired_soc_deps) @@ -627,6 +628,7 @@ def recursive_dict_updater(dict_to_change, filter_function, modify_function): The filter criteria are checked by the filter_function which gets the arguments key and value. The values are updated by the modify_function which gets the arguments key and value and returns the updated value. + :param dict_to_change: nested dictionary that needs to be updated :type dict_to_change: dict :param filter_function: function that returns True if the value should be changed with key and @@ -635,6 +637,7 @@ def recursive_dict_updater(dict_to_change, filter_function, modify_function): :param modify_function: function that returns the dictionary value with key and value as arguments :type modify_function: function + """ # iterate over all items. For every item, try iterating over it as well until an AttributeError for key, value in dict_to_change.items(): @@ -658,6 +661,7 @@ def combination_generator(iterable: typing.Iterable, amount: int): :param amount: Number of elements which should be drawn from iterable :type amount: int :yields: list of items + """ iterable = list(iterable) diff --git a/ebus_toolbox/util.py b/ebus_toolbox/util.py index 485690d4..91e01bec 100644 --- a/ebus_toolbox/util.py +++ b/ebus_toolbox/util.py @@ -27,9 +27,9 @@ def get_buffer_time(trip, default=0): hours of the day are covered. E.g. buffer_time = { - "10-22": 2, - "22-6": 3, - "else": 1 + "10-22": 2, + "22-6": 3, + "else": 1 } :param trip: The of buffer time of this trips arrival is returned. From c927cc3ef42ce96737f0716e07e5f23416d11b06 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 11:08:06 +0200 Subject: [PATCH 34/58] Add modules and ebus_toolbox rst --- docs/source/ebus_toolbox.rst | 109 +++++++++++++++++++++++++++++++++++ docs/source/modules.rst | 9 +++ 2 files changed, 118 insertions(+) create mode 100644 docs/source/ebus_toolbox.rst create mode 100644 docs/source/modules.rst diff --git a/docs/source/ebus_toolbox.rst b/docs/source/ebus_toolbox.rst new file mode 100644 index 00000000..e7a1a296 --- /dev/null +++ b/docs/source/ebus_toolbox.rst @@ -0,0 +1,109 @@ +ebus\_toolbox package +===================== + +Submodules +---------- + +ebus\_toolbox.consumption module +-------------------------------- + +.. automodule:: ebus_toolbox.consumption + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.costs module +-------------------------- + +.. automodule:: ebus_toolbox.costs + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.optimization module +--------------------------------- + +.. automodule:: ebus_toolbox.optimization + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.optimizer\_util module +------------------------------------ + +.. automodule:: ebus_toolbox.optimizer_util + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.report module +--------------------------- + +.. automodule:: ebus_toolbox.report + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.rotation module +----------------------------- + +.. automodule:: ebus_toolbox.rotation + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.schedule module +----------------------------- + +.. automodule:: ebus_toolbox.schedule + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.simulate module +----------------------------- + +.. automodule:: ebus_toolbox.simulate + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.station\_optimization module +------------------------------------------ + +.. automodule:: ebus_toolbox.station_optimization + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.station\_optimizer module +--------------------------------------- + +.. automodule:: ebus_toolbox.station_optimizer + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.trip module +------------------------- + +.. automodule:: ebus_toolbox.trip + :members: + :undoc-members: + :show-inheritance: + +ebus\_toolbox.util module +------------------------- + +.. automodule:: ebus_toolbox.util + :members: + :undoc-members: + :show-inheritance: + +Module contents +--------------- + +.. automodule:: ebus_toolbox + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/modules.rst b/docs/source/modules.rst new file mode 100644 index 00000000..7e007c3b --- /dev/null +++ b/docs/source/modules.rst @@ -0,0 +1,9 @@ +:orphan: + +ebus_toolbox +============ + +.. toctree:: + :maxdepth: 4 + + ebus_toolbox From 25d70a859bf7da71ddbb1e2d36839a6cc4faed40 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 11:08:35 +0200 Subject: [PATCH 35/58] Minor changes to make flake8 and sphinx happy --- ebus_toolbox/station_optimizer.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ebus_toolbox/station_optimizer.py b/ebus_toolbox/station_optimizer.py index a9c565f5..988d24f2 100644 --- a/ebus_toolbox/station_optimizer.py +++ b/ebus_toolbox/station_optimizer.py @@ -1,4 +1,5 @@ """ Optimizer class which implements the optimizer object and methods needed""" + import logging import pickle from copy import deepcopy, copy @@ -13,7 +14,7 @@ class StationOptimizer: - """ Class for station optimization""" + """Class for station optimization""" def __init__(self, sched: schedule.Schedule, scen: scenario.Scenario, args, config: 'opt_util.OptimizerConfig', logger: logging.Logger): From bfca020c734ae68498daa1335575bc7b3ac84a65 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 13:47:54 +0200 Subject: [PATCH 36/58] Remove minor changes from dev --- ebus_toolbox/consumption.py | 2 +- ebus_toolbox/optimizer_util.py | 4 ++-- ebus_toolbox/rotation.py | 6 +++--- ebus_toolbox/simulate.py | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ebus_toolbox/consumption.py b/ebus_toolbox/consumption.py index d8c1e6aa..f66cc0f5 100644 --- a/ebus_toolbox/consumption.py +++ b/ebus_toolbox/consumption.py @@ -60,7 +60,7 @@ def calculate_consumption(self, time, distance, vehicle_type, charging_type, tem :raises AttributeError: if there is no path to temperature or lol data provided """ - assert self.vehicle_types.get(vehicle_type, {}).get(charging_type), \ + assert self.vehicle_types.get(vehicle_type, {}).get(charging_type),\ f"Combination of vehicle type {vehicle_type} and {charging_type} not defined." vehicle_info = self.vehicle_types[vehicle_type][charging_type] diff --git a/ebus_toolbox/optimizer_util.py b/ebus_toolbox/optimizer_util.py index aa8b6e3b..4c917683 100644 --- a/ebus_toolbox/optimizer_util.py +++ b/ebus_toolbox/optimizer_util.py @@ -246,12 +246,12 @@ def get_charging_start(trip1, args): def get_buffer_time(trip, default_buffer_time_opps): - """Return the buffer time as timedelta object + """ Return the buffer time as timedelta object :param trip: trip to be checked :type trip: ebus_toolbox.trip.Trip :param default_buffer_time_opps: the default buffer time at opps charging stations - :return: buffer ti + :return: buffer time :rtype: datetime.timedelta """ return timedelta(minutes=get_buffer_time_util(trip, default_buffer_time_opps)) diff --git a/ebus_toolbox/rotation.py b/ebus_toolbox/rotation.py index fa1d8c7e..d07991f8 100644 --- a/ebus_toolbox/rotation.py +++ b/ebus_toolbox/rotation.py @@ -58,10 +58,10 @@ def add_trip(self, trip): # set charging type if given charging_type = trip.get('charging_type') if charging_type in ['depb', 'oppb']: - assert self.charging_type is None or self.charging_type == charging_type, \ + assert self.charging_type is None or self.charging_type == charging_type,\ f"Two trips of rotation {self.id} have distinct charging types" assert self.schedule.vehicle_types.get( - self.vehicle_type, {}).get(charging_type) is not None, \ + self.vehicle_type, {}).get(charging_type) is not None,\ (f"The required vehicle type {self.vehicle_type}({charging_type}) " "is not given in the vehicle_types.json file.") self.set_charging_type(charging_type) @@ -93,7 +93,7 @@ def set_charging_type(self, ct): if ct == self.charging_type: return - assert self.schedule.vehicle_types.get(self.vehicle_type, {}).get(ct), \ + assert self.schedule.vehicle_types.get(self.vehicle_type, {}).get(ct),\ f"Combination of vehicle type {self.vehicle_type} and {ct} not defined." old_consumption = self.consumption diff --git a/ebus_toolbox/simulate.py b/ebus_toolbox/simulate.py index 745c98f7..ebb8967a 100644 --- a/ebus_toolbox/simulate.py +++ b/ebus_toolbox/simulate.py @@ -59,7 +59,7 @@ def simulate(args): scenario = schedule.run(args) # run the mode(s) specified in config - if not isinstance(args.mode, list): + if type(args.mode) != list: # backwards compatibility: run single mode args.mode = [args.mode] From 17c120ba60f92bd5c1e8dcf6f35bef4dc4dd5ad0 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 13:51:27 +0200 Subject: [PATCH 37/58] Remove minor changes from dev --- ebus_toolbox/util.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ebus_toolbox/util.py b/ebus_toolbox/util.py index 91e01bec..ae1527b6 100644 --- a/ebus_toolbox/util.py +++ b/ebus_toolbox/util.py @@ -20,7 +20,14 @@ def get_buffer_time(trip, default=0): Get buffer time at arrival station of a trip. Buffer_time is an abstraction of delays like docking procedures and is added to the planned arrival time. - NOTE: Buffertime dictionaries map hours of the day to a buffer time. + :param trip: The of buffer time of this trips arrival is returned. + :type trip: ebus_toolbox.Trip + :param default: Default buffer time if no station specific buffer time is given. [minutes] + :type default: dict, numeric + :return: Buffer time + :rtype: numeric + + NOTE: Buffertime dictionaries map hours of the day to a buffer time. Keys are ranges of hours and corresponding values provide buffer time in minutes for that time range. An entry with key "else" is a must if not all @@ -31,13 +38,6 @@ def get_buffer_time(trip, default=0): "22-6": 3, "else": 1 } - - :param trip: The of buffer time of this trips arrival is returned. - :type trip: ebus_toolbox.Trip - :param default: Default buffer time if no station specific buffer time is given. [minutes] - :type default: dict, numeric - :return: Buffer time - :rtype: numeric """ schedule = trip.rotation.schedule From 7f325f41984ecb12a9aa951ec87f13c951feec1c Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 13:53:55 +0200 Subject: [PATCH 38/58] Make flake8 up to date and happy --- ebus_toolbox/consumption.py | 2 +- ebus_toolbox/costs.py | 1 - ebus_toolbox/rotation.py | 6 +++--- ebus_toolbox/simulate.py | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ebus_toolbox/consumption.py b/ebus_toolbox/consumption.py index f66cc0f5..d8c1e6aa 100644 --- a/ebus_toolbox/consumption.py +++ b/ebus_toolbox/consumption.py @@ -60,7 +60,7 @@ def calculate_consumption(self, time, distance, vehicle_type, charging_type, tem :raises AttributeError: if there is no path to temperature or lol data provided """ - assert self.vehicle_types.get(vehicle_type, {}).get(charging_type),\ + assert self.vehicle_types.get(vehicle_type, {}).get(charging_type), \ f"Combination of vehicle type {vehicle_type} and {charging_type} not defined." vehicle_info = self.vehicle_types[vehicle_type][charging_type] diff --git a/ebus_toolbox/costs.py b/ebus_toolbox/costs.py index b54d7e4d..6d78ebec 100644 --- a/ebus_toolbox/costs.py +++ b/ebus_toolbox/costs.py @@ -149,7 +149,6 @@ def calculate_costs(c_params, scenario, schedule, args): costs["c_maint_annual"] = (costs["c_maint_infrastructure_annual"] + costs["c_maint_vehicles_annual"]) costs["c_invest"] = costs["c_vehicles"] + costs["c_cs"] + costs["c_gcs"] + costs["c_garage"] - # ToDo: add stat storages to investment costs (also annual)? costs["c_invest_annual"] = (costs["c_vehicles_annual"] + costs["c_cs_annual"] + costs["c_gcs_annual"] + costs["c_garage_annual"]) diff --git a/ebus_toolbox/rotation.py b/ebus_toolbox/rotation.py index d07991f8..fa1d8c7e 100644 --- a/ebus_toolbox/rotation.py +++ b/ebus_toolbox/rotation.py @@ -58,10 +58,10 @@ def add_trip(self, trip): # set charging type if given charging_type = trip.get('charging_type') if charging_type in ['depb', 'oppb']: - assert self.charging_type is None or self.charging_type == charging_type,\ + assert self.charging_type is None or self.charging_type == charging_type, \ f"Two trips of rotation {self.id} have distinct charging types" assert self.schedule.vehicle_types.get( - self.vehicle_type, {}).get(charging_type) is not None,\ + self.vehicle_type, {}).get(charging_type) is not None, \ (f"The required vehicle type {self.vehicle_type}({charging_type}) " "is not given in the vehicle_types.json file.") self.set_charging_type(charging_type) @@ -93,7 +93,7 @@ def set_charging_type(self, ct): if ct == self.charging_type: return - assert self.schedule.vehicle_types.get(self.vehicle_type, {}).get(ct),\ + assert self.schedule.vehicle_types.get(self.vehicle_type, {}).get(ct), \ f"Combination of vehicle type {self.vehicle_type} and {ct} not defined." old_consumption = self.consumption diff --git a/ebus_toolbox/simulate.py b/ebus_toolbox/simulate.py index ebb8967a..745c98f7 100644 --- a/ebus_toolbox/simulate.py +++ b/ebus_toolbox/simulate.py @@ -59,7 +59,7 @@ def simulate(args): scenario = schedule.run(args) # run the mode(s) specified in config - if type(args.mode) != list: + if not isinstance(args.mode, list): # backwards compatibility: run single mode args.mode = [args.mode] From ffe9a34bf7dfaaf3df6c7ee1711b1209e77a92eb Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Wed, 2 Aug 2023 14:46:58 +0200 Subject: [PATCH 39/58] Make flake8 happy --- ebus_toolbox/consumption.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ebus_toolbox/consumption.py b/ebus_toolbox/consumption.py index cb10fa29..bf76f554 100644 --- a/ebus_toolbox/consumption.py +++ b/ebus_toolbox/consumption.py @@ -60,7 +60,6 @@ def calculate_consumption(self, time, distance, vehicle_type, charging_type, tem :raises AttributeError: if there is no path to temperature or lol data provided """ - assert self.vehicle_types.get(vehicle_type, {}).get(charging_type), ( f"Combination of vehicle type {vehicle_type} and {charging_type} not defined.") From f682921c487d1a1ab52b4327e76bf2e7ebaecc48 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 2 Aug 2023 16:26:27 +0200 Subject: [PATCH 40/58] add explanation for vehicle dispatch to rtd --- docs/source/getting_started.rst | 10 +++++----- docs/source/simba_modules.rst | 4 +++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index ce5e9a94..b7793816 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -35,9 +35,9 @@ To use SimBa with PyCharm, create a new python (>= 3.7) environment and clone th Now add a new "run/debug configuration" with the following information: -| module name: ``SimBA`` -| Parameters: ``--config data/examples/ebus_toolbox.cfg`` -| Working directory: ``Path\to\local\SimBa`` +| module name: ``simba`` +| Parameters: ``--config data/examples/simba.cfg`` +| Working directory: ``path/to/local/simba_repo`` | Run with Python Console: true Now you can run the scenario specified in the conif usin PyCharm. @@ -51,9 +51,9 @@ SimBA is designed as a toolbox, so the specific use can be adapted to the users :alt: figure_simba_modules :width: 600 - Modules of SimBA +:ref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. -:numref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. + Modules of SimBA Depending on the given simulation parameters, the vehicles are then dispatched. In this step, every rotation – the sum of all trips between leaving the depot until return – is allocated to a specific vehicle. The vehicles can be charged at any number of :ref:`electrified_stations`. These can be classified either as depot stations (deps) or as opportunity stations (opps). Each vehicle can be charged following one of the two charging strategies: Either as opportunity charging bus (oppb) or as depot charging bus (depb). While an oppb is charged at both deps and opps, depb are only charged at deps. The charging strategy can either be defined for each rotation in the :ref:`schedule` data or for all not explicitly defined rotations using the "preferred charging type" option in the :ref:`config`. Using this information, the charging simulation is then carried out. diff --git a/docs/source/simba_modules.rst b/docs/source/simba_modules.rst index 1928aa18..64783002 100644 --- a/docs/source/simba_modules.rst +++ b/docs/source/simba_modules.rst @@ -19,6 +19,8 @@ The level_of_loading describes the share between an empty vehicle (0) and a full Vehicle Dispatch ---------------- +To allocate the rotations to vehicles, vehicles of the needed type to fulfil the rotation are used. If no suitable vehicle is available, a new vehicle is created. Available vehilces are defined as not currently serving a rotation, having the same depot and having had enough time after return to the depot to be fully charged, when returning with an empty battery. This "minimum standing time" at the depot is calculated using the variable min_recharge_deps_oppb or min_recharge_deps_depb from the config together with the respective battery capacity of the vehicle and assuming the maximum available power of the depot chargning stations. + Charging simulation ------------------- @@ -163,4 +165,4 @@ Consistency check .. _rotation_filter: Rotation filter ---------------- \ No newline at end of file +--------------- From e75d1b1bf18ed1ac2b573ff45f428d8ea0261ef0 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 2 Aug 2023 16:57:22 +0200 Subject: [PATCH 41/58] make rtd run with simba --- docs/source/getting_started.rst | 20 ++++---- docs/source/index.rst | 2 +- docs/source/modes.rst | 6 +-- docs/source/modules.rst | 6 +-- docs/source/{ebus_toolbox.rst => simba.rst} | 52 ++++++++++----------- 5 files changed, 43 insertions(+), 43 deletions(-) rename docs/source/{ebus_toolbox.rst => simba.rst} (56%) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index b7793816..673eb982 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -1,7 +1,7 @@ Getting Started =============== -SimBa - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. +SimBA - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. It be used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and circulations, determining charging strategies, and calculating investments and costs. .. Without creating links like in the line below, subpages go missing from the sidebar @@ -10,21 +10,21 @@ It be used for locating and dimensioning charging infrastructure, dimensioning b Installation ------------ -To try it out, first clone `this repository `_ and then install the required packages to your current python environment by running +To try it out, first clone `this repository `_ and then install the required packages to your current python environment by running ``pip install -r requirements.txt`` -Now you can start the eBus Toolbox module with all configurations stored at `data/configs/ebus_toolbox.cfg` via the command +Now you can start SimBA with all configurations stored at `data/configs/simba.cfg` via the command -``python -m ebus_toolbox --config data/examples/ebus_toolbox.cfg`` +``python -m simba --config data/examples/simba.cfg`` The repo provides an example for each necessary input file, so the example case can be executed without the need for the user to provide any data themselves. To run SimBA with your own `schedule.csv` (see :ref:`schedule`)) file and default configurations run -``python -m ebus_toolbox --input_schedule path/to/schedule.csv`` +``python -m simba --input_schedule path/to/schedule.csv`` -Default configurations are detailed at `data/configs/ebus_toolbox.cfg`. +Default configurations are detailed at `data/configs/simba.cfg`. Usage with PyCharm ################## @@ -51,19 +51,19 @@ SimBA is designed as a toolbox, so the specific use can be adapted to the users :alt: figure_simba_modules :width: 600 -:ref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. +:numref:`figure_simba_modules` shows the structure of the toolbox with its needed input data and how different modules work together to calculate the scenario. The optional input data and modules are indicated with dashed lines. A simulation starts by calculating the energy consumption of each trip, that is specified in the :ref:`schedule` data. A trip is defined by its departure name and time, arrival name and time, distance, pause, rotation_id and vehicle_type. For each of the :ref:`vehicle_types` either a specific consumption depending on current conditions like temperature and incline can be defined as a :ref:`consumption_table` or a constant specific consumption can be used. The specific consumption of the vehicles is then used to analyze the consumption of each trip. Modules of SimBA Depending on the given simulation parameters, the vehicles are then dispatched. In this step, every rotation – the sum of all trips between leaving the depot until return – is allocated to a specific vehicle. The vehicles can be charged at any number of :ref:`electrified_stations`. These can be classified either as depot stations (deps) or as opportunity stations (opps). Each vehicle can be charged following one of the two charging strategies: Either as opportunity charging bus (oppb) or as depot charging bus (depb). While an oppb is charged at both deps and opps, depb are only charged at deps. The charging strategy can either be defined for each rotation in the :ref:`schedule` data or for all not explicitly defined rotations using the "preferred charging type" option in the :ref:`config`. Using this information, the charging simulation is then carried out. -As a result of each simulation the energy demand at each electrified station, the development of vehicles SoCs (State of Charge), summaries of all rotations, estimated costs for vehicles, infrastructure and operationand further data can be displayed and saved. Some information can also be plotted, an example can be seen in :numref:`ebus_toolbox_default_plot`. +As a result of each simulation the energy demand at each electrified station, the development of vehicles SoCs (State of Charge), summaries of all rotations, estimated costs for vehicles, infrastructure and operationand further data can be displayed and saved. Some information can also be plotted, an example can be seen in :numref:`simba_default_plot`. In case an optimization is carried out, the results are then analyzed, the optimizer adapts the input data and parameters and starts the process again with the trip consumption analysis. In which order and for what purpose the individual modules are executed is mainly defined using the different modes. These modes can be used to manipulate the defined scenario e.g. by altering bus types from depot to opportunity chargers, optimize sets of rotations to increase electrification or suggest stations for electrification by minimizing the amount of stations needed. You can learn more about the modes :ref:`here `. -.. _ebus_toolbox_default_plot: +.. _simba_default_plot: .. figure:: _static/run_overview.png - :alt: ebus_toolbox_default_plot + :alt: simba_default_plot :width: 600 Default output plot for a single simulation. diff --git a/docs/source/index.rst b/docs/source/index.rst index e9ba43dd..75378179 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -9,7 +9,7 @@ :width: 200 Welcome to the SimBA documentation! -======================================== +=================================== SimBa - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. diff --git a/docs/source/modes.rst b/docs/source/modes.rst index c8548363..f38a6ae9 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -19,7 +19,7 @@ different modes support the user in finding optimal solutions for their eBus-Sys Chained Modes ------------- -While the default mode of the 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: ebus_toolbox.cfg) under the keyword *mode*: +While the default mode of the 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*: :: @@ -82,7 +82,7 @@ Station Optimization -------------------- Greedy Optimization #################### -This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. Two basic approaches to use the optimization module are setting the mode in the ebus_toolbox configuration file to +This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. Two basic approaches to use the optimization module are setting the mode in the simba configuration file to :: @@ -198,7 +198,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 ebus_toolbox.cfg used for calling the eBus_Toolbox. +The functionality of the optimizer is controlled through the optimizer.cfg specified in the simba.cfg used for calling the SimBA. .. list-table:: Optimizer.cfg parameters :header-rows: 1 diff --git a/docs/source/modules.rst b/docs/source/modules.rst index 7e007c3b..b9190bc1 100644 --- a/docs/source/modules.rst +++ b/docs/source/modules.rst @@ -1,9 +1,9 @@ :orphan: -ebus_toolbox -============ +simba +===== .. toctree:: :maxdepth: 4 - ebus_toolbox + simba diff --git a/docs/source/ebus_toolbox.rst b/docs/source/simba.rst similarity index 56% rename from docs/source/ebus_toolbox.rst rename to docs/source/simba.rst index e7a1a296..859a0325 100644 --- a/docs/source/ebus_toolbox.rst +++ b/docs/source/simba.rst @@ -1,101 +1,101 @@ -ebus\_toolbox package +simba package ===================== Submodules ---------- -ebus\_toolbox.consumption module +simba.consumption module -------------------------------- -.. automodule:: ebus_toolbox.consumption +.. automodule:: simba.consumption :members: :undoc-members: :show-inheritance: -ebus\_toolbox.costs module +simba.costs module -------------------------- -.. automodule:: ebus_toolbox.costs +.. automodule:: simba.costs :members: :undoc-members: :show-inheritance: -ebus\_toolbox.optimization module +simba.optimization module --------------------------------- -.. automodule:: ebus_toolbox.optimization +.. automodule:: simba.optimization :members: :undoc-members: :show-inheritance: -ebus\_toolbox.optimizer\_util module +simba.optimizer\_util module ------------------------------------ -.. automodule:: ebus_toolbox.optimizer_util +.. automodule:: simba.optimizer_util :members: :undoc-members: :show-inheritance: -ebus\_toolbox.report module +simba.report module --------------------------- -.. automodule:: ebus_toolbox.report +.. automodule:: simba.report :members: :undoc-members: :show-inheritance: -ebus\_toolbox.rotation module +simba.rotation module ----------------------------- -.. automodule:: ebus_toolbox.rotation +.. automodule:: simba.rotation :members: :undoc-members: :show-inheritance: -ebus\_toolbox.schedule module +simba.schedule module ----------------------------- -.. automodule:: ebus_toolbox.schedule +.. automodule:: simba.schedule :members: :undoc-members: :show-inheritance: -ebus\_toolbox.simulate module +simba.simulate module ----------------------------- -.. automodule:: ebus_toolbox.simulate +.. automodule:: simba.simulate :members: :undoc-members: :show-inheritance: -ebus\_toolbox.station\_optimization module +simba.station\_optimization module ------------------------------------------ -.. automodule:: ebus_toolbox.station_optimization +.. automodule:: simba.station_optimization :members: :undoc-members: :show-inheritance: -ebus\_toolbox.station\_optimizer module +simba.station\_optimizer module --------------------------------------- -.. automodule:: ebus_toolbox.station_optimizer +.. automodule:: simba.station_optimizer :members: :undoc-members: :show-inheritance: -ebus\_toolbox.trip module +simba.trip module ------------------------- -.. automodule:: ebus_toolbox.trip +.. automodule:: simba.trip :members: :undoc-members: :show-inheritance: -ebus\_toolbox.util module +simba.util module ------------------------- -.. automodule:: ebus_toolbox.util +.. automodule:: simba.util :members: :undoc-members: :show-inheritance: @@ -103,7 +103,7 @@ ebus\_toolbox.util module Module contents --------------- -.. automodule:: ebus_toolbox +.. automodule:: simba :members: :undoc-members: :show-inheritance: From b16e4e1721035dc1f1fdcdd5ff036ebf92d324d8 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Fri, 4 Aug 2023 11:53:09 +0200 Subject: [PATCH 42/58] rename modules to features --- docs/source/getting_started.rst | 2 +- docs/source/index.rst | 2 +- .../{simba_modules.rst => simba_features.rst} | 23 ++++++++++++++++--- 3 files changed, 22 insertions(+), 5 deletions(-) rename docs/source/{simba_modules.rst => simba_features.rst} (89%) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 673eb982..b616b798 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -40,7 +40,7 @@ Now add a new "run/debug configuration" with the following information: | Working directory: ``path/to/local/simba_repo`` | Run with Python Console: true -Now you can run the scenario specified in the conif usin PyCharm. +Now you can run the scenario specified in the conif using PyCharm. General Concept --------------- diff --git a/docs/source/index.rst b/docs/source/index.rst index 75378179..7a8f2bb6 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -18,7 +18,7 @@ SimBa - the Simulation toolbox for Bus Applications - was designed to analyze an :caption: Contents: getting_started - simba_modules + simba_features modes simulation_parameters modindex diff --git a/docs/source/simba_modules.rst b/docs/source/simba_features.rst similarity index 89% rename from docs/source/simba_modules.rst rename to docs/source/simba_features.rst index 64783002..479d677c 100644 --- a/docs/source/simba_modules.rst +++ b/docs/source/simba_features.rst @@ -1,8 +1,8 @@ -.. _simba_modules: +.. _simba_features: -SimBA modules -============= +Features of SimBA +================= Consumption analysis -------------------- @@ -161,8 +161,25 @@ There are several options for optimizations that are implemented as :ref:`sim_mo Consistency check ----------------- +SimBA makes certain assumption, that have to be valid to trust the results. these are: + +* The trips inside a rotation are chronologically sorted +* The trip time is not negative, so the arrival of the trip is later or equal to its departure. +* The break time between trips is not negative, so the departure of the consecutive trip is later or equal to the arrival of the preceding trip. +* Each rotation has a defined and fixed depot, so the rotation starts and ends at the same station +* Every trip within a rotation starts where the previous trip ended + +In order to test these assumptions, the flag "check_rotation_consistency" can be activated in the :ref:`config`, which will result in the display of cases were assumptions are broken in the console and in the log file. Additionally the inconsistent totaions can be filtered out of the simulation by setting the "skip_inconsistent_rotations" flag to true. + .. _rotation_filter: Rotation filter --------------- + +Before all rotations specified in the :ref:`schedule` are simulated, there is the option to filter only the ones relevant to for the actual analysis. This is activated by setting the "rotation_filter_variable" in the :ref:`config` to either "include", than only certain rotations from the schedule are considered, or to "exclude", than certain rotations are excluded from the analysis. The list of rotations for both options is specified as "rotation_filter" in the Path paragraph of the :ref:`config`. + +Logging +------- + +SimBA uses the "logging" package for logging. All logging messages are both displayed in the Terminal and written to a .log file. The filepath and the loglevel can be defined in the :ref:`config`. Four loglevels are available in the following order: DEBUG, INFO, WARN and ERROR. INFO includes INFO, WARN and ERROR but excludes DEBUG. \ No newline at end of file From 74732527229f8ac78f2d56f9c2262696bb13f496 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Fri, 4 Aug 2023 12:07:04 +0200 Subject: [PATCH 43/58] clean readme --- README.md | 41 ++--------------------------------------- 1 file changed, 2 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 077c747d..e77c4e8c 100644 --- a/README.md +++ b/README.md @@ -2,43 +2,6 @@ The SimBA toolbox assists the user in analysing and optimising electrified bus fleets and schedules. -### Usage +Please refer to the documentation for further instructions: -At the current stage, only a single functionality is implemented, which is processing a bus schedule stored in a specific CSV format (see `data/examples/trips_examples.csv`) and run it through a module called SpiceEV for an in-depth SOC analysis. - -To try it out, first clone this repository and then install the required packages to your current environment by running - -`pip install -r requirements.txt` - -Now you can start the SimBA module with all configurations stored at `data/examples/simba.cfg` via the command - -``python -m simba --config data/examples/simba.cfg`` - -The repo provides an example for each necessary input file, so the example case can be executed without the need for the user to provide any data themselves. - -To run SimBA with your own `schedule.csv` (see details [below](#input-data)) file and default configurations run - -`python -m simba --input_schedule path/to/schedule.csv` - -Default configurations are detailed at `data/configs/simba.cfg`. - - - -### Input Data - -To analyze your own electric bus schedule, the data needs to be provided as a CSV file where each row contains the details of a single trip of that schedule. Find the details about the various columns in this file below. The first table lists the **mandatory** columns while the second one (tbd) lists optional parameters. Refer to `data/examples/trips.csv` for an example. - -| Column Name | Description | Example | -| -------------- | ------------------------------------------------------------ | ----------------- | -| rotation_id | Unique alphanumeric ID to identify rotations | 27312 | -| departure_name | Name of the station the trip starts at | Warschauer Straße | -| departure_time | Date and Time at which bus starts trip | 2022-03-13T10:25 | -| arrival_name | Name of the station the trip ends at | Ostbahnhof Berlin | -| arrival_time | Date and Time at which bus completes trip (e.g. yyyy-mm-ddThh:mm[:ss]) | 2022-03-13T10:30 | -| distance | Distance traveled in **m** | 1340 | -| vehicle_type | ID of vehicle type defined in vehicle types file. Set path of this file in config.
(see default for reference: `data/examples/vehicle_types.json`) | some_bus_type | - -| Column Name | Description | Example | -| :------------ | :----------------------------------------------------------- | ---------------------------- | -| line | The bus line | 512, M10, X11 etc | -| charging_type | The preferred charging type for this trip.
NOTE: All trips of a rotation need to have the same charging type. If omitted, charging type is set according to preferred charging type provided in the config file. | Options: **depb**, **oppb** | +***LINK TO READ THE DOCS*** From 64e5a93cb01f1456f44f14673a93264d7232b122 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Fri, 4 Aug 2023 12:08:16 +0200 Subject: [PATCH 44/58] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e77c4e8c..481121c1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # SimBA: Simulation toolbox for Bus Applications -The SimBA toolbox assists the user in analysing and optimising electrified bus fleets and schedules. +SimBA - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. -Please refer to the documentation for further instructions: +Please refer to the documentation for further information: ***LINK TO READ THE DOCS*** From 1b820620683995ac8e8b4989be1a661571e769e3 Mon Sep 17 00:00:00 2001 From: "paul.scheer" Date: Fri, 4 Aug 2023 15:03:05 +0200 Subject: [PATCH 45/58] Fix typos and grammar --- docs/source/getting_started.rst | 9 +++-- docs/source/modes.rst | 35 ++++++++++--------- docs/source/simba_features.rst | 22 ++++++------ docs/source/simulation_parameters.rst | 48 +++++++++++++-------------- 4 files changed, 56 insertions(+), 58 deletions(-) diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index b616b798..5c230886 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -2,8 +2,7 @@ Getting Started =============== SimBA - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. -It be used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and circulations, determining charging strategies, and calculating investments and costs. - +It is used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and circulations, determining charging strategies, and calculating investments and costs. .. Without creating links like in the line below, subpages go missing from the sidebar .. _installation_label: @@ -40,11 +39,11 @@ Now add a new "run/debug configuration" with the following information: | Working directory: ``path/to/local/simba_repo`` | Run with Python Console: true -Now you can run the scenario specified in the conif using PyCharm. +Now you can run the scenario specified in the config using PyCharm. General Concept --------------- -SimBA is designed as a toolbox, so the specific use can be adapted to the users needs. Its core functionality is to run scenariobased simulations. A scenario is defined by a set of input files. Next to the simulation mode, several optimization modes exist, that can be linked and executed consecutively. +SimBA is designed as a toolbox, so the specific use can be adapted to the users needs. Its core functionality is to run scenario based simulations. A scenario is defined by a set of input files. Next to the simulation mode, several optimization modes exist, that can be linked and executed consecutively. .. _figure_simba_modules: .. figure:: _static/SimBA_module_overview.png @@ -57,7 +56,7 @@ SimBA is designed as a toolbox, so the specific use can be adapted to the users Depending on the given simulation parameters, the vehicles are then dispatched. In this step, every rotation – the sum of all trips between leaving the depot until return – is allocated to a specific vehicle. The vehicles can be charged at any number of :ref:`electrified_stations`. These can be classified either as depot stations (deps) or as opportunity stations (opps). Each vehicle can be charged following one of the two charging strategies: Either as opportunity charging bus (oppb) or as depot charging bus (depb). While an oppb is charged at both deps and opps, depb are only charged at deps. The charging strategy can either be defined for each rotation in the :ref:`schedule` data or for all not explicitly defined rotations using the "preferred charging type" option in the :ref:`config`. Using this information, the charging simulation is then carried out. -As a result of each simulation the energy demand at each electrified station, the development of vehicles SoCs (State of Charge), summaries of all rotations, estimated costs for vehicles, infrastructure and operationand further data can be displayed and saved. Some information can also be plotted, an example can be seen in :numref:`simba_default_plot`. +As a result of each simulation the energy demand at each electrified station, the development of vehicles SoCs (State of Charge), summaries of all rotations, estimated costs for vehicles, infrastructure and operation and further data can be displayed and saved. Some information can also be plotted, an example can be seen in :numref:`simba_default_plot`. In case an optimization is carried out, the results are then analyzed, the optimizer adapts the input data and parameters and starts the process again with the trip consumption analysis. In which order and for what purpose the individual modules are executed is mainly defined using the different modes. These modes can be used to manipulate the defined scenario e.g. by altering bus types from depot to opportunity chargers, optimize sets of rotations to increase electrification or suggest stations for electrification by minimizing the amount of stations needed. You can learn more about the modes :ref:`here `. diff --git a/docs/source/modes.rst b/docs/source/modes.rst index f38a6ae9..f3a00802 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -8,7 +8,7 @@ Modes of SimBA ============== SimBA assists the user in analyzing and optimising electrified bus fleets and schedules. Besides a simple simulation run, several -different modes support the user in finding optimal solutions for their eBus-System. Supported Modes are +different modes support the user in finding optimal solutions for their eBus-System. Supported modes are * simple simulation * negative depot to opportunity charger @@ -19,7 +19,7 @@ different modes support the user in finding optimal solutions for their eBus-Sys Chained Modes ------------- -While the default mode of the 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 (default: simba.cfg) under the keyword *mode*: :: @@ -31,8 +31,7 @@ This results in a simple simulation with a following report. To run a simulation mode = ["sim", "report" ,"neg_depb_to_oppb", "report] -Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. The description what the modes do -can be found below. +Where the scenario is run as is, a report is generated, the schedule is changed and simulated again and a second report is generated. Descriptions for the modes can be found below. Simple Simulation ----------------- @@ -74,7 +73,7 @@ It takes the results of the previous simulation, and changes the charging type o Service Optimization -------------------- -It can happen that several busses influence each other while simulataiously charging at the same charging station, e.g. due to limited grid power or limited number of charging stations, which can lead to negative SoCs due to hindered charging. In this case, this mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. +It can happen that several buses influence each other while simultaneously charging at the same charging station, e.g. due to limited grid power or limited number of charging stations, which can lead to negative SoCs due to hindered charging. In this case, this mode finds the largest set of rotations that results in no negative SoC. This is done by first taking all rotations that do become negative and finding their dependent rotations, i.e., ones that can have an influence by sharing a station earlier with the negative rotation. Next, all rotations are filtered out that stay negative when running with just their dependent rotations. Now, only rotations are left that are non-negative when viewed alone, but might become negative when run together. To find the largest subset of non-negative rotations, all possible set combinations are generated and tried out. When a union of two rotation-sets is non-negative, it is taken as the basis for new possible combinations. In the end, the largest number of rotations that produce a non-negative result when taken together is returned as the optimized scenario. @@ -96,7 +95,7 @@ or mode = ["sim","neg_depb_to_oppb", "station_optimization", "report"] While the first call optimizes the scenario straight away trying to electrify all opportunity chargers, the second call, changes depot chargers to opportunity chargers, if they were not able to finish their rotations in the first simulation run. This way the second approach can lead to a higher degree of electrification for the system. -The network with no opportunity charging station is first analyzed to find rotations which fail at the current stage and to estimate the potential of electrifying each station by its own. *Step-by-step* new opportunity stations are electrified until full electrification is reached. The optimization assumes that at every electrified station unlimited charging points exist, i.e. the number of simultaneously charging buses is not limited. In between each electrification a simulation is run and the network is analyzed again. The first run called the **base optimization** leads to a scenario which often times is better than extensively optimizing the scenario by hand. Since a greedy approach can not guarantee a global optimum a second extensive optimization can be chained to this base optimization. This *deep* optimization can make use of a *step-by-step* decision tree expansion which evaluates new combinations of electrified stations starting with the most promising combinations **OR** use a *brute* force approach trying to reduce the amount of electrified stations by one in comparison to the base optimization. The step-by-step process of the optimization follows :numref:`optimization_loop` +The network with no opportunity charging station is first analyzed to find rotations which fail at the current stage and to estimate the potential of electrifying each station by its own. *Step-by-step* new opportunity stations are electrified until full electrification is reached. The optimization assumes that at every newly electrified station unlimited charging points exist, i.e. the number of simultaneously charging buses is not limited. In between each electrification a simulation is run and the network is analyzed again. The first run called the **base optimization** leads to a scenario which often times is better than extensively optimizing the scenario by hand. Since a greedy approach can not guarantee a global optimum a second extensive optimization can be chained to this base optimization. This *deep* optimization can make use of a *step-by-step* decision tree expansion which evaluates new combinations of electrified stations starting with the most promising combinations **OR** use a *brute* force approach trying to reduce the amount of electrified stations by one in comparison to the base optimization. The step-by-step process of the optimization follows :numref:`optimization_loop` .. _optimization_loop: .. figure:: https://user-images.githubusercontent.com/104760879/217225177-66201146-d31a-4127-9ca0-4d6e6e5a3cc4.png @@ -114,19 +113,19 @@ After a single simulation is run the rotations are analyzed. Any time a vehicle Low SoC event and classification of stations. -The next step groups low SoC events based on the stations which were found earlier. Events which share at least one station could possibly interact with each other, e.g. vehicles could share a charging station. Therefore groups are build which do not share any stations in between groups. This speeds up the optimization process since for every electrification and simulation only rotations are calculated which could be impacted by the change. +The next step groups low SoC events based on the stations which were found earlier. Events which share at least one station could possibly interact with each other, e.g. vehicles could share a charging station. Therefore, groups are build which do not share any stations in between groups. This speeds up the optimization process since for every electrification and simulation only rotations are calculated which could be impacted by the change. -Since greedy approaches execute the step which seems most promising in the current situation an evaluation function is needed. One possible approach could be to simulate each scenario, meaning simulating every case in which one of all possible stations is electrified and continuing with the best case. The optimizer does not use this approach. Instead an approximation function is used to evaluate the potential of electrifying a station. This approximation function analyzes the duration at each stop, the possible charging time, the SoC and resulting possible charging power (battery with high SoCs are charged at a lower rate) as well as the upper SoC threshold and minimal SoC of the event. While this methodology is not accurate in all cases, e.g. a station could exist multiple times inside of a low SoC event, therefore charging the first time at this station would alter the SoC and charging power the vehicle has the second time it reaches the station, it seems well suited as heuristic for choosing the most promising station. The objective function of choosing what the *best* station is, is the mitigation of missing charge, i.e. what is the minimal amount of energy that needs to be inserted into the battery, so that no SoC is below 0. +Since greedy approaches execute the step which seems most promising in the current situation an evaluation function is needed. One possible approach could be to simulate each scenario, meaning simulating every case in which one of all possible stations is electrified and continuing with the best case. The optimizer does not use this approach. Instead, an approximation function is used to evaluate the potential of electrifying a station. This approximation function analyzes the duration at each stop, the possible charging time, the SoC and resulting possible charging power (in general batteries with high SoCs are charged at a lower rate) as well as the upper SoC threshold and minimal SoC of the event. While this methodology is not accurate in all cases, e.g. a station could exist multiple times inside a low SoC event, therefore charging the first time at this station would alter the SoC and charging power the vehicle has the second time it reaches the station, it seems well suited as heuristic for choosing the most promising station. The objective function of choosing what the *best* station is, is the mitigation of missing charge, i.e. what is the minimal amount of energy that needs to be inserted into the battery, so that no SoC is below 0. -After the evaluation selected a station to be electrified the scenario input data is altered so that vehicles at this station are charged without limitation of charging points. This is followed up by a detailed simulation which can make use of a highly accurate solver for charging events called *SpiceEV* or a less accurate but faster solver. Now the resulting system has less missing charge and the potentials of stations might be decreased. Also a single group might have been split up into several smaller groups which can be analyzed even quicker. Therefore the loop repeats up until the point the missing charge in the system is zero or in other words the system is fully electrified. +After the evaluation selected a station to be electrified the scenario input data is altered so that vehicles at this station are charged without limitation of charging points. This is followed up by a detailed simulation which can make use of a highly accurate solver for charging events called *SpiceEV* or a less accurate but faster solver. Now the resulting system has less missing charge and the potentials of stations might be decreased. Also, a single group might have been split up into several smaller groups which can be analyzed even quicker. Therefore, the loop repeats up until the point the missing charge in the system is zero or in other words the system is fully electrified. At the current stage the scenario to be optimized needs depot charging stations at the start and end of each rotation. The scenario should not contain any opportunity charging stations. If for a given scenario opportunity charging stations are predefined, i.e. the scenario should contain a specific electrification and is set in the *electrified_station.json* the solver type *spice_ev* should be used in the *optimizer.cfg*. If the *quick* solver is supposed to be used the station can be listed in *inclusion_stations* while the *electrified_stations.json* should only contain depot stations. Stations can be also excluded from optimization by adding their name to *exclusion_stations*. Deep Optimization #################### -The greedy algorithm in the base optimization can not guarantee that the solution is the global optimum. This is why the use of the *deep* mode is recommended for systems with high requirements. After the first run, instead of electrifying the station with the highest potential the second best station is electrified. This is similar to a decision tree, where every node is a set of electrified stations, with the first node being zero stations electrified and the last node being all stations electrified. The nodes in between correlate with every possible state of electrification. Each branch therefore represents an additional electrification of a single station. The algorithm continues electrifying the best station, as long as this node has not been evaluated yet. This way gradually all possible nodes are checked. The search stops whenever the number of stations surpasses the number of the current optimal solution. If several options with the same optimal number of stations arise, they can be found in the log file of the optimizer, but only one file with optimized stations is produced. +The greedy algorithm in the base optimization can not guarantee that the solution is the global optimum. This is why the use of the *deep* mode is recommended for systems with high requirements. After the first run, instead of electrifying the station with the highest potential the second-best station is electrified. This is similar to a decision tree, where every node is a set of electrified stations, with the first node being zero stations electrified and the last node being all stations electrified. The nodes in between correlate with every possible state of electrification. Each branch therefore represents an additional electrification of a single station. The algorithm continues electrifying the best station, as long as this node has not been evaluated yet. This way gradually all possible nodes are checked. The search stops whenever the number of stations surpasses the number of the current optimal solution. If several options with the same optimal number of stations arise, they can be found in the log file of the optimizer, but only one file with optimized stations is produced. -**Pruning** is used to stop evaluation of branches, whenever foresight predicts that no better solution will be reached. This is done through the simple heuristic of checking the sum of potential of the n remaining stations with the highest potentials, with n being the number until the number of stations of the current optimal solution is reached. +**Pruning** is used to stop evaluation of branches, whenever foresight predicts that no better solution will be reached. This is done through the simple heuristic of checking the sum of potentials of the n remaining stations with the highest potentials, with n being the number until the number of stations of the current optimal solution is reached. | **Example:** | The base optimization found a set of 5 stations to fully electrify the scenario. These stations are *A*, *B*, *C*, *D* and *E* which were chosen in the same order. The whole scenario consists of the whole alphabet of stations. The deep optimization starts with evaluating a scenario without any electrified opportunity stations. Depot stations are electrified. The first evaluation gives a sorted list of potentials by @@ -159,17 +158,17 @@ For every vehicle the amount of missing energy is calculated and summed up. In t Pot = Pot_B + Pot_E + Pot_C + Pot_G = 28 + 25 + 20 +18 = 91 -In this case the potential is high enough to continue the exploration of this branch. If the potential would have been below 85 the branch would have been pruned, meaning it would not be explored any further and labeled as *not promising*. It is not promising since it will not lead to a better solution than the current one. This is the case since on one hand the evaluation by approximation tends to overestimate the potential while the missing energy is accurately calculated and on the other hand electrification of stations can reduce the potential of other stations, for example if 2 stations charge the same rotation, electrifying one station might fully electrify the rotation meaning the potential of the other station drops to zero. +In this case the potential is high enough to continue the exploration of this branch. If the potential had been below 85 the branch would have been pruned, meaning it would not be explored any further and labeled as *not promising*. It is not promising since it will not lead to a better solution than the current one. This is the case since on one hand the evaluation by approximation tends to overestimate the potential while the missing energy is accurately calculated and on the other hand electrification of stations can reduce the potential of other stations, for example if 2 stations charge the same rotation, electrifying one station might fully electrify the rotation meaning the potential of the other station drops to zero. This concept can reduce the amount of nodes which have to be checked. Other Optimization Functionality ################################### -**Mandatory stations** can be attained to increase the optimization process. Mandatory stations are defined by being stations which are needed for a fully electrified system. To check if a station *Y* is a mandatory station can be easily attained by simulating the network with every station electrified except *Y*. If the system has vehicle SoCs which drop below the minimal SoC (default value is 0) in this scenario, the station is mandatory. In the later exploration of best combinations of stations this station will be included in any case. +**Mandatory stations** can be attained to increase the speed of the optimization process. Mandatory stations are defined by being stations which are needed for a fully electrified system. To check if a station *Y* is mandatory the network with every station electrified except *Y* is simulated. If the system has vehicle SoCs which drop below the minimal SoC (default value is 0) in this scenario, the station is mandatory. In the later exploration of the best combinations of stations this station will be included in every case. **Impossible rotations** are rotations which given the settings are not possible to be run as opportunity chargers, given the vehicle properties, even when every station is electrified. Before starting an optimization it is recommended to remove these rotations from the optimization, since the optimizer will not reach the goal of full electrification. **Quick solver** -Instead of using the regular SpiceEV solver for optimization the user can also choose the *quick* solver. This approximates the SoC history of a vehicle by straight manipulation of the SoC data and numeric approximations of the charged energy. Therefore small differences between solving a scenario with SpiceEV and the quick solver exist. For the quick solver to work, some assumptions have to be met as well +Instead of using the regular SpiceEV solver for optimization the user can also choose the *quick* solver. This approximates the SoC history of a vehicle by straight manipulation of the SoC data and numeric approximations of the charged energy. Therefore, small differences between solving a scenario with SpiceEV and the quick solver exist. For the quick solver to work, some assumptions have to be met as well * Depots charge the vehicles to 100% SoC * Station electrification leads to unlimited charging points @@ -198,7 +197,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 the SimBA. +The functionality of the optimizer is controlled through the optimizer.cfg specified in the simba.cfg used for calling SimBA. .. list-table:: Optimizer.cfg parameters :header-rows: 1 @@ -210,7 +209,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci * - debug_level - 1 - 1 to 99 - - Level of debugging information that is printed to the .log file between. debug_level = 1 prints everything + - Level of debugging information that is printed to the .log file. debug_level = 1 prints everything * - console_level - 99 - 1 to 99 @@ -278,7 +277,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci * - pruning_threshold - 3 - positive integer value - - Number of stations left until number of stations in optimal solution is reached,where pruning is activated. Calculation time of checking for pruning is not negligible, meaning that a lot of pruning checks (high pruning threshold, e.g. 99) lead to slower optimization. Low values will rarely check for pruning but also pruning will be rarely achieved + - Number of stations left until number of stations in optimal solution is reached,where pruning is activated. Calculation time of checking for pruning is not negligible, meaning that a lot of pruning checks (high pruning threshold, e.g. 99) lead to slower optimization. Low values will rarely check for pruning but also pruning will rarely be achieved * - opt_type - greedy - [greedy, deep] @@ -322,7 +321,7 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci Report ------ -The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Please refer to :ref:`generate_report` for more datailed information. +The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Please refer to :ref:`generate_report` for more detailed information. diff --git a/docs/source/simba_features.rst b/docs/source/simba_features.rst index 479d677c..b18878b3 100644 --- a/docs/source/simba_features.rst +++ b/docs/source/simba_features.rst @@ -9,9 +9,9 @@ Consumption analysis The consumption can be calculated in two ways: Either with a constant average specific consumption or using a consumption table, where the consumption depends on the temperature, the incline, the level of loading and the speed profile/ average speed. -To use a constant consumption, this value can be defined in the :ref:`vehicle_types` as "mileage" in the unit of [kWh/km]. To use the relative consumtion, a consumption table need to be created with data for each vehicle type and the path to the consumption table is assigned to the variable "mileage" in :ref:`vehicle_types`. The consumption table should have the columns "vehicle_type", "level_of_loading", "incline" ,"mean_speed_kmh", "t_amb", "consumption_kwh_per_km" and its creation is at ths point of development not part of SimBA. +To use a constant consumption, this value can be defined in the :ref:`vehicle_types` as "mileage" in the unit of [kWh/km]. To use the relative consumption, a consumption table needs to be created with data for each vehicle type and the path to the consumption table is assigned to the variable "mileage" in :ref:`vehicle_types`. The consumption table should have the columns "vehicle_type", "level_of_loading", "incline" ,"mean_speed_kmh", "t_amb", "consumption_kwh_per_km" and its creation is at ths point of development not part of SimBA. -The level_of_loading describes the share between an empty vehicle (0) and a fully loaded vehicle (1) can be handed over in two ways: Either directcly as a column in :ref:`schedule` with specific values for each individual trip or as an input file "default_level_of_loading.csv" (path defined in :ref:`config`) containing values for each hour of the day. SimBA will first look into schedule and take this value and if it is not defined take the one from the .csv file. The temperature information is obtained in the same way as the level of loading and should be given in °C. In Order to calculate the consumption based on the in incline, an extra "all_stations.csv" file (path defined in :ref:`config`) has to be provided containing information on the elevation in m of each station. The incline is then calculated as the average incline between start and stop of the trip, which is an assumption that creates good results for vehicles with recuperation technology, as most electric vehicles have. The mean speed is calculated using the information provided in :ref:`schedule` about duration and length of each trip. +The level_of_loading describes the share between an empty vehicle (0) and a fully loaded vehicle (1) and can be handed over in two ways: Either directly as a column in :ref:`schedule` with specific values for each individual trip or as an input file "default_level_of_loading.csv" (path defined in :ref:`config`) containing values for each hour of the day. SimBA will first look into schedule and take this value and if it is not defined take the one from the .csv file. The temperature information is obtained in the same way as the level of loading and should be given in °C. In order to calculate the consumption based on the incline, an extra "all_stations.csv" file (path defined in :ref:`config`) has to be provided containing information on the elevation in m of each station. The incline is then calculated as the average incline between start and stop of the trip, which is an assumption that creates good results for vehicles with recuperation technology, as most electric vehicles have. The mean speed is calculated using the information provided in :ref:`schedule` about duration and length of each trip. .. _vehicle_dispatch: @@ -19,19 +19,19 @@ The level_of_loading describes the share between an empty vehicle (0) and a full Vehicle Dispatch ---------------- -To allocate the rotations to vehicles, vehicles of the needed type to fulfil the rotation are used. If no suitable vehicle is available, a new vehicle is created. Available vehilces are defined as not currently serving a rotation, having the same depot and having had enough time after return to the depot to be fully charged, when returning with an empty battery. This "minimum standing time" at the depot is calculated using the variable min_recharge_deps_oppb or min_recharge_deps_depb from the config together with the respective battery capacity of the vehicle and assuming the maximum available power of the depot chargning stations. +To allocate the rotations to vehicles, vehicles of the needed type to fulfil the rotation are used. If no suitable vehicle is available, a new vehicle is created. Available vehicles are defined as not currently serving a rotation, having the same depot and having had enough time after return to the depot to be fully charged, when returning with an empty battery. This "minimum standing time" at the depot is calculated using the variable min_recharge_deps_oppb or min_recharge_deps_depb from the config together with the respective battery capacity of the vehicle and assuming the maximum available power of the depot charging stations. Charging simulation ------------------- -The charging simulation is carried out in the open source software `SpiceEV `_, that is included in SimBA as a package. SimBA therefore uses SpiceEVs carging strategy "distributed", that allows to sepatarte the charging strategy depending on the station type. The station types can be either depot charging station (deps) or opportunity charging station (opps). At depot charging stations vehicles are being charged using SpiceEVs strategy "balanced", which uses the whole standing time to charge with the minimal power to reach a desired SoC. At opportunity charging stations the strategy "greedy" is employed, that charges with the maximum available power due to restrictions from the grid connectoion, the charging curve of the vehicle and the charging station. +The charging simulation is carried out in the open source software `SpiceEV `_, that is included in SimBA as a package. SimBA therefore uses SpiceEVs charging strategy "distributed", that allows to separate the charging strategy depending on the station type. The station types can be either depot charging station (deps) or opportunity charging station (opps). At depot charging stations vehicles are being charged using SpiceEVs strategy "balanced", which uses the whole standing time to charge with the minimal power to reach a desired SoC. At opportunity charging stations the strategy "greedy" is employed, that charges with the maximum available power due to restrictions from the grid connection, the charging curve of the vehicle and the charging station. .. _generate_report: Generate report --------------- -The generation of the report is implemented as a mode, that can be activated with the keyword "report" in modes (:ref:`report`). The report generates most of the output files. These are saved in a subfolder of the output directory as defined in :ref:`config` named as a string with the modes executed up to the point when report is called. e.g. mode = ['sim', 'report', 'neg_oppb_to_depb', 'report'] will create two subfolders in the output directory named "sim" and "sim__neg_oppb_to_depb" containing the output files for the respective times in simulation. +The generation of the report is implemented as a mode, that can be activated with the keyword "report" in modes (:ref:`report`). The report generates most of the output files. These are saved in a sub-folder of the output directory as defined in :ref:`config` named as a string with the modes executed up to the point when report is called. e.g. mode = ['sim', 'report', 'neg_oppb_to_depb', 'report'] will create two sub-folders in the output directory named "sim" and "sim__neg_oppb_to_depb" containing the output files for the respective times in simulation. The generation of the report can be modified using the flag "cost_calculation" in :ref:`config`. If this flag is set to true, each report will also generate the file "summary_vehicles_costs.csv". @@ -63,7 +63,7 @@ Default outputs | Contains station specific time series including price of electricity, grid supply, fixed loads, battery power, energy stored in battery, flex band boundaries, battery feed, charging station power use, occupied charging stations and charging stations in use as well as vehicles which are at the station. | **Overview on costs and vehicles (summary_vehicles_costs.csv)** -| If colst_caluclation is activated, this file contains the cost report as described below in :ref:`cost_calculation`. +| If cost_calculation is activated, this file contains the cost report as described below in :ref:`cost_calculation`. .. _cost_calculation: @@ -74,13 +74,13 @@ Cost calculation | The following costs are calculated as both total and annual, depending on the lifetime of each component. See `SpiceEV documentation `_ for the calculation of electricity costs. * Investment - * **Busses**: Costs for all busses used in the simulation. Costs include battery swaps, depending on the lifetime of both busses and batteries. + * **Buses**: Costs for all buses used in the simulation. Costs include battery swaps, depending on the lifetime of both buses and batteries. * **Charging infrastructure**: Costs for all depot and opportunity charging stations, depending on the number of actually used charging stations at each grid connector. * **Grid connectors**: Costs for grid connectors and transformers, depending on the voltage level and the distance to the grid. * **Garages**: Costs for workstations and charging infrastructure at garages. * **Stationary storages**: Costs for stationary batteries at depot and opportunity stations, depending on its capacity. * Maintenance - * Depending on the lifetime of each component maintenance costs are calculated for busses, charging infrastructure, grid connectors and stationary storages. + * Depending on the lifetime of each component maintenance costs are calculated for buses, charging infrastructure, grid connectors and stationary storages. * Electricity * **Power procurement**: Costs for the procurement of energy. * **Grid fees**: Costs for power and energy price, depending on the voltage level and the utilization time per year. @@ -169,7 +169,7 @@ SimBA makes certain assumption, that have to be valid to trust the results. thes * Each rotation has a defined and fixed depot, so the rotation starts and ends at the same station * Every trip within a rotation starts where the previous trip ended -In order to test these assumptions, the flag "check_rotation_consistency" can be activated in the :ref:`config`, which will result in the display of cases were assumptions are broken in the console and in the log file. Additionally the inconsistent totaions can be filtered out of the simulation by setting the "skip_inconsistent_rotations" flag to true. +In order to test these assumptions, the flag "check_rotation_consistency" can be activated in the :ref:`config`, which will result in the display of cases where assumptions are broken in the console and in the log file. Additionally, the inconsistent rotations can be filtered out of the simulation by setting the "skip_inconsistent_rotations" flag to true. .. _rotation_filter: @@ -177,9 +177,9 @@ In order to test these assumptions, the flag "check_rotation_consistency" can be Rotation filter --------------- -Before all rotations specified in the :ref:`schedule` are simulated, there is the option to filter only the ones relevant to for the actual analysis. This is activated by setting the "rotation_filter_variable" in the :ref:`config` to either "include", than only certain rotations from the schedule are considered, or to "exclude", than certain rotations are excluded from the analysis. The list of rotations for both options is specified as "rotation_filter" in the Path paragraph of the :ref:`config`. +Before all rotations specified in the :ref:`schedule` are simulated, there is the option to filter only the ones relevant to for the actual analysis. This is activated by setting the "rotation_filter_variable" in the :ref:`config` to either "include" to consider only certain rotations from the schedule, or to "exclude" to exclude certain rotations from the analysis. The list of rotations for both options is specified as "rotation_filter" in the Path paragraph of the :ref:`config`. Logging ------- -SimBA uses the "logging" package for logging. All logging messages are both displayed in the Terminal and written to a .log file. The filepath and the loglevel can be defined in the :ref:`config`. Four loglevels are available in the following order: DEBUG, INFO, WARN and ERROR. INFO includes INFO, WARN and ERROR but excludes DEBUG. \ No newline at end of file +SimBA uses the "logging" package for logging. All logging messages are both displayed in the Terminal and written to a .log file. The filepath and the loglevel can be defined in the :ref:`config`. Four log levels are available in the following order: DEBUG, INFO, WARN and ERROR. INFO includes INFO, WARN and ERROR but excludes DEBUG. \ No newline at end of file diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index 78a63d87..e1d75e76 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -20,7 +20,7 @@ The configuration file config.cfg is provided as example in ./examples/ and prov | Modes: Here the modes of execution can be defined | Flags: Here, optional functionality can be activated or deactivated | Physical setup of environment: Here, the physical setup is characterized -| Simulation Parameters: The simulation can be adjusted using these paramteres +| 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: @@ -33,35 +33,35 @@ The example (data/simba.cfg) contains parameter descriptions which are explained - Description * - input_schedule - Mandatory: no default given - - path as string + - Path as string - Input file containing :ref:`schedule` information - * - output_directory - - data/sim_outputs - - path as string + * - Output_directory + - Data/sim_outputs + - Path as string - Output files are stored here * - electrified_stations - ./data/examples/vehicle_types.json - - path as string + - Path as string - Path to Electrified stations data * - vehicle_types - ./data/examples/vehicle_types.json - - path as string + - Path as string - Path to :ref:`vehicle_types` * - station_data_path - Optional: no default given - - path as string + - Path as string - Path to :ref:`station_geo_data` * - outside_temperature_over_day_path - Optional: no default given - - path as string + - Path as string - Path to :ref:`temperature_data` * - level_of_loading_over_day_path - Optional: no default given - - path as string + - Path as string - Path to :ref:`level_of_loading` * - cost_parameters_file - Optional: no default given - - path as string + - Path as string - Path to :ref:`cost_params` * - mode - ['sim', 'report'] @@ -78,7 +78,7 @@ The example (data/simba.cfg) contains parameter descriptions which are explained * - skip_inconsistent_rotations - false - Boolean - - If check_rotation_consistency is active, rotations that don't comply with the checked assumtions are removed from the schedule if skip_inconsistent_rotations is set true + - If check_rotation_consistency is active, rotations that don't comply with the checked assumptions are removed from the schedule if skip_inconsistent_rotations is set true * - show_plots - false - Boolean @@ -91,23 +91,23 @@ The example (data/simba.cfg) contains parameter descriptions which are explained * - gc_power_opps - 100000 - Numeric - - Default max power [kW] of grid connectors at opportunity charging stations, Individual gc_power per gc can be defined in :ref:`electrified_stations` + - Default max. power [kW] of grid connectors at opportunity charging stations, Individual gc_power per gc can be defined in :ref:`electrified_stations` * - gc_power_deps - 100000 - Numeric - - Default max power [kW] of grid connectors at depot charging stations, Individual gc_power per gc can be defined in :ref:`electrified_stations` + - Default max. power [kW] of grid connectors at depot charging stations, Individual gc_power per gc can be defined in :ref:`electrified_stations` * - cs_power_opps - 300 - Numeric - - Default max power [kW] of opportunity charging stations + - Default max. power [kW] of opportunity charging stations * - cs_power_deps_depb - 300 - Numeric - - Default max power [kW] of depot charging stations for depot charging busses. Individual cs_power per gc and cs type can be defined in :ref:`electrified_stations` + - Default max. power [kW] of depot charging stations for depot charging buses. Individual cs_power per gc and cs type can be defined in :ref:`electrified_stations` * - cs_power_deps_oppb - 300 - Numeric - - Default max power [kW] of depot charging stations for opportunity charging busses. Individual cs_power per gc and cs type can be defined in :ref:`electrified_stations` + - Default max. power [kW] of depot charging stations for opportunity charging buses. Individual cs_power per gc and cs type can be defined in :ref:`electrified_stations` * - desired_soc_deps - 1 - 0...1 @@ -135,23 +135,23 @@ The example (data/simba.cfg) contains parameter descriptions which are explained * - default_voltage_level - MV - HV, HV/MV, MV, MV/LV, LV - - The default volage level is used, if no specific voltage level is defined per station in :ref:`electrified_stations`. It is used to calculate the costs. Choices describe high voltage (HV), transfomer between high and medium voltage (HV/MV), medium voltage MV, transfomer between medium and low voltage (MV/LV) and low voltage (LV) + - The default voltage level is used, if no specific voltage level is defined per station in :ref:`electrified_stations`. It is used to calculate the costs. Choices describe high voltage (HV), transformer between high and medium voltage (HV/MV), medium voltage MV, transformer between medium and low voltage (MV/LV) and low voltage (LV) * - days - Optional: no default given - - numeric + - Numeric - If this value is defined only the first number of 'days' of the schedule are simulated * - interval - 1 - - numeric - - timestep in minutes + - Numeric + - Timestep in minutes * - signal_time_dif - 10 - - numeric - - Some strategies use limited foresight. E.g. priorization of vehicles at limited number of charging stations is carried out only for this time ahead of actual time step. Also used in spiceEV as time difference between signal time and actual start time of a vehicle event in min. + - Numeric + - Some strategies use limited foresight. E.g. prioritization of vehicles at limited number of charging stations is carried out only for this time ahead of actual time step. Also used in spiceEV as time difference between signal time and actual start time of a vehicle event in min. * - eta - false - - boolen + - Boolean - Show estimated time to finish simulation after each step. Not recommended for fast computations From c0e1caaf7688a8e1122e07bb0eb66280ecee4541 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Tue, 8 Aug 2023 10:18:25 +0200 Subject: [PATCH 46/58] still wip: doku sim_params --- data/examples/electrified_stations.json | 36 +++---- data/examples/trips_example.csv | 130 ++++++++++++------------ data/examples/vehicle_types.json | 20 ++-- docs/source/getting_started.rst | 2 +- docs/source/modes.rst | 11 +- docs/source/simba_features.rst | 6 +- docs/source/simulation_parameters.rst | 35 ++++++- 7 files changed, 130 insertions(+), 110 deletions(-) diff --git a/data/examples/electrified_stations.json b/data/examples/electrified_stations.json index 62d27a90..c8755001 100644 --- a/data/examples/electrified_stations.json +++ b/data/examples/electrified_stations.json @@ -1,24 +1,24 @@ { - "Station-0": { - "type": "deps", - "n_charging_stations": null, - "distance_to_grid": 150, - "energy_feed_in": { - "csv_file": "data/examples/example_pv_feedin.csv", - "start_time": "2022-03-07T00:00:00", - "step_duration_s": 3600, - "column": "Feed-in Total (kW)", - "nominal_power": 10, - "factor": 1 + "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, // distance to grid, needed for cost calculation + "energy_feed_in": { // energy feed in e.g. by local renewables + "csv_file": "data/examples/example_pv_feedin.csv", // path to feedin.csv + "start_time": "2022-03-07T00:00:00", // start time as YYYY-MM-DDThh:mm:ss + "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 PV remuneration + "factor": 1 // factor to multiply column values, eg 0.001 for conversion from W to kW }, - "external_load": { - "csv_file": "data/examples/example_external_load.csv", - "start_time": "2022-03-07T00:00:00", - "step_duration_s": 900, - "column": "External Load (kW)", - "factor": 2 + "external_load": { // local external loads + "csv_file": "data/examples/example_external_load.csv", // path to feedin.csv + "start_time": "2022-03-07T00:00:00", // start time as YYYY-MM-DDThh:mm:ss + "step_duration_s": 900, // 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 }, - "battery": { + "battery": { // 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 diff --git a/data/examples/trips_example.csv b/data/examples/trips_example.csv index 4036a2c2..a08c3e83 100644 --- a/data/examples/trips_example.csv +++ b/data/examples/trips_example.csv @@ -1,65 +1,65 @@ -line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading -LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0 -LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9 -LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,, -LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,, -LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,, -LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,, -LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,, -LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,, -LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,, -LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,, -LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,, -LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,, -LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,, -LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,, -LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,, -LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,, -LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,, -LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,, -LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,, -LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,, -LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,, -LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,, -LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,, -LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,, -LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,, -LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,, -LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,, -LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,, -LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,, -LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,, -LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,, -LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,, -LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,, -LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,, -LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,, -LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,, -LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,, -LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,, -LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,, -LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,, -LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,, -LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,, -LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,, -LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,, -LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,, -LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,, -LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,, -LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,, -LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,, -LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,, -LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,, -LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,, -LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,, -LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,, -LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,, \ No newline at end of file +line,departure_name,departure_time,arrival_time,arrival_name,distance,pause,rotation_id,vehicle_type,temperature,level_of_loading,charging_type +LINE_0,Station-0,2022-03-07 21:31:00,2022-03-07 21:31:00,Station-1,0.06,0,1,AB,20,0,oppb +LINE_0,Station-1,2022-03-07 21:31:00,2022-03-07 22:04:00,Station-2,14519,4,1,AB,-5,0.9,oppb +LINE_0,Station-2,2022-03-07 22:08:00,2022-03-07 22:43:00,Station-1,13541,8,1,AB,,,oppb +LINE_0,Station-1,2022-03-07 22:51:00,2022-03-07 23:24:00,Station-2,14519,4,1,AB,,,oppb +LINE_0,Station-2,2022-03-07 23:28:00,2022-03-08 00:03:00,Station-1,13541,8,1,AB,,,oppb +LINE_0,Station-1,2022-03-08 00:11:00,2022-03-08 00:44:00,Station-2,14519,0,1,AB,,,oppb +LINE_1,Station-2,2022-03-08 00:44:00,2022-03-08 00:54:00,Station-3,4.1,25,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 01:19:00,2022-03-08 01:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 01:48:00,2022-03-08 02:06:00,Station-3,9067,13,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 02:19:00,2022-03-08 02:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 02:48:00,2022-03-08 03:06:00,Station-3,9067,13,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 03:19:00,2022-03-08 03:42:00,Station-4,8.36,6,1,AB,,,oppb +LINE_1,Station-4,2022-03-08 03:48:00,2022-03-08 04:06:00,Station-3,9067,0,1,AB,,,oppb +LINE_1,Station-3,2022-03-08 04:06:00,2022-03-08 04:06:00,Station-0,0.06,0,1,AB,,,oppb +LINE_0,Station-0,2022-03-07 22:11:00,2022-03-07 22:11:00,Station-1,0.06,0,2,AB,,, +LINE_0,Station-1,2022-03-07 22:11:00,2022-03-07 22:44:00,Station-2,14519,4,2,AB,,, +LINE_0,Station-2,2022-03-07 22:48:00,2022-03-07 23:23:00,Station-1,13541,8,2,AB,,, +LINE_0,Station-1,2022-03-07 23:31:00,2022-03-08 00:04:00,Station-2,14519,4,2,AB,,, +LINE_0,Station-2,2022-03-08 00:08:00,2022-03-08 00:39:00,Station-5,12213,0,2,AB,,, +LINE_1,Station-5,2022-03-08 00:39:00,2022-03-08 00:47:00,Station-3,4.0,2,2,AB,,, +LINE_1,Station-3,2022-03-08 00:49:00,2022-03-08 01:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 01:18:00,2022-03-08 01:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 01:49:00,2022-03-08 02:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 02:18:00,2022-03-08 02:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 02:49:00,2022-03-08 03:12:00,Station-4,8.36,6,2,AB,,, +LINE_1,Station-4,2022-03-08 03:18:00,2022-03-08 03:36:00,Station-3,9067,13,2,AB,,, +LINE_1,Station-3,2022-03-08 03:49:00,2022-03-08 04:12:00,Station-4,8.36,0,2,AB,,, +LINE_1,Station-4,2022-03-08 04:12:00,2022-03-08 04:12:00,Station-0,0.06,0,2,AB,,, +LINE_2,Station-0,2022-03-07 21:06:00,2022-03-07 21:06:00,Station-6,0.06,0,3,AB,,, +LINE_2,Station-6,2022-03-07 21:06:00,2022-03-07 21:34:00,Station-7,13018,19,3,AB,,, +LINE_2,Station-7,2022-03-07 21:53:00,2022-03-07 22:13:00,Station-8,10332,17,3,AB,,, +LINE_2,Station-8,2022-03-07 22:30:00,2022-03-07 22:54:00,Station-7,10.48,19,3,AB,,, +LINE_2,Station-7,2022-03-07 23:13:00,2022-03-07 23:33:00,Station-8,10332,17,3,AB,,, +LINE_2,Station-8,2022-03-07 23:50:00,2022-03-08 00:14:00,Station-7,10.48,2,3,AB,,, +LINE_2,Station-7,2022-03-08 00:16:00,2022-03-08 00:23:00,Station-9,3709,5,3,AB,,, +LINE_3,Station-9,2022-03-08 00:28:00,2022-03-08 00:44:00,Station-10,6404,3,3,AB,,, +LINE_3,Station-10,2022-03-08 00:47:00,2022-03-08 01:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 01:17:00,2022-03-08 01:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 01:47:00,2022-03-08 02:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 02:17:00,2022-03-08 02:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 02:47:00,2022-03-08 03:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 03:17:00,2022-03-08 03:44:00,Station-10,12007,3,3,AB,,, +LINE_3,Station-10,2022-03-08 03:47:00,2022-03-08 04:10:00,Station-11,10579,7,3,AB,,, +LINE_3,Station-11,2022-03-08 04:17:00,2022-03-08 04:44:00,Station-10,12007,0,3,AB,,, +LINE_3,Station-10,2022-03-08 04:44:00,2022-03-08 04:44:00,Station-0,0.06,0,3,AB,,, +LINE_2,Station-0,2022-03-07 20:26:00,2022-03-07 20:26:00,Station-6,0.06,0,4,AB,,, +LINE_2,Station-6,2022-03-07 20:26:00,2022-03-07 20:56:00,Station-12,14097,14,4,AB,,, +LINE_2,Station-12,2022-03-07 21:10:00,2022-03-07 21:38:00,Station-6,13.19,8,4,AB,,, +LINE_2,Station-6,2022-03-07 21:46:00,2022-03-07 22:14:00,Station-7,13018,19,4,AB,,, +LINE_2,Station-7,2022-03-07 22:33:00,2022-03-07 22:53:00,Station-8,10332,17,4,AB,,, +LINE_2,Station-8,2022-03-07 23:10:00,2022-03-07 23:34:00,Station-7,10.48,19,4,AB,,, +LINE_2,Station-7,2022-03-07 23:53:00,2022-03-08 00:13:00,Station-8,10332,2,4,AB,,, +LINE_2,Station-8,2022-03-08 00:15:00,2022-03-08 00:16:00,Station-10,506,1,4,AB,,, +LINE_3,Station-10,2022-03-08 00:17:00,2022-03-08 00:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 00:47:00,2022-03-08 01:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 01:17:00,2022-03-08 01:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 01:47:00,2022-03-08 02:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 02:17:00,2022-03-08 02:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 02:47:00,2022-03-08 03:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 03:17:00,2022-03-08 03:40:00,Station-11,10579,7,4,AB,,, +LINE_3,Station-11,2022-03-08 03:47:00,2022-03-08 04:14:00,Station-10,12007,3,4,AB,,, +LINE_3,Station-10,2022-03-08 04:17:00,2022-03-08 04:40:00,Station-11,10579,3,4,AB,,, +LINE_4,Station-11,2022-03-08 04:43:00,2022-03-08 04:58:00,Station-13,6161,0,4,AB,,, +LINE_4,Station-13,2022-03-08 04:58:00,2022-03-08 04:58:00,Station-0,0.06,0,4,AB,,, \ No newline at end of file diff --git a/data/examples/vehicle_types.json b/data/examples/vehicle_types.json index cba0ff05..912e4978 100644 --- a/data/examples/vehicle_types.json +++ b/data/examples/vehicle_types.json @@ -1,12 +1,12 @@ { - "AB": { - "depb": { - "name": "articulated bus - depot charging", - "capacity": 250, - "charging_curve": [[0, 150], [0.8, 150], [1, 15]], - "min_charging_power": 0, - "v2g": false, - "mileage": "data/examples/energy_consumption_example.csv", + "AB": { // vehicle_type + "depb": { // charging_type + "name": "articulated bus - depot charging", // long name + "capacity": 250, // battery capacity in kWh + "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 "battery_efficiency": 0.95 // optional. default: 0.95 }, "oppb": { @@ -25,7 +25,7 @@ "charging_curve": [[0, 150], [0.8, 150], [1, 15]], "min_charging_power": 0, "v2g": false, - "mileage": "data/examples/energy_consumption_example.csv" + "mileage": 1.2 }, "oppb": { "name": "solo bus - opportunity charging", @@ -33,7 +33,7 @@ "charging_curve": [[0, 250], [0.8, 250], [1, 25]], "min_charging_power": 0, "v2g": false, - "mileage": "data/examples/energy_consumption_example.csv" + "mileage": 1.1 } } } diff --git a/docs/source/getting_started.rst b/docs/source/getting_started.rst index 5c230886..ad08e6eb 100644 --- a/docs/source/getting_started.rst +++ b/docs/source/getting_started.rst @@ -2,7 +2,7 @@ Getting Started =============== SimBA - the Simulation toolbox for Bus Applications - was designed to analyze and optimize electrified bus fleets. -It is used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and circulations, determining charging strategies, and calculating investments and costs. +It is used for locating and dimensioning charging infrastructure, dimensioning buses, analyzing the feasibility of electrification of trips and rotations, determining charging strategies, and calculating investments and costs. .. Without creating links like in the line below, subpages go missing from the sidebar .. _installation_label: diff --git a/docs/source/modes.rst b/docs/source/modes.rst index f3a00802..54b6fd6b 100644 --- a/docs/source/modes.rst +++ b/docs/source/modes.rst @@ -81,7 +81,7 @@ Station Optimization -------------------- Greedy Optimization #################### -This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. Two basic approaches to use the optimization module are setting the mode in the simba configuration file to +This mode optimizes a scenario by electrifying as few opportunity stations as possible using a greedy approach. Two basic approaches to use the optimization module are setting the mode in the SimBA configuration file to :: @@ -322,12 +322,3 @@ The functionality of the optimizer is controlled through the optimizer.cfg speci Report ------ The report will generate several files which include information about the expected SoCs, power loads at the charging stations or depots, default plots for the scenario and other useful data. Please refer to :ref:`generate_report` for more detailed information. - - - - - - - - - diff --git a/docs/source/simba_features.rst b/docs/source/simba_features.rst index b18878b3..a1515f69 100644 --- a/docs/source/simba_features.rst +++ b/docs/source/simba_features.rst @@ -7,9 +7,9 @@ Features of SimBA Consumption analysis -------------------- -The consumption can be calculated in two ways: Either with a constant average specific consumption or using a consumption table, where the consumption depends on the temperature, the incline, the level of loading and the speed profile/ average speed. +The consumption can be calculated in two ways: Either with a constant average specific consumption or with a trip specific consumption, where the consumption depends on the temperature, the incline, the level of loading and the average speed. -To use a constant consumption, this value can be defined in the :ref:`vehicle_types` as "mileage" in the unit of [kWh/km]. To use the relative consumption, a consumption table needs to be created with data for each vehicle type and the path to the consumption table is assigned to the variable "mileage" in :ref:`vehicle_types`. The consumption table should have the columns "vehicle_type", "level_of_loading", "incline" ,"mean_speed_kmh", "t_amb", "consumption_kwh_per_km" and its creation is at ths point of development not part of SimBA. +To use a constant consumption, this value can be defined in the :ref:`vehicle_types` as "mileage" in the unit of [kWh/km]. To use the trip specific consumption, a consumption table needs to be created with data for each vehicle type. The path to the consumption table is assigned to the variable "mileage" in :ref:`vehicle_types`. The consumption table should have the columns "vehicle_type", "level_of_loading", "incline" ,"mean_speed_kmh", "t_amb", "consumption_kwh_per_km" and its creation is at ths point of development not part of SimBA. The consumption for each trip is then calculated by interpolation of the datapoints provided in the table. The level_of_loading describes the share between an empty vehicle (0) and a fully loaded vehicle (1) and can be handed over in two ways: Either directly as a column in :ref:`schedule` with specific values for each individual trip or as an input file "default_level_of_loading.csv" (path defined in :ref:`config`) containing values for each hour of the day. SimBA will first look into schedule and take this value and if it is not defined take the one from the .csv file. The temperature information is obtained in the same way as the level of loading and should be given in °C. In order to calculate the consumption based on the incline, an extra "all_stations.csv" file (path defined in :ref:`config`) has to be provided containing information on the elevation in m of each station. The incline is then calculated as the average incline between start and stop of the trip, which is an assumption that creates good results for vehicles with recuperation technology, as most electric vehicles have. The mean speed is calculated using the information provided in :ref:`schedule` about duration and length of each trip. @@ -19,7 +19,7 @@ The level_of_loading describes the share between an empty vehicle (0) and a full Vehicle Dispatch ---------------- -To allocate the rotations to vehicles, vehicles of the needed type to fulfil the rotation are used. If no suitable vehicle is available, a new vehicle is created. Available vehicles are defined as not currently serving a rotation, having the same depot and having had enough time after return to the depot to be fully charged, when returning with an empty battery. This "minimum standing time" at the depot is calculated using the variable min_recharge_deps_oppb or min_recharge_deps_depb from the config together with the respective battery capacity of the vehicle and assuming the maximum available power of the depot charging stations. +To allocate the rotations to vehicles, vehicles of the needed type to fulfil the rotation are used. If no suitable vehicle is available, a new vehicle is created. A vehicle is defined as "available" if it is currently not serving another rotation, has the same depot and if it had enough time after return to the depot to be charged. This "minimum standing time" at the depot is calculated using the variable min_recharge_deps_oppb or min_recharge_deps_depb from the :ref`config` together with the respective battery capacity of the vehicle and assuming the maximum available power of the depot charging stations. Charging simulation ------------------- diff --git a/docs/source/simulation_parameters.rst b/docs/source/simulation_parameters.rst index e1d75e76..abcbba77 100644 --- a/docs/source/simulation_parameters.rst +++ b/docs/source/simulation_parameters.rst @@ -231,14 +231,43 @@ This is how a schedule file might look like. Vehicle types ------------- -vehicle_type.json -tbc + +The vehicle types that can be used are defined in the "vehicle_type.json". The path to this file has to be defined in the :ref:`config` and an example is given at `data/examples/vehicle_types.json`. + +The data is structured as a .json where the top level key represents the vehicle_type, that needs to correspont to the "vehicle_type" defined in the :ref:`schedule`. The next level key defines the charging_type ("oppb" or "depb"). For one vehicle type either one or both charging types can be defined and for each given charging type the specifications in the third level of the .json have to be given. In this level, the parameters for the specified vehicle are be defined. The specification of one vehicle with the vehicle_type "AB" and the charging_types "depb" and "oppb" is given as follows: + +.. code-block:: json + + { + "AB": { // vehicle_type + "depb": { // charging_type + "name": "articulated bus - depot charging", // long name + "capacity": 250, // battery capacity in kWh + "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 + "battery_efficiency": 0.95 // optional. default: 0.95 + }, + "oppb": { + "name": "articulated bus - opportunity charging", + "capacity": 150, + "charging_curve": [[0, 250], [0.8, 250], [1, 25]], + "min_charging_power": 0, + "v2g": false, + "mileage": "data/examples/energy_consumption_example.csv" + } + } + } .. _electrified_stations: Electrified stations -------------------- -Stations which are electrified. TBC + +All stations, that are or could be equipped with charging infrastructure have to be parameterized in the "electrified_stations.json" together with their grid connection, charging infrastructure and local energy systems. The path to this file has to be defined in the :ref:`config` and an example is given at `data/examples/electrified_stations.json`. + +TODO: HIER WEITER .. _cost_params: From 1e450e9b4391db2936620cc133806ab9e1393701 Mon Sep 17 00:00:00 2001 From: Julian Brendel Date: Wed, 9 Aug 2023 08:14:40 +0200 Subject: [PATCH 47/58] remove unneeded picture --- docs/source/_static/PyCharm_Configuration.png | Bin 69829 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/source/_static/PyCharm_Configuration.png diff --git a/docs/source/_static/PyCharm_Configuration.png b/docs/source/_static/PyCharm_Configuration.png deleted file mode 100644 index 8d42e3651376d5a8944eba4511a97ae7ae36c510..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 69829 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