From 12257eeb3e8147ecc74c5a0345b063e75bb946d0 Mon Sep 17 00:00:00 2001 From: martavp Date: Tue, 15 Jun 2021 09:26:56 +0200 Subject: [PATCH 01/23] Update .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a55300e2..abfb926e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,7 +27,7 @@ gurobi.log /data/.nfs* /data/Industrial_Database.csv /data/retro/tabula-calculator-calcsetbuilding.csv - +/data *.org *.nc From e2354c18ac63d327d2171721ba07ee46c75a7c4c Mon Sep 17 00:00:00 2001 From: martavp Date: Wed, 16 Jun 2021 17:52:42 +0200 Subject: [PATCH 02/23] Add fictitious load to account for non-transformed shipping emissions The share of shipping demand that is transformed is defined now for different years to be used with the myopic code. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. --- config.default.yaml | 9 +++++++++ doc/release_notes.rst | 2 +- scripts/prepare_sector_network.py | 14 +++++++++++++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 617e716a..06f4af86 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -116,6 +116,14 @@ sector: '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 + 'shipping_hydrogen_share': # 1 means all hydrogen FC + 2020: 0 + 2025: 0 + 2030: 0.05 + 2035: 0.15 + 2040: 0.3 + 2045: 0.6 + 2050: 1 'time_dep_hp_cop' : True #time dependent heat pump coefficient of performance 'heat_pump_sink_T' : 55. # Celsius, based on DTU / large area radiators; used in build_cop_profiles.py # conservatively high to cover hot water and space heating in poorly-insulated buildings @@ -381,6 +389,7 @@ plotting: "solid biomass" : "#DAA520" "today" : "#D2691E" "shipping" : "#6495ED" + "shipping oil emissions" : "#6495ED" "electricity distribution grid" : "#333333" nice_names: # OCGT: "Gas" diff --git a/doc/release_notes.rst b/doc/release_notes.rst index cca25c7f..e5bd8d10 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -6,7 +6,7 @@ Future release ============== * Include new features here. - +The share of shipping transformed into hydrogen fuel cell can be now defined for different years in the ``config.yaml`` file. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. PyPSA-Eur-Sec 0.5.0 (21st May 2021) =================================== diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 94fb5048..f3dec3e4 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1682,13 +1682,25 @@ def add_industry(network): p_set=industrial_demand.loc[nodes,"hydrogen"]/8760.) + shipping_hydrogen_share = get_parameter(options['shipping_hydrogen_share']) network.madd("Load", nodes, suffix=" H2 for shipping", bus=nodes + " H2", carrier="H2 for shipping", - p_set = nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum(axis=1)*1e6*options['shipping_average_efficiency']/costs.at["fuel cell","efficiency"]/8760.) + p_set = shipping_hydrogen_share*nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum(axis=1)*1e6*options['shipping_average_efficiency']/costs.at["fuel cell","efficiency"]/8760.) + if shipping_hydrogen_share < 1: + shipping_oil_share= 1 - shipping_hydrogen_share + co2 = shipping_oil_share*nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum().sum()*1e6/8760.*costs.at["oil",'CO2 intensity'] + + network.madd("Load", + ["shipping oil emissions"], + bus="co2 atmosphere", + carrier="shipping oil emissions", + p_set=-co2) + + if "EU oil" not in network.buses.index: network.madd("Bus", ["EU oil"], From a57135b086f63e0a6dfc6e84c7ecfdf56421247f Mon Sep 17 00:00:00 2001 From: martavp Date: Thu, 17 Jun 2021 15:12:10 +0200 Subject: [PATCH 03/23] Split colours for H2 in Industry and H2 in shipping when plotting balances. When plotting the balance for H2, the rename dictionary merges all the demands containing H2. This commit disables such merging and keeps different colours for H2 in shipping and H2 in industry. This is useful when one wants to look at the H2 balance and have an overview of where the H2 is consumed in the model. --- config.default.yaml | 2 ++ scripts/plot_summary.py | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config.default.yaml b/config.default.yaml index 06f4af86..26937853 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -388,6 +388,8 @@ plotting: "biogas" : "#800000" "solid biomass" : "#DAA520" "today" : "#D2691E" + "H2 for industry" : "#222222" + "H2 for shipping" : "#6495ED" "shipping" : "#6495ED" "shipping oil emissions" : "#6495ED" "electricity distribution grid" : "#333333" diff --git a/scripts/plot_summary.py b/scripts/plot_summary.py index 9b3a81e1..276dc842 100644 --- a/scripts/plot_summary.py +++ b/scripts/plot_summary.py @@ -20,7 +20,9 @@ def rename_techs(label): rename_if_contains_dict = {"water tanks" : "hot water storage", "retrofitting" : "building retrofitting", - "H2" : "hydrogen storage", + "H2 Electrolysis" : "hydrogen storage", + "H2 Fuel Cell" : "hydrogen storage", + "H2 pipeline" : "hydrogen storage", "battery" : "battery storage", "CC" : "CC"} From 0a92d23698688ef1b6f4a5863d61537a426f9ece Mon Sep 17 00:00:00 2001 From: martavp Date: Thu, 17 Jun 2021 16:13:05 +0200 Subject: [PATCH 04/23] Make transformation of Steel and Aluminum production depends on year Previously, the transformation of the Steel and Aluminum production was assumed to occur overnight. This commit enables the definition of a transformation path via the config.yaml file. This requires adding the {planning_horizon} to the input and output file name of the following rules: build_industrial_production_per_country_tomorrow build_industrial_production_per_node build_industry_energy_demand_per_node prepare_sector_network --- Snakefile | 20 +++++++------- config.default.yaml | 26 +++++++++++++++++-- doc/release_notes.rst | 3 ++- ...ustrial_production_per_country_tomorrow.py | 21 +++++++++++---- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/Snakefile b/Snakefile index 9ab7d2f1..9babe249 100644 --- a/Snakefile +++ b/Snakefile @@ -189,7 +189,7 @@ rule build_industrial_production_per_country_tomorrow: input: industrial_production_per_country="resources/industrial_production_per_country.csv" output: - industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow.csv" + industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 script: 'scripts/build_industrial_production_per_country_tomorrow.py' @@ -214,9 +214,9 @@ rule build_industrial_distribution_key: rule build_industrial_production_per_node: input: industrial_distribution_key="resources/industrial_distribution_key_elec_s{simpl}_{clusters}.csv", - industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow.csv" + industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow_{planning_horizons}.csv" output: - industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}.csv" + industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 script: 'scripts/build_industrial_production_per_node.py' @@ -225,10 +225,10 @@ rule build_industrial_production_per_node: rule build_industrial_energy_demand_per_node: input: industry_sector_ratios="resources/industry_sector_ratios.csv", - industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}.csv", + industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}_{planning_horizons}.csv", industrial_energy_demand_per_node_today="resources/industrial_energy_demand_today_elec_s{simpl}_{clusters}.csv" output: - industrial_energy_demand_per_node="resources/industrial_energy_demand_elec_s{simpl}_{clusters}.csv" + industrial_energy_demand_per_node="resources/industrial_energy_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 script: 'scripts/build_industrial_energy_demand_per_node.py' @@ -260,9 +260,9 @@ rule build_industrial_energy_demand_per_node_today: rule build_industrial_energy_demand_per_country: input: industry_sector_ratios="resources/industry_sector_ratios.csv", - industrial_production_per_country="resources/industrial_production_per_country_tomorrow.csv" + industrial_production_per_country="resources/industrial_production_per_country_tomorrow_{planning_horizons}.csv" output: - industrial_energy_demand_per_country="resources/industrial_energy_demand_per_country.csv" + industrial_energy_demand_per_country="resources/industrial_energy_demand_per_country_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 script: 'scripts/build_industrial_energy_demand_per_country.py' @@ -271,9 +271,9 @@ rule build_industrial_energy_demand_per_country: rule build_industrial_demand: input: clustered_pop_layout="resources/pop_layout_elec_s{simpl}_{clusters}.csv", - industrial_demand_per_country="resources/industrial_energy_demand_per_country.csv" + industrial_demand_per_country="resources/industrial_energy_demand_per_country_{planning_horizons}.csv" output: - industrial_demand="resources/industrial_demand_elec_s{simpl}_{clusters}.csv" + industrial_demand="resources/industrial_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 script: 'scripts/build_industrial_demand.py' @@ -315,7 +315,7 @@ rule prepare_sector_network: busmap=pypsaeur("resources/busmap_elec_s{simpl}_{clusters}.csv"), clustered_pop_layout="resources/pop_layout_elec_s{simpl}_{clusters}.csv", simplified_pop_layout="resources/pop_layout_elec_s{simpl}.csv", - industrial_demand="resources/industrial_energy_demand_elec_s{simpl}_{clusters}.csv", + industrial_demand="resources/industrial_energy_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv", heat_demand_urban="resources/heat_demand_urban_elec_s{simpl}_{clusters}.nc", heat_demand_rural="resources/heat_demand_rural_elec_s{simpl}_{clusters}.nc", heat_demand_total="resources/heat_demand_total_elec_s{simpl}_{clusters}.nc", diff --git a/config.default.yaml b/config.default.yaml index 26937853..70dfc009 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -230,10 +230,32 @@ solving: mem: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2 industry: - 'St_primary_fraction' : 0.3 # fraction of steel produced via primary route (DRI + EAF) versus secondary route (EAF); today fraction is 0.6 + 'St_primary_fraction' : # fraction of steel produced via primary route versus secondary route (scrap+EAF); today fraction is 0.6 + 2020: 0.6 + 2025: 0.55 + 2030: 0.5 + 2035: 0.45 + 2040: 0.4 + 2045: 0.35 + 2050: 0.3 + 'DRI_fraction' : # fraction of the primary route converted to DRI + EAF + 2020: 0 + 2025: 0 + 2030: 0.05 + 2035: 0.2 + 2040: 0.4 + 2045: 0.7 + 2050: 1 'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from 51kgH2/tSt in Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279 'elec_DRI' : 0.322 #electricity consumption in Direct Reduced Iron (DRI) shaft, MWh/tSt HYBRIT brochure https://ssabwebsitecdn.azureedge.net/-/media/hybrit/files/hybrit_brochure.pdf - 'Al_primary_fraction' : 0.2 # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4 + 'Al_primary_fraction' : # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4 + 2020: 0.4 + 2025: 0.375 + 2030: 0.35 + 2035: 0.325 + 2040: 0.3 + 2045: 0.25 + 2050: 0.2 'MWh_CH4_per_tNH3_SMR' : 10.8 # 2012's demand from https://ec.europa.eu/docsroom/documents/4165/attachments/1/translations/en/renditions/pdf 'MWh_elec_per_tNH3_SMR' : 0.7 # same source, assuming 94-6% split methane-elec of total energy demand 11.5 MWh/tNH3 'MWh_H2_per_tNH3_electrolysis' : 6.5 # from https://doi.org/10.1016/j.joule.2018.04.017, around 0.197 tH2/tHN3 (>3/17 since some H2 lost and used for energy) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index e5bd8d10..ebdbdd7c 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -6,7 +6,8 @@ Future release ============== * Include new features here. -The share of shipping transformed into hydrogen fuel cell can be now defined for different years in the ``config.yaml`` file. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. +* The share of shipping transformed into hydrogen fuel cell can be now defined for different years in the ``config.yaml`` file. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. +* The transformation of the Steel and Aluminium production can be now defined for different years in the ``config.yaml`` file. PyPSA-Eur-Sec 0.5.0 (21st May 2021) =================================== diff --git a/scripts/build_industrial_production_per_country_tomorrow.py b/scripts/build_industrial_production_per_country_tomorrow.py index bc66077c..4bb9fab3 100644 --- a/scripts/build_industrial_production_per_country_tomorrow.py +++ b/scripts/build_industrial_production_per_country_tomorrow.py @@ -1,23 +1,34 @@ import pandas as pd +def get_parameter(item): + """Check whether it depends on investment year""" + if type(item) is dict: + return item[investment_year] + else: + return item +investment_year=int(snakemake.wildcards.planning_horizons[-4:]) + industrial_production = pd.read_csv(snakemake.input.industrial_production_per_country, index_col=0) total_steel = industrial_production[["Integrated steelworks","Electric arc"]].sum(axis=1) -fraction_primary_stays_primary = snakemake.config["industry"]["St_primary_fraction"]*total_steel.sum()/industrial_production["Integrated steelworks"].sum() +St_primary_fraction=get_parameter(snakemake.config["industry"]["St_primary_fraction"]) +DRI_fraction=get_parameter(snakemake.config["industry"]["DRI_fraction"]) +fraction_primary_stays_primary = St_primary_fraction*total_steel.sum()/industrial_production["Integrated steelworks"].sum() industrial_production.insert(2, "DRI + Electric arc", - fraction_primary_stays_primary*industrial_production["Integrated steelworks"]) + DRI_fraction*fraction_primary_stays_primary*industrial_production["Integrated steelworks"]) -industrial_production["Electric arc"] = total_steel - industrial_production["DRI + Electric arc"] -industrial_production["Integrated steelworks"] = 0. +industrial_production["Integrated steelworks"] = (1-DRI_fraction)*fraction_primary_stays_primary*industrial_production["Integrated steelworks"] +industrial_production["Electric arc"] = total_steel - industrial_production["DRI + Electric arc"] - industrial_production["Integrated steelworks"] +Al_primary_fraction=get_parameter(snakemake.config["industry"]["Al_primary_fraction"]) total_aluminium = industrial_production[["Aluminium - primary production","Aluminium - secondary production"]].sum(axis=1) -fraction_primary_stays_primary = snakemake.config["industry"]["Al_primary_fraction"]*total_aluminium.sum()/industrial_production["Aluminium - primary production"].sum() +fraction_primary_stays_primary = Al_primary_fraction*total_aluminium.sum()/industrial_production["Aluminium - primary production"].sum() industrial_production["Aluminium - primary production"] = fraction_primary_stays_primary*industrial_production["Aluminium - primary production"] industrial_production["Aluminium - secondary production"] = total_aluminium - industrial_production["Aluminium - primary production"] From ad3da281176589958202ccd6240b9aefe106cd3d Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Sat, 3 Jul 2021 13:03:47 +0200 Subject: [PATCH 05/23] small follow-up to merge --- config.default.yaml | 3 --- scripts/prepare_sector_network.py | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 715f4ce3..15b727aa 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -235,7 +235,6 @@ sector: industry: - # St_primary_fraction: 0.3 St_primary_fraction: # fraction of steel produced via primary route versus secondary route (scrap+EAF); today fraction is 0.6 2020: 0.6 2025: 0.55 @@ -254,7 +253,6 @@ industry: 2050: 1 H2_DRI: 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from 51kgH2/tSt in Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279 elec_DRI: 0.322 #electricity consumption in Direct Reduced Iron (DRI) shaft, MWh/tSt HYBRIT brochure https://ssabwebsitecdn.azureedge.net/-/media/hybrit/files/hybrit_brochure.pdf - # Al_primary_fraction: 0.2 # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4 Al_primary_fraction: # fraction of aluminium produced via the primary route versus scrap; today fraction is 0.4 2020: 0.4 2025: 0.375 @@ -272,7 +270,6 @@ industry: HVC_primary_fraction: 1.0 #fraction of current non-ammonia basic chemicals produced via primary route hotmaps_locate_missing: false reference_year: 2015 - industry: costs: diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 86d74656..a9482d6b 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1716,7 +1716,7 @@ def add_industry(n, costs): all_navigation = ["total international navigation", "total domestic navigation"] efficiency = options['shipping_average_efficiency'] / costs.at["fuel cell", "efficiency"] - shipping_hydrogen_share = get_parameter(options['shipping_hydrogen_share']) + shipping_hydrogen_share = get(options['shipping_hydrogen_share'], investment_year) p_set = shipping_hydrogen_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 * efficiency / 8760 n.madd("Load", From 82e9a48b74a181aaf0659e0d363f5bd17367e171 Mon Sep 17 00:00:00 2001 From: martavp Date: Mon, 5 Jul 2021 11:29:02 +0200 Subject: [PATCH 06/23] Add oil consumed in shipping as a load to EU oil bus --- config.default.yaml | 1 + scripts/prepare_sector_network.py | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/config.default.yaml b/config.default.yaml index 15b727aa..3026a2f7 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -500,6 +500,7 @@ plotting: solid biomass: '#DAA520' today: '#D2691E' shipping: '#6495ED' + shipping oil: "#6495ED" shipping oil emissions: "#6495ED" electricity distribution grid: '#333333' H2 for industry: "#222222" diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index a9482d6b..17a2262f 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1730,6 +1730,15 @@ def add_industry(n, costs): if shipping_hydrogen_share < 1: shipping_oil_share = 1 - shipping_hydrogen_share + + n.madd("Load", + nodes, + suffix=" shipping oil", + bus="EU oil", + carrier="shipping oil", + p_set=shipping_oil_share*nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum(axis=1)*1e6/8760. + ) + co2 = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum().sum() * 1e6 / 8760 * costs.at["oil", "CO2 intensity"] n.add("Load", From c3f554e442d8bb44e62d01a2b08631ac74625ebd Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Tue, 6 Jul 2021 10:54:34 +0200 Subject: [PATCH 07/23] Update scripts/prepare_sector_network.py --- scripts/prepare_sector_network.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 17a2262f..3eafe8aa 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1731,13 +1731,15 @@ def add_industry(n, costs): shipping_oil_share = 1 - shipping_hydrogen_share + p_set = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 / 8760. + n.madd("Load", - nodes, - suffix=" shipping oil", - bus="EU oil", - carrier="shipping oil", - p_set=shipping_oil_share*nodal_energy_totals.loc[nodes,["total international navigation","total domestic navigation"]].sum(axis=1)*1e6/8760. - ) + nodes, + suffix=" shipping oil", + bus="EU oil", + carrier="shipping oil", + p_set=p_set + ) co2 = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum().sum() * 1e6 / 8760 * costs.at["oil", "CO2 intensity"] From 2e336e5e7043976c97580471cbd6075d837bf742 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Thu, 8 Jul 2021 14:41:13 +0200 Subject: [PATCH 08/23] add missing wildcards for benchmarks, add new input data for district heating share --- Snakefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Snakefile b/Snakefile index f52045cb..6ff7555f 100644 --- a/Snakefile +++ b/Snakefile @@ -223,7 +223,7 @@ rule build_industrial_production_per_country_tomorrow: industrial_production_per_country_tomorrow="resources/industrial_production_per_country_tomorrow_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 - benchmark: "benchmarks/build_industrial_production_per_country_tomorrow" + benchmark: "benchmarks/build_industrial_production_per_country_tomorrow_{planning_horizons}" script: 'scripts/build_industrial_production_per_country_tomorrow.py' @@ -248,7 +248,7 @@ rule build_industrial_production_per_node: industrial_production_per_node="resources/industrial_production_elec_s{simpl}_{clusters}_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 - benchmark: "benchmarks/build_industrial_production_per_node/s{simpl}_{clusters}" + benchmark: "benchmarks/build_industrial_production_per_node/s{simpl}_{clusters}_{planning_horizons}" script: 'scripts/build_industrial_production_per_node.py' @@ -261,7 +261,7 @@ rule build_industrial_energy_demand_per_node: industrial_energy_demand_per_node="resources/industrial_energy_demand_elec_s{simpl}_{clusters}_{planning_horizons}.csv" threads: 1 resources: mem_mb=1000 - benchmark: "benchmarks/build_industrial_energy_demand_per_node/s{simpl}_{clusters}" + benchmark: "benchmarks/build_industrial_energy_demand_per_node/s{simpl}_{clusters}_{planning_horizons}" script: 'scripts/build_industrial_energy_demand_per_node.py' @@ -323,6 +323,7 @@ rule prepare_sector_network: transport_name='resources/transport_data.csv', traffic_data_KFZ = "data/emobility/KFZ__count", traffic_data_Pkw = "data/emobility/Pkw__count", + dh_share = "data/district_heat_share.csv", biomass_potentials='resources/biomass_potentials.csv', heat_profile="data/heat_load_profile_BDEW.csv", costs=CDIR + "costs_{planning_horizons}.csv", From 76f36d0a1a2706f9bf2cf7fce0551f9676b133be Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Thu, 8 Jul 2021 14:41:34 +0200 Subject: [PATCH 09/23] add option to take today's district heating share --- config.default.yaml | 8 +- scripts/prepare_sector_network.py | 124 +++++++++++++++++++----------- 2 files changed, 88 insertions(+), 44 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 3026a2f7..d23cc033 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -141,6 +141,12 @@ existing_capacities: sector: central: true central_fraction: 0.6 + district_heating_increase: true + dh_strength: + 2020: 0 # starting at today's share + 2030: 0.2 + 2040: 0.5 + 2050: 1 # maximum possible share defined in central fraction 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. @@ -332,7 +338,7 @@ solving: plotting: map: - boundaries: [-11, 30, 34, 71] + boundaries: [-11, 30, 34, 71] color_geomap: ocean: white land: whitesmoke diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 3eafe8aa..92fce889 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -75,7 +75,7 @@ def co2_emissions_year(countries, opts, year): co2_emissions = co2_totals.loc[countries, sectors].sum().sum() # convert MtCO2 to GtCO2 - co2_emissions *= 0.001 + co2_emissions *= 0.001 return co2_emissions @@ -102,17 +102,17 @@ def build_carbon_budget(o, fn): #emissions at the beginning of the path (last year available 2018) e_0 = co2_emissions_year(countries, opts, year=2018) - + #emissions in 2019 and 2020 assumed equal to 2018 and substracted carbon_budget -= 2 * e_0 - + planning_horizons = snakemake.config['scenario']['planning_horizons'] t_0 = planning_horizons[0] if "be" in o: # final year in the path - t_f = t_0 + (2 * carbon_budget / e_0).round(0) + t_f = t_0 + (2 * carbon_budget / e_0).round(0) def beta_decay(t): cdf_term = (t - t_0) / (t_f - t_0) @@ -818,7 +818,7 @@ def insert_gas_distribution_costs(n, costs): # TODO options? f_costs = options['gas_distribution_grid_cost_factor'] - + print("Inserting gas distribution grid with investment cost factor of", f_costs) capital_cost = costs.loc['electricity distribution grid']["fixed"] * f_costs @@ -827,7 +827,7 @@ def insert_gas_distribution_costs(n, costs): gas_b = n.links.index[n.links.carrier.str.contains("gas boiler") & (~n.links.carrier.str.contains("urban central"))] n.links.loc[gas_b, "capital_cost"] += capital_cost - + # micro CHPs mchp = n.links.index[n.links.carrier.str.contains("micro gas")] n.links.loc[mchp, "capital_cost"] += capital_cost @@ -1075,7 +1075,7 @@ def add_land_transport(n, costs): suffix=" EV battery", carrier="Li ion" ) - + p_set = electric_share * (transport[nodes] + cycling_shift(transport[nodes], 1) + cycling_shift(transport[nodes], 2)) / 3 n.madd("Load", @@ -1086,8 +1086,8 @@ def add_land_transport(n, costs): p_set=p_set ) - - p_nom = nodal_transport_data["number cars"] * options.get("bev_charge_rate", 0.011) * electric_share + + p_nom = nodal_transport_data["number cars"] * options.get("bev_charge_rate", 0.011) * electric_share n.madd("Link", nodes, @@ -1119,7 +1119,7 @@ def add_land_transport(n, costs): if electric_share > 0 and options["bev_dsm"]: - e_nom = nodal_transport_data["number cars"] * options.get("bev_energy", 0.05) * options["bev_availability"] * electric_share + e_nom = nodal_transport_data["number cars"] * options.get("bev_energy", 0.05) * options["bev_availability"] * electric_share n.madd("Store", nodes, @@ -1179,11 +1179,10 @@ def add_heat(n, costs): sectors = ["residential", "services"] - nodes = create_nodes_for_heat_sector() - #NB: must add costs of central heating afterwards (EUR 400 / kWpeak, 50a, 1% FOM from Fraunhofer ISE) + nodes, dist_fraction, urban_fraction = create_nodes_for_heat_sector() - urban_fraction = options['central_fraction'] * pop_layout["urban"] / pop_layout[["urban", "rural"]].sum(axis=1) + #NB: must add costs of central heating afterwards (EUR 400 / kWpeak, 50a, 1% FOM from Fraunhofer ISE) # exogenously reduce space heat demand if options["reduce_space_heat_exogenously"]: @@ -1199,7 +1198,7 @@ def add_heat(n, costs): "services urban decentral", "urban central" ] - + for name in heat_systems: name_type = "central" if name == "urban central" else "decentral" @@ -1215,10 +1214,17 @@ def add_heat(n, costs): ## Add heat load for sector in sectors: + # heat demand weighting if "rural" in name: factor = 1 - urban_fraction[nodes[name]] - elif "urban" in name: - factor = urban_fraction[nodes[name]] + elif "urban central" in name: + factor = dist_fraction[nodes[name]] + elif "urban decentral" in name: + factor = urban_fraction[nodes[name]] - \ + dist_fraction[nodes[name]] + else: + factor = None + if sector in name: heat_load = heat_demand[[sector + " water",sector + " space"]].groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor) @@ -1281,16 +1287,16 @@ def add_heat(n, costs): p_nom_extendable=True ) - + if isinstance(options["tes_tau"], dict): tes_time_constant_days = options["tes_tau"][name_type] else: logger.warning("Deprecated: a future version will require you to specify 'tes_tau' ", "for 'decentral' and 'central' separately.") tes_time_constant_days = options["tes_tau"] if name_type == "decentral" else 180. - + # conversion from EUR/m^3 to EUR/MWh for 40 K diff and 1.17 kWh/m^3/K - capital_cost = costs.at[name_type + ' water tank storage', 'fixed'] / 0.00117 / 40 + capital_cost = costs.at[name_type + ' water tank storage', 'fixed'] / 0.00117 / 40 n.madd("Store", nodes[name] + f" {name} water tanks", @@ -1503,24 +1509,55 @@ def create_nodes_for_heat_sector(): # rural are areas with low heating density and individual heating # urban are areas with high heating density # urban can be split into district heating (central) and individual heating (decentral) - + + ct_urban = pop_layout.urban.groupby(pop_layout["ct"]).sum() + pop_layout["urban_ct_fraction"] = pop_layout["urban"] / \ + pop_layout["ct"].map(ct_urban.get) + # todays district heating share per country + dist_heat_share_ct = pd.read_csv(snakemake.input.dh_share, index_col=0, + usecols=[0,1]).dropna()/100 + dist_heat_share = pop_layout.ct.map(dist_heat_share_ct["district heating share"]) + + sectors = ["residential", "services"] - + nodes = {} + urban_fraction = pop_layout["urban"] / \ + (pop_layout[["urban", "rural"]].sum(axis=1)) + for sector in sectors: nodes[sector + " rural"] = pop_layout.index + nodes[sector + " urban decentral"] = pop_layout.index + + if options["central"] and not options['district_heating_increase']: + central_fraction = options['central_fraction'] + dist_fraction = central_fraction * urban_fraction + nodes["urban central"] = dist_fraction.index + + if options['district_heating_increase']: # take current district heating share + dist_fraction = dist_heat_share * \ + pop_layout["urban_ct_fraction"] / pop_layout["fraction"] + nodes["urban central"] = dist_fraction.index + # if district heating share larger than urban fraction -> set urban + # fraction to district heating share + urban_fraction = pd.concat([urban_fraction, dist_fraction], + axis=1).max(axis=1) + diff = urban_fraction - dist_fraction + dist_fraction += diff * get(options["dh_strength"], investment_year) + print("************************************") + print( + "the current DH share compared to the maximum possible is increased \ + \n by a factor of ", + get(options["dh_strength"], investment_year), + "resulting DH share: ", + dist_fraction) + print("**********************************") - if options["central"]: - # TODO: this looks hardcoded, move to config - urban_decentral_ct = pd.Index(["ES", "GR", "PT", "IT", "BG"]) - nodes[sector + " urban decentral"] = pop_layout.index[pop_layout.ct.isin(urban_decentral_ct)] - else: - nodes[sector + " urban decentral"] = pop_layout.index - - # for central nodes, residential and services are aggregated - nodes["urban central"] = pop_layout.index.symmetric_difference(nodes["residential urban decentral"]) - - return nodes + else: + dist_fraction = urban_fraction * 0 + nodes["urban central"] = dist_fraction.index + + return nodes, dist_fraction, urban_fraction def add_biomass(n, costs): @@ -1730,9 +1767,9 @@ def add_industry(n, costs): if shipping_hydrogen_share < 1: shipping_oil_share = 1 - shipping_hydrogen_share - + p_set = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 / 8760. - + n.madd("Load", nodes, suffix=" shipping oil", @@ -1740,7 +1777,7 @@ def add_industry(n, costs): carrier="shipping oil", p_set=p_set ) - + co2 = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum().sum() * 1e6 / 8760 * costs.at["oil", "CO2 intensity"] n.add("Load", @@ -1759,7 +1796,7 @@ def add_industry(n, costs): ) if "EU oil Store" not in n.stores.index: - + #could correct to e.g. 0.001 EUR/kWh * annuity and O&M n.add("Store", "EU oil Store", @@ -1781,7 +1818,7 @@ def add_industry(n, costs): if options["oil_boilers"]: - nodes_heat = create_nodes_for_heat_sector() + nodes_heat = create_nodes_for_heat_sector()[0] for name in ["residential rural", "services rural", "residential urban decentral", "services urban decentral"]: @@ -1926,7 +1963,7 @@ def add_waste_heat(n): def decentral(n): - """Removes the electricity transmission system.""" + """Removes the electricity transmission system.""" n.lines.drop(n.lines.index, inplace=True) n.links.drop(n.links.index[n.links.carrier.isin(["DC", "B2B"])], inplace=True) @@ -1973,17 +2010,18 @@ def limit_individual_line_extension(n, maxext): hvdc = n.links.index[n.links.carrier == 'DC'] n.links.loc[hvdc, 'p_nom_max'] = n.links.loc[hvdc, 'p_nom'] + maxext - +#%% if __name__ == "__main__": if 'snakemake' not in globals(): from helper import mock_snakemake snakemake = mock_snakemake( 'prepare_sector_network', simpl='', - clusters=48, + opts="", + clusters="37", lv=1.0, sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', - planning_horizons=2020, + planning_horizons="2020", ) logging.basicConfig(level=snakemake.config['logging_level']) @@ -1998,7 +2036,7 @@ def limit_individual_line_extension(n, maxext): n = pypsa.Network(snakemake.input.network, override_component_attrs=overrides) pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout, index_col=0) - Nyears = n.snapshot_weightings.generators.sum() / 8760 + Nyears = n.snapshot_weightings.sum() / 8760 costs = prepare_costs(snakemake.input.costs, snakemake.config['costs']['USD2013_to_EUR2013'], @@ -2009,7 +2047,7 @@ def limit_individual_line_extension(n, maxext): patch_electricity_network(n) if snakemake.config["foresight"] == 'myopic': - + add_lifetime_wind_solar(n, costs) conventional = snakemake.config['existing_capacities']['conventional_carriers'] From 0127c47035e6b80133dcb1f210dc0316dc942e4a Mon Sep 17 00:00:00 2001 From: lisazeyen <35347358+lisazeyen@users.noreply.github.com> Date: Fri, 9 Jul 2021 13:56:44 +0200 Subject: [PATCH 10/23] Update prepare_sector_network.py bug fix when calculating urban central heat demand --- scripts/prepare_sector_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 92fce889..61a5c896 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1229,7 +1229,7 @@ def add_heat(n, costs): heat_load = heat_demand[[sector + " water",sector + " space"]].groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor) if name == "urban central": - heat_load = heat_demand.groupby(level=1,axis=1).sum()[nodes[name]].multiply(urban_fraction[nodes[name]] * (1 + options['district_heating_loss'])) + heat_load = heat_demand.groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor * (1 + options['district_heating_loss'])) n.madd("Load", nodes[name], From 9039b130fa1dde78898fd4ceee9a5489d57c165c Mon Sep 17 00:00:00 2001 From: lisazeyen <35347358+lisazeyen@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:30:21 +0200 Subject: [PATCH 11/23] bug fix to avoid same link names for DAX --- scripts/prepare_sector_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 61a5c896..54f1bab9 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -328,7 +328,7 @@ def add_co2_tracking(n, options): def add_dac(n, costs): - heat_carriers = ["urban central heat", "services urban decentral heat"] + heat_carriers = ["urban central heat"] heat_buses = n.buses.index[n.buses.carrier.isin(heat_carriers)] locations = n.buses.location[heat_buses] From aa8cefeb5b1b18da3317e28cdb608eeac4935d9f Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Thu, 19 Aug 2021 10:07:51 +0200 Subject: [PATCH 12/23] add district_heat_share.csv --- .gitignore | 2 +- data/district_heat_share.csv | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 data/district_heat_share.csv diff --git a/.gitignore b/.gitignore index ac252a84..4677557b 100644 --- a/.gitignore +++ b/.gitignore @@ -28,7 +28,7 @@ gurobi.log /data/.nfs* /data/Industrial_Database.csv /data/retro/tabula-calculator-calcsetbuilding.csv -/data +/data/nuts* *.org *.nc diff --git a/data/district_heat_share.csv b/data/district_heat_share.csv new file mode 100644 index 00000000..5afd65c8 --- /dev/null +++ b/data/district_heat_share.csv @@ -0,0 +1,34 @@ +country,share to satisfy heat demand (residential) in percent,capacity[MWth] +AT,14,11200 +BG,16,6162 +BA,8, +HR,6.3,2221 +CZ,40, +DK,65, +FI,38,23390 +FR,5, +DE,13.8, +HU,7.92875588637399,8549 +IS,90,8079000 +IE,0.8, +IT,3,8727 +LV,73,2254 +LT,56, +MK,23.7745607009008,636 +NO,4,3400 +PL,42,54912 +PT,0.070754716981132,34 +RS,25,5821 +SI,8.86,1739 +ES,0.251589260787732,1273 +SE,50.4, +UK,2, +BY,70, +EE,52,5406 +KO,3,207 +RO,23,9962 +SK,54,15000 +NL,4,9800 +CH,4,2792 +AL,0, +ME,0, From 234a32c504b893dc3c0c4a7af76f0f40448a834d Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Fri, 9 Jul 2021 13:33:26 +0200 Subject: [PATCH 13/23] bug fix --- scripts/prepare_sector_network.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 0282b5eb..6e992f03 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -2246,7 +2246,7 @@ def limit_individual_line_extension(n, maxext): lv=1.0, opts='', sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', - planning_horizons="2020", + planning_horizons="2030", ) logging.basicConfig(level=snakemake.config['logging_level']) From e27ec46878f3327d43a04570e1da11d23ed0ced4 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Thu, 23 Sep 2021 14:10:56 +0200 Subject: [PATCH 14/23] add further comments --- scripts/prepare_sector_network.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 6e992f03..f669e309 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1668,6 +1668,7 @@ def create_nodes_for_heat_sector(): # urban can be split into district heating (central) and individual heating (decentral) ct_urban = pop_layout.urban.groupby(pop_layout["ct"]).sum() + # distribution of urban population within a country pop_layout["urban_ct_fraction"] = pop_layout["urban"] / \ pop_layout["ct"].map(ct_urban.get) # todays district heating share per country @@ -1690,7 +1691,8 @@ def create_nodes_for_heat_sector(): dist_fraction = central_fraction * urban_fraction nodes["urban central"] = dist_fraction.index - if options['district_heating_increase']: # take current district heating share + # take current district heating share + if options['district_heating_increase']: dist_fraction = dist_heat_share * \ pop_layout["urban_ct_fraction"] / pop_layout["fraction"] nodes["urban central"] = dist_fraction.index From 8322350feea47bc5de2bfb4d65247ca3d8236540 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Wed, 29 Sep 2021 14:36:56 +0200 Subject: [PATCH 15/23] move calculation of district heating share to build_energy_totals --- Snakefile | 2 +- scripts/build_energy_totals.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Snakefile b/Snakefile index 9400d301..a16e60f0 100644 --- a/Snakefile +++ b/Snakefile @@ -160,6 +160,7 @@ rule build_energy_totals: co2="data/eea/UNFCCC_v23.csv", swiss="data/switzerland-sfoe/switzerland-new_format.csv", idees="data/jrc-idees-2015", + district_heat_share='data/district_heat_share.csv', eurostat=input_eurostat output: energy_name='resources/energy_totals.csv', @@ -339,7 +340,6 @@ rule prepare_sector_network: energy_totals_name='resources/energy_totals.csv', co2_totals_name='resources/co2_totals.csv', transport_name='resources/transport_data.csv', - dh_share = "data/district_heat_share.csv", traffic_data_KFZ="data/emobility/KFZ__count", traffic_data_Pkw="data/emobility/Pkw__count", biomass_potentials='resources/biomass_potentials.csv', diff --git a/scripts/build_energy_totals.py b/scripts/build_energy_totals.py index aec1c61b..751f23bf 100644 --- a/scripts/build_energy_totals.py +++ b/scripts/build_energy_totals.py @@ -212,6 +212,12 @@ def idees_per_country(ct, year): assert df.index[47] == "Electricity" ct_totals["electricity residential"] = df[47] + assert df.index[46] == "Derived heat" + ct_totals["Derived heat residential"] = df[46] + + assert df.index[50] == 'Thermal uses' + ct_totals["Thermal uses residential"] = df[50] + # services df = pd.read_excel(fn_services, "SER_hh_fec", index_col=0)[year] @@ -239,6 +245,12 @@ def idees_per_country(ct, year): assert df.index[50] == "Electricity" ct_totals["electricity services"] = df[50] + assert df.index[49] == "Derived heat" + ct_totals["Derived heat services"] = df[49] + + assert df.index[53] == 'Thermal uses' + ct_totals["Thermal uses services"] = df[53] + # transport df = pd.read_excel(fn_transport, "TrRoad_ene", index_col=0)[year] @@ -342,6 +354,7 @@ def build_idees(countries, year): with mp.Pool(processes=nprocesses) as pool: totals_list = list(tqdm(pool.imap(func, countries), **tqdm_kwargs)) + totals = pd.concat(totals_list, axis=1) # convert ktoe to TWh @@ -351,6 +364,13 @@ def build_idees(countries, year): # convert TWh/100km to kWh/km totals.loc["passenger car efficiency"] *= 10 + # district heating share + district_heat = totals.loc[["Derived heat residential", + "Derived heat services"]].sum() + total_heat = totals.loc[["Thermal uses residential", + "Thermal uses services"]].sum() + totals.loc["district heat share"] = district_heat.div(total_heat) + return totals.T @@ -493,7 +513,7 @@ def build_energy_totals(countries, eurostat, swiss, idees): for purpose in ["passenger", "freight"]: attrs = [f"total domestic aviation {purpose}", f"total international aviation {purpose}"] - df.loc[missing, f"total aviation {purpose}"] = df.loc[missing, attrs].sum(axis=1) + df.loc[missing, f"total aviation {purpose}"] = df.loc[missing, attrs].sum(axis=1) if "BA" in df.index: # fill missing data for BA (services and road energy data) @@ -502,6 +522,14 @@ def build_energy_totals(countries, eurostat, swiss, idees): ratio = df.at["BA", "total residential"] / df.at["RS", "total residential"] df.loc['BA', missing] = ratio * df.loc["RS", missing] + # Missing district heating share + dh_share = pd.read_csv(snakemake.input.district_heat_share, + index_col=0, usecols=[0, 1]) + # make conservative assumption and take minimum from both data sets + df["district heat share"] = (pd.concat([df["district heat share"], + dh_share.reindex(index=df.index)/100], + axis=1).min(axis=1)) + return df From 854bd80818e81b80003c661eb214be4eb19e8f25 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Wed, 29 Sep 2021 14:37:36 +0200 Subject: [PATCH 16/23] rename central_fraction->district heating potential, restructure district heating share implementation --- scripts/prepare_sector_network.py | 101 ++++++++++++++---------------- 1 file changed, 46 insertions(+), 55 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index f669e309..fea03d69 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -26,7 +26,7 @@ def define_spatial(nodes): """ Namespace for spatial - + Parameters ---------- nodes : list-like @@ -36,7 +36,7 @@ def define_spatial(nodes): global options spatial.nodes = nodes - + # biomass spatial.biomass = SimpleNamespace() @@ -53,11 +53,11 @@ def define_spatial(nodes): spatial.biomass.industry_cc = ["solid biomass for industry CC"] spatial.biomass.df = pd.DataFrame(vars(spatial.biomass), index=nodes) - + # co2 spatial.co2 = SimpleNamespace() - + if options["co2_network"]: spatial.co2.nodes = nodes + " co2 stored" spatial.co2.locations = nodes @@ -72,7 +72,7 @@ def define_spatial(nodes): def emission_sectors_from_opts(opts): - sectors = ["electricity"] + sectors = ["electricity"] if "T" in opts: sectors += [ "rail non-elec", @@ -107,13 +107,13 @@ def get(item, investment_year=None): def create_network_topology(n, prefix, connector=" -> "): """ Create a network topology like the power transmission network. - + Parameters ---------- n : pypsa.Network prefix : str connector : str - + Returns ------- pd.DataFrame with columns bus0, bus1 and length @@ -228,7 +228,7 @@ def add_lifetime_wind_solar(n, costs): def create_network_topology(n, prefix, connector=" -> ", bidirectional=True): """ Create a network topology like the power transmission network. - + Parameters ---------- n : pypsa.Network @@ -237,7 +237,7 @@ def create_network_topology(n, prefix, connector=" -> ", bidirectional=True): bidirectional : bool, default True True: one link for each connection False: one link for each connection and direction (back and forth) - + Returns ------- pd.DataFrame with columns bus0, bus1 and length @@ -256,19 +256,19 @@ def create_network_topology(n, prefix, connector=" -> ", bidirectional=True): swap_buses = {"bus0": "bus1", "bus1": "bus0"} candidates_n = candidates[~positive_order].rename(columns=swap_buses) candidates = pd.concat([candidates_p, candidates_n]) - + def make_index(c): return prefix + c.bus0 + connector + c.bus1 topo = candidates.groupby(["bus0", "bus1"], as_index=False).mean() topo.index = topo.apply(make_index, axis=1) - + if not bidirectional: topo_reverse = topo.copy() topo_reverse.rename(columns=swap_buses, inplace=True) topo_reverse.index = topo_reverse.apply(make_index, axis=1) topo = topo.append(topo_reverse) - + return topo @@ -439,7 +439,7 @@ def add_co2_tracking(n, options): n.madd("Store", spatial.co2.nodes, e_nom_extendable=True, - e_nom_max=np.inf, + e_nom_max=np.inf, capital_cost=options['co2_sequestration_cost'], carrier="co2 stored", bus=spatial.co2.nodes @@ -458,14 +458,14 @@ def add_co2_tracking(n, options): def add_co2_network(n, costs): - + logger.info("Adding CO2 network.") co2_links = create_network_topology(n, "CO2 pipeline ") cost_onshore = (1 - co2_links.underwater_fraction) * costs.at['CO2 pipeline', 'fixed'] * co2_links.length cost_submarine = co2_links.underwater_fraction * costs.at['CO2 submarine pipeline', 'fixed'] * co2_links.length capital_cost = cost_onshore + cost_submarine - + n.madd("Link", co2_links.index, bus0=co2_links.bus0.values + " co2 stored", @@ -636,6 +636,9 @@ def prepare_data(n): nodal_energy_totals = energy_totals.loc[pop_layout.ct].fillna(0.) nodal_energy_totals.index = pop_layout.index + # district heat share not weighted by population + district_heat_share = round(nodal_energy_totals["district heat share"], + ndigits=2) nodal_energy_totals = nodal_energy_totals.multiply(pop_layout.fraction, axis=0) # copy forward the daily average heat demand into each hour, so it can be multipled by the intraday profile @@ -758,7 +761,7 @@ def prepare_data(n): ) - return nodal_energy_totals, heat_demand, ashp_cop, gshp_cop, solar_thermal, transport, avail_profile, dsm_profile, nodal_transport_data + return nodal_energy_totals, heat_demand, ashp_cop, gshp_cop, solar_thermal, transport, avail_profile, dsm_profile, nodal_transport_data, district_heat_share # TODO checkout PyPSA-Eur script @@ -1386,7 +1389,7 @@ def add_heat(n, costs): heat_load = heat_demand[[sector + " water",sector + " space"]].groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor) if name == "urban central": - heat_load = heat_demand.groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor * (1 + options['district_heating_loss'])) + heat_load = heat_demand.groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor * (1 + options['district_heating']['district_heating_loss'])) n.madd("Load", nodes[name], @@ -1671,10 +1674,6 @@ def create_nodes_for_heat_sector(): # distribution of urban population within a country pop_layout["urban_ct_fraction"] = pop_layout["urban"] / \ pop_layout["ct"].map(ct_urban.get) - # todays district heating share per country - dist_heat_share_ct = pd.read_csv(snakemake.input.dh_share, index_col=0, - usecols=[0,1]).dropna()/100 - dist_heat_share = pop_layout.ct.map(dist_heat_share_ct["district heating share"]) sectors = ["residential", "services"] @@ -1686,36 +1685,29 @@ def create_nodes_for_heat_sector(): nodes[sector + " rural"] = pop_layout.index nodes[sector + " urban decentral"] = pop_layout.index - if options["central"] and not options['district_heating_increase']: - central_fraction = options['central_fraction'] - dist_fraction = central_fraction * urban_fraction - nodes["urban central"] = dist_fraction.index - - # take current district heating share - if options['district_heating_increase']: - dist_fraction = dist_heat_share * \ - pop_layout["urban_ct_fraction"] / pop_layout["fraction"] - nodes["urban central"] = dist_fraction.index - # if district heating share larger than urban fraction -> set urban - # fraction to district heating share - urban_fraction = pd.concat([urban_fraction, dist_fraction], - axis=1).max(axis=1) - diff = urban_fraction - dist_fraction - dist_fraction += diff * get(options["dh_strength"], investment_year) - print("************************************") - print( - "the current DH share compared to the maximum possible is increased \ - \n by a factor of ", - get(options["dh_strength"], investment_year), - "resulting DH share: ", - dist_fraction) - print("**********************************") - - else: - dist_fraction = urban_fraction * 0 - nodes["urban central"] = dist_fraction.index - - return nodes, dist_fraction, urban_fraction + # maximum potential of urban demand covered by district heating + central_fraction = options['district_heating']["potential"] + # district heating share at each node + dist_fraction_node = district_heat_share * pop_layout["urban_ct_fraction"] / pop_layout["fraction"] + nodes["urban central"] = dist_fraction_node.index + # if district heating share larger than urban fraction -> set urban + # fraction to district heating share + urban_fraction = pd.concat([urban_fraction, dist_fraction_node], + axis=1).max(axis=1) + # difference of max potential and today's share of district heating + diff = (urban_fraction * central_fraction) - dist_fraction_node + progress = get(options["district_heating"]["potential"], investment_year) + dist_fraction_node += diff * progress + print("************************************") + print( + "the current DH share compared to the maximum possible is increased \ + \n by a progress factor of ", + progress, + "resulting DH share: ", + dist_fraction_node) + print("**********************************") + + return nodes, dist_fraction_node, urban_fraction def add_biomass(n, costs): @@ -1788,7 +1780,7 @@ def add_biomass(n, costs): index_col=0, squeeze=True ) - + # add biomass transport biomass_transport = create_network_topology(n, "biomass transport ", bidirectional=False) @@ -2246,7 +2238,6 @@ def limit_individual_line_extension(n, maxext): opts="", clusters="37", lv=1.0, - opts='', sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', planning_horizons="2030", ) @@ -2300,10 +2291,10 @@ def limit_individual_line_extension(n, maxext): if o == "biomasstransport": options["biomass_transport"] = True - nodal_energy_totals, heat_demand, ashp_cop, gshp_cop, solar_thermal, transport, avail_profile, dsm_profile, nodal_transport_data = prepare_data(n) + nodal_energy_totals, heat_demand, ashp_cop, gshp_cop, solar_thermal, transport, avail_profile, dsm_profile, nodal_transport_data, district_heat_share = prepare_data(n) if "nodistrict" in opts: - options["central"] = False + options["district_heating"]["progress"] = 0.0 if "T" in opts: add_land_transport(n, costs) From f6bb49873028b5c99b97621f6599504180e23af8 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Wed, 29 Sep 2021 16:13:23 +0200 Subject: [PATCH 17/23] include PR review --- doc/data.csv | 54 ++++++++++++++++--------------- scripts/prepare_sector_network.py | 19 +++++------ 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/doc/data.csv b/doc/data.csv index 8e316281..75bdc10e 100644 --- a/doc/data.csv +++ b/doc/data.csv @@ -1,26 +1,28 @@ -description,file/folder,licence,source -JRC IDEES database,jrc-idees-2015/,CC BY 4.0,https://ec.europa.eu/jrc/en/potencia/jrc-idees -urban/rural fraction,urban_percent.csv,unknown,unknown -JRC biomass potentials,biomass/,unknown,https://doi.org/10.2790/39014 -EEA emission statistics,eea/UNFCCC_v23.csv,EEA standard re-use policy,https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16 -Eurostat Energy Balances,eurostat-energy_balances-*/,Eurostat,https://ec.europa.eu/eurostat/web/energy/data/energy-balances -Swiss energy statistics from Swiss Federal Office of Energy,switzerland-sfoe/,unknown,http://www.bfe.admin.ch/themen/00526/00541/00542/02167/index.html?dossier_id=02169 -BASt emobility statistics,emobility/,unknown,http://www.bast.de/DE/Verkehrstechnik/Fachthemen/v2-verkehrszaehlung/Stundenwerte.html?nn=626916 -timezone mappings,timezone_mappings.csv,CC BY 4.0,Tom Brown -BDEW heating profile,heat_load_profile_BDEW.csv,unknown,https://github.com/oemof/demandlib -heating profiles for Aarhus,heat_load_profile_DK_AdamJensen.csv,unknown,Adam Jensen MA thesis at Aarhus University -George Lavidas wind/wave costs,WindWaveWEC_GLTB.xlsx,unknown,George Lavidas -country codes,Country_codes.csv,CC BY 4.0,Marta Victoria -co2 budgets,co2_budget.csv,CC BY 4.0,https://arxiv.org/abs/2004.11009 -existing heating potentials,existing_infrastructure/existing_heating_raw.csv,unknown,https://ec.europa.eu/energy/studies/mapping-and-analyses-current-and-future-2020-2030-heatingcooling-fuel-deployment_en?redir=1 -IRENA existing VRE capacities,existing_infrastructure/{solar|onwind|offwind}_capcity_IRENA.csv,unknown,https://www.irena.org/Statistics/Download-Data -USGS ammonia production,myb1-2017-nitro.xls,unknown,https://www.usgs.gov/centers/nmic/nitrogen-statistics-and-information -hydrogen salt cavern potentials,hydrogen_salt_cavern_potentials.csv,CC BY 4.0,https://doi.org/10.1016/j.ijhydene.2019.12.161 -hotmaps industrial site database,Industrial_Database.csv,CC BY 4.0,https://gitlab.com/hotmaps/industrial_sites/industrial_sites_Industrial_Database -Hotmaps building stock data,data_building_stock.csv,CC BY 4.0,https://gitlab.com/hotmaps/building-stock -U-values Poland,u_values_poland.csv,unknown,https://data.europa.eu/euodp/de/data/dataset/building-stock-observatory -Floor area missing in hotmaps building stock data,floor_area_missing.csv,unknown,https://data.europa.eu/euodp/de/data/dataset/building-stock-observatory -Comparative level investment,comparative_level_investment.csv,Eurostat,https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Comparative_price_levels_for_investment -Electricity taxes,electricity_taxes_eu.csv,Eurostat,https://appsso.eurostat.ec.europa.eu/nui/show.do?dataset=nrg_pc_204&lang=en -Building topologies and corresponding standard values,tabula-calculator-calcsetbuilding.csv,unknown,https://episcope.eu/fileadmin/tabula/public/calc/tabula-calculator.xlsx -Retrofitting thermal envelope costs for Germany,retro_cost_germany.csv,unkown,https://www.iwu.de/forschung/handlungslogiken/kosten-energierelevanter-bau-und-anlagenteile-bei-modernisierung/ +description,file/folder,licence,source,, +JRC IDEES database,jrc-idees-2015/,CC BY 4.0,https://ec.europa.eu/jrc/en/potencia/jrc-idees,, +urban/rural fraction,urban_percent.csv,unknown,unknown,, +JRC biomass potentials,biomass/,unknown,https://doi.org/10.2790/39014,, +EEA emission statistics,eea/UNFCCC_v23.csv,EEA standard re-use policy,https://www.eea.europa.eu/data-and-maps/data/national-emissions-reported-to-the-unfccc-and-to-the-eu-greenhouse-gas-monitoring-mechanism-16,, +Eurostat Energy Balances,eurostat-energy_balances-*/,Eurostat,https://ec.europa.eu/eurostat/web/energy/data/energy-balances,, +Swiss energy statistics from Swiss Federal Office of Energy,switzerland-sfoe/,unknown,http://www.bfe.admin.ch/themen/00526/00541/00542/02167/index.html?dossier_id=02169,, +BASt emobility statistics,emobility/,unknown,http://www.bast.de/DE/Verkehrstechnik/Fachthemen/v2-verkehrszaehlung/Stundenwerte.html?nn=626916,, +timezone mappings,timezone_mappings.csv,CC BY 4.0,Tom Brown,, +BDEW heating profile,heat_load_profile_BDEW.csv,unknown,https://github.com/oemof/demandlib,, +heating profiles for Aarhus,heat_load_profile_DK_AdamJensen.csv,unknown,Adam Jensen MA thesis at Aarhus University,, +George Lavidas wind/wave costs,WindWaveWEC_GLTB.xlsx,unknown,George Lavidas,, +country codes,Country_codes.csv,CC BY 4.0,Marta Victoria,, +co2 budgets,co2_budget.csv,CC BY 4.0,https://arxiv.org/abs/2004.11009,, +existing heating potentials,existing_infrastructure/existing_heating_raw.csv,unknown,https://ec.europa.eu/energy/studies/mapping-and-analyses-current-and-future-2020-2030-heatingcooling-fuel-deployment_en?redir=1,, +IRENA existing VRE capacities,existing_infrastructure/{solar,onwind,offwind}_capcity_IRENA.csv,unknown,https://www.irena.org/Statistics/Download-Data +USGS ammonia production,myb1-2017-nitro.xls,unknown,https://www.usgs.gov/centers/nmic/nitrogen-statistics-and-information,, +hydrogen salt cavern potentials,hydrogen_salt_cavern_potentials.csv,CC BY 4.0,https://doi.org/10.1016/j.ijhydene.2019.12.161,, +hotmaps industrial site database,Industrial_Database.csv,CC BY 4.0,https://gitlab.com/hotmaps/industrial_sites/industrial_sites_Industrial_Database,, +Hotmaps building stock data,data_building_stock.csv,CC BY 4.0,https://gitlab.com/hotmaps/building-stock,, +U-values Poland,u_values_poland.csv,unknown,https://data.europa.eu/euodp/de/data/dataset/building-stock-observatory,, +Floor area missing in hotmaps building stock data,floor_area_missing.csv,unknown,https://data.europa.eu/euodp/de/data/dataset/building-stock-observatory,, +Comparative level investment,comparative_level_investment.csv,Eurostat,https://ec.europa.eu/eurostat/statistics-explained/index.php?title=Comparative_price_levels_for_investment,, +Electricity taxes,electricity_taxes_eu.csv,Eurostat,https://appsso.eurostat.ec.europa.eu/nui/show.do?dataset=nrg_pc_204&lang=en,, +Building topologies and corresponding standard values,tabula-calculator-calcsetbuilding.csv,unknown,https://episcope.eu/fileadmin/tabula/public/calc/tabula-calculator.xlsx,, +Retrofitting thermal envelope costs for Germany,retro_cost_germany.csv,unkown,https://www.iwu.de/forschung/handlungslogiken/kosten-energierelevanter-bau-und-anlagenteile-bei-modernisierung/,, +District heating most countries,jrc-idees-2015/,CC BY 4.0,https://ec.europa.eu/jrc/en/potencia/jrc-idees,, +District heating missing countries,district_heat_share.csv,unkown,https://www.euroheat.org/knowledge-hub/country-profiles,, diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index fea03d69..89ccbebb 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -481,7 +481,7 @@ def add_co2_network(n, costs): def add_dac(n, costs): - heat_carriers = ["urban central heat"] + heat_carriers = ["urban central heat", "services urban decentral heat"] heat_buses = n.buses.index[n.buses.carrier.isin(heat_carriers)] locations = n.buses.location[heat_buses] @@ -489,8 +489,7 @@ def add_dac(n, costs): efficiency3 = -(costs.at['direct air capture', 'heat-input'] - costs.at['direct air capture', 'compression-heat-output']) n.madd("Link", - locations, - suffix=" DAC", + heat_buses.str.replace(" heat", " DAC"), bus0="co2 atmosphere", bus1=spatial.co2.df.loc[locations, "nodes"].values, bus2=locations.values, @@ -1383,7 +1382,7 @@ def add_heat(n, costs): factor = urban_fraction[nodes[name]] - \ dist_fraction[nodes[name]] else: - factor = None + raise NotImplementedError(f" {name} not in " f"heat systems: {heat_systems}") if sector in name: heat_load = heat_demand[[sector + " water",sector + " space"]].groupby(level=1,axis=1).sum()[nodes[name]].multiply(factor) @@ -1670,16 +1669,14 @@ def create_nodes_for_heat_sector(): # urban are areas with high heating density # urban can be split into district heating (central) and individual heating (decentral) - ct_urban = pop_layout.urban.groupby(pop_layout["ct"]).sum() + ct_urban = pop_layout.urban.groupby(pop_layout.ct).sum() # distribution of urban population within a country - pop_layout["urban_ct_fraction"] = pop_layout["urban"] / \ - pop_layout["ct"].map(ct_urban.get) + pop_layout["urban_ct_fraction"] = pop_layout.urban / pop_layout.ct.map(ct_urban.get) sectors = ["residential", "services"] nodes = {} - urban_fraction = pop_layout["urban"] / \ - (pop_layout[["urban", "rural"]].sum(axis=1)) + urban_fraction = pop_layout.urban / pop_layout[["rural", "urban"]].sum(axis=1) for sector in sectors: nodes[sector + " rural"] = pop_layout.index @@ -2239,7 +2236,7 @@ def limit_individual_line_extension(n, maxext): clusters="37", lv=1.0, sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', - planning_horizons="2030", + planning_horizons="2020", ) logging.basicConfig(level=snakemake.config['logging_level']) @@ -2254,7 +2251,7 @@ def limit_individual_line_extension(n, maxext): n = pypsa.Network(snakemake.input.network, override_component_attrs=overrides) pop_layout = pd.read_csv(snakemake.input.clustered_pop_layout, index_col=0) - Nyears = n.snapshot_weightings.sum() / 8760 + Nyears = n.snapshot_weightings.generators.sum() / 8760 costs = prepare_costs(snakemake.input.costs, snakemake.config['costs']['USD2013_to_EUR2013'], From 339187c1f1344a90ee5fbd13fe7d956aa39cbe74 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Wed, 29 Sep 2021 16:23:38 +0200 Subject: [PATCH 18/23] update config --- config.default.yaml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index f8d8082b..e1ddd60d 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -141,14 +141,16 @@ existing_capacities: sector: - central: true - central_fraction: 0.6 - district_heating_increase: true - dh_strength: - 2020: 0 # starting at today's share - 2030: 0.2 - 2040: 0.5 - 2050: 1 # maximum possible share defined in central fraction + district_heating: + potential: 0.6 # maximum fraction of urban demand which can be supplied by district heating + # increase of today's district heating demand to potential maximum district heating share + # progress = 0 means today's district heating share, progress = 1 means maximum fraction of urban demand is supplied by district heating + progress: + 2020: 0.0 + 2030: 0.3 + 2040: 0.6 + 2050: 1.0 + district_heating_loss: 0.15 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. @@ -157,7 +159,6 @@ sector: ICE_upper_degree_factor: 1.6 EV_lower_degree_factor: 0.98 EV_upper_degree_factor: 0.63 - district_heating_loss: 0.15 bev_dsm: true #turns on EV battery bev_availability: 0.5 #How many cars do smart charging bev_energy: 0.05 #average battery size in MWh From 18fabd930e0b7e736a845755a0d228db5873bbc2 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Thu, 30 Sep 2021 17:46:26 +0200 Subject: [PATCH 19/23] Apply suggestions from code review --- scripts/prepare_sector_network.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 320c4726..727b2de8 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1695,14 +1695,13 @@ def create_nodes_for_heat_sector(): diff = (urban_fraction * central_fraction) - dist_fraction_node progress = get(options["district_heating"]["potential"], investment_year) dist_fraction_node += diff * progress - print("************************************") - print( - "the current DH share compared to the maximum possible is increased \ - \n by a progress factor of ", + logger.info( + "The current district heating share compared to the maximum", + "possible is increased by a progress factor of ", progress, - "resulting DH share: ", - dist_fraction_node) - print("**********************************") + "resulting in a district heating share of ", + dist_fraction_node + ) return nodes, dist_fraction_node, urban_fraction @@ -2230,7 +2229,6 @@ def limit_individual_line_extension(n, maxext): lv=1.0, sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1', planning_horizons="2020", - planning_horizons="2030", ) logging.basicConfig(level=snakemake.config['logging_level']) From 0d999a49912429d151fceb5735bad7d888753922 Mon Sep 17 00:00:00 2001 From: lisazeyen <35347358+lisazeyen@users.noreply.github.com> Date: Fri, 1 Oct 2021 17:10:42 +0200 Subject: [PATCH 20/23] prepare_sector_network: code formatting Co-authored-by: Fabian Neumann --- scripts/prepare_sector_network.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 727b2de8..1bb5caf9 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -636,8 +636,7 @@ def prepare_data(n): nodal_energy_totals = energy_totals.loc[pop_layout.ct].fillna(0.) nodal_energy_totals.index = pop_layout.index # district heat share not weighted by population - district_heat_share = round(nodal_energy_totals["district heat share"], - ndigits=2) + district_heat_share = nodal_energy_totals["district heat share"].round(2) nodal_energy_totals = nodal_energy_totals.multiply(pop_layout.fraction, axis=0) # copy forward the daily average heat demand into each hour, so it can be multipled by the intraday profile From c0adb51454622f07ee44151bd87cad101e042f2b Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Sat, 2 Oct 2021 10:03:40 +0200 Subject: [PATCH 21/23] decapitalize columns in build_energy_totals --- scripts/build_energy_totals.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/build_energy_totals.py b/scripts/build_energy_totals.py index 751f23bf..efb5d6da 100644 --- a/scripts/build_energy_totals.py +++ b/scripts/build_energy_totals.py @@ -216,7 +216,7 @@ def idees_per_country(ct, year): ct_totals["Derived heat residential"] = df[46] assert df.index[50] == 'Thermal uses' - ct_totals["Thermal uses residential"] = df[50] + ct_totals["thermal uses residential"] = df[50] # services @@ -246,10 +246,10 @@ def idees_per_country(ct, year): ct_totals["electricity services"] = df[50] assert df.index[49] == "Derived heat" - ct_totals["Derived heat services"] = df[49] + ct_totals["derived heat services"] = df[49] assert df.index[53] == 'Thermal uses' - ct_totals["Thermal uses services"] = df[53] + ct_totals["thermal uses services"] = df[53] # transport @@ -365,10 +365,10 @@ def build_idees(countries, year): totals.loc["passenger car efficiency"] *= 10 # district heating share - district_heat = totals.loc[["Derived heat residential", - "Derived heat services"]].sum() - total_heat = totals.loc[["Thermal uses residential", - "Thermal uses services"]].sum() + district_heat = totals.loc[["derived heat residential", + "derived heat services"]].sum() + total_heat = totals.loc[["thermal uses residential", + "thermal uses services"]].sum() totals.loc["district heat share"] = district_heat.div(total_heat) return totals.T From a60f180f613a9678b2c28c330c9075a5f451bc24 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Sat, 2 Oct 2021 10:23:27 +0200 Subject: [PATCH 22/23] fix logging --- scripts/prepare_sector_network.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 1bb5caf9..5fc4a6e3 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1694,12 +1694,10 @@ def create_nodes_for_heat_sector(): diff = (urban_fraction * central_fraction) - dist_fraction_node progress = get(options["district_heating"]["potential"], investment_year) dist_fraction_node += diff * progress - logger.info( + print( "The current district heating share compared to the maximum", - "possible is increased by a progress factor of ", - progress, - "resulting in a district heating share of ", - dist_fraction_node + f"possible is increased by a progress factor of\n{progress}", + f"resulting in a district heating share of\n{dist_fraction_node}" ) return nodes, dist_fraction_node, urban_fraction From 7987fd23cfa00cc5b53e46fab73c630520c7ab43 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Sat, 2 Oct 2021 10:33:56 +0200 Subject: [PATCH 23/23] add release note --- doc/release_notes.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 16889268..eb3f7a18 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -88,6 +88,7 @@ Future release * Compatibility with ``xarray`` version 0.19. * Separate basic chemicals into HVC, chlorine, methanol and ammonia [`#166 `_]. * Add option to specify reuse, primary production, and mechanical and chemical recycling fraction of platics [`#166 `_]. +* Include today's district heating shares in myopic optimisation and add option to specify exogenous path for district heating share increase under ``sector: district_heating:`` [`#149 `_]. PyPSA-Eur-Sec 0.5.0 (21st May 2021) ===================================