safe transport demand in unit kinetic energy

This commit is contained in:
lisazeyen 2024-03-01 11:32:12 +01:00
parent 986c7be48e
commit b70aa59dce

View File

@ -19,13 +19,16 @@ logger = logging.getLogger(__name__)
def build_nodal_transport_data(fn, pop_layout): def build_nodal_transport_data(fn, pop_layout):
# get numbers of car and fuel efficieny per country
transport_data = pd.read_csv(fn, index_col=0) transport_data = pd.read_csv(fn, index_col=0)
# break number of cars down to nodal level based on population density
nodal_transport_data = transport_data.loc[pop_layout.ct].fillna(0.0) nodal_transport_data = transport_data.loc[pop_layout.ct].fillna(0.0)
nodal_transport_data.index = pop_layout.index nodal_transport_data.index = pop_layout.index
nodal_transport_data["number cars"] = ( nodal_transport_data["number cars"] = (
pop_layout["fraction"] * nodal_transport_data["number cars"] pop_layout["fraction"] * nodal_transport_data["number cars"]
) )
# fill missing fuel efficiency with average data
nodal_transport_data.loc[ nodal_transport_data.loc[
nodal_transport_data["average fuel efficiency"] == 0.0, nodal_transport_data["average fuel efficiency"] == 0.0,
"average fuel efficiency", "average fuel efficiency",
@ -35,10 +38,14 @@ def build_nodal_transport_data(fn, pop_layout):
def build_transport_demand(traffic_fn, airtemp_fn, nodes, nodal_transport_data): def build_transport_demand(traffic_fn, airtemp_fn, nodes, nodal_transport_data):
## Get overall demand curve for all vehicles """
returns transport demand per bus in unit kinetic energy.
traffic = pd.read_csv(traffic_fn, skiprows=2, usecols=["count"]).squeeze("columns") """
# averaged weekly counts from the year 2010-2015
traffic = pd.read_csv(traffic_fn, skiprows=2,
usecols=["count"]).squeeze("columns")
# create annual profile take account time zone + summer time
transport_shape = generate_periodic_profiles( transport_shape = generate_periodic_profiles(
dt_index=snapshots, dt_index=snapshots,
nodes=nodes, nodes=nodes,
@ -46,15 +53,6 @@ def build_transport_demand(traffic_fn, airtemp_fn, nodes, nodal_transport_data):
) )
transport_shape = transport_shape / transport_shape.sum() transport_shape = transport_shape / transport_shape.sum()
# electric motors are more efficient, so alter transport demand
plug_to_wheels_eta = options["bev_plug_to_wheel_efficiency"]
battery_to_wheels_eta = plug_to_wheels_eta * options["bev_charge_efficiency"]
efficiency_gain = (
nodal_transport_data["average fuel efficiency"] / battery_to_wheels_eta
)
# get heating demand for correction to demand time series # get heating demand for correction to demand time series
temperature = xr.open_dataarray(airtemp_fn).to_pandas() temperature = xr.open_dataarray(airtemp_fn).to_pandas()
@ -67,16 +65,8 @@ def build_transport_demand(traffic_fn, airtemp_fn, nodes, nodal_transport_data):
options["ICE_upper_degree_factor"], options["ICE_upper_degree_factor"],
) )
dd_EV = transport_degree_factor(
temperature,
options["transport_heating_deadband_lower"],
options["transport_heating_deadband_upper"],
options["EV_lower_degree_factor"],
options["EV_upper_degree_factor"],
)
# divide out the heating/cooling demand from ICE totals # divide out the heating/cooling demand from ICE totals
# and multiply back in the heating/cooling demand for EVs
ice_correction = (transport_shape * (1 + dd_ICE)).sum() / transport_shape.sum() ice_correction = (transport_shape * (1 + dd_ICE)).sum() / transport_shape.sum()
energy_totals_transport = ( energy_totals_transport = (
@ -87,8 +77,7 @@ def build_transport_demand(traffic_fn, airtemp_fn, nodes, nodal_transport_data):
return ( return (
(transport_shape.multiply(energy_totals_transport) * 1e6 * nyears) (transport_shape.multiply(energy_totals_transport) * 1e6 * nyears)
.divide(efficiency_gain * ice_correction) .divide(nodal_transport_data["average fuel efficiency"] * ice_correction)
.multiply(1 + dd_EV)
) )
@ -125,11 +114,14 @@ def bev_availability_profile(fn, snapshots, nodes, options):
""" """
Derive plugged-in availability for passenger electric vehicles. Derive plugged-in availability for passenger electric vehicles.
""" """
# car count in typical week
traffic = pd.read_csv(fn, skiprows=2, usecols=["count"]).squeeze("columns") traffic = pd.read_csv(fn, skiprows=2, usecols=["count"]).squeeze("columns")
# maximum share plugged-in availability for passenger electric vehicles
avail_max = options["bev_avail_max"] avail_max = options["bev_avail_max"]
# average share plugged-in availability for passenger electric vehicles
avail_mean = options["bev_avail_mean"] avail_mean = options["bev_avail_mean"]
# linear scaling, highest when traffic is lowest, decreases if traffic increases
avail = avail_max - (avail_max - avail_mean) * (traffic - traffic.min()) / ( avail = avail_max - (avail_max - avail_mean) * (traffic - traffic.min()) / (
traffic.mean() - traffic.min() traffic.mean() - traffic.min()
) )
@ -150,6 +142,8 @@ def bev_availability_profile(fn, snapshots, nodes, options):
def bev_dsm_profile(snapshots, nodes, options): def bev_dsm_profile(snapshots, nodes, options):
dsm_week = np.zeros((24 * 7,)) dsm_week = np.zeros((24 * 7,))
# assuming that at a certain time ("bev_dsm_restriction_time") EVs have to
# be charged to a minimum value (defined in bev_dsm_restriction_value)
dsm_week[(np.arange(0, 7, 1) * 24 + options["bev_dsm_restriction_time"])] = options[ dsm_week[(np.arange(0, 7, 1) * 24 + options["bev_dsm_restriction_time"])] = options[
"bev_dsm_restriction_value" "bev_dsm_restriction_value"
] ]
@ -160,7 +154,7 @@ def bev_dsm_profile(snapshots, nodes, options):
weekly_profile=dsm_week, weekly_profile=dsm_week,
) )
#%%
if __name__ == "__main__": if __name__ == "__main__":
if "snakemake" not in globals(): if "snakemake" not in globals():
from _helpers import mock_snakemake from _helpers import mock_snakemake
@ -168,7 +162,7 @@ if __name__ == "__main__":
snakemake = mock_snakemake( snakemake = mock_snakemake(
"build_transport_demand", "build_transport_demand",
simpl="", simpl="",
clusters=48, clusters=37,
) )
configure_logging(snakemake) configure_logging(snakemake)
set_scenario_config(snakemake) set_scenario_config(snakemake)