From 90e1d75df69cfa8bfdcd245f14929721cd4b4ff5 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Mon, 30 Nov 2020 16:20:26 +0100 Subject: [PATCH] land transport: allow share of fossil-FCEV-EV to change over time Allow share of land transport to be set exogenously in config.yaml. --- config.default.yaml | 26 +++-- scripts/prepare_sector_network.py | 170 ++++++++++++++++++------------ 2 files changed, 120 insertions(+), 76 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 024c0e10..26d34870 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -73,8 +73,8 @@ existing_capacities: sector: 'central' : True 'central_fraction' : 0.6 - 'dsm_restriction_value' : 0.75 #Set to 0 for no restriction on BEV DSM - 'dsm_restriction_time' : 7 #Time at which SOC of BEV has to be dsm_restriction_value + 'bev_dsm_restriction_value' : 0.75 #Set to 0 for no restriction on BEV DSM + 'bev_dsm_restriction_time' : 7 #Time at which SOC of BEV has to be dsm_restriction_value 'transport_heating_deadband_upper' : 20. 'transport_heating_deadband_lower' : 15. 'ICE_lower_degree_factor' : 0.375 #in per cent increase in fuel consumption per degree above deadband @@ -82,10 +82,22 @@ sector: 'EV_lower_degree_factor' : 0.98 'EV_upper_degree_factor' : 0.63 'district_heating_loss' : 0.15 - 'bev' : True #turns on EV battery + 'bev_dsm' : True #turns on EV battery 'bev_availability' : 0.5 #How many cars do smart charging 'v2g' : True #allows feed-in to grid from EV battery - 'transport_fuel_cell_share' : 0. #0 means all EVs, 1 means all FCs + #what is not EV or FCEV is fossil-fuelled + 'land_transport_fuel_cell_share': # 1 means all FCEVs + 2020: 0 + 2030: 0.05 + 2040: 0.1 + 2050: 0.15 + 'land_transport_electric_share': # 1 means all EVs + 2020: 0 + 2030: 0.25 + 2040: 0.6 + 2050: 0.85 + 'transport_fuel_cell_efficiency': 0.5 + 'transport_internal_combustion_efficiency': 0.3 'shipping_average_efficiency' : 0.4 #For conversion of fuel oil to propulsion in 2011 'time_dep_hp_cop' : True 'space_heating_fraction' : 1.0 #fraction of space heating active @@ -293,6 +305,7 @@ plotting: "Fischer-Tropsch" : "#44DD33" "kerosene for aviation": "#44BB11" "naphtha for industry" : "#44FF55" + "land transport fossil" : "#44DD33" "water tanks" : "#BBBBBB" "hot water storage" : "#BBBBBB" "hot water charging" : "#BBBBBB" @@ -304,7 +317,6 @@ plotting: "Ambient" : "k" "Electric load" : "b" "Heat load" : "r" - "Transport load" : "grey" "heat" : "darkred" "rural heat" : "#880000" "central heat" : "#b22222" @@ -319,7 +331,7 @@ plotting: "building retrofitting" : "purple" "BEV charger" : "grey" "V2G" : "grey" - "transport" : "grey" + "land transport EV" : "grey" "electricity" : "k" "gas for industry" : "#333333" "solid biomass for industry" : "#555555" @@ -328,7 +340,7 @@ plotting: "process emissions to stored" : "#444444" "process emissions to atmosphere" : "#888888" "process emissions" : "#222222" - "transport fuel cell" : "#AAAAAA" + "land transport fuel cell" : "#AAAAAA" "biogas" : "#800000" "solid biomass" : "#DAA520" "today" : "#D2691E" diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 8e825292..566fd8b9 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -520,7 +520,7 @@ def prepare_data(network): dsm_week = np.zeros((24*7,)) - dsm_week[(np.arange(0,7,1)*24+options['dsm_restriction_time'])] = options['dsm_restriction_value'] + dsm_week[(np.arange(0,7,1)*24+options['bev_dsm_restriction_time'])] = options['bev_dsm_restriction_value'] dsm_profile = generate_periodic_profiles(dt_index=network.snapshots.tz_localize("UTC"), nodes=pop_layout.index, @@ -963,78 +963,105 @@ def add_storage(network): lifetime=costs.at['SMR','lifetime']) -def add_transport(network): - print("adding transport") +def add_land_transport(network): + + print("adding land transport") + + fuel_cell_share = get_parameter(options["land_transport_fuel_cell_share"]) + electric_share = get_parameter(options["land_transport_electric_share"]) + fossil_share = 1 - fuel_cell_share - electric_share + + print("shares of FCEV, EV and ICEV are", + fuel_cell_share, + electric_share, + fossil_share) + + if fossil_share < 0: + print("Error, more FCEV and EV share than 1.") + sys.exit() + nodes = pop_layout.index - network.add("Carrier","Li ion") - network.madd("Bus", - nodes, - location=nodes, - suffix=" EV battery", - carrier="Li ion") + if electric_share > 0: - network.madd("Load", - nodes, - suffix=" transport", - bus=nodes + " EV battery", - carrier="transport", - p_set=(1-options['transport_fuel_cell_share'])*(transport[nodes]+shift_df(transport[nodes],1)+shift_df(transport[nodes],2))/3.) + network.add("Carrier","Li ion") - p_nom = nodal_transport_data["number cars"]*0.011*(1-options['transport_fuel_cell_share']) #3-phase charger with 11 kW * x% of time grid-connected - - network.madd("Link", - nodes, - suffix= " BEV charger", - bus0=nodes, - bus1=nodes + " EV battery", - p_nom=p_nom, - carrier="BEV charger", - p_max_pu=avail_profile[nodes], - efficiency=0.9, #[B] - #These were set non-zero to find LU infeasibility when availability = 0.25 - #p_nom_extendable=True, - #p_nom_min=p_nom, - #capital_cost=1e6, #i.e. so high it only gets built where necessary - ) - - if options["v2g"]: - - network.madd("Link", + network.madd("Bus", nodes, - suffix=" V2G", - bus1=nodes, - bus0=nodes + " EV battery", - p_nom=p_nom, - carrier="V2G", - p_max_pu=avail_profile[nodes], - efficiency=0.9) #[B] - - - - if options["bev"]: - - network.madd("Store", - nodes, - suffix=" battery storage", - bus=nodes + " EV battery", - carrier="battery storage", - e_cyclic=True, - e_nom=nodal_transport_data["number cars"]*0.05*options["bev_availability"]*(1-options['transport_fuel_cell_share']), #50 kWh battery http://www.zeit.de/mobilitaet/2014-10/auto-fahrzeug-bestand - e_max_pu=1, - e_min_pu=dsm_profile[nodes]) - - - if options['transport_fuel_cell_share'] != 0: + location=nodes, + suffix=" EV battery", + carrier="Li ion") network.madd("Load", nodes, - suffix=" transport fuel cell", - bus=nodes + " H2", - carrier="transport fuel cell", - p_set=options['transport_fuel_cell_share']/costs.at["fuel cell","efficiency"]*transport[nodes]) + suffix=" land transport EV", + bus=nodes + " EV battery", + carrier="land transport EV", + p_set=electric_share*(transport[nodes]+shift_df(transport[nodes],1)+shift_df(transport[nodes],2))/3.) + p_nom = nodal_transport_data["number cars"]*0.011*electric_share #3-phase charger with 11 kW * x% of time grid-connected + + network.madd("Link", + nodes, + suffix= " BEV charger", + bus0=nodes, + bus1=nodes + " EV battery", + p_nom=p_nom, + carrier="BEV charger", + p_max_pu=avail_profile[nodes], + efficiency=0.9, #[B] + #These were set non-zero to find LU infeasibility when availability = 0.25 + #p_nom_extendable=True, + #p_nom_min=p_nom, + #capital_cost=1e6, #i.e. so high it only gets built where necessary + ) + + if options["v2g"]: + + network.madd("Link", + nodes, + suffix=" V2G", + bus1=nodes, + bus0=nodes + " EV battery", + p_nom=p_nom, + carrier="V2G", + p_max_pu=avail_profile[nodes], + efficiency=0.9) #[B] + + + + if options["bev_dsm"]: + + network.madd("Store", + nodes, + suffix=" battery storage", + bus=nodes + " EV battery", + carrier="battery storage", + e_cyclic=True, + e_nom=nodal_transport_data["number cars"]*0.05*options["bev_availability"]*electric_share, #50 kWh battery http://www.zeit.de/mobilitaet/2014-10/auto-fahrzeug-bestand + e_max_pu=1, + e_min_pu=dsm_profile[nodes]) + + + if fuel_cell_share > 0: + + network.madd("Load", + nodes, + suffix=" land transport fuel cell", + bus=nodes + " H2", + carrier="land transport fuel cell", + p_set=fuel_cell_share/options['transport_fuel_cell_efficiency']*transport[nodes]) + + + if fossil_share > 0: + + network.madd("Load", + nodes, + suffix=" land transport fossil", + bus="Fischer-Tropsch", + carrier="land transport fossil", + p_set=fossil_share/options['transport_internal_combustion_efficiency']*transport[nodes]) @@ -1738,6 +1765,13 @@ def remove_h2_network(n): carrier="H2 Store", capital_cost=h2_capital_cost) +def get_parameter(item): + """Check whether it depends on investment year""" + if type(item) is dict: + return item[investment_year] + else: + return item + if __name__ == "__main__": @@ -1782,6 +1816,8 @@ if __name__ == "__main__": opts = snakemake.wildcards.sector_opts.split('-') + investment_year=int(snakemake.wildcards.planning_horizons[-4:]) + n = pypsa.Network(snakemake.input.network, override_component_attrs=override_component_attrs) @@ -1838,7 +1874,7 @@ if __name__ == "__main__": options["central"] = False if "T" in opts: - add_transport(n) + add_land_transport(n) if "H" in opts: add_heat(n) @@ -1867,11 +1903,7 @@ if __name__ == "__main__": logger.info("No resampling") #process CO2 limit - if type(snakemake.config["co2_budget"]) == dict: - year=int(snakemake.wildcards.planning_horizons[-4:]) - limit=snakemake.config["co2_budget"][year] - else: - limit=snakemake.config["co2_budget"] + limit = get_parameter(snakemake.config["co2_budget"]) print("CO2 limit set to",limit) for o in opts: