From 9fac6f539247333cab50345a17e12ae3f575d65a Mon Sep 17 00:00:00 2001 From: eb5194 Date: Fri, 2 Oct 2020 12:20:55 +0200 Subject: [PATCH 01/13] prepare_sector_network: read input file as .csv --- scripts/prepare_sector_network.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 0bab8487..536378f2 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -68,11 +68,9 @@ def update_wind_solar_costs(n,costs): #assign clustered bus #map initial network -> simplified network - busmap_s = pd.read_hdf(snakemake.input.clustermaps, - key="/busmap_s") + busmap_s = pd.read_csv(snakemake.input.busmap_s, index_col=0).squeeze() #map simplified network -> clustered network - busmap = pd.read_hdf(snakemake.input.clustermaps, - key="/busmap") + busmap = pd.read_csv(snakemake.input.busmap, index_col=0).squeeze() #map initial network -> clustered network clustermaps = busmap_s.map(busmap) @@ -1747,7 +1745,8 @@ if __name__ == "__main__": costs='technology-data/outputs/costs_{planning_horizons}.csv', profile_offwind_ac='pypsa-eur/resources/profile_offwind-ac.nc', profile_offwind_dc='pypsa-eur/resources/profile_offwind-dc.nc', - clustermaps="pypsa-eur/resources/clustermaps_{network}_s{simpl}_{clusters}.h5", + busmap_s='pypsa-eur/resources/busmap_{network}_s{simpl}.csv', + busmap='pypsa-eur/resources/busmap_{network}_s{simpl}_{clusters}.csv', cop_air_total='pypsa-eur-sec/resources/cop_air_total_{network}_s{simpl}_{clusters}.nc', cop_soil_total='pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc', solar_thermal_total='pypsa-eur-sec/resources/solar_thermal_total_{network}_s{simpl}_{clusters}.nc', From 5dabdac28865e7b2ee6a1533658a539c3bd323e4 Mon Sep 17 00:00:00 2001 From: eb5194 Date: Fri, 2 Oct 2020 12:21:31 +0200 Subject: [PATCH 02/13] add_existing_baseyear: read input file as .csv --- scripts/add_existing_baseyear.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/add_existing_baseyear.py b/scripts/add_existing_baseyear.py index 5010e8e7..cfef2e5e 100644 --- a/scripts/add_existing_baseyear.py +++ b/scripts/add_existing_baseyear.py @@ -170,10 +170,8 @@ def add_power_capacities_installed_before_baseyear(n, grouping_years, costs, bas df_agg.Fueltype = df_agg.Fueltype.map(rename_fuel) #assign clustered bus - busmap_s = pd.read_hdf(snakemake.input.clustermaps, - key="/busmap_s") - busmap = pd.read_hdf(snakemake.input.clustermaps, - key="/busmap") + busmap_s = pd.read_csv(snakemake.input.busmap_s, index_col=0).squeeze() + busmap = pd.read_csv(snakemake.input.busmap, index_col=0).squeeze() clustermaps = busmap_s.map(busmap) clustermaps.index = clustermaps.index.astype(int) @@ -416,7 +414,8 @@ if __name__ == "__main__": planning_horizons='2020'), input=dict(network='pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc', powerplants='pypsa-eur/resources/powerplants.csv', - clustermaps='pypsa-eur/resources/clustermaps_{network}_s{simpl}_{clusters}.h5', + busmap_s='pypsa-eur/resources/busmap_{network}_s{simpl}.csv', + busmap='pypsa-eur/resources/busmap_{network}_s{simpl}_{clusters}.csv', costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv', cop_air_total="pypsa-eur-sec/resources/cop_air_total_{network}_s{simpl}_{clusters}.nc", cop_soil_total="pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc"), From 30adabbcaa534bd1f354069ad9ff6926ea4a2985 Mon Sep 17 00:00:00 2001 From: eb5194 Date: Fri, 2 Oct 2020 12:22:25 +0200 Subject: [PATCH 03/13] Snakefile: input files in pypsa-eur became .csv --- Snakefile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Snakefile b/Snakefile index b01d7edd..028c2c78 100644 --- a/Snakefile +++ b/Snakefile @@ -245,7 +245,8 @@ rule prepare_sector_network: co2_budget="data/co2_budget.csv", profile_offwind_ac=pypsaeur("resources/profile_offwind-ac.nc"), profile_offwind_dc=pypsaeur("resources/profile_offwind-dc.nc"), - clustermaps=pypsaeur('resources/clustermaps_{network}_s{simpl}_{clusters}.h5'), + busmap_s=pypsaeur("resources/busmap_{network}_s{simpl}.csv"), + busmap=pypsaeur("resources/busmap_{network}_s{simpl}_{clusters}.csv"), clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv", simplified_pop_layout="resources/pop_layout_{network}_s{simpl}.csv", industrial_demand="resources/industrial_demand_{network}_s{simpl}_{clusters}.csv", @@ -365,7 +366,8 @@ if config["foresight"] == "myopic": input: network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc', powerplants=pypsaeur('resources/powerplants.csv'), - clustermaps=pypsaeur('resources/clustermaps_{network}_s{simpl}_{clusters}.h5'), + busmap_s=pypsaeur("resources/busmap_{network}_s{simpl}.csv"), + busmap=pypsaeur("resources/busmap_{network}_s{simpl}_{clusters}.csv"), clustered_pop_layout="resources/pop_layout_{network}_s{simpl}_{clusters}.csv", costs=config['costs_dir'] + "costs_{}.csv".format(config['scenario']['planning_horizons'][0]), cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc", From 989495ce79693d1c1b41bb095f6c2b3340f6127b Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Wed, 21 Oct 2020 14:31:37 +0200 Subject: [PATCH 04/13] prepare_sector_network: Type of new busmap index and values to str Otherwise they're read in as integers and the mapping fails. --- scripts/prepare_sector_network.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index a5221bee..df299d20 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -69,8 +69,12 @@ def update_wind_solar_costs(n,costs): #assign clustered bus #map initial network -> simplified network busmap_s = pd.read_csv(snakemake.input.busmap_s, index_col=0).squeeze() + busmap_s.index = busmap_s.index.astype(str) + busmap_s = busmap_s.astype(str) #map simplified network -> clustered network busmap = pd.read_csv(snakemake.input.busmap, index_col=0).squeeze() + busmap.index = busmap.index.astype(str) + busmap = busmap.astype(str) #map initial network -> clustered network clustermaps = busmap_s.map(busmap) From 9721dccc0f72d0d53505d9b6dcaa0a4a2ed7e881 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Wed, 28 Oct 2020 18:21:28 +0100 Subject: [PATCH 05/13] Make micro CHP optional, option to reduce non-NH3 basic chemicals Also add option to limit extension of HVAC and HVDC transmission lines. Also fix bug that option to limit solar & wind potential was bypassed. --- config.default.yaml | 3 +++ config.myopic.yaml | 3 +++ ...industrial_production_per_country_tomorrow.py | 2 ++ scripts/prepare_sector_network.py | 16 ++++++++++++---- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 3498a33b..7aa23901 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -87,6 +87,7 @@ sector: 'boilers' : True 'oil_boilers': False 'chp' : True + 'micro_chp' : False 'solar_thermal' : True 'solar_cf_correction': 0.788457 # = >>> 1/1.2683 'marginal_cost_storage' : 0. #1e-4 @@ -174,6 +175,7 @@ industry: 'MWh_elec_per_tNH3_electrolysis' : 1.17 # from https://doi.org/10.1016/j.joule.2018.04.017 Table 13 (air separation and HB) 'NH3_process_emissions' : 24.5 # in MtCO2/a from SMR for H2 production for NH3 from UNFCCC for 2015 for EU28 'petrochemical_process_emissions' : 25.5 # in MtCO2/a for petrochemical and other from UNFCCC for 2015 for EU28 + 'HVC_primary_fraction' : 1.0 #fraction of current non-ammonia basic chemicals produced via primary route plotting: map: @@ -310,6 +312,7 @@ plotting: "electricity" : "k" "gas for industry" : "#333333" "solid biomass for industry" : "#555555" + "industry electricity" : "#222222" "industry new electricity" : "#222222" "process emissions to stored" : "#444444" "process emissions to atmosphere" : "#888888" diff --git a/config.myopic.yaml b/config.myopic.yaml index 454a8525..c7f5ac1e 100644 --- a/config.myopic.yaml +++ b/config.myopic.yaml @@ -87,6 +87,7 @@ sector: 'boilers' : True 'oil_boilers': False 'chp' : True + 'micro_chp' : False 'solar_thermal' : True 'solar_cf_correction': 0.788457 # = >>> 1/1.2683 'marginal_cost_storage' : 0. #1e-4 @@ -174,6 +175,7 @@ industry: 'MWh_elec_per_tNH3_electrolysis' : 1.17 # from https://doi.org/10.1016/j.joule.2018.04.017 Table 13 (air separation and HB) 'NH3_process_emissions' : 24.5 # in MtCO2/a from SMR for H2 production for NH3 from UNFCCC for 2015 for EU28 'petrochemical_process_emissions' : 25.5 # in MtCO2/a for petrochemical and other from UNFCCC for 2015 for EU28 + 'HVC_primary_fraction' : 1.0 #fraction of current non-ammonia basic chemicals produced via primary route plotting: map: @@ -310,6 +312,7 @@ plotting: "electricity" : "k" "gas for industry" : "#333333" "solid biomass for industry" : "#555555" + "industry electricity" : "#222222" "industry new electricity" : "#222222" "process emissions to stored" : "#444444" "process emissions to atmosphere" : "#888888" diff --git a/scripts/build_industrial_production_per_country_tomorrow.py b/scripts/build_industrial_production_per_country_tomorrow.py index 1bfc40f2..bc66077c 100644 --- a/scripts/build_industrial_production_per_country_tomorrow.py +++ b/scripts/build_industrial_production_per_country_tomorrow.py @@ -22,6 +22,8 @@ fraction_primary_stays_primary = snakemake.config["industry"]["Al_primary_fracti 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"] +industrial_production["Basic chemicals (without ammonia)"] *= snakemake.config["industry"]['HVC_primary_fraction'] + industrial_production.to_csv(snakemake.output.industrial_production_per_country_tomorrow, float_format='%.2f') diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index df299d20..f6e8a7be 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1248,7 +1248,8 @@ def add_heat(network): lifetime=costs.at['central gas CHP CCS','lifetime']) else: - network.madd("Link", + if options["micro_chp"]: + network.madd("Link", nodes[name] + " " + name + " micro gas CHP", p_nom_extendable=True, bus0="EU gas", @@ -1883,17 +1884,24 @@ if __name__ == "__main__": else: limit = float(limit.replace("p",".").replace("m","-")) add_co2limit(n, Nyears, limit) - # add_emission_prices(n, exclude_co2=True) - # if 'Ep' in opts: - # add_emission_prices(n) + for o in opts: for tech in ["solar","onwind","offwind"]: if tech in o: limit = o[o.find(tech)+len(tech):] limit = float(limit.replace("p",".").replace("m","-")) + print("changing potential for",tech,"by factor",limit) restrict_technology_potential(n,tech,limit) + if o[:10] == 'linemaxext': + maxext = float(o[10:])*1e3 + print("limiting new HVAC and HVDC extensions to",maxext,"MW") + n.lines['s_nom_max'] = n.lines['s_nom'] + maxext + hvdc = n.links.index[n.links.carrier == 'DC'] + n.links.loc[hvdc,'p_nom_max'] = n.links.loc[hvdc,'p_nom'] + maxext + + if snakemake.config["sector"]['electricity_distribution_grid']: insert_electricity_distribution_grid(n) if snakemake.config["sector"]['gas_distribution_grid']: From a613da6031980ce6f717cf2f51eafb8fbe3618b5 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Wed, 28 Oct 2020 18:24:54 +0100 Subject: [PATCH 06/13] make_summary: Don't add back line costs for LV for PyPSA-Eur > 0.2.0 PyPSA-Eur now includes HVAC and HVDC line costs with LV option. So don't add them back to costs afterwards. --- scripts/make_summary.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/scripts/make_summary.py b/scripts/make_summary.py index 2ef0285d..e3e937a0 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -186,14 +186,6 @@ def calculate_costs(n,label,costs): costs.loc[marginal_costs_grouped.index,label] = marginal_costs_grouped - #add back in costs of links if there is a line volume limit - if label[1] != "opt": - costs.loc[("links-added","capital","transmission lines"),label] = ((costs_db.at['HVDC overhead', 'fixed']*n.links.length + costs_db.at['HVDC inverter pair', 'fixed'])*n.links.p_nom_opt)[n.links.carrier == "DC"].sum() - costs.loc[("lines-added","capital","transmission lines"),label] = costs_db.at["HVAC overhead", "fixed"]*(n.lines.length*n.lines.s_nom_opt).sum() - else: - costs.loc[("links-added","capital","transmission lines"),label] = (costs_db.at['HVDC inverter pair', 'fixed']*n.links.p_nom_opt)[n.links.carrier == "DC"].sum() - - #add back in all hydro #costs.loc[("storage_units","capital","hydro"),label] = (0.01)*2e6*n.storage_units.loc[n.storage_units.group=="hydro","p_nom"].sum() #costs.loc[("storage_units","capital","PHS"),label] = (0.01)*2e6*n.storage_units.loc[n.storage_units.group=="PHS","p_nom"].sum() From 65944e20caf78071feb18a3f2234fd904fa5e683 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Wed, 28 Oct 2020 18:47:28 +0100 Subject: [PATCH 07/13] plot_network: Fix bugs in plotting of today's network --- scripts/plot_network.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/plot_network.py b/scripts/plot_network.py index 707481e7..cd419808 100644 --- a/scripts/plot_network.py +++ b/scripts/plot_network.py @@ -324,7 +324,7 @@ def plot_map_without(network): fig.set_size_inches(7, 6) # PDF has minimum width, so set these to zero - line_lower_threshold = 0. + line_lower_threshold = 200. line_upper_threshold = 1e4 linewidth_factor = 2e3 ac_color = "gray" @@ -343,19 +343,19 @@ def plot_map_without(network): line_widths = n.lines.s_nom_min link_widths = n.links.p_nom_min - line_widths[line_widths < line_upper_threshold] = 0. - link_widths[link_widths < line_upper_threshold] = 0. + line_widths[line_widths < line_lower_threshold] = 0. + link_widths[link_widths < line_lower_threshold] = 0. line_widths[line_widths > line_upper_threshold] = line_upper_threshold link_widths[link_widths > line_upper_threshold] = line_upper_threshold - n.plot(bus_sizes=10, - bus_colors="k", + n.plot(bus_colors="k", line_colors=ac_color, link_colors=dc_color, line_widths=line_widths / linewidth_factor, link_widths=link_widths / linewidth_factor, - ax=ax, boundaries=(-10, 30, 34, 70)) + ax=ax, boundaries=(-10, 30, 34, 70), + color_geomap={'ocean': 'lightblue', 'land': "palegoldenrod"}) handles = [] labels = [] From 5b4f8837db608982d51ef5a2d0ed981626e75728 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Wed, 28 Oct 2020 18:54:30 +0100 Subject: [PATCH 08/13] doc: Update information on spatial distribution of industry demand --- doc/index.rst | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/doc/index.rst b/doc/index.rst index b8294571..d9108eda 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -78,27 +78,26 @@ For example: Electricity network: nodal. Electricity demand: nodal, distributed in each country based on -population and GDP. +population, GDP and location of industrial facilities. Building heating demand: nodal, distributed in each country based on population. Industry demand: nodal, distributed in each country based on -population (will be corrected to real locations of industry, see -github issue). +locations of industry from `HotMaps database `_. Hydrogen network: nodal. -Methane network: copper-plated for Europe, since future demand is so +Methane network: single node for Europe, since future demand is so low and no bottlenecks are expected. -Solid biomass: copper-plated until transport costs can be +Solid biomass: single node for Europe, until transport costs can be incorporated. -CO2: copper-plated (but a transport and storage cost is added for -sequestered CO2). +CO2: single node for Europe, but a transport and storage cost is added for +sequestered CO2. -Liquid hydrocarbons: copper-plated since transport costs are low. +Liquid hydrocarbons: single node for Europe, since transport costs are low. From a143ab7122e7ec8311bbb0d2fdcb5d05fd075a8e Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Tue, 24 Nov 2020 13:44:02 +0100 Subject: [PATCH 09/13] energy_totals: only fix 'BA' if in list of countries --- scripts/build_energy_totals.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/build_energy_totals.py b/scripts/build_energy_totals.py index 1682ac40..0cfa709b 100644 --- a/scripts/build_energy_totals.py +++ b/scripts/build_energy_totals.py @@ -378,12 +378,12 @@ def build_energy_totals(): clean_df.loc[missing,"total aviation passenger"] = clean_df.loc[missing,["total domestic aviation passenger","total international aviation passenger"]].sum(axis=1) clean_df.loc[missing,"total aviation freight"] = clean_df.loc[missing,["total domestic aviation freight","total international aviation freight"]].sum(axis=1) + if "BA" in clean_df.index: + #fix missing data for BA (services and road energy data) + missing = (clean_df.loc["BA"] == 0.) - #fix missing data for BA (services and road energy data) - missing = (clean_df.loc["BA"] == 0.) - - #add back in proportional to RS with ratio of total residential demand - clean_df.loc["BA",missing] = clean_df.loc["BA","total residential"]/clean_df.loc["RS","total residential"]*clean_df.loc["RS",missing] + #add back in proportional to RS with ratio of total residential demand + clean_df.loc["BA",missing] = clean_df.loc["BA","total residential"]/clean_df.loc["RS","total residential"]*clean_df.loc["RS",missing] clean_df.to_csv(snakemake.output.energy_name) From abbaa0d098d335696a1e8f14d065658d1585e109 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Mon, 30 Nov 2020 13:21:38 +0100 Subject: [PATCH 10/13] Move CO2 budgets from data/co2_budget.csv to dict in config.yaml Strategy is too keep as much of configuration in config.yaml as possible. We also aim to allow exogenous investment-year-dependent configurations to be done in a similar manner (e.g. share of district heating or FCEV transport). --- Snakefile | 60 ++++++++++++++----------------- config.default.yaml | 8 +++-- config.myopic.yaml | 16 +++++++-- data/co2_budget.csv | 8 ----- scripts/make_summary.py | 8 ++--- scripts/plot_summary.py | 3 +- scripts/prepare_sector_network.py | 32 ++++++++--------- scripts/solve_network.py | 2 +- 8 files changed, 68 insertions(+), 69 deletions(-) delete mode 100644 data/co2_budget.csv diff --git a/Snakefile b/Snakefile index f003bd5e..1a572562 100644 --- a/Snakefile +++ b/Snakefile @@ -25,17 +25,12 @@ rule all: rule solve_all_networks: input: - expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc", + expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc", **config['scenario']) -rule test_script: - input: - expand("resources/heat_demand_urban_elec_s_{clusters}.nc", - **config['scenario']) - rule prepare_sector_networks: input: - expand(config['results_dir'] + config['run'] + "/prenetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc", + expand(config['results_dir'] + config['run'] + "/prenetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc", **config['scenario']) @@ -295,7 +290,6 @@ rule prepare_sector_network: heat_profile="data/heat_load_profile_BDEW.csv", costs=config['costs_dir'] + "costs_{planning_horizons}.csv", h2_cavern = "data/hydrogen_salt_cavern_potentials.csv", - co2_budget="data/co2_budget.csv", profile_offwind_ac=pypsaeur("resources/profile_offwind-ac.nc"), profile_offwind_dc=pypsaeur("resources/profile_offwind-dc.nc"), busmap_s=pypsaeur("resources/busmap_{network}_s{simpl}.csv"), @@ -321,20 +315,20 @@ rule prepare_sector_network: solar_thermal_total="resources/solar_thermal_total_{network}_s{simpl}_{clusters}.nc", solar_thermal_urban="resources/solar_thermal_urban_{network}_s{simpl}_{clusters}.nc", solar_thermal_rural="resources/solar_thermal_rural_{network}_s{simpl}_{clusters}.nc" - output: config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc' + output: config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc' threads: 1 resources: mem_mb=2000 - benchmark: config['results_dir'] + config['run'] + "/benchmarks/prepare_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}" + benchmark: config['results_dir'] + config['run'] + "/benchmarks/prepare_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}" script: "scripts/prepare_sector_network.py" rule plot_network: input: - network=config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc" + network=config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc" output: - map=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{co2_budget_name}_{planning_horizons}.pdf", - today=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}-today.pdf" + map=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{planning_horizons}.pdf", + today=config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}-today.pdf" threads: 2 resources: mem_mb=10000 script: "scripts/plot_network.py" @@ -351,10 +345,10 @@ rule copy_config: rule make_summary: input: - networks=expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc", + networks=expand(config['results_dir'] + config['run'] + "/postnetworks/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc", **config['scenario']), costs=config['costs_dir'] + "costs_{}.csv".format(config['scenario']['planning_horizons'][0]), - plots=expand(config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{co2_budget_name}_{planning_horizons}.pdf", + plots=expand(config['results_dir'] + config['run'] + "/maps/elec_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}-costs-all_{planning_horizons}.pdf", **config['scenario']) #heat_demand_name='data/heating/daily_heat_demand.h5' output: @@ -397,16 +391,16 @@ if config["foresight"] == "overnight": rule solve_network: input: - network=config['results_dir'] + config['run'] + "/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc", + network=config['results_dir'] + config['run'] + "/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc", costs=config['costs_dir'] + "costs_{planning_horizons}.csv", config=config['summary_dir'] + '/' + config['run'] + '/configs/config.yaml' - output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc" + output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc" shadow: "shallow" log: - solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_solver.log", - python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_python.log", - memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_memory.log" - benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}" + solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_solver.log", + python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_python.log", + memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_memory.log" + benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}" threads: 4 resources: mem_mb=config['solving']['mem'] # group: "solve" # with group, threads is ignored https://bitbucket.org/snakemake/snakemake/issues/971/group-job-description-does-not-contain @@ -417,7 +411,7 @@ if config["foresight"] == "myopic": rule add_existing_baseyear: input: - network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc', + network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc', powerplants=pypsaeur('resources/powerplants.csv'), busmap_s=pypsaeur("resources/busmap_{network}_s{simpl}.csv"), busmap=pypsaeur("resources/busmap_{network}_s{simpl}_{clusters}.csv"), @@ -425,7 +419,7 @@ if config["foresight"] == "myopic": costs=config['costs_dir'] + "costs_{}.csv".format(config['scenario']['planning_horizons'][0]), cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc", cop_air_total="resources/cop_air_total_{network}_s{simpl}_{clusters}.nc" - output: config['results_dir'] + config['run'] + '/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc' + output: config['results_dir'] + config['run'] + '/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc' wildcard_constraints: planning_horizons=config['scenario']['planning_horizons'][0] #only applies to baseyear threads: 1 @@ -434,36 +428,36 @@ if config["foresight"] == "myopic": def process_input(wildcards): i = config["scenario"]["planning_horizons"].index(int(wildcards.planning_horizons)) - return config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_" + str(config["scenario"]["planning_horizons"][i-1]) + ".nc" + return config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_" + str(config["scenario"]["planning_horizons"][i-1]) + ".nc" rule add_brownfield: input: - network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc', + network=config['results_dir'] + config['run'] + '/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc', network_p=process_input, #solved network at previous time step costs=config['costs_dir'] + "costs_{planning_horizons}.csv", cop_soil_total="resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc", cop_air_total="resources/cop_air_total_{network}_s{simpl}_{clusters}.nc" - output: config['results_dir'] + config['run'] + "/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc" + output: config['results_dir'] + config['run'] + "/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc" threads: 4 - resources: mem_mb=2000 + resources: mem_mb=10000 script: "scripts/add_brownfield.py" ruleorder: add_existing_baseyear > add_brownfield rule solve_network_myopic: input: - network=config['results_dir'] + config['run'] + "/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc", + network=config['results_dir'] + config['run'] + "/prenetworks-brownfield/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc", costs=config['costs_dir'] + "costs_{planning_horizons}.csv", config=config['summary_dir'] + '/' + config['run'] + '/configs/config.yaml' - output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}.nc" + output: config['results_dir'] + config['run'] + "/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}.nc" shadow: "shallow" log: - solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_solver.log", - python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_python.log", - memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}_memory.log" - benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{co2_budget_name}_{planning_horizons}" + solver=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_solver.log", + python=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_python.log", + memory=config['results_dir'] + config['run'] + "/logs/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}_memory.log" + benchmark: config['results_dir'] + config['run'] + "/benchmarks/solve_network/{network}_s{simpl}_{clusters}_lv{lv}_{opts}_{sector_opts}_{planning_horizons}" threads: 4 resources: mem_mb=config['solving']['mem'] script: "scripts/solve_network.py" diff --git a/config.default.yaml b/config.default.yaml index 7aa23901..cd3ceca9 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -25,7 +25,11 @@ scenario: # solarx or onwindx changes the available installable potential by factor x # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv planning_horizons : [2030] #investment years for myopic and perfect; or costs year for overnight - co2_budget_name: ['go'] #gives shape of CO2 budgets over planning horizon + +#CO2 budget as a fraction of 1990 emission +#this is over-ridden if CO2Lx is set in sector_opts +co2_budget: + 2030: 0 # snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec snapshots: @@ -166,7 +170,7 @@ solving: industry: 'St_primary_fraction' : 0.3 # fraction of steel produced via primary route (DRI + EAF) versus secondary route (EAF); today fraction is 0.6 - 'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279 + '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 'MWh_CH4_per_tNH3_SMR' : 10.8 # 2012's demand from https://ec.europa.eu/docsroom/documents/4165/attachments/1/translations/en/renditions/pdf diff --git a/config.myopic.yaml b/config.myopic.yaml index c7f5ac1e..a9a1279e 100644 --- a/config.myopic.yaml +++ b/config.myopic.yaml @@ -25,7 +25,19 @@ scenario: # solarx or onwindx changes the available installable potential by factor x # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv planning_horizons : [2020, 2030, 2040, 2050] #investment years for myopic and perfect; or costs year for overnight - co2_budget_name: ['go'] #gives shape of CO2 budgets over planning horizon + + +#CO2 budget as a fraction of 1990 emission +#this is over-ridden if CO2Lx is set in sector_opts +co2_budget: + 2020: 0.7011648746 + 2025: 0.5241935484 + 2030: 0.2970430108 + 2035: 0.1500896057 + 2040: 0.0712365591 + 2045: 0.0322580645 + 2050: 0 + # snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec snapshots: @@ -166,7 +178,7 @@ solving: industry: 'St_primary_fraction' : 0.3 # fraction of steel produced via primary route (DRI + EAF) versus secondary route (EAF); today fraction is 0.6 - 'H2_DRI' : 1.7 #H2 consumption in Direct Reduced Iron (DRI), MWh_H2,LHV/ton_Steel from Vogl et al (2018) doi:10.1016/j.jclepro.2018.08.279 + '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 'MWh_CH4_per_tNH3_SMR' : 10.8 # 2012's demand from https://ec.europa.eu/docsroom/documents/4165/attachments/1/translations/en/renditions/pdf diff --git a/data/co2_budget.csv b/data/co2_budget.csv deleted file mode 100644 index 8e66a993..00000000 --- a/data/co2_budget.csv +++ /dev/null @@ -1,8 +0,0 @@ -,go,wait -2020,0.7011648746,0.7011648746 -2025,0.5241935484,0.6285842294 -2030,0.2970430108,0.3503584229 -2035,0.1500896057,0.0725806452 -2040,0.0712365591,0 -2045,0.0322580645,0 -2050,0,0 diff --git a/scripts/make_summary.py b/scripts/make_summary.py index e3e937a0..3ff79934 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -522,7 +522,7 @@ outputs = ["nodal_costs", def make_summaries(networks_dict): - columns = pd.MultiIndex.from_tuples(networks_dict.keys(),names=["cluster","lv","opt", "co2_budget_name","planning_horizon"]) + columns = pd.MultiIndex.from_tuples(networks_dict.keys(),names=["cluster","lv","opt","planning_horizon"]) df = {} @@ -571,21 +571,19 @@ if __name__ == "__main__": for item in outputs: snakemake.output[item] = snakemake.config['summary_dir'] + '/{name}/csvs/{item}.csv'.format(name=snakemake.config['run'],item=item) - networks_dict = {(cluster,lv,opt+sector_opt, co2_budget_name, planning_horizon) : - snakemake.config['results_dir'] + snakemake.config['run'] + '/postnetworks/elec_s{simpl}_{cluster}_lv{lv}_{opt}_{sector_opt}_{co2_budget_name}_{planning_horizon}.nc'\ + networks_dict = {(cluster, lv, opt+sector_opt, planning_horizon) : + snakemake.config['results_dir'] + snakemake.config['run'] + '/postnetworks/elec_s{simpl}_{cluster}_lv{lv}_{opt}_{sector_opt}_{planning_horizon}.nc'\ .format(simpl=simpl, cluster=cluster, opt=opt, lv=lv, sector_opt=sector_opt, - co2_budget_name=co2_budget_name, planning_horizon=planning_horizon)\ for simpl in snakemake.config['scenario']['simpl'] \ for cluster in snakemake.config['scenario']['clusters'] \ for opt in snakemake.config['scenario']['opts'] \ for sector_opt in snakemake.config['scenario']['sector_opts'] \ for lv in snakemake.config['scenario']['lv'] \ - for co2_budget_name in snakemake.config['scenario']['co2_budget_name'] \ for planning_horizon in snakemake.config['scenario']['planning_horizons']} print(networks_dict) diff --git a/scripts/plot_summary.py b/scripts/plot_summary.py index 79064690..9ecea108 100644 --- a/scripts/plot_summary.py +++ b/scripts/plot_summary.py @@ -256,7 +256,8 @@ if __name__ == "__main__": snakemake.input["balances"] = snakemake.config['summary_dir'] + '/test/csvs/supply_energy.csv' snakemake.output["balances"] = snakemake.config['summary_dir'] + '/test/graphs/balances-energy.csv' - n_header = 5 + n_header = 4 + plot_costs() plot_energy() diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index f6e8a7be..8e825292 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -1747,11 +1747,9 @@ if __name__ == "__main__": snakemake = MockSnakemake( wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0', opts='', planning_horizons='2020', - co2_budget_name='go', sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1'), input=dict(network='pypsa-eur/networks/{network}_s{simpl}_{clusters}_ec_lv{lv}_{opts}.nc', timezone_mappings='pypsa-eur-sec/data/timezone_mappings.csv', - co2_budget='pypsa-eur-sec/data/co2_budget.csv', clustered_pop_layout='pypsa-eur-sec/resources/pop_layout_{network}_s{simpl}_{clusters}.csv', costs='technology-data/outputs/costs_{planning_horizons}.csv', profile_offwind_ac='pypsa-eur/resources/profile_offwind-ac.nc', @@ -1868,22 +1866,22 @@ if __name__ == "__main__": else: logger.info("No resampling") - - if snakemake.config["foresight"] == 'myopic': - co2_limits=pd.read_csv(snakemake.input.co2_budget, index_col=0) - year=snakemake.wildcards.planning_horizons[-4:] - limit=co2_limits.loc[int(year),snakemake.config["scenario"]["co2_budget_name"]] - add_co2limit(n, Nyears, limit) + #process CO2 limit + if type(snakemake.config["co2_budget"]) == dict: + year=int(snakemake.wildcards.planning_horizons[-4:]) + limit=snakemake.config["co2_budget"][year] else: - for o in opts: - if "Co2L" in o: - limit = o[o.find("Co2L")+4:] - print(o,limit) - if limit == "": - limit = snakemake.config['co2_reduction'] - else: - limit = float(limit.replace("p",".").replace("m","-")) - add_co2limit(n, Nyears, limit) + limit=snakemake.config["co2_budget"] + print("CO2 limit set to",limit) + + for o in opts: + if "Co2L" in o: + limit = o[o.find("Co2L")+4:] + limit = float(limit.replace("p",".").replace("m","-")) + print("overriding CO2 limit with scenario limit",limit) + + print("adding CO2 budget limit as per unit of 1990 levels of",limit) + add_co2limit(n, Nyears, limit) for o in opts: diff --git a/scripts/solve_network.py b/scripts/solve_network.py index a7078433..51086038 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -351,7 +351,7 @@ def solve_network(n, config=None, solver_log=None, opts=None): # fn = os.path.basename(snakemake.output[0]) # n.export_to_netcdf('/home/vres/data/jonas/playground/pypsa-eur/' + fn) - status, termination_condition = run_lopf(n, fix_ext_lines=True) + status, termination_condition = run_lopf(n, allow_warning_status=True, fix_ext_lines=True) # Drop zero lines from network # zero_lines_i = n.lines.index[(n.lines.s_nom_opt == 0.) & n.lines.s_nom_extendable] From 801f0a403d05a48aeef8dec63379e2e746131b07 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Mon, 30 Nov 2020 16:10:11 +0100 Subject: [PATCH 11/13] Remove config.myopic.yaml to avoid many duplicated parameters It is identical to config.default.yaml except for two parameters (foresight and planning_horizons) so I decided to consolidate the example configs. Instructions for how to use the myopic foresight can be found in the documentation (now updated). --- config.default.yaml | 19 ++- config.myopic.yaml | 355 -------------------------------------------- doc/myopic.rst | 4 +- doc/overnight.rst | 2 + 4 files changed, 18 insertions(+), 362 deletions(-) delete mode 100644 config.myopic.yaml diff --git a/config.default.yaml b/config.default.yaml index cd3ceca9..024c0e10 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -6,8 +6,8 @@ results_dir: 'results/' summary_dir: results costs_dir: '../technology-data/outputs/' run: 'your-run-name' # use this to keep track of runs with different settings -foresight: 'overnight' #options are overnight, myopic, perfect (perfect is not yet implemented) - +foresight: 'overnight' # options are overnight, myopic, perfect (perfect is not yet implemented) +# if you use myopic or perfect foresight, set the investment years in "planning_horizons" below scenario: sectors: [E] # ignore this legacy setting @@ -24,12 +24,19 @@ scenario: # B for biomass supply, I for industry, shipping and aviation # solarx or onwindx changes the available installable potential by factor x # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv - planning_horizons : [2030] #investment years for myopic and perfect; or costs year for overnight + planning_horizons : [2030] # investment years for myopic and perfect; or costs year for overnight + # for example, set to [2020, 2030, 2040, 2050] for myopic foresight -#CO2 budget as a fraction of 1990 emission -#this is over-ridden if CO2Lx is set in sector_opts +# CO2 budget as a fraction of 1990 emissions +# this is over-ridden if CO2Lx is set in sector_opts co2_budget: - 2030: 0 + 2020: 0.7011648746 + 2025: 0.5241935484 + 2030: 0.2970430108 + 2035: 0.1500896057 + 2040: 0.0712365591 + 2045: 0.0322580645 + 2050: 0 # snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec snapshots: diff --git a/config.myopic.yaml b/config.myopic.yaml deleted file mode 100644 index a9a1279e..00000000 --- a/config.myopic.yaml +++ /dev/null @@ -1,355 +0,0 @@ -version: 0.3.0 - -logging_level: INFO - -results_dir: 'results/' -summary_dir: results -costs_dir: '../technology-data/outputs/' -run: 'your-run-name' # use this to keep track of runs with different settings -foresight: 'myopic' #options are overnight, myopic, perfect (perfect is not yet implemented) - - -scenario: - sectors: [E] # ignore this legacy setting - simpl: [''] # only relevant for PyPSA-Eur - lv: [1.0,1.5] # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt" - clusters: [45,50] # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred - opts: [''] # only relevant for PyPSA-Eur - sector_opts: [Co2L0-3H-H-B-solar3-dist1] # this is where the main scenario settings are - # to really understand the options here, look in scripts/prepare_sector_network.py - # Co2Lx specifies the CO2 target in x% of the 1990 values; default will give default (5%); - # Co2L0p25 will give 25% CO2 emissions; Co2Lm0p05 will give 5% negative emissions - # xH is the temporal resolution; 3H is 3-hourly, i.e. one snapshot every 3 hours - # single letters are sectors: T for land transport, H for building heating, - # B for biomass supply, I for industry, shipping and aviation - # solarx or onwindx changes the available installable potential by factor x - # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv - planning_horizons : [2020, 2030, 2040, 2050] #investment years for myopic and perfect; or costs year for overnight - - -#CO2 budget as a fraction of 1990 emission -#this is over-ridden if CO2Lx is set in sector_opts -co2_budget: - 2020: 0.7011648746 - 2025: 0.5241935484 - 2030: 0.2970430108 - 2035: 0.1500896057 - 2040: 0.0712365591 - 2045: 0.0322580645 - 2050: 0 - - -# snapshots are originally set in PyPSA-Eur/config.yaml but used again by PyPSA-Eur-Sec -snapshots: - # arguments to pd.date_range - start: "2013-01-01" - end: "2014-01-01" - closed: 'left' # end is not inclusive - -atlite: - cutout_dir: '../pypsa-eur/cutouts' - cutout_name: "europe-2013-era5" - -# this information is NOT used but needed as an argument for -# pypsa-eur/scripts/add_electricity.py/load_costs in make_summary.py -electricity: - max_hours: - battery: 6 - H2: 168 - -biomass: - year: 2030 - scenario: "Med" - classes: - solid biomass: ['Primary agricultural residues', 'Forestry energy residue', 'Secondary forestry residues', 'Secondary Forestry residues – sawdust', 'Forestry residues from landscape care biomass', 'Municipal waste'] - not included: ['Bioethanol sugar beet biomass', 'Rapeseeds for biodiesel', 'sunflower and soya for Biodiesel', 'Starchy crops biomass', 'Grassy crops biomass', 'Willow biomass', 'Poplar biomass potential', 'Roundwood fuelwood', 'Roundwood Chips & Pellets'] - biogas: ['Manure biomass potential', 'Sludge biomass'] - -# only relevant for foresight = myopic or perfect -existing_capacities: - grouping_years: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] - threshold_capacity: 10 - conventional_carriers: ['lignite', 'coal', 'oil', 'uranium'] - -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 - '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 - 'ICE_upper_degree_factor' : 1.6 - 'EV_lower_degree_factor' : 0.98 - 'EV_upper_degree_factor' : 0.63 - 'district_heating_loss' : 0.15 - 'bev' : 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 - '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 - 'retrofitting' : False - 'retroI-fraction' : 0.25 - 'retroII-fraction' : 0.55 - 'retrofitting-cost_factor' : 1.0 - 'tes' : True - 'tes_tau' : 3. - 'boilers' : True - 'oil_boilers': False - 'chp' : True - 'micro_chp' : False - 'solar_thermal' : True - 'solar_cf_correction': 0.788457 # = >>> 1/1.2683 - 'marginal_cost_storage' : 0. #1e-4 - 'methanation' : True - 'helmeth' : True - 'dac' : True - 'co2_vent' : True - 'SMR' : True - 'ccs_fraction' : 0.9 - 'hydrogen_underground_storage' : True - 'use_fischer_tropsch_waste_heat' : True - 'use_fuel_cell_waste_heat' : True - 'electricity_distribution_grid' : False - 'electricity_distribution_grid_cost_factor' : 1.0 #multiplies cost in data/costs.csv - 'electricity_grid_connection' : True # only applies to onshore wind and utility PV - 'gas_distribution_grid' : True - 'gas_distribution_grid_cost_factor' : 1.0 #multiplies cost in data/costs.csv - -costs: - year: 2030 - lifetime: 25 #default lifetime - # From a Lion Hirth paper, also reflects average of Noothout et al 2016 - discountrate: 0.07 - # [EUR/USD] ECB: https://www.ecb.europa.eu/stats/exchange/eurofxref/html/eurofxref-graph-usd.en.html # noqa: E501 - USD2013_to_EUR2013: 0.7532 - - # Marginal and capital costs can be overwritten - # capital_cost: - # Wind: Bla - marginal_cost: # - solar: 0.01 - onwind: 0.015 - offwind: 0.015 - hydro: 0. - H2: 0. - battery: 0. - - emission_prices: # only used with the option Ep (emission prices) - co2: 0. - - lines: - length_factor: 1.25 #to estimate offwind connection costs - - -solving: - #tmpdir: "path/to/tmp" - options: - formulation: kirchhoff - clip_p_max_pu: 1.e-2 - load_shedding: false - noisy_costs: true - - min_iterations: 1 - max_iterations: 1 - # nhours: 1 - - solver: - name: gurobi - threads: 4 - method: 2 # barrier - crossover: 0 - BarConvTol: 1.e-5 - Seed: 123 - AggFill: 0 - PreDual: 0 - GURO_PAR_BARDENSETHRESH: 200 - #FeasibilityTol: 1.e-6 - - #name: cplex - #threads: 4 - #lpmethod: 4 # barrier - #solutiontype: 2 # non basic solution, ie no crossover - #barrier_convergetol: 1.e-5 - #feasopt_tolerance: 1.e-6 - 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 - '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 - '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) - 'MWh_elec_per_tNH3_electrolysis' : 1.17 # from https://doi.org/10.1016/j.joule.2018.04.017 Table 13 (air separation and HB) - 'NH3_process_emissions' : 24.5 # in MtCO2/a from SMR for H2 production for NH3 from UNFCCC for 2015 for EU28 - 'petrochemical_process_emissions' : 25.5 # in MtCO2/a for petrochemical and other from UNFCCC for 2015 for EU28 - 'HVC_primary_fraction' : 1.0 #fraction of current non-ammonia basic chemicals produced via primary route - -plotting: - map: - figsize: [7, 7] - boundaries: [-10.2, 29, 35, 72] - p_nom: - bus_size_factor: 5.e+4 - linewidth_factor: 3.e+3 # 1.e+3 #3.e+3 - - costs_max: 1200 - costs_threshold: 1 - - - energy_max: 20000. - energy_min: -15000. - energy_threshold: 50. - - - vre_techs: ["onwind", "offwind-ac", "offwind-dc", "solar", "ror"] - renewable_storage_techs: ["PHS","hydro"] - conv_techs: ["OCGT", "CCGT", "Nuclear", "Coal"] - storage_techs: ["hydro+PHS", "battery", "H2"] - # store_techs: ["Li ion", "water tanks"] - load_carriers: ["AC load"] #, "heat load", "Li ion load"] - AC_carriers: ["AC line", "AC transformer"] - link_carriers: ["DC line", "Converter AC-DC"] - heat_links: ["heat pump", "resistive heater", "CHP heat", "CHP electric", - "gas boiler", "central heat pump", "central resistive heater", "central CHP heat", - "central CHP electric", "central gas boiler"] - heat_generators: ["gas boiler", "central gas boiler", "solar thermal collector", "central solar thermal collector"] - tech_colors: - "onwind" : "b" - "onshore wind" : "b" - 'offwind' : "c" - 'offshore wind' : "c" - 'offwind-ac' : "c" - 'offshore wind (AC)' : "c" - 'offwind-dc' : "#009999" - 'offshore wind (DC)' : "#009999" - 'wave' : "#004444" - "hydro" : "#3B5323" - "hydro reservoir" : "#3B5323" - "ror" : "#78AB46" - "run of river" : "#78AB46" - 'hydroelectricity' : '#006400' - 'solar' : "y" - 'solar PV' : "y" - 'solar thermal' : 'coral' - 'solar rooftop' : '#e6b800' - "OCGT" : "wheat" - "OCGT marginal" : "sandybrown" - "OCGT-heat" : "orange" - "gas boiler" : "orange" - "gas boilers" : "orange" - "gas boiler marginal" : "orange" - "gas-to-power/heat" : "orange" - "gas" : "brown" - "natural gas" : "brown" - "SMR" : "#4F4F2F" - "oil" : "#B5A642" - "oil boiler" : "#B5A677" - "lines" : "k" - "transmission lines" : "k" - "H2" : "m" - "hydrogen storage" : "m" - "battery" : "slategray" - "battery storage" : "slategray" - "home battery" : "#614700" - "home battery storage" : "#614700" - "Nuclear" : "r" - "Nuclear marginal" : "r" - "nuclear" : "r" - "uranium" : "r" - "Coal" : "k" - "coal" : "k" - "Coal marginal" : "k" - "Lignite" : "grey" - "lignite" : "grey" - "Lignite marginal" : "grey" - "CCGT" : "orange" - "CCGT marginal" : "orange" - "heat pumps" : "#76EE00" - "heat pump" : "#76EE00" - "air heat pump" : "#76EE00" - "ground heat pump" : "#40AA00" - "power-to-heat" : "#40AA00" - "resistive heater" : "pink" - "Sabatier" : "#FF1493" - "methanation" : "#FF1493" - "power-to-gas" : "#FF1493" - "power-to-liquid" : "#FFAAE9" - "helmeth" : "#7D0552" - "helmeth" : "#7D0552" - "DAC" : "#E74C3C" - "co2 stored" : "#123456" - "CO2 sequestration" : "#123456" - "CCS" : "k" - "co2" : "#123456" - "co2 vent" : "#654321" - "solid biomass for industry co2 from atmosphere" : "#654321" - "solid biomass for industry co2 to stored": "#654321" - "gas for industry co2 to atmosphere": "#654321" - "gas for industry co2 to stored": "#654321" - "Fischer-Tropsch" : "#44DD33" - "kerosene for aviation": "#44BB11" - "naphtha for industry" : "#44FF55" - "water tanks" : "#BBBBBB" - "hot water storage" : "#BBBBBB" - "hot water charging" : "#BBBBBB" - "hot water discharging" : "#999999" - "CHP" : "r" - "CHP heat" : "r" - "CHP electric" : "r" - "PHS" : "g" - "Ambient" : "k" - "Electric load" : "b" - "Heat load" : "r" - "Transport load" : "grey" - "heat" : "darkred" - "rural heat" : "#880000" - "central heat" : "#b22222" - "decentral heat" : "#800000" - "low-temperature heat for industry" : "#991111" - "process heat" : "#FF3333" - "heat demand" : "darkred" - "electric demand" : "k" - "Li ion" : "grey" - "district heating" : "#CC4E5C" - "retrofitting" : "purple" - "building retrofitting" : "purple" - "BEV charger" : "grey" - "V2G" : "grey" - "transport" : "grey" - "electricity" : "k" - "gas for industry" : "#333333" - "solid biomass for industry" : "#555555" - "industry electricity" : "#222222" - "industry new electricity" : "#222222" - "process emissions to stored" : "#444444" - "process emissions to atmosphere" : "#888888" - "process emissions" : "#222222" - "transport fuel cell" : "#AAAAAA" - "biogas" : "#800000" - "solid biomass" : "#DAA520" - "today" : "#D2691E" - "shipping" : "#6495ED" - "electricity distribution grid" : "#333333" - nice_names: - # OCGT: "Gas" - # OCGT marginal: "Gas (marginal)" - offwind: "offshore wind" - onwind: "onshore wind" - battery: "Battery storage" - lines: "Transmission lines" - AC line: "AC lines" - AC-AC: "DC lines" - ror: "Run of river" - nice_names_n: - offwind: "offshore\nwind" - onwind: "onshore\nwind" - # OCGT: "Gas" - H2: "Hydrogen\nstorage" - # OCGT marginal: "Gas (marginal)" - lines: "transmission\nlines" - ror: "run of river" diff --git a/doc/myopic.rst b/doc/myopic.rst index 1b1cdb01..6faaaeff 100644 --- a/doc/myopic.rst +++ b/doc/myopic.rst @@ -17,12 +17,14 @@ See also other `outstanding issues Date: Mon, 30 Nov 2020 16:20:26 +0100 Subject: [PATCH 12/13] 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: From 17bf0dfbb100fc9e1baa91bfe9c0acf6383eb873 Mon Sep 17 00:00:00 2001 From: Tom Brown Date: Mon, 30 Nov 2020 17:01:14 +0100 Subject: [PATCH 13/13] prepare_costs: use default lifetime from config.yaml Rather than hard-coding 25 years. --- config.default.yaml | 1 - scripts/add_existing_baseyear.py | 3 ++- scripts/make_summary.py | 3 ++- scripts/prepare_sector_network.py | 7 ++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 26d34870..1d882c33 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -130,7 +130,6 @@ sector: 'gas_distribution_grid_cost_factor' : 1.0 #multiplies cost in data/costs.csv costs: - year: 2030 lifetime: 25 #default lifetime # From a Lion Hirth paper, also reflects average of Noothout et al 2016 discountrate: 0.07 diff --git a/scripts/add_existing_baseyear.py b/scripts/add_existing_baseyear.py index cfef2e5e..852c5bb0 100644 --- a/scripts/add_existing_baseyear.py +++ b/scripts/add_existing_baseyear.py @@ -442,7 +442,8 @@ if __name__ == "__main__": costs = prepare_costs(snakemake.input.costs, snakemake.config['costs']['USD2013_to_EUR2013'], snakemake.config['costs']['discountrate'], - Nyears) + Nyears, + snakemake.config['costs']['lifetime']) grouping_years=snakemake.config['existing_capacities']['grouping_years'] add_power_capacities_installed_before_baseyear(n, grouping_years, costs, baseyear) diff --git a/scripts/make_summary.py b/scripts/make_summary.py index 3ff79934..53ca8624 100644 --- a/scripts/make_summary.py +++ b/scripts/make_summary.py @@ -592,7 +592,8 @@ if __name__ == "__main__": costs_db = prepare_costs(snakemake.input.costs, snakemake.config['costs']['USD2013_to_EUR2013'], snakemake.config['costs']['discountrate'], - Nyears) + Nyears, + snakemake.config['costs']['lifetime']) df = make_summaries(networks_dict) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 566fd8b9..13bb8157 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -540,7 +540,7 @@ def prepare_data(network): -def prepare_costs(cost_file, USD_to_EUR, discount_rate, Nyears): +def prepare_costs(cost_file, USD_to_EUR, discount_rate, Nyears, lifetime): #set all asset costs and other parameters costs = pd.read_csv(cost_file,index_col=list(range(2))).sort_index() @@ -558,7 +558,7 @@ def prepare_costs(cost_file, USD_to_EUR, discount_rate, Nyears): "efficiency" : 1, "fuel" : 0, "investment" : 0, - "lifetime" : 25 + "lifetime" : lifetime }) costs["fixed"] = [(annuity(v["lifetime"],v["discount rate"])+v["FOM"]/100.)*v["investment"]*Nyears for i,v in costs.iterrows()] @@ -1834,7 +1834,8 @@ if __name__ == "__main__": costs = prepare_costs(snakemake.input.costs, snakemake.config['costs']['USD2013_to_EUR2013'], snakemake.config['costs']['discountrate'], - Nyears) + Nyears, + snakemake.config['costs']['lifetime']) remove_elec_base_techs(n)