From 0e5caa61d3d92c90de78306709f30f66e7606b4b Mon Sep 17 00:00:00 2001 From: millingermarkus Date: Thu, 23 Feb 2023 18:57:21 +0100 Subject: [PATCH 01/13] Endogenised industrial heat supply in steam, mediumT and highT segments --- config.default.yaml | 26 +++ scripts/plot_summary.py | 2 +- scripts/prepare_sector_network.py | 355 +++++++++++++++++++++++------- 3 files changed, 306 insertions(+), 77 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 4085e719ed..c36f52504b 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -264,6 +264,14 @@ sector: conventional_generation: # generator : carrier OCGT: gas biomass_to_liquid: true + industry_steam_biomass: true + industry_steam_heat_pumps: true + industry_steam_electric_boiler: true + industry_steam_methane: true + industry_mediumT_biomass: true + industry_mediumT_methane: true + industry_mediumT_hydrogen: true + industry_highT_hydrogen: true industry: @@ -611,3 +619,21 @@ plotting: gas-to-power/heat: '#ee8340' waste: '#e3d37d' other: '#000000' + industry process steam: "#555555" + mediumT industry: "yellow" + highT industry: "brown" + industry process steam solid biomass: "green" + industry process steam solid biomass CC: "green" + industry process steam methane: "yellow" + industry process steam methane CC: "yellow" + industry process steam H2: "blue" + gas for mediumT industry: '#333666' + gas for mediumT industry CC: '#333666' + gas for highT industry: '#333333' + gas for highT industry CC: '#333333' + hydrogen for mediumT industry: '#993666' + hydrogen for highT industry: '#993333' + industry process steam electricity: "pink" + industry process steam heat pump: "purple" + solid biomass for mediumT industry: '#009E60' + solid biomass for mediumT industry CC: '#009E60' diff --git a/scripts/plot_summary.py b/scripts/plot_summary.py index 7ebfde24c8..e1c6affcb6 100644 --- a/scripts/plot_summary.py +++ b/scripts/plot_summary.py @@ -439,7 +439,7 @@ def plot_carbon_budget_distribution(): from helper import mock_snakemake snakemake = mock_snakemake('plot_summary') - update_config_with_sector_opts(snakemake.config, snakemake.wildcards.sector_opts) + # update_config_with_sector_opts(snakemake.config, snakemake.wildcards.sector_opts) n_header = 4 diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 15e30a656e..95acd76bf2 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -107,6 +107,7 @@ def define_spatial(nodes, options): spatial.coal = SimpleNamespace() spatial.coal.nodes = ["EU coal"] spatial.coal.locations = ["EU"] + spatial.coal.locations = ["EU"] # lignite spatial.lignite = SimpleNamespace() @@ -1907,93 +1908,294 @@ def add_industry(n, costs): industrial_demand = pd.read_csv(snakemake.input.industrial_demand, index_col=0) * 1e6 n.madd("Bus", - spatial.biomass.industry, - location=spatial.biomass.locations, - carrier="solid biomass for industry", - unit="MWh_LHV" - ) - - if options["biomass_transport"]: - p_set = industrial_demand.loc[spatial.biomass.locations, "solid biomass"].rename(index=lambda x: x + " solid biomass for industry") / 8760 - else: - p_set = industrial_demand["solid biomass"].sum() / 8760 + nodes + " industry process steam", + location=nodes, + carrier="industry process steam", + unit="MWh_LHV") n.madd("Load", - spatial.biomass.industry, - bus=spatial.biomass.industry, - carrier="solid biomass for industry", - p_set=p_set - ) - - n.madd("Link", - spatial.biomass.industry, - bus0=spatial.biomass.nodes, - bus1=spatial.biomass.industry, - carrier="solid biomass for industry", - p_nom_extendable=True, - efficiency=1. - ) - - n.madd("Link", - spatial.biomass.industry_cc, - bus0=spatial.biomass.nodes, - bus1=spatial.biomass.industry, - bus2="co2 atmosphere", - bus3=spatial.co2.nodes, - carrier="solid biomass for industry CC", - p_nom_extendable=True, - capital_cost=costs.at["cement capture", "fixed"] * costs.at['solid biomass', 'CO2 intensity'], - efficiency=0.9, # TODO: make config option - efficiency2=-costs.at['solid biomass', 'CO2 intensity'] * costs.at["cement capture", "capture_rate"], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] * costs.at["cement capture", "capture_rate"], - lifetime=costs.at['cement capture', 'lifetime'] - ) + nodes, + suffix=" industry process steam", + bus=nodes + " industry process steam", + carrier="industry process steam", + p_set=industrial_demand.loc[nodes, "solid biomass"] / 8760.) n.madd("Bus", - spatial.gas.industry, - location=spatial.gas.locations, - carrier="gas for industry", - unit="MWh_LHV") + nodes + " mediumT industry", + location=nodes, + carrier="mediumT industry", + unit="MWh_LHV") - gas_demand = industrial_demand.loc[nodes, "methane"] / 8760. + # TODO: Set real shares of medium and high T industry + n.madd("Load", + nodes, + suffix=" mediumT industry", + bus=nodes + " mediumT industry", + carrier="mediumT industry", + p_set=0.3 * industrial_demand.loc[nodes, "methane"] / 8760.) - if options["gas_network"]: - spatial_gas_demand = gas_demand.rename(index=lambda x: x + " gas for industry") - else: - spatial_gas_demand = gas_demand.sum() + n.madd("Bus", + nodes + " highT industry", + location=nodes, + carrier="highT industry") n.madd("Load", - spatial.gas.industry, - bus=spatial.gas.industry, - carrier="gas for industry", - p_set=spatial_gas_demand - ) + nodes, + suffix=" highT industry", + bus=nodes + " highT industry", + carrier="highT industry", + p_set=0.7 * industrial_demand.loc[nodes, "methane"] / 8760.) + + #NB: industrial heat demand is in reality supplied at site by discrete plants + # which follow the local demand and therefore cannot be dispatched too much. + # Thus, p_min_pu is set to 0.8 to avoid too much dispatch behaviour. Improvements welcome! + if options['industry_steam_biomass']: + n.madd("Link", + nodes, + suffix=" solid biomass for lowT industry", + bus0=spatial.biomass.nodes, + bus1=nodes + " industry process steam", + bus3="co2 atmosphere", + carrier="industry process steam solid biomass", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['solid biomass boiler steam', 'efficiency'], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at[ + 'solid biomass', 'CO2 intensity'], + capital_cost=costs.at['solid biomass boiler steam', 'fixed'] * costs.at[ + 'solid biomass boiler steam', 'efficiency'], + marginal_cost=costs.at['solid biomass boiler steam', 'VOM']) - n.madd("Link", - spatial.gas.industry, - bus0=spatial.gas.nodes, - bus1=spatial.gas.industry, - bus2="co2 atmosphere", - carrier="gas for industry", - p_nom_extendable=True, - efficiency=1., - efficiency2=costs.at['gas', 'CO2 intensity'] - ) + n.madd("Link", + nodes, + suffix=" solid biomass for lowT industry CC", + bus0=spatial.biomass.nodes, + bus1=nodes + " industry process steam", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="industry process steam solid biomass CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['solid biomass boiler steam CC', 'efficiency'], + capital_cost=costs.at['solid biomass boiler steam CC', 'fixed'] * costs.at[ + 'solid biomass boiler steam CC', 'efficiency'] + costs.at[ + 'biomass CHP capture', 'fixed'] * costs.at[ + 'solid biomass', 'CO2 intensity'], + marginal_cost=costs.at['solid biomass boiler steam CC', 'VOM'], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( + 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ + 'solid biomass', 'CO2 intensity'], + efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'capture_rate'], + lifetime=costs.at['solid biomass boiler steam CC', 'lifetime']) + + if options['industry_mediumT_biomass']: + n.madd("Link", + nodes, + suffix=" solid biomass for mediumT industry", + bus0=spatial.biomass.nodes, + bus1=nodes + " mediumT industry", + bus3="co2 atmosphere", + carrier="solid biomass for mediumT industry", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing solid fuels', 'efficiency'], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], + capital_cost=costs.at['direct firing solid fuels', 'fixed'] * costs.at['direct firing solid fuels', 'efficiency'], + marginal_cost=costs.at['direct firing solid fuels', 'VOM'] + costs.at['biomass boiler', 'pelletizing cost'], + lifetime=costs.at['direct firing solid fuels', 'lifetime']) + n.madd("Link", + nodes, + suffix=" solid biomass for mediumT industry CC", + bus0=spatial.biomass.nodes, + bus1=nodes + " mediumT industry", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="solid biomass for mediumT industry CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing solid fuels CC', 'efficiency'], + capital_cost=costs.at['direct firing solid fuels CC', 'fixed'] * costs.at[ + 'direct firing solid fuels CC', 'efficiency'] + costs.at[ + 'biomass CHP capture', 'fixed'] * costs.at[ + 'solid biomass', 'CO2 intensity'], + marginal_cost=costs.at['direct firing solid fuels CC', 'VOM'] + costs.at[ + 'biomass boiler', 'pelletizing cost'], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( + 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ + 'solid biomass', 'CO2 intensity'], + efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'capture_rate'], + lifetime=costs.at['direct firing solid fuels CC', 'lifetime']) + + if options["industry_steam_methane"]: + n.madd("Link", + nodes, + suffix=" gas for lowT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " industry process steam", + bus3="co2 atmosphere", + carrier="industry process steam methane", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['gas boiler steam', 'efficiency'], + capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'], + marginal_cost=costs.at['gas boiler steam', 'VOM'], + efficiency3=costs.at['gas', 'CO2 intensity']) + + eta = costs.at['gas boiler steam', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'heat-input'] + n.madd("Link", + nodes, + suffix=" gas for lowT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " industry process steam", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="industry process steam methane CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=eta, + capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'] + + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], + marginal_cost=costs.at['gas boiler steam', 'VOM'], + efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), + efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], + lifetime=costs.at['gas boiler steam', 'lifetime']) + + if options["industry_steam_heat_pumps"]: + eta = costs.at['industrial heat pump high temperature', 'efficiency'] + n.madd("Link", + nodes, + suffix=" industrial heat pump steam for lowT industry", + bus0=nodes, + bus1=nodes + " industry process steam", + carrier="industry process steam heat pump", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=eta, + capital_cost=costs.at['industrial heat pump high temperature', 'fixed'] * eta, + marginal_cost=costs.at['industrial heat pump high temperature', 'VOM'], + lifetime=costs.at['industrial heat pump high temperature', 'lifetime']) + + if options["industry_steam_electric_boiler"]: + n.madd("Link", + nodes, + suffix=" electricity for lowT industry", + bus0=nodes, + bus1=nodes + " industry process steam", + carrier="industry process steam electricity", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['electric boiler steam', 'efficiency'], + capital_cost=costs.at['electric boiler steam', 'fixed'] * costs.at[ + 'electric boiler steam', 'efficiency'], + marginal_cost=costs.at['electric boiler steam', 'VOM'], + lifetime=costs.at['electric boiler steam', 'lifetime']) + + if options["industry_mediumT_methane"]: + # TODO: add electricity input from DEA and adapt VOM to exclude electricity cost! + n.madd("Link", + nodes, + suffix=" gas for mediumT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " mediumT industry", + bus3="co2 atmosphere", + carrier="gas for mediumT industry", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing gas', 'efficiency'], + efficiency3=costs.at['gas', 'CO2 intensity'], + capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], + marginal_cost=costs.at['direct firing gas', 'VOM'], + lifetime=costs.at['direct firing gas', 'lifetime']) + + eta = costs.at['direct firing gas', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'heat-input'] + n.madd("Link", + nodes, + suffix=" gas for mediumT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " mediumT industry", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="gas for mediumT industry CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=eta, + efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), + efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], + capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], + marginal_cost=costs.at['direct firing gas CC', 'VOM'], + lifetime=costs.at['direct firing gas', 'lifetime']) + + # TODO: differentiate medium and high T processes n.madd("Link", - spatial.gas.industry_cc, - bus0=spatial.gas.nodes, - bus1=spatial.gas.industry, - bus2="co2 atmosphere", - bus3=spatial.co2.nodes, - carrier="gas for industry CC", - p_nom_extendable=True, - capital_cost=costs.at["cement capture", "fixed"] * costs.at['gas', 'CO2 intensity'], - efficiency=0.9, - efficiency2=costs.at['gas', 'CO2 intensity'] * (1 - costs.at["cement capture", "capture_rate"]), - efficiency3=costs.at['gas', 'CO2 intensity'] * costs.at["cement capture", "capture_rate"], - lifetime=costs.at['cement capture', 'lifetime'] - ) + nodes, + suffix=" gas for highT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " highT industry", + bus3="co2 atmosphere", + carrier="gas for highT industry", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing gas', 'efficiency'], + efficiency3=costs.at['gas', 'CO2 intensity'], + capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], + marginal_cost=costs.at['direct firing gas', 'VOM'], + lifetime=costs.at['direct firing gas', 'lifetime']) + + eta = costs.at['direct firing gas', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'heat-input'] + n.madd("Link", + nodes, + suffix=" gas for highT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " highT industry", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="gas for highT industry CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=eta, + efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), + efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], + capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], + marginal_cost=costs.at['direct firing gas CC', 'VOM'], + lifetime=costs.at['direct firing gas', 'lifetime']) + + if options["industry_mediumT_hydrogen"]: + print('Adding H2 for mediumT industry') + #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion + n.madd("Link", + nodes, + suffix=" hydrogen for mediumT industry", + bus0=nodes + " H2", + bus1=nodes + " mediumT industry", + carrier="hydrogen for mediumT industry", + capital_cost=10 * costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], + marginal_cost=10 * costs.at['direct firing gas', 'VOM'], + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing gas', 'efficiency']) + + if options["industry_highT_hydrogen"]: + print('Adding H2 for highT industry') + #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion + n.madd("Link", + nodes, + suffix=" hydrogen for highT industry", + bus0=nodes + " H2", + bus1=nodes + " highT industry", + carrier="hydrogen for highT industry", + capital_cost=10 * costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], + marginal_cost=10 * costs.at['direct firing gas', 'VOM'], + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing gas', 'efficiency']) n.madd("Load", nodes, @@ -2486,6 +2688,7 @@ def limit_individual_line_extension(n, maxext): print("Add CO2 limit from", limit_type) add_co2limit(n, Nyears, limit) + for o in opts: if not o[:10] == 'linemaxext': continue maxext = float(o[10:]) * 1e3 From 2cf2a38e3c06da956a8030fa55c507ea228596f6 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 27 Feb 2023 13:37:20 +0100 Subject: [PATCH 02/13] rename industry process steam to lowT industry --- config.default.yaml | 16 +++---- scripts/prepare_sector_network.py | 80 +++++++++++++++---------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index c2e11fbb0e..9ee5e9c19a 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -706,21 +706,21 @@ plotting: gas-to-power/heat: '#ee8340' waste: '#e3d37d' other: '#000000' - industry process steam: "#555555" + lowT industry: "#555555" mediumT industry: "yellow" highT industry: "brown" - industry process steam solid biomass: "green" - industry process steam solid biomass CC: "green" - industry process steam methane: "yellow" - industry process steam methane CC: "yellow" - industry process steam H2: "blue" + lowT industry solid biomass: "green" + lowT industry solid biomass CC: "green" + lowT industry methane: "yellow" + lowT industry methane CC: "yellow" + lowT industry H2: "blue" gas for mediumT industry: '#333666' gas for mediumT industry CC: '#333666' gas for highT industry: '#333333' gas for highT industry CC: '#333333' hydrogen for mediumT industry: '#993666' hydrogen for highT industry: '#993333' - industry process steam electricity: "pink" - industry process steam heat pump: "purple" + lowT industry electricity: "pink" + lowT industry heat pump: "purple" solid biomass for mediumT industry: '#009E60' solid biomass for mediumT industry CC: '#009E60' diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 28f665aef7..ff87b7f3d5 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -576,28 +576,28 @@ def add_co2_network(n, costs): ) -def add_allam(n, costs): - - logger.info("Adding Allam cycle gas power plants.") - - nodes = pop_layout.index - - n.madd("Link", +def add_allam(n, costs): + + logger.info("Adding Allam cycle gas power plants.") + + nodes = pop_layout.index + + n.madd("Link", nodes, - suffix=" allam", - bus0=spatial.gas.df.loc[nodes, "nodes"].values, - bus1=nodes, - bus2=spatial.co2.df.loc[nodes, "nodes"].values, - carrier="allam", - p_nom_extendable=True, + suffix=" allam", + bus0=spatial.gas.df.loc[nodes, "nodes"].values, + bus1=nodes, + bus2=spatial.co2.df.loc[nodes, "nodes"].values, + carrier="allam", + p_nom_extendable=True, # TODO: add costs to technology-data - capital_cost=0.6*1.5e6*0.1, # efficiency * EUR/MW * annuity - marginal_cost=2, - efficiency=0.6, - efficiency2=costs.at['gas', 'CO2 intensity'], + capital_cost=0.6*1.5e6*0.1, # efficiency * EUR/MW * annuity + marginal_cost=2, + efficiency=0.6, + efficiency2=costs.at['gas', 'CO2 intensity'], lifetime=30., ) - + def add_dac(n, costs): @@ -1323,7 +1323,7 @@ def add_land_transport(n, costs): fuel_cell_share = get(options["land_transport_fuel_cell_share"], investment_year) electric_share = get(options["land_transport_electric_share"], investment_year) ice_share = get(options["land_transport_ice_share"], investment_year) - + total_share = fuel_cell_share + electric_share + ice_share if total_share != 1: logger.warning(f"Total land transport shares sum up to {total_share:.2%}, corresponding to increased or decreased demand assumptions.") @@ -2094,16 +2094,16 @@ def add_industry(n, costs): industrial_demand = pd.read_csv(snakemake.input.industrial_demand, index_col=0) * 1e6 n.madd("Bus", - nodes + " industry process steam", + nodes + " lowT industry", location=nodes, - carrier="industry process steam", + carrier="lowT industry", unit="MWh_LHV") n.madd("Load", nodes, - suffix=" industry process steam", - bus=nodes + " industry process steam", - carrier="industry process steam", + suffix=" lowT industry", + bus=nodes + " lowT industry", + carrier="lowT industry", p_set=industrial_demand.loc[nodes, "solid biomass"] / 8760.) n.madd("Bus", @@ -2140,9 +2140,9 @@ def add_industry(n, costs): nodes, suffix=" solid biomass for lowT industry", bus0=spatial.biomass.nodes, - bus1=nodes + " industry process steam", + bus1=nodes + " lowT industry", bus3="co2 atmosphere", - carrier="industry process steam solid biomass", + carrier="lowT industry solid biomass", p_nom_extendable=True, p_min_pu=0.8, efficiency=costs.at['solid biomass boiler steam', 'efficiency'], @@ -2156,10 +2156,10 @@ def add_industry(n, costs): nodes, suffix=" solid biomass for lowT industry CC", bus0=spatial.biomass.nodes, - bus1=nodes + " industry process steam", + bus1=nodes + " lowT industry", bus3="co2 atmosphere", bus2="co2 stored", - carrier="industry process steam solid biomass CC", + carrier="lowT industry solid biomass CC", p_nom_extendable=True, p_min_pu=0.8, efficiency=costs.at['solid biomass boiler steam CC', 'efficiency'], @@ -2220,9 +2220,9 @@ def add_industry(n, costs): nodes, suffix=" gas for lowT industry", bus0=spatial.gas.nodes, - bus1=nodes + " industry process steam", + bus1=nodes + " lowT industry", bus3="co2 atmosphere", - carrier="industry process steam methane", + carrier="lowT industry methane", p_nom_extendable=True, p_min_pu=0.8, efficiency=costs.at['gas boiler steam', 'efficiency'], @@ -2236,10 +2236,10 @@ def add_industry(n, costs): nodes, suffix=" gas for lowT industry CC", bus0=spatial.gas.nodes, - bus1=nodes + " industry process steam", + bus1=nodes + " lowT industry", bus3="co2 atmosphere", bus2="co2 stored", - carrier="industry process steam methane CC", + carrier="lowT industry methane CC", p_nom_extendable=True, p_min_pu=0.8, efficiency=eta, @@ -2256,8 +2256,8 @@ def add_industry(n, costs): nodes, suffix=" industrial heat pump steam for lowT industry", bus0=nodes, - bus1=nodes + " industry process steam", - carrier="industry process steam heat pump", + bus1=nodes + " lowT industry", + carrier="lowT industry heat pump", p_nom_extendable=True, p_min_pu=0.8, efficiency=eta, @@ -2270,8 +2270,8 @@ def add_industry(n, costs): nodes, suffix=" electricity for lowT industry", bus0=nodes, - bus1=nodes + " industry process steam", - carrier="industry process steam electricity", + bus1=nodes + " lowT industry", + carrier="lowT industry electricity", p_nom_extendable=True, p_min_pu=0.8, efficiency=costs.at['electric boiler steam', 'efficiency'], @@ -3037,10 +3037,10 @@ def set_temporal_aggregation(n, opts, solver_name): 'prepare_sector_network', simpl='', opts="", - clusters="37", - lv=1.5, - sector_opts='cb40ex0-365H-T-H-B-I-A-solar+p3-dist1', - planning_horizons="2020", + clusters="45", + lv=1.0, + sector_opts='Co2L0-365H-T-H-B-I-A-solar+p3-dist1', + planning_horizons="2050", ) logging.basicConfig(level=snakemake.config['logging_level']) From 32c5f68fe0926b7e9e7aac9871370bf1bd3b0e72 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 27 Feb 2023 14:22:02 +0100 Subject: [PATCH 03/13] split temperatures into functions --- scripts/prepare_sector_network.py | 264 ++++++++++++++++-------------- 1 file changed, 145 insertions(+), 119 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index ff87b7f3d5..ccc41561ba 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -2084,15 +2084,10 @@ def add_biomass(n, costs): ) -def add_industry(n, costs): - - logger.info("Add industrial demand") - - nodes = pop_layout.index - - # 1e6 to convert TWh to MWh - industrial_demand = pd.read_csv(snakemake.input.industrial_demand, index_col=0) * 1e6 - +def add_low_t_industry(n, nodes, industrial_demand, costs): + """Add low temperature heat for industry. + """ + logger.info("Add low temperature industry demand.") n.madd("Bus", nodes + " lowT industry", location=nodes, @@ -2106,36 +2101,10 @@ def add_industry(n, costs): carrier="lowT industry", p_set=industrial_demand.loc[nodes, "solid biomass"] / 8760.) - n.madd("Bus", - nodes + " mediumT industry", - location=nodes, - carrier="mediumT industry", - unit="MWh_LHV") - - # TODO: Set real shares of medium and high T industry - n.madd("Load", - nodes, - suffix=" mediumT industry", - bus=nodes + " mediumT industry", - carrier="mediumT industry", - p_set=0.3 * industrial_demand.loc[nodes, "methane"] / 8760.) - - n.madd("Bus", - nodes + " highT industry", - location=nodes, - carrier="highT industry") - - n.madd("Load", - nodes, - suffix=" highT industry", - bus=nodes + " highT industry", - carrier="highT industry", - p_set=0.7 * industrial_demand.loc[nodes, "methane"] / 8760.) - #NB: industrial heat demand is in reality supplied at site by discrete plants # which follow the local demand and therefore cannot be dispatched too much. # Thus, p_min_pu is set to 0.8 to avoid too much dispatch behaviour. Improvements welcome! - if options['industry_steam_biomass']: + if options["industry_t"]['low_T']["biomass"] or not options["industry_t"]['endogen']: n.madd("Link", nodes, suffix=" solid biomass for lowT industry", @@ -2175,47 +2144,7 @@ def add_industry(n, costs): 'biomass CHP capture', 'capture_rate'], lifetime=costs.at['solid biomass boiler steam CC', 'lifetime']) - if options['industry_mediumT_biomass']: - n.madd("Link", - nodes, - suffix=" solid biomass for mediumT industry", - bus0=spatial.biomass.nodes, - bus1=nodes + " mediumT industry", - bus3="co2 atmosphere", - carrier="solid biomass for mediumT industry", - p_nom_extendable=True, - p_min_pu=0.8, - efficiency=costs.at['direct firing solid fuels', 'efficiency'], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], - capital_cost=costs.at['direct firing solid fuels', 'fixed'] * costs.at['direct firing solid fuels', 'efficiency'], - marginal_cost=costs.at['direct firing solid fuels', 'VOM'] + costs.at['biomass boiler', 'pelletizing cost'], - lifetime=costs.at['direct firing solid fuels', 'lifetime']) - - n.madd("Link", - nodes, - suffix=" solid biomass for mediumT industry CC", - bus0=spatial.biomass.nodes, - bus1=nodes + " mediumT industry", - bus3="co2 atmosphere", - bus2="co2 stored", - carrier="solid biomass for mediumT industry CC", - p_nom_extendable=True, - p_min_pu=0.8, - efficiency=costs.at['direct firing solid fuels CC', 'efficiency'], - capital_cost=costs.at['direct firing solid fuels CC', 'fixed'] * costs.at[ - 'direct firing solid fuels CC', 'efficiency'] + costs.at[ - 'biomass CHP capture', 'fixed'] * costs.at[ - 'solid biomass', 'CO2 intensity'], - marginal_cost=costs.at['direct firing solid fuels CC', 'VOM'] + costs.at[ - 'biomass boiler', 'pelletizing cost'], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( - 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ - 'solid biomass', 'CO2 intensity'], - efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'capture_rate'], - lifetime=costs.at['direct firing solid fuels CC', 'lifetime']) - - if options["industry_steam_methane"]: + if options["industry_t"]['low_T']["methane"]: n.madd("Link", nodes, suffix=" gas for lowT industry", @@ -2250,7 +2179,7 @@ def add_industry(n, costs): efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], lifetime=costs.at['gas boiler steam', 'lifetime']) - if options["industry_steam_heat_pumps"]: + if options["industry_t"]['low_T']["heat_pumps"]: eta = costs.at['industrial heat pump high temperature', 'efficiency'] n.madd("Link", nodes, @@ -2265,7 +2194,7 @@ def add_industry(n, costs): marginal_cost=costs.at['industrial heat pump high temperature', 'VOM'], lifetime=costs.at['industrial heat pump high temperature', 'lifetime']) - if options["industry_steam_electric_boiler"]: + if options["industry_t"]['low_T']["electric_boiler"]: n.madd("Link", nodes, suffix=" electricity for lowT industry", @@ -2280,7 +2209,69 @@ def add_industry(n, costs): marginal_cost=costs.at['electric boiler steam', 'VOM'], lifetime=costs.at['electric boiler steam', 'lifetime']) - if options["industry_mediumT_methane"]: + + +def add_medium_t_industry(n, nodes, industrial_demand, costs): + """Add medium temperature heat for industry. + """ + logger.info("Add medium temperature industry demand.") + + n.madd("Bus", + nodes + " mediumT industry", + location=nodes, + carrier="mediumT industry", + unit="MWh_LHV") + + # TODO: Set real shares of medium and high T industry + n.madd("Load", + nodes, + suffix=" mediumT industry", + bus=nodes + " mediumT industry", + carrier="mediumT industry", + p_set=0.3 * industrial_demand.loc[nodes, "methane"] / 8760.) + + if options["industry_t"]['medium_T']['biomass']: + n.madd("Link", + nodes, + suffix=" solid biomass for mediumT industry", + bus0=spatial.biomass.nodes, + bus1=nodes + " mediumT industry", + bus3="co2 atmosphere", + carrier="solid biomass for mediumT industry", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing solid fuels', 'efficiency'], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], + capital_cost=costs.at['direct firing solid fuels', 'fixed'] * costs.at['direct firing solid fuels', 'efficiency'], + marginal_cost=costs.at['direct firing solid fuels', 'VOM'] + costs.at['biomass boiler', 'pelletizing cost'], + lifetime=costs.at['direct firing solid fuels', 'lifetime']) + + n.madd("Link", + nodes, + suffix=" solid biomass for mediumT industry CC", + bus0=spatial.biomass.nodes, + bus1=nodes + " mediumT industry", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="solid biomass for mediumT industry CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing solid fuels CC', 'efficiency'], + capital_cost=costs.at['direct firing solid fuels CC', 'fixed'] * costs.at[ + 'direct firing solid fuels CC', 'efficiency'] + costs.at[ + 'biomass CHP capture', 'fixed'] * costs.at[ + 'solid biomass', 'CO2 intensity'], + marginal_cost=costs.at['direct firing solid fuels CC', 'VOM'] + costs.at[ + 'biomass boiler', 'pelletizing cost'], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( + 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ + 'solid biomass', 'CO2 intensity'], + efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'capture_rate'], + lifetime=costs.at['direct firing solid fuels CC', 'lifetime']) + + + if options["industry_t"]['medium_T']['methane']: # TODO: add electricity input from DEA and adapt VOM to exclude electricity cost! n.madd("Link", nodes, @@ -2317,44 +2308,7 @@ def add_industry(n, costs): marginal_cost=costs.at['direct firing gas CC', 'VOM'], lifetime=costs.at['direct firing gas', 'lifetime']) - # TODO: differentiate medium and high T processes - n.madd("Link", - nodes, - suffix=" gas for highT industry", - bus0=spatial.gas.nodes, - bus1=nodes + " highT industry", - bus3="co2 atmosphere", - carrier="gas for highT industry", - p_nom_extendable=True, - p_min_pu=0.8, - efficiency=costs.at['direct firing gas', 'efficiency'], - efficiency3=costs.at['gas', 'CO2 intensity'], - capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], - marginal_cost=costs.at['direct firing gas', 'VOM'], - lifetime=costs.at['direct firing gas', 'lifetime']) - - eta = costs.at['direct firing gas', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'heat-input'] - n.madd("Link", - nodes, - suffix=" gas for highT industry CC", - bus0=spatial.gas.nodes, - bus1=nodes + " highT industry", - bus3="co2 atmosphere", - bus2="co2 stored", - carrier="gas for highT industry CC", - p_nom_extendable=True, - p_min_pu=0.8, - efficiency=eta, - efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), - efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], - capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + - costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], - marginal_cost=costs.at['direct firing gas CC', 'VOM'], - lifetime=costs.at['direct firing gas', 'lifetime']) - - if options["industry_mediumT_hydrogen"]: - print('Adding H2 for mediumT industry') + if options["industry_t"]['medium_T']['hydrogen']: #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion n.madd("Link", nodes, @@ -2368,7 +2322,64 @@ def add_industry(n, costs): p_min_pu=0.8, efficiency=costs.at['direct firing gas', 'efficiency']) - if options["industry_highT_hydrogen"]: + +def add_high_t_industry(n, nodes, industrial_demand, costs): + """Add high temperature heat for industry. + """ + logger.info("Add high temperature industry demand.") + + n.madd("Bus", + nodes + " highT industry", + location=nodes, + carrier="highT industry") + + n.madd("Load", + nodes, + suffix=" highT industry", + bus=nodes + " highT industry", + carrier="highT industry", + p_set=0.7 * industrial_demand.loc[nodes, "methane"] / 8760.) + + + if options["industry_t"]['high_T']['methane']: + # TODO: differentiate medium and high T processes + n.madd("Link", + nodes, + suffix=" gas for highT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " highT industry", + bus3="co2 atmosphere", + carrier="gas for highT industry", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=costs.at['direct firing gas', 'efficiency'], + efficiency3=costs.at['gas', 'CO2 intensity'], + capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], + marginal_cost=costs.at['direct firing gas', 'VOM'], + lifetime=costs.at['direct firing gas', 'lifetime']) + + eta = costs.at['direct firing gas', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'heat-input'] + n.madd("Link", + nodes, + suffix=" gas for highT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " highT industry", + bus3="co2 atmosphere", + bus2="co2 stored", + carrier="gas for highT industry CC", + p_nom_extendable=True, + p_min_pu=0.8, + efficiency=eta, + efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), + efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], + capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], + marginal_cost=costs.at['direct firing gas CC', 'VOM'], + lifetime=costs.at['direct firing gas', 'lifetime']) + + + if options["industry_t"]['high_T']['hydrogen']: print('Adding H2 for highT industry') #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion n.madd("Link", @@ -2383,6 +2394,21 @@ def add_industry(n, costs): p_min_pu=0.8, efficiency=costs.at['direct firing gas', 'efficiency']) +def add_industry(n, costs): + + logger.info("Add industrial demand") + + nodes = pop_layout.index + + # 1e6 to convert TWh to MWh + industrial_demand = pd.read_csv(snakemake.input.industrial_demand, index_col=0) * 1e6 + + add_low_t_industry(n, nodes, industrial_demand, costs) + + add_medium_t_industry(n, nodes, industrial_demand, costs) + + add_high_t_industry(n, nodes, industrial_demand, costs) + n.madd("Load", nodes, suffix=" H2 for industry", From b78fd8e73818f3255a60041f90a2c801870b66eb Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 27 Feb 2023 14:32:47 +0100 Subject: [PATCH 04/13] add default assumptions function --- scripts/prepare_sector_network.py | 157 +++++++++++++++++++++++++----- 1 file changed, 132 insertions(+), 25 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index ccc41561ba..7a7cbdfe66 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -2084,10 +2084,13 @@ def add_biomass(n, costs): ) -def add_low_t_industry(n, nodes, industrial_demand, costs): +def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): """Add low temperature heat for industry. """ + logger.info("Add low temperature industry demand.") + + n.madd("Bus", nodes + " lowT industry", location=nodes, @@ -2101,9 +2104,6 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): carrier="lowT industry", p_set=industrial_demand.loc[nodes, "solid biomass"] / 8760.) - #NB: industrial heat demand is in reality supplied at site by discrete plants - # which follow the local demand and therefore cannot be dispatched too much. - # Thus, p_min_pu is set to 0.8 to avoid too much dispatch behaviour. Improvements welcome! if options["industry_t"]['low_T']["biomass"] or not options["industry_t"]['endogen']: n.madd("Link", nodes, @@ -2113,7 +2113,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): bus3="co2 atmosphere", carrier="lowT industry solid biomass", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['solid biomass boiler steam', 'efficiency'], efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at[ 'solid biomass', 'CO2 intensity'], @@ -2130,7 +2130,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): bus2="co2 stored", carrier="lowT industry solid biomass CC", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['solid biomass boiler steam CC', 'efficiency'], capital_cost=costs.at['solid biomass boiler steam CC', 'fixed'] * costs.at[ 'solid biomass boiler steam CC', 'efficiency'] + costs.at[ @@ -2153,7 +2153,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): bus3="co2 atmosphere", carrier="lowT industry methane", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['gas boiler steam', 'efficiency'], capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'], marginal_cost=costs.at['gas boiler steam', 'VOM'], @@ -2170,7 +2170,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): bus2="co2 stored", carrier="lowT industry methane CC", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=eta, capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'] + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], @@ -2188,7 +2188,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): bus1=nodes + " lowT industry", carrier="lowT industry heat pump", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=eta, capital_cost=costs.at['industrial heat pump high temperature', 'fixed'] * eta, marginal_cost=costs.at['industrial heat pump high temperature', 'VOM'], @@ -2202,7 +2202,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): bus1=nodes + " lowT industry", carrier="lowT industry electricity", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['electric boiler steam', 'efficiency'], capital_cost=costs.at['electric boiler steam', 'fixed'] * costs.at[ 'electric boiler steam', 'efficiency'], @@ -2211,10 +2211,11 @@ def add_low_t_industry(n, nodes, industrial_demand, costs): -def add_medium_t_industry(n, nodes, industrial_demand, costs): +def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): """Add medium temperature heat for industry. """ - logger.info("Add medium temperature industry demand.") + + logger.info("Add medium temperature industry demand") n.madd("Bus", nodes + " mediumT industry", @@ -2239,7 +2240,7 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs): bus3="co2 atmosphere", carrier="solid biomass for mediumT industry", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['direct firing solid fuels', 'efficiency'], efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], capital_cost=costs.at['direct firing solid fuels', 'fixed'] * costs.at['direct firing solid fuels', 'efficiency'], @@ -2255,7 +2256,7 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs): bus2="co2 stored", carrier="solid biomass for mediumT industry CC", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['direct firing solid fuels CC', 'efficiency'], capital_cost=costs.at['direct firing solid fuels CC', 'fixed'] * costs.at[ 'direct firing solid fuels CC', 'efficiency'] + costs.at[ @@ -2281,7 +2282,7 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs): bus3="co2 atmosphere", carrier="gas for mediumT industry", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['direct firing gas', 'efficiency'], efficiency3=costs.at['gas', 'CO2 intensity'], capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], @@ -2299,7 +2300,7 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs): bus2="co2 stored", carrier="gas for mediumT industry CC", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=eta, efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], @@ -2319,14 +2320,15 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs): capital_cost=10 * costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], marginal_cost=10 * costs.at['direct firing gas', 'VOM'], p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['direct firing gas', 'efficiency']) -def add_high_t_industry(n, nodes, industrial_demand, costs): +def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): """Add high temperature heat for industry. """ - logger.info("Add high temperature industry demand.") + + logger.info(f"Add high temperature industry demand.") n.madd("Bus", nodes + " highT industry", @@ -2351,7 +2353,7 @@ def add_high_t_industry(n, nodes, industrial_demand, costs): bus3="co2 atmosphere", carrier="gas for highT industry", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['direct firing gas', 'efficiency'], efficiency3=costs.at['gas', 'CO2 intensity'], capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], @@ -2369,7 +2371,7 @@ def add_high_t_industry(n, nodes, industrial_demand, costs): bus2="co2 stored", carrier="gas for highT industry CC", p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=eta, efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], @@ -2391,9 +2393,107 @@ def add_high_t_industry(n, nodes, industrial_demand, costs): capital_cost=10 * costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], marginal_cost=10 * costs.at['direct firing gas', 'VOM'], p_nom_extendable=True, - p_min_pu=0.8, + p_min_pu=must_run, efficiency=costs.at['direct firing gas', 'efficiency']) + +def add_exogen_t_industry(n, nodes, industrial_demand, costs): + """Add heat demand for industry with exogenous supply. + + low temperature is supplied by biomass + medium and high temperature is supplied by gas + """ + + n.madd("Bus", + spatial.biomass.industry, + location=spatial.biomass.locations, + carrier="solid biomass for industry", + unit="MWh_LHV" + ) + + if options.get("biomass_spatial", options["biomass_transport"]): + p_set = industrial_demand.loc[spatial.biomass.locations, "solid biomass"].rename(index=lambda x: x + " solid biomass for industry") / 8760 + else: + p_set = industrial_demand["solid biomass"].sum() / 8760 + + n.madd("Load", + spatial.biomass.industry, + bus=spatial.biomass.industry, + carrier="solid biomass for industry", + p_set=p_set + ) + + n.madd("Link", + spatial.biomass.industry, + bus0=spatial.biomass.nodes, + bus1=spatial.biomass.industry, + carrier="solid biomass for industry", + p_nom_extendable=True, + efficiency=1. + ) + + n.madd("Link", + spatial.biomass.industry_cc, + bus0=spatial.biomass.nodes, + bus1=spatial.biomass.industry, + bus2="co2 atmosphere", + bus3=spatial.co2.nodes, + carrier="solid biomass for industry CC", + p_nom_extendable=True, + capital_cost=costs.at["cement capture", "fixed"] * costs.at['solid biomass', 'CO2 intensity'], + efficiency=0.9, # TODO: make config option + efficiency2=-costs.at['solid biomass', 'CO2 intensity'] * costs.at["cement capture", "capture_rate"], + efficiency3=costs.at['solid biomass', 'CO2 intensity'] * costs.at["cement capture", "capture_rate"], + lifetime=costs.at['cement capture', 'lifetime'] + ) + + n.madd("Bus", + spatial.gas.industry, + location=spatial.gas.locations, + carrier="gas for industry", + unit="MWh_LHV") + + gas_demand = industrial_demand.loc[nodes, "methane"] / 8760. + + if options["gas_network"]: + spatial_gas_demand = gas_demand.rename(index=lambda x: x + " gas for industry") + else: + spatial_gas_demand = gas_demand.sum() + + n.madd("Load", + spatial.gas.industry, + bus=spatial.gas.industry, + carrier="gas for industry", + p_set=spatial_gas_demand + ) + + n.madd("Link", + spatial.gas.industry, + bus0=spatial.gas.nodes, + bus1=spatial.gas.industry, + bus2="co2 atmosphere", + carrier="gas for industry", + p_nom_extendable=True, + efficiency=1., + efficiency2=costs.at['gas', 'CO2 intensity'] + ) + + n.madd("Link", + spatial.gas.industry_cc, + bus0=spatial.gas.nodes, + bus1=spatial.gas.industry, + bus2="co2 atmosphere", + bus3=spatial.co2.nodes, + carrier="gas for industry CC", + p_nom_extendable=True, + capital_cost=costs.at["cement capture", "fixed"] * costs.at['gas', 'CO2 intensity'], + efficiency=0.9, + efficiency2=costs.at['gas', 'CO2 intensity'] * (1 - costs.at["cement capture", "capture_rate"]), + efficiency3=costs.at['gas', 'CO2 intensity'] * costs.at["cement capture", "capture_rate"], + lifetime=costs.at['cement capture', 'lifetime'] + ) + + def add_industry(n, costs): logger.info("Add industrial demand") @@ -2403,11 +2503,18 @@ def add_industry(n, costs): # 1e6 to convert TWh to MWh industrial_demand = pd.read_csv(snakemake.input.industrial_demand, index_col=0) * 1e6 - add_low_t_industry(n, nodes, industrial_demand, costs) + # endogenous heat supply for industry + if options["industry_t"]["endogen"]: + must_run = options["industry_t"]["must_run"] + logger.info(f"Endogenise heat supply of indutry with must run condition {must_run}") + + add_low_t_industry(n, nodes, industrial_demand, costs, must_run) - add_medium_t_industry(n, nodes, industrial_demand, costs) + add_medium_t_industry(n, nodes, industrial_demand, costs, must_run) - add_high_t_industry(n, nodes, industrial_demand, costs) + add_high_t_industry(n, nodes, industrial_demand, costs, must_run) + else: + add_exogen_t_industry(n, nodes, industrial_demand, costs) n.madd("Load", nodes, From 89d80ddd437404455e17e620070eaffba209e6e7 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 27 Feb 2023 15:13:35 +0100 Subject: [PATCH 05/13] update config, clean up --- config.default.yaml | 28 +++++++++++----- scripts/prepare_sector_network.py | 56 +++++++++++++++---------------- 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 9ee5e9c19a..693f28cba1 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -304,14 +304,26 @@ sector: biomass_transport: false # allow transport of solid biomass between nodes conventional_generation: # generator : carrier OCGT: gas - industry_steam_biomass: true - industry_steam_heat_pumps: true - industry_steam_electric_boiler: true - industry_steam_methane: true - industry_mediumT_biomass: true - industry_mediumT_methane: true - industry_mediumT_hydrogen: true - industry_highT_hydrogen: true + industry_t: # heat supply industry + endogen: true # if heat supply for industry should be enodgenously optimised + must_run: 0.8 # NB: industrial heat demand is in reality supplied at site by discrete plants + # which follow the local demand and therefore cannot be dispatched too much. + # Thus, p_min_pu is set to must run to avoid too much dispatch behaviour. Improvements welcome! + share_medium: 0.3 # TODO + share_high: 0.7 + # Options in case of endogenous industry heat supply + low_T: + biomass: true + heat_pumps: true + electric_boiler: true + methane: true + medium_T: + biomass: true + methane: true + hydrogen: true + high_T: + hydrogen: true + methane: true biomass_to_liquid: false biosng: false diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 7a7cbdfe66..626a55f1ca 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -2088,7 +2088,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): """Add low temperature heat for industry. """ - logger.info("Add low temperature industry demand.") + logger.info("Add low temperature industry.") n.madd("Bus", @@ -2110,12 +2110,12 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for lowT industry", bus0=spatial.biomass.nodes, bus1=nodes + " lowT industry", - bus3="co2 atmosphere", + bus2="co2 atmosphere", carrier="lowT industry solid biomass", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at['solid biomass boiler steam', 'efficiency'], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at[ + efficiency2=costs.at['solid biomass', 'CO2 intensity'] - costs.at[ 'solid biomass', 'CO2 intensity'], capital_cost=costs.at['solid biomass boiler steam', 'fixed'] * costs.at[ 'solid biomass boiler steam', 'efficiency'], @@ -2126,8 +2126,8 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for lowT industry CC", bus0=spatial.biomass.nodes, bus1=nodes + " lowT industry", + bus2=spatial.co2.nodes, bus3="co2 atmosphere", - bus2="co2 stored", carrier="lowT industry solid biomass CC", p_nom_extendable=True, p_min_pu=must_run, @@ -2150,14 +2150,14 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" gas for lowT industry", bus0=spatial.gas.nodes, bus1=nodes + " lowT industry", - bus3="co2 atmosphere", + bus2="co2 atmosphere", carrier="lowT industry methane", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at['gas boiler steam', 'efficiency'], capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'], marginal_cost=costs.at['gas boiler steam', 'VOM'], - efficiency3=costs.at['gas', 'CO2 intensity']) + efficiency2=costs.at['gas', 'CO2 intensity']) eta = costs.at['gas boiler steam', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ 'biomass CHP capture', 'heat-input'] @@ -2166,8 +2166,8 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" gas for lowT industry CC", bus0=spatial.gas.nodes, bus1=nodes + " lowT industry", + bus2=spatial.co2.nodes, bus3="co2 atmosphere", - bus2="co2 stored", carrier="lowT industry methane CC", p_nom_extendable=True, p_min_pu=must_run, @@ -2215,7 +2215,7 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): """Add medium temperature heat for industry. """ - logger.info("Add medium temperature industry demand") + logger.info("Add medium temperature industry.") n.madd("Bus", nodes + " mediumT industry", @@ -2223,13 +2223,13 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): carrier="mediumT industry", unit="MWh_LHV") - # TODO: Set real shares of medium and high T industry + share_m = options["industry_t"]["share_medium"] n.madd("Load", nodes, suffix=" mediumT industry", bus=nodes + " mediumT industry", carrier="mediumT industry", - p_set=0.3 * industrial_demand.loc[nodes, "methane"] / 8760.) + p_set=share_m * industrial_demand.loc[nodes, "methane"] / 8760.) if options["industry_t"]['medium_T']['biomass']: n.madd("Link", @@ -2237,12 +2237,12 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for mediumT industry", bus0=spatial.biomass.nodes, bus1=nodes + " mediumT industry", - bus3="co2 atmosphere", + bus2="co2 atmosphere", carrier="solid biomass for mediumT industry", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at['direct firing solid fuels', 'efficiency'], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], + efficiency2=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], capital_cost=costs.at['direct firing solid fuels', 'fixed'] * costs.at['direct firing solid fuels', 'efficiency'], marginal_cost=costs.at['direct firing solid fuels', 'VOM'] + costs.at['biomass boiler', 'pelletizing cost'], lifetime=costs.at['direct firing solid fuels', 'lifetime']) @@ -2252,8 +2252,8 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for mediumT industry CC", bus0=spatial.biomass.nodes, bus1=nodes + " mediumT industry", + bus2=spatial.co2.nodes, bus3="co2 atmosphere", - bus2="co2 stored", carrier="solid biomass for mediumT industry CC", p_nom_extendable=True, p_min_pu=must_run, @@ -2264,11 +2264,11 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): 'solid biomass', 'CO2 intensity'], marginal_cost=costs.at['direct firing solid fuels CC', 'VOM'] + costs.at[ 'biomass boiler', 'pelletizing cost'], + efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ + 'biomass CHP capture', 'capture_rate'], efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ 'solid biomass', 'CO2 intensity'], - efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'capture_rate'], lifetime=costs.at['direct firing solid fuels CC', 'lifetime']) @@ -2279,12 +2279,12 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" gas for mediumT industry", bus0=spatial.gas.nodes, bus1=nodes + " mediumT industry", - bus3="co2 atmosphere", + bus2="co2 atmosphere", carrier="gas for mediumT industry", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at['direct firing gas', 'efficiency'], - efficiency3=costs.at['gas', 'CO2 intensity'], + efficiency2=costs.at['gas', 'CO2 intensity'], capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], marginal_cost=costs.at['direct firing gas', 'VOM'], lifetime=costs.at['direct firing gas', 'lifetime']) @@ -2296,14 +2296,14 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" gas for mediumT industry CC", bus0=spatial.gas.nodes, bus1=nodes + " mediumT industry", + bus2=spatial.co2.nodes, bus3="co2 atmosphere", - bus2="co2 stored", carrier="gas for mediumT industry CC", p_nom_extendable=True, p_min_pu=must_run, efficiency=eta, - efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], + efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], marginal_cost=costs.at['direct firing gas CC', 'VOM'], @@ -2328,34 +2328,35 @@ def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): """Add high temperature heat for industry. """ - logger.info(f"Add high temperature industry demand.") + logger.info("Add high temperature industry.") n.madd("Bus", nodes + " highT industry", location=nodes, carrier="highT industry") + share_h = options["industry_t"]["share_high"] + n.madd("Load", nodes, suffix=" highT industry", bus=nodes + " highT industry", carrier="highT industry", - p_set=0.7 * industrial_demand.loc[nodes, "methane"] / 8760.) + p_set=share_h * industrial_demand.loc[nodes, "methane"] / 8760.) if options["industry_t"]['high_T']['methane']: - # TODO: differentiate medium and high T processes n.madd("Link", nodes, suffix=" gas for highT industry", bus0=spatial.gas.nodes, bus1=nodes + " highT industry", - bus3="co2 atmosphere", + bus2="co2 atmosphere", carrier="gas for highT industry", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at['direct firing gas', 'efficiency'], - efficiency3=costs.at['gas', 'CO2 intensity'], + efficiency2=costs.at['gas', 'CO2 intensity'], capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], marginal_cost=costs.at['direct firing gas', 'VOM'], lifetime=costs.at['direct firing gas', 'lifetime']) @@ -2367,14 +2368,14 @@ def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" gas for highT industry CC", bus0=spatial.gas.nodes, bus1=nodes + " highT industry", + bus2=spatial.co2.nodes, bus3="co2 atmosphere", - bus2="co2 stored", carrier="gas for highT industry CC", p_nom_extendable=True, p_min_pu=must_run, efficiency=eta, - efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], + efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], marginal_cost=costs.at['direct firing gas CC', 'VOM'], @@ -2382,7 +2383,6 @@ def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): if options["industry_t"]['high_T']['hydrogen']: - print('Adding H2 for highT industry') #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion n.madd("Link", nodes, @@ -2506,7 +2506,7 @@ def add_industry(n, costs): # endogenous heat supply for industry if options["industry_t"]["endogen"]: must_run = options["industry_t"]["must_run"] - logger.info(f"Endogenise heat supply of indutry with must run condition {must_run}") + logger.info(f"Endogenise heat supply of industry with must run condition {must_run}") add_low_t_industry(n, nodes, industrial_demand, costs, must_run) From 8f51ac4befb0ddae5c9010a598701c68ba2d066c Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 27 Feb 2023 15:16:50 +0100 Subject: [PATCH 06/13] change default to exogenous industry heat --- config.default.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.default.yaml b/config.default.yaml index 693f28cba1..bee3d1177d 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -305,7 +305,7 @@ sector: conventional_generation: # generator : carrier OCGT: gas industry_t: # heat supply industry - endogen: true # if heat supply for industry should be enodgenously optimised + endogen: false # if heat supply for industry should be enodgenously optimised must_run: 0.8 # NB: industrial heat demand is in reality supplied at site by discrete plants # which follow the local demand and therefore cannot be dispatched too much. # Thus, p_min_pu is set to must run to avoid too much dispatch behaviour. Improvements welcome! From 4f45df13a9ce845a5e8ef797ce0488cc66c0e428 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Thu, 2 Mar 2023 16:15:04 +0100 Subject: [PATCH 07/13] adjust medium and high t share --- config.default.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index bee3d1177d..8e1d91b4c0 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -309,8 +309,10 @@ sector: must_run: 0.8 # NB: industrial heat demand is in reality supplied at site by discrete plants # which follow the local demand and therefore cannot be dispatched too much. # Thus, p_min_pu is set to must run to avoid too much dispatch behaviour. Improvements welcome! - share_medium: 0.3 # TODO - share_high: 0.7 + # share of medium and high temperature for process heat based on table 3 for EU28 in https://doi.org/10.1002/er.3436 + # TODO: should be improved and split up by country and sector + share_medium: 0.36 + share_high: 0.64 # Options in case of endogenous industry heat supply low_T: biomass: true From cafbb1c739650c717bdb5205b4a78f112a3322c3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 26 Jul 2023 08:36:11 +0000 Subject: [PATCH 08/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- config.default.yaml | 162 ++++---- scripts/prepare_sector_network.py | 650 +++++++++++++++++------------- 2 files changed, 440 insertions(+), 372 deletions(-) diff --git a/config.default.yaml b/config.default.yaml index 8e1d91b4c0..119e4229c1 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -13,17 +13,17 @@ foresight: overnight # options are overnight, myopic, perfect (perfect is not ye scenario: simpl: # only relevant for PyPSA-Eur - - '' + - '' lv: # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt" - - 1.0 - - 1.5 + - 1.0 + - 1.5 clusters: # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred - - 45 - - 50 + - 45 + - 50 opts: # only relevant for PyPSA-Eur - - '' + - '' sector_opts: # this is where the main scenario settings are - - Co2L0-3H-T-H-B-I-A-solar+p3-dist1 + - Co2L0-3H-T-H-B-I-A-solar+p3-dist1 # 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 @@ -41,7 +41,7 @@ scenario: # cb40ex0 distributes a carbon budget of 40 GtCO2 following an exponential # decay with initial growth rate 0 planning_horizons: # investment years for myopic and perfect; for overnight, year of cost assumptions can be different and is defined under 'costs' - - 2050 + - 2050 # for example, set to # - 2020 # - 2030 @@ -84,18 +84,18 @@ electricity: # in PyPSA-Eur-Sec pypsa_eur: Bus: - - AC + - AC Link: - - DC + - DC Generator: - - onwind - - offwind-ac - - offwind-dc - - solar - - ror + - onwind + - offwind-ac + - offwind-dc + - solar + - ror StorageUnit: - - PHS - - hydro + - PHS + - hydro Store: [] @@ -110,25 +110,25 @@ biomass: scenario: ENS_Med classes: solid biomass: - - Agricultural waste - - Fuelwood residues - - Secondary Forestry residues - woodchips - - Sawdust - - Residues from landscape care - - Municipal waste + - Agricultural waste + - Fuelwood residues + - Secondary Forestry residues - woodchips + - Sawdust + - Residues from landscape care + - Municipal waste not included: - - Sugar from sugar beet - - Rape seed - - "Sunflower, soya seed " - - Bioethanol barley, wheat, grain maize, oats, other cereals and rye - - Miscanthus, switchgrass, RCG - - Willow - - Poplar - - FuelwoodRW - - C&P_RW + - Sugar from sugar beet + - Rape seed + - "Sunflower, soya seed " + - Bioethanol barley, wheat, grain maize, oats, other cereals and rye + - Miscanthus, switchgrass, RCG + - Willow + - Poplar + - FuelwoodRW + - C&P_RW biogas: - - Manure solid, liquid - - Sludge + - Manure solid, liquid + - Sludge solar_thermal: @@ -143,10 +143,10 @@ existing_capacities: grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # these should not extend 2020 threshold_capacity: 10 conventional_carriers: - - lignite - - coal - - oil - - uranium + - lignite + - coal + - oil + - uranium sector: @@ -238,7 +238,7 @@ sector: 2040: 0.16 2045: 0.21 2050: 0.29 - retrofitting : # co-optimises building renovation to reduce space heat demand + retrofitting: # co-optimises building renovation to reduce space heat demand retro_endogen: false # co-optimise space heat savings cost_factor: 1.0 # weight costs for building renovation interest_rate: 0.04 # for investment in building components @@ -279,7 +279,7 @@ sector: hydrogen_underground_storage: true hydrogen_underground_storage_locations: # - onshore # more than 50 km from sea - - nearshore # within 50 km of sea + - nearshore # within 50 km of sea # - offshore ammonia: false # can be false (no NH3 carrier), true (copperplated NH3), "regional" (regionalised NH3 without network) min_part_load_fischer_tropsch: 0.9 # p_min_pu @@ -422,14 +422,14 @@ solving: min_iterations: 4 max_iterations: 6 keep_shadowprices: - - Bus - - Line - - Link - - Transformer - - GlobalConstraint - - Generator - - Store - - StorageUnit + - Bus + - Line + - Link + - Transformer + - GlobalConstraint + - Generator + - Store + - StorageUnit solver: name: gurobi @@ -495,47 +495,47 @@ plotting: energy_min: -20000 energy_threshold: 50 vre_techs: - - onwind - - offwind-ac - - offwind-dc - - solar - - ror + - onwind + - offwind-ac + - offwind-dc + - solar + - ror renewable_storage_techs: - - PHS - - hydro + - PHS + - hydro conv_techs: - - OCGT - - CCGT - - Nuclear - - Coal + - OCGT + - CCGT + - Nuclear + - Coal storage_techs: - - hydro+PHS - - battery - - H2 + - hydro+PHS + - battery + - H2 load_carriers: - - AC load + - AC load AC_carriers: - - AC line - - AC transformer + - AC line + - AC transformer link_carriers: - - DC line - - Converter AC-DC + - 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 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 + - gas boiler + - central gas boiler + - solar thermal collector + - central solar thermal collector tech_colors: # wind onwind: "#235ebc" diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 53f94bdce8..446bbb8ba1 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -615,7 +615,6 @@ def add_co2_network(n, costs): def add_allam(n, costs): - logger.info("Adding Allam cycle gas power plants.") nodes = pop_layout.index @@ -2350,323 +2349,392 @@ def add_biomass(n, costs): def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): - """Add low temperature heat for industry. + """ + Add low temperature heat for industry. """ logger.info("Add low temperature industry.") + n.madd( + "Bus", + nodes + " lowT industry", + location=nodes, + carrier="lowT industry", + unit="MWh_LHV", + ) - n.madd("Bus", - nodes + " lowT industry", - location=nodes, - carrier="lowT industry", - unit="MWh_LHV") - - n.madd("Load", - nodes, - suffix=" lowT industry", - bus=nodes + " lowT industry", - carrier="lowT industry", - p_set=industrial_demand.loc[nodes, "solid biomass"] / 8760.) - - if options["industry_t"]['low_T']["biomass"] or not options["industry_t"]['endogen']: - n.madd("Link", - nodes, - suffix=" solid biomass for lowT industry", - bus0=spatial.biomass.nodes, - bus1=nodes + " lowT industry", - bus2="co2 atmosphere", - carrier="lowT industry solid biomass", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['solid biomass boiler steam', 'efficiency'], - efficiency2=costs.at['solid biomass', 'CO2 intensity'] - costs.at[ - 'solid biomass', 'CO2 intensity'], - capital_cost=costs.at['solid biomass boiler steam', 'fixed'] * costs.at[ - 'solid biomass boiler steam', 'efficiency'], - marginal_cost=costs.at['solid biomass boiler steam', 'VOM']) - - n.madd("Link", - nodes, - suffix=" solid biomass for lowT industry CC", - bus0=spatial.biomass.nodes, - bus1=nodes + " lowT industry", - bus2=spatial.co2.nodes, - bus3="co2 atmosphere", - carrier="lowT industry solid biomass CC", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['solid biomass boiler steam CC', 'efficiency'], - capital_cost=costs.at['solid biomass boiler steam CC', 'fixed'] * costs.at[ - 'solid biomass boiler steam CC', 'efficiency'] + costs.at[ - 'biomass CHP capture', 'fixed'] * costs.at[ - 'solid biomass', 'CO2 intensity'], - marginal_cost=costs.at['solid biomass boiler steam CC', 'VOM'], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( - 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ - 'solid biomass', 'CO2 intensity'], - efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'capture_rate'], - lifetime=costs.at['solid biomass boiler steam CC', 'lifetime']) - - if options["industry_t"]['low_T']["methane"]: - n.madd("Link", - nodes, - suffix=" gas for lowT industry", - bus0=spatial.gas.nodes, - bus1=nodes + " lowT industry", - bus2="co2 atmosphere", - carrier="lowT industry methane", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['gas boiler steam', 'efficiency'], - capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'], - marginal_cost=costs.at['gas boiler steam', 'VOM'], - efficiency2=costs.at['gas', 'CO2 intensity']) - - eta = costs.at['gas boiler steam', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'heat-input'] - n.madd("Link", - nodes, - suffix=" gas for lowT industry CC", - bus0=spatial.gas.nodes, - bus1=nodes + " lowT industry", - bus2=spatial.co2.nodes, - bus3="co2 atmosphere", - carrier="lowT industry methane CC", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=eta, - capital_cost=costs.at['gas boiler steam', 'fixed'] * costs.at['gas boiler steam', 'efficiency'] + - costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], - marginal_cost=costs.at['gas boiler steam', 'VOM'], - efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), - efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], - lifetime=costs.at['gas boiler steam', 'lifetime']) - - if options["industry_t"]['low_T']["heat_pumps"]: - eta = costs.at['industrial heat pump high temperature', 'efficiency'] - n.madd("Link", - nodes, - suffix=" industrial heat pump steam for lowT industry", - bus0=nodes, - bus1=nodes + " lowT industry", - carrier="lowT industry heat pump", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=eta, - capital_cost=costs.at['industrial heat pump high temperature', 'fixed'] * eta, - marginal_cost=costs.at['industrial heat pump high temperature', 'VOM'], - lifetime=costs.at['industrial heat pump high temperature', 'lifetime']) - - if options["industry_t"]['low_T']["electric_boiler"]: - n.madd("Link", - nodes, - suffix=" electricity for lowT industry", - bus0=nodes, - bus1=nodes + " lowT industry", - carrier="lowT industry electricity", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['electric boiler steam', 'efficiency'], - capital_cost=costs.at['electric boiler steam', 'fixed'] * costs.at[ - 'electric boiler steam', 'efficiency'], - marginal_cost=costs.at['electric boiler steam', 'VOM'], - lifetime=costs.at['electric boiler steam', 'lifetime']) + n.madd( + "Load", + nodes, + suffix=" lowT industry", + bus=nodes + " lowT industry", + carrier="lowT industry", + p_set=industrial_demand.loc[nodes, "solid biomass"] / 8760.0, + ) + if ( + options["industry_t"]["low_T"]["biomass"] + or not options["industry_t"]["endogen"] + ): + n.madd( + "Link", + nodes, + suffix=" solid biomass for lowT industry", + bus0=spatial.biomass.nodes, + bus1=nodes + " lowT industry", + bus2="co2 atmosphere", + carrier="lowT industry solid biomass", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["solid biomass boiler steam", "efficiency"], + efficiency2=costs.at["solid biomass", "CO2 intensity"] + - costs.at["solid biomass", "CO2 intensity"], + capital_cost=costs.at["solid biomass boiler steam", "fixed"] + * costs.at["solid biomass boiler steam", "efficiency"], + marginal_cost=costs.at["solid biomass boiler steam", "VOM"], + ) + + n.madd( + "Link", + nodes, + suffix=" solid biomass for lowT industry CC", + bus0=spatial.biomass.nodes, + bus1=nodes + " lowT industry", + bus2=spatial.co2.nodes, + bus3="co2 atmosphere", + carrier="lowT industry solid biomass CC", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["solid biomass boiler steam CC", "efficiency"], + capital_cost=costs.at["solid biomass boiler steam CC", "fixed"] + * costs.at["solid biomass boiler steam CC", "efficiency"] + + costs.at["biomass CHP capture", "fixed"] + * costs.at["solid biomass", "CO2 intensity"], + marginal_cost=costs.at["solid biomass boiler steam CC", "VOM"], + efficiency3=costs.at["solid biomass", "CO2 intensity"] + * (1 - costs.at["biomass CHP capture", "capture_rate"]) + - costs.at["solid biomass", "CO2 intensity"], + efficiency2=costs.at["solid biomass", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], + lifetime=costs.at["solid biomass boiler steam CC", "lifetime"], + ) + + if options["industry_t"]["low_T"]["methane"]: + n.madd( + "Link", + nodes, + suffix=" gas for lowT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " lowT industry", + bus2="co2 atmosphere", + carrier="lowT industry methane", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["gas boiler steam", "efficiency"], + capital_cost=costs.at["gas boiler steam", "fixed"] + * costs.at["gas boiler steam", "efficiency"], + marginal_cost=costs.at["gas boiler steam", "VOM"], + efficiency2=costs.at["gas", "CO2 intensity"], + ) + + eta = ( + costs.at["gas boiler steam", "efficiency"] + - costs.at["gas", "CO2 intensity"] + * costs.at["biomass CHP capture", "heat-input"] + ) + n.madd( + "Link", + nodes, + suffix=" gas for lowT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " lowT industry", + bus2=spatial.co2.nodes, + bus3="co2 atmosphere", + carrier="lowT industry methane CC", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=eta, + capital_cost=costs.at["gas boiler steam", "fixed"] + * costs.at["gas boiler steam", "efficiency"] + + costs.at["biomass CHP capture", "fixed"] + * costs.at["gas", "CO2 intensity"], + marginal_cost=costs.at["gas boiler steam", "VOM"], + efficiency3=costs.at["gas", "CO2 intensity"] + * (1 - costs.at["biomass CHP capture", "capture_rate"]), + efficiency2=costs.at["gas", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], + lifetime=costs.at["gas boiler steam", "lifetime"], + ) + + if options["industry_t"]["low_T"]["heat_pumps"]: + eta = costs.at["industrial heat pump high temperature", "efficiency"] + n.madd( + "Link", + nodes, + suffix=" industrial heat pump steam for lowT industry", + bus0=nodes, + bus1=nodes + " lowT industry", + carrier="lowT industry heat pump", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=eta, + capital_cost=costs.at["industrial heat pump high temperature", "fixed"] + * eta, + marginal_cost=costs.at["industrial heat pump high temperature", "VOM"], + lifetime=costs.at["industrial heat pump high temperature", "lifetime"], + ) + + if options["industry_t"]["low_T"]["electric_boiler"]: + n.madd( + "Link", + nodes, + suffix=" electricity for lowT industry", + bus0=nodes, + bus1=nodes + " lowT industry", + carrier="lowT industry electricity", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["electric boiler steam", "efficiency"], + capital_cost=costs.at["electric boiler steam", "fixed"] + * costs.at["electric boiler steam", "efficiency"], + marginal_cost=costs.at["electric boiler steam", "VOM"], + lifetime=costs.at["electric boiler steam", "lifetime"], + ) def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): - """Add medium temperature heat for industry. + """ + Add medium temperature heat for industry. """ logger.info("Add medium temperature industry.") - n.madd("Bus", - nodes + " mediumT industry", - location=nodes, - carrier="mediumT industry", - unit="MWh_LHV") + n.madd( + "Bus", + nodes + " mediumT industry", + location=nodes, + carrier="mediumT industry", + unit="MWh_LHV", + ) share_m = options["industry_t"]["share_medium"] - n.madd("Load", - nodes, - suffix=" mediumT industry", - bus=nodes + " mediumT industry", - carrier="mediumT industry", - p_set=share_m * industrial_demand.loc[nodes, "methane"] / 8760.) - - if options["industry_t"]['medium_T']['biomass']: - n.madd("Link", - nodes, - suffix=" solid biomass for mediumT industry", - bus0=spatial.biomass.nodes, - bus1=nodes + " mediumT industry", - bus2="co2 atmosphere", - carrier="solid biomass for mediumT industry", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['direct firing solid fuels', 'efficiency'], - efficiency2=costs.at['solid biomass', 'CO2 intensity'] - costs.at['solid biomass', 'CO2 intensity'], - capital_cost=costs.at['direct firing solid fuels', 'fixed'] * costs.at['direct firing solid fuels', 'efficiency'], - marginal_cost=costs.at['direct firing solid fuels', 'VOM'] + costs.at['biomass boiler', 'pelletizing cost'], - lifetime=costs.at['direct firing solid fuels', 'lifetime']) - - n.madd("Link", - nodes, - suffix=" solid biomass for mediumT industry CC", - bus0=spatial.biomass.nodes, - bus1=nodes + " mediumT industry", - bus2=spatial.co2.nodes, - bus3="co2 atmosphere", - carrier="solid biomass for mediumT industry CC", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['direct firing solid fuels CC', 'efficiency'], - capital_cost=costs.at['direct firing solid fuels CC', 'fixed'] * costs.at[ - 'direct firing solid fuels CC', 'efficiency'] + costs.at[ - 'biomass CHP capture', 'fixed'] * costs.at[ - 'solid biomass', 'CO2 intensity'], - marginal_cost=costs.at['direct firing solid fuels CC', 'VOM'] + costs.at[ - 'biomass boiler', 'pelletizing cost'], - efficiency2=costs.at['solid biomass', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'capture_rate'], - efficiency3=costs.at['solid biomass', 'CO2 intensity'] * ( - 1 - costs.at['biomass CHP capture', 'capture_rate']) - costs.at[ - 'solid biomass', 'CO2 intensity'], - lifetime=costs.at['direct firing solid fuels CC', 'lifetime']) - - - if options["industry_t"]['medium_T']['methane']: + n.madd( + "Load", + nodes, + suffix=" mediumT industry", + bus=nodes + " mediumT industry", + carrier="mediumT industry", + p_set=share_m * industrial_demand.loc[nodes, "methane"] / 8760.0, + ) + + if options["industry_t"]["medium_T"]["biomass"]: + n.madd( + "Link", + nodes, + suffix=" solid biomass for mediumT industry", + bus0=spatial.biomass.nodes, + bus1=nodes + " mediumT industry", + bus2="co2 atmosphere", + carrier="solid biomass for mediumT industry", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["direct firing solid fuels", "efficiency"], + efficiency2=costs.at["solid biomass", "CO2 intensity"] + - costs.at["solid biomass", "CO2 intensity"], + capital_cost=costs.at["direct firing solid fuels", "fixed"] + * costs.at["direct firing solid fuels", "efficiency"], + marginal_cost=costs.at["direct firing solid fuels", "VOM"] + + costs.at["biomass boiler", "pelletizing cost"], + lifetime=costs.at["direct firing solid fuels", "lifetime"], + ) + + n.madd( + "Link", + nodes, + suffix=" solid biomass for mediumT industry CC", + bus0=spatial.biomass.nodes, + bus1=nodes + " mediumT industry", + bus2=spatial.co2.nodes, + bus3="co2 atmosphere", + carrier="solid biomass for mediumT industry CC", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["direct firing solid fuels CC", "efficiency"], + capital_cost=costs.at["direct firing solid fuels CC", "fixed"] + * costs.at["direct firing solid fuels CC", "efficiency"] + + costs.at["biomass CHP capture", "fixed"] + * costs.at["solid biomass", "CO2 intensity"], + marginal_cost=costs.at["direct firing solid fuels CC", "VOM"] + + costs.at["biomass boiler", "pelletizing cost"], + efficiency2=costs.at["solid biomass", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], + efficiency3=costs.at["solid biomass", "CO2 intensity"] + * (1 - costs.at["biomass CHP capture", "capture_rate"]) + - costs.at["solid biomass", "CO2 intensity"], + lifetime=costs.at["direct firing solid fuels CC", "lifetime"], + ) + + if options["industry_t"]["medium_T"]["methane"]: # TODO: add electricity input from DEA and adapt VOM to exclude electricity cost! - n.madd("Link", - nodes, - suffix=" gas for mediumT industry", - bus0=spatial.gas.nodes, - bus1=nodes + " mediumT industry", - bus2="co2 atmosphere", - carrier="gas for mediumT industry", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['direct firing gas', 'efficiency'], - efficiency2=costs.at['gas', 'CO2 intensity'], - capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], - marginal_cost=costs.at['direct firing gas', 'VOM'], - lifetime=costs.at['direct firing gas', 'lifetime']) - - eta = costs.at['direct firing gas', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'heat-input'] - n.madd("Link", - nodes, - suffix=" gas for mediumT industry CC", - bus0=spatial.gas.nodes, - bus1=nodes + " mediumT industry", - bus2=spatial.co2.nodes, - bus3="co2 atmosphere", - carrier="gas for mediumT industry CC", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=eta, - efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], - efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), - capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + - costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], - marginal_cost=costs.at['direct firing gas CC', 'VOM'], - lifetime=costs.at['direct firing gas', 'lifetime']) - - if options["industry_t"]['medium_T']['hydrogen']: - #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion - n.madd("Link", - nodes, - suffix=" hydrogen for mediumT industry", - bus0=nodes + " H2", - bus1=nodes + " mediumT industry", - carrier="hydrogen for mediumT industry", - capital_cost=10 * costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], - marginal_cost=10 * costs.at['direct firing gas', 'VOM'], - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['direct firing gas', 'efficiency']) + n.madd( + "Link", + nodes, + suffix=" gas for mediumT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " mediumT industry", + bus2="co2 atmosphere", + carrier="gas for mediumT industry", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["direct firing gas", "efficiency"], + efficiency2=costs.at["gas", "CO2 intensity"], + capital_cost=costs.at["direct firing gas", "fixed"] + * costs.at["direct firing gas", "efficiency"], + marginal_cost=costs.at["direct firing gas", "VOM"], + lifetime=costs.at["direct firing gas", "lifetime"], + ) + + eta = ( + costs.at["direct firing gas", "efficiency"] + - costs.at["gas", "CO2 intensity"] + * costs.at["biomass CHP capture", "heat-input"] + ) + n.madd( + "Link", + nodes, + suffix=" gas for mediumT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " mediumT industry", + bus2=spatial.co2.nodes, + bus3="co2 atmosphere", + carrier="gas for mediumT industry CC", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=eta, + efficiency2=costs.at["gas", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], + efficiency3=costs.at["gas", "CO2 intensity"] + * (1 - costs.at["biomass CHP capture", "capture_rate"]), + capital_cost=costs.at["direct firing gas CC", "fixed"] + * costs.at["direct firing gas CC", "efficiency"] + + costs.at["biomass CHP capture", "fixed"] + * costs.at["gas", "CO2 intensity"], + marginal_cost=costs.at["direct firing gas CC", "VOM"], + lifetime=costs.at["direct firing gas", "lifetime"], + ) + + if options["industry_t"]["medium_T"]["hydrogen"]: + # TODO: research cost of industrial H2 combustion, here set to 10x methane combustion + n.madd( + "Link", + nodes, + suffix=" hydrogen for mediumT industry", + bus0=nodes + " H2", + bus1=nodes + " mediumT industry", + carrier="hydrogen for mediumT industry", + capital_cost=10 + * costs.at["direct firing gas", "fixed"] + * costs.at["direct firing gas", "efficiency"], + marginal_cost=10 * costs.at["direct firing gas", "VOM"], + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["direct firing gas", "efficiency"], + ) def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): - """Add high temperature heat for industry. + """ + Add high temperature heat for industry. """ logger.info("Add high temperature industry.") - n.madd("Bus", - nodes + " highT industry", - location=nodes, - carrier="highT industry") + n.madd("Bus", nodes + " highT industry", location=nodes, carrier="highT industry") share_h = options["industry_t"]["share_high"] - n.madd("Load", - nodes, - suffix=" highT industry", - bus=nodes + " highT industry", - carrier="highT industry", - p_set=share_h * industrial_demand.loc[nodes, "methane"] / 8760.) - - - if options["industry_t"]['high_T']['methane']: - n.madd("Link", - nodes, - suffix=" gas for highT industry", - bus0=spatial.gas.nodes, - bus1=nodes + " highT industry", - bus2="co2 atmosphere", - carrier="gas for highT industry", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['direct firing gas', 'efficiency'], - efficiency2=costs.at['gas', 'CO2 intensity'], - capital_cost=costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], - marginal_cost=costs.at['direct firing gas', 'VOM'], - lifetime=costs.at['direct firing gas', 'lifetime']) - - eta = costs.at['direct firing gas', 'efficiency'] - costs.at['gas', 'CO2 intensity'] * costs.at[ - 'biomass CHP capture', 'heat-input'] - n.madd("Link", - nodes, - suffix=" gas for highT industry CC", - bus0=spatial.gas.nodes, - bus1=nodes + " highT industry", - bus2=spatial.co2.nodes, - bus3="co2 atmosphere", - carrier="gas for highT industry CC", - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=eta, - efficiency2=costs.at['gas', 'CO2 intensity'] * costs.at['biomass CHP capture', 'capture_rate'], - efficiency3=costs.at['gas', 'CO2 intensity'] * (1 - costs.at['biomass CHP capture', 'capture_rate']), - capital_cost=costs.at['direct firing gas CC', 'fixed'] * costs.at['direct firing gas CC', 'efficiency'] + - costs.at['biomass CHP capture', 'fixed'] * costs.at['gas', 'CO2 intensity'], - marginal_cost=costs.at['direct firing gas CC', 'VOM'], - lifetime=costs.at['direct firing gas', 'lifetime']) - - - if options["industry_t"]['high_T']['hydrogen']: - #TODO: research cost of industrial H2 combustion, here set to 10x methane combustion - n.madd("Link", - nodes, - suffix=" hydrogen for highT industry", - bus0=nodes + " H2", - bus1=nodes + " highT industry", - carrier="hydrogen for highT industry", - capital_cost=10 * costs.at['direct firing gas', 'fixed'] * costs.at['direct firing gas', 'efficiency'], - marginal_cost=10 * costs.at['direct firing gas', 'VOM'], - p_nom_extendable=True, - p_min_pu=must_run, - efficiency=costs.at['direct firing gas', 'efficiency']) + n.madd( + "Load", + nodes, + suffix=" highT industry", + bus=nodes + " highT industry", + carrier="highT industry", + p_set=share_h * industrial_demand.loc[nodes, "methane"] / 8760.0, + ) + + if options["industry_t"]["high_T"]["methane"]: + n.madd( + "Link", + nodes, + suffix=" gas for highT industry", + bus0=spatial.gas.nodes, + bus1=nodes + " highT industry", + bus2="co2 atmosphere", + carrier="gas for highT industry", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["direct firing gas", "efficiency"], + efficiency2=costs.at["gas", "CO2 intensity"], + capital_cost=costs.at["direct firing gas", "fixed"] + * costs.at["direct firing gas", "efficiency"], + marginal_cost=costs.at["direct firing gas", "VOM"], + lifetime=costs.at["direct firing gas", "lifetime"], + ) + + eta = ( + costs.at["direct firing gas", "efficiency"] + - costs.at["gas", "CO2 intensity"] + * costs.at["biomass CHP capture", "heat-input"] + ) + n.madd( + "Link", + nodes, + suffix=" gas for highT industry CC", + bus0=spatial.gas.nodes, + bus1=nodes + " highT industry", + bus2=spatial.co2.nodes, + bus3="co2 atmosphere", + carrier="gas for highT industry CC", + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=eta, + efficiency2=costs.at["gas", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], + efficiency3=costs.at["gas", "CO2 intensity"] + * (1 - costs.at["biomass CHP capture", "capture_rate"]), + capital_cost=costs.at["direct firing gas CC", "fixed"] + * costs.at["direct firing gas CC", "efficiency"] + + costs.at["biomass CHP capture", "fixed"] + * costs.at["gas", "CO2 intensity"], + marginal_cost=costs.at["direct firing gas CC", "VOM"], + lifetime=costs.at["direct firing gas", "lifetime"], + ) + + if options["industry_t"]["high_T"]["hydrogen"]: + # TODO: research cost of industrial H2 combustion, here set to 10x methane combustion + n.madd( + "Link", + nodes, + suffix=" hydrogen for highT industry", + bus0=nodes + " H2", + bus1=nodes + " highT industry", + carrier="hydrogen for highT industry", + capital_cost=10 + * costs.at["direct firing gas", "fixed"] + * costs.at["direct firing gas", "efficiency"], + marginal_cost=10 * costs.at["direct firing gas", "VOM"], + p_nom_extendable=True, + p_min_pu=must_run, + efficiency=costs.at["direct firing gas", "efficiency"], + ) def add_exogen_t_industry(n, nodes, industrial_demand, costs): - """Add heat demand for industry with exogenous supply. + """ + Add heat demand for industry with exogenous supply. - low temperature is supplied by biomass - medium and high temperature is supplied by gas + low temperature is supplied by biomass medium and high temperature + is supplied by gas """ n.madd( @@ -2780,7 +2848,6 @@ def add_exogen_t_industry(n, nodes, industrial_demand, costs): def add_industry(n, costs): - logger.info("Add industrial demand") nodes = pop_layout.index @@ -2795,7 +2862,9 @@ def add_industry(n, costs): # endogenous heat supply for industry if options["industry_t"]["endogen"]: must_run = options["industry_t"]["must_run"] - logger.info(f"Endogenise heat supply of industry with must run condition {must_run}") + logger.info( + f"Endogenise heat supply of industry with must run condition {must_run}" + ) add_low_t_industry(n, nodes, industrial_demand, costs, must_run) @@ -3729,7 +3798,6 @@ def set_temporal_aggregation(n, opts, solver_name): logger.info(f"Add CO2 limit from {limit_type}") add_co2limit(n, nyears, limit) - for o in opts: if not o[:10] == "linemaxext": continue From 22a69d50538e3c77c5c62991633f6147a6b01b50 Mon Sep 17 00:00:00 2001 From: Fabian Neumann Date: Wed, 26 Jul 2023 10:36:56 +0200 Subject: [PATCH 09/13] merge-conflict: delete extra config.default.yaml --- config.default.yaml | 740 -------------------------------------------- 1 file changed, 740 deletions(-) delete mode 100644 config.default.yaml diff --git a/config.default.yaml b/config.default.yaml deleted file mode 100644 index 8e1d91b4c0..0000000000 --- a/config.default.yaml +++ /dev/null @@ -1,740 +0,0 @@ -version: 0.7.0 - -logging_level: INFO - -retrieve_sector_databundle: true -retrieve_cost_data: true - -results_dir: results/ -summary_dir: results -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) -# if you use myopic or perfect foresight, set the investment years in "planning_horizons" below - -scenario: - simpl: # only relevant for PyPSA-Eur - - '' - lv: # allowed transmission line volume expansion, can be any float >= 1.0 (today) or "opt" - - 1.0 - - 1.5 - clusters: # number of nodes in Europe, any integer between 37 (1 node per country-zone) and several hundred - - 45 - - 50 - opts: # only relevant for PyPSA-Eur - - '' - sector_opts: # this is where the main scenario settings are - - Co2L0-3H-T-H-B-I-A-solar+p3-dist1 - # 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, - # A for agriculture, forestry and fishing - # solar+c0.5 reduces the capital cost of solar to 50\% of reference value - # solar+p3 multiplies the available installable potential by factor 3 - # seq400 sets the potential of CO2 sequestration to 400 Mt CO2 per year - # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv - # for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative - # emissions throughout the transition path in the timeframe determined by the - # planning_horizons), be:beta decay; ex:exponential decay - # cb40ex0 distributes a carbon budget of 40 GtCO2 following an exponential - # decay with initial growth rate 0 - planning_horizons: # investment years for myopic and perfect; for overnight, year of cost assumptions can be different and is defined under 'costs' - - 2050 - # for example, set to - # - 2020 - # - 2030 - # - 2040 - # - 2050 - # for myopic foresight - -# CO2 budget as a fraction of 1990 emissions -# this is over-ridden if CO2Lx is set in sector_opts -# this is also over-ridden if cb 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" - inclusive: left # end is not inclusive - -atlite: - cutout: ../pypsa-eur/cutouts/europe-2013-era5.nc - -# 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 - -# regulate what components with which carriers are kept from PyPSA-Eur; -# some technologies are removed because they are implemented differently -# (e.g. battery or H2 storage) or have different year-dependent costs -# in PyPSA-Eur-Sec -pypsa_eur: - Bus: - - AC - Link: - - DC - Generator: - - onwind - - offwind-ac - - offwind-dc - - solar - - ror - StorageUnit: - - PHS - - hydro - Store: [] - - -energy: - energy_totals_year: 2011 - base_emissions_year: 1990 - eurostat_report_year: 2016 - emissions: CO2 # "CO2" or "All greenhouse gases - (CO2 equivalent)" - -biomass: - year: 2030 - scenario: ENS_Med - classes: - solid biomass: - - Agricultural waste - - Fuelwood residues - - Secondary Forestry residues - woodchips - - Sawdust - - Residues from landscape care - - Municipal waste - not included: - - Sugar from sugar beet - - Rape seed - - "Sunflower, soya seed " - - Bioethanol barley, wheat, grain maize, oats, other cereals and rye - - Miscanthus, switchgrass, RCG - - Willow - - Poplar - - FuelwoodRW - - C&P_RW - biogas: - - Manure solid, liquid - - Sludge - - -solar_thermal: - clearsky_model: simple # should be "simple" or "enhanced"? - orientation: - slope: 45. - azimuth: 180. - -# only relevant for foresight = myopic or perfect -existing_capacities: - grouping_years_power: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020, 2025, 2030] - grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # these should not extend 2020 - threshold_capacity: 10 - conventional_carriers: - - lignite - - coal - - oil - - uranium - - -sector: - 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 - cluster_heat_buses: false # cluster residential and service heat buses to one to save memory - 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 - ICE_upper_degree_factor: 1.6 - EV_lower_degree_factor: 0.98 - EV_upper_degree_factor: 0.63 - 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 - bev_charge_efficiency: 0.9 #BEV (dis-)charging efficiency - bev_plug_to_wheel_efficiency: 0.2 #kWh/km from EPA https://www.fueleconomy.gov/feg/ for Tesla Model S - bev_charge_rate: 0.011 #3-phase charger with 11 kW - bev_avail_max: 0.95 - bev_avail_mean: 0.8 - v2g: true #allows feed-in to grid from EV battery - #what is not EV or FCEV is oil-fuelled ICE - land_transport_fuel_cell_share: - 2020: 0 - 2030: 0.05 - 2040: 0.1 - 2050: 0.15 - land_transport_electric_share: - 2020: 0 - 2030: 0.25 - 2040: 0.6 - 2050: 0.85 - land_transport_ice_share: - 2020: 1 - 2030: 0.7 - 2040: 0.3 - 2050: 0 - transport_fuel_cell_efficiency: 0.5 - transport_internal_combustion_efficiency: 0.3 - agriculture_machinery_electric_share: 0 - agriculture_machinery_oil_share: 1 - agriculture_machinery_fuel_efficiency: 0.7 # fuel oil per use - agriculture_machinery_electric_efficiency: 0.3 # electricity per use - MWh_MeOH_per_MWh_H2: 0.8787 # in LHV, source: DECHEMA (2017): Low carbon energy and feedstock for the European chemical industry , pg. 64. - MWh_MeOH_per_tCO2: 4.0321 # in LHV, source: DECHEMA (2017): Low carbon energy and feedstock for the European chemical industry , pg. 64. - MWh_MeOH_per_MWh_e: 3.6907 # in LHV, source: DECHEMA (2017): Low carbon energy and feedstock for the European chemical industry , pg. 64. - shipping_hydrogen_liquefaction: false # whether to consider liquefaction costs for shipping H2 demands - shipping_hydrogen_share: - 2020: 0 - 2030: 0 - 2040: 0 - 2050: 0 - shipping_methanol_share: - 2020: 0 - 2030: 0.3 - 2040: 0.7 - 2050: 1 - shipping_oil_share: - 2020: 1 - 2030: 0.7 - 2040: 0.3 - 2050: 0 - shipping_methanol_efficiency: 0.46 # 10-15% higher https://www.iea-amf.org/app/webroot/files/file/Annex%20Reports/AMF_Annex_56.pdf, https://users.ugent.be/~lsileghe/documents/extended_abstract.pdf - shipping_oil_efficiency: 0.40 #For conversion of fuel oil to propulsion in 2011 - aviation_demand_factor: 1. # relative aviation demand compared to today - HVC_demand_factor: 1. # relative HVC demand compared to today - 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 - reduce_space_heat_exogenously: true # reduces space heat demand by a given factor (applied before losses in DH) - # this can represent e.g. building renovation, building demolition, or if - # the factor is negative: increasing floor area, increased thermal comfort, population growth - reduce_space_heat_exogenously_factor: # per unit reduction in space heat demand - # the default factors are determined by the LTS scenario from http://tool.european-calculator.eu/app/buildings/building-types-area/?levers=1ddd4444421213bdbbbddd44444ffffff11f411111221111211l212221 - 2020: 0.10 # this results in a space heat demand reduction of 10% - 2025: 0.09 # first heat demand increases compared to 2020 because of larger floor area per capita - 2030: 0.09 - 2035: 0.11 - 2040: 0.16 - 2045: 0.21 - 2050: 0.29 - retrofitting : # co-optimises building renovation to reduce space heat demand - retro_endogen: false # co-optimise space heat savings - cost_factor: 1.0 # weight costs for building renovation - interest_rate: 0.04 # for investment in building components - annualise_cost: true # annualise the investment costs - tax_weighting: false # weight costs depending on taxes in countries - construction_index: true # weight costs depending on labour/material costs per country - tes: true - tes_tau: # 180 day time constant for centralised, 3 day for decentralised - decentral: 3 - central: 180 - boilers: true - oil_boilers: false - biomass_boiler: true - 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 - coal_cc: false - dac: true - co2_vent: false - allam_cycle: false - SMR: true - regional_co2_sequestration_potential: - enable: false # enable regionally resolved geological co2 storage potential - attribute: 'conservative estimate Mt' - include_onshore: false # include onshore sequestration potentials - min_size: 3 # Gt, sites with lower potential will be excluded - max_size: 25 # Gt, max sequestration potential for any one site, TODO research suitable value - years_of_storage: 25 # years until potential exhausted at optimised annual rate - co2_sequestration_potential: 200 #MtCO2/a sequestration potential for Europe - co2_sequestration_cost: 10 #EUR/tCO2 for sequestration of CO2 - co2_spatial: false - co2network: false - cc_fraction: 0.9 # default fraction of CO2 captured with post-combustion capture - hydrogen_underground_storage: true - hydrogen_underground_storage_locations: - # - onshore # more than 50 km from sea - - nearshore # within 50 km of sea - # - offshore - ammonia: false # can be false (no NH3 carrier), true (copperplated NH3), "regional" (regionalised NH3 without network) - min_part_load_fischer_tropsch: 0.9 # p_min_pu - min_part_load_methanolisation: 0.5 # p_min_pu - use_fischer_tropsch_waste_heat: true - use_fuel_cell_waste_heat: true - use_electrolysis_waste_heat: false - electricity_distribution_grid: true - 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 - H2_network: true - gas_network: false - H2_retrofit: false # if set to True existing gas pipes can be retrofitted to H2 pipes - # according to hydrogen backbone strategy (April, 2020) p.15 - # https://gasforclimate2050.eu/wp-content/uploads/2020/07/2020_European-Hydrogen-Backbone_Report.pdf - # 60% of original natural gas capacity could be used in cost-optimal case as H2 capacity - H2_retrofit_capacity_per_CH4: 0.6 # ratio for H2 capacity per original CH4 capacity of retrofitted pipelines - gas_network_connectivity_upgrade: 1 # https://networkx.org/documentation/stable/reference/algorithms/generated/networkx.algorithms.connectivity.edge_augmentation.k_edge_augmentation.html#networkx.algorithms.connectivity.edge_augmentation.k_edge_augmentation - gas_distribution_grid: true - gas_distribution_grid_cost_factor: 1.0 #multiplies cost in data/costs.csv - biomass_spatial: false # regionally resolve biomass (e.g. potentials) - biomass_transport: false # allow transport of solid biomass between nodes - conventional_generation: # generator : carrier - OCGT: gas - industry_t: # heat supply industry - endogen: false # if heat supply for industry should be enodgenously optimised - must_run: 0.8 # NB: industrial heat demand is in reality supplied at site by discrete plants - # which follow the local demand and therefore cannot be dispatched too much. - # Thus, p_min_pu is set to must run to avoid too much dispatch behaviour. Improvements welcome! - # share of medium and high temperature for process heat based on table 3 for EU28 in https://doi.org/10.1002/er.3436 - # TODO: should be improved and split up by country and sector - share_medium: 0.36 - share_high: 0.64 - # Options in case of endogenous industry heat supply - low_T: - biomass: true - heat_pumps: true - electric_boiler: true - methane: true - medium_T: - biomass: true - methane: true - hydrogen: true - high_T: - hydrogen: true - methane: true - biomass_to_liquid: false - biosng: false - - -industry: - 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: # 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_NH3_per_tNH3: 5.166 # LHV - 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) - MWh_NH3_per_MWh_H2_cracker: 1.46 # https://github.com/euronion/trace/blob/44a5ff8401762edbef80eff9cfe5a47c8d3c8be4/data/efficiencies.csv - 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. # fraction of today's HVC produced via primary route - HVC_mechanical_recycling_fraction: 0. # fraction of today's HVC produced via mechanical recycling - HVC_chemical_recycling_fraction: 0. # fraction of today's HVC produced via chemical recycling - HVC_production_today: 52. # MtHVC/a from DECHEMA (2017), Figure 16, page 107; includes ethylene, propylene and BTX - MWh_elec_per_tHVC_mechanical_recycling: 0.547 # from SI of https://doi.org/10.1016/j.resconrec.2020.105010, Table S5, for HDPE, PP, PS, PET. LDPE would be 0.756. - MWh_elec_per_tHVC_chemical_recycling: 6.9 # Material Economics (2019), page 125; based on pyrolysis and electric steam cracking - chlorine_production_today: 9.58 # MtCl/a from DECHEMA (2017), Table 7, page 43 - MWh_elec_per_tCl: 3.6 # DECHEMA (2017), Table 6, page 43 - MWh_H2_per_tCl: -0.9372 # DECHEMA (2017), page 43; negative since hydrogen produced in chloralkali process - methanol_production_today: 1.5 # MtMeOH/a from DECHEMA (2017), page 62 - MWh_elec_per_tMeOH: 0.167 # DECHEMA (2017), Table 14, page 65 - MWh_CH4_per_tMeOH: 10.25 # DECHEMA (2017), Table 14, page 65 - hotmaps_locate_missing: false - reference_year: 2015 - # references: - # DECHEMA (2017): https://dechema.de/dechema_media/Downloads/Positionspapiere/Technology_study_Low_carbon_energy_and_feedstock_for_the_European_chemical_industry-p-20002750.pdf - # Material Economics (2019): https://materialeconomics.com/latest-updates/industrial-transformation-2050 - -costs: - year: 2030 - version: v0.5.0 - 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: - # onwind: 500 - 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 - skip_iterations: true - track_iterations: false - min_iterations: 4 - max_iterations: 6 - keep_shadowprices: - - Bus - - Line - - Link - - Transformer - - GlobalConstraint - - Generator - - Store - - StorageUnit - - solver: - name: gurobi - options: gurobi-default - - solver_options: - gurobi-default: - threads: 4 - method: 2 # barrier - crossover: 0 - BarConvTol: 1.e-6 - Seed: 123 - AggFill: 0 - PreDual: 0 - GURO_PAR_BARDENSETHRESH: 200 - seed: 10 # Consistent seed for all plattforms - gurobi-numeric-focus: - name: gurobi - NumericFocus: 3 # Favour numeric stability over speed - method: 2 # barrier - crossover: 0 # do not use crossover - BarHomogeneous: 1 # Use homogeneous barrier if standard does not converge - BarConvTol: 1.e-5 - FeasibilityTol: 1.e-4 - OptimalityTol: 1.e-4 - ObjScale: -0.5 - threads: 8 - Seed: 123 - gurobi-fallback: # Use gurobi defaults - name: gurobi - crossover: 0 - method: 2 # barrier - BarHomogeneous: 1 # Use homogeneous barrier if standard does not converge - BarConvTol: 1.e-5 - FeasibilityTol: 1.e-5 - OptimalityTol: 1.e-5 - Seed: 123 - threads: 8 - cplex-default: - threads: 4 - lpmethod: 4 # barrier - solutiontype: 2 # non basic solution, ie no crossover - barrier_convergetol: 1.e-5 - feasopt_tolerance: 1.e-6 - - cbc-default: {} # Used in CI - - mem: 30000 #memory in MB; 20 GB enough for 50+B+I+H2; 100 GB for 181+B+I+H2 - - -plotting: - map: - boundaries: [-11, 30, 34, 71] - color_geomap: - ocean: white - land: white - eu_node_location: - x: -5.5 - y: 46. - costs_max: 1000 - costs_threshold: 1 - energy_max: 20000 - energy_min: -20000 - 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 - load_carriers: - - AC 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: - # wind - onwind: "#235ebc" - onshore wind: "#235ebc" - offwind: "#6895dd" - offshore wind: "#6895dd" - offwind-ac: "#6895dd" - offshore wind (AC): "#6895dd" - offwind-dc: "#74c6f2" - offshore wind (DC): "#74c6f2" - # water - hydro: '#298c81' - hydro reservoir: '#298c81' - ror: '#3dbfb0' - run of river: '#3dbfb0' - hydroelectricity: '#298c81' - PHS: '#51dbcc' - wave: '#a7d4cf' - # solar - solar: "#f9d002" - solar PV: "#f9d002" - solar thermal: '#ffbf2b' - solar rooftop: '#ffea80' - # gas - OCGT: '#e0986c' - OCGT marginal: '#e0986c' - OCGT-heat: '#e0986c' - gas boiler: '#db6a25' - gas boilers: '#db6a25' - gas boiler marginal: '#db6a25' - gas: '#e05b09' - fossil gas: '#e05b09' - natural gas: '#e05b09' - CCGT: '#a85522' - CCGT marginal: '#a85522' - allam: '#B98F76' - gas for industry co2 to atmosphere: '#692e0a' - gas for industry co2 to stored: '#8a3400' - gas for industry: '#853403' - gas for industry CC: '#692e0a' - gas pipeline: '#ebbca0' - gas pipeline new: '#a87c62' - # oil - oil: '#c9c9c9' - oil boiler: '#adadad' - agriculture machinery oil: '#949494' - shipping oil: "#808080" - land transport oil: '#afafaf' - # nuclear - Nuclear: '#ff8c00' - Nuclear marginal: '#ff8c00' - nuclear: '#ff8c00' - uranium: '#ff8c00' - # coal - Coal: '#545454' - coal: '#545454' - Coal marginal: '#545454' - solid: '#545454' - Lignite: '#826837' - lignite: '#826837' - Lignite marginal: '#826837' - # biomass - biogas: '#e3d37d' - biomass: '#baa741' - solid biomass: '#baa741' - solid biomass transport: '#baa741' - solid biomass for industry: '#7a6d26' - solid biomass for industry CC: '#47411c' - solid biomass for industry co2 from atmosphere: '#736412' - solid biomass for industry co2 to stored: '#47411c' - biomass boiler: '#8A9A5B' - biomass to liquid: '#32CD32' - BioSNG: '#123456' - # power transmission - lines: '#6c9459' - transmission lines: '#6c9459' - electricity distribution grid: '#97ad8c' - # electricity demand - Electric load: '#110d63' - electric demand: '#110d63' - electricity: '#110d63' - industry electricity: '#2d2a66' - industry new electricity: '#2d2a66' - agriculture electricity: '#494778' - # battery + EVs - battery: '#ace37f' - battery storage: '#ace37f' - home battery: '#80c944' - home battery storage: '#80c944' - BEV charger: '#baf238' - V2G: '#e5ffa8' - land transport EV: '#baf238' - Li ion: '#baf238' - # hot water storage - water tanks: '#e69487' - hot water storage: '#e69487' - hot water charging: '#e69487' - hot water discharging: '#e69487' - # heat demand - Heat load: '#cc1f1f' - heat: '#cc1f1f' - heat demand: '#cc1f1f' - rural heat: '#ff5c5c' - central heat: '#cc1f1f' - decentral heat: '#750606' - low-temperature heat for industry: '#8f2727' - process heat: '#ff0000' - agriculture heat: '#d9a5a5' - # heat supply - heat pumps: '#2fb537' - heat pump: '#2fb537' - air heat pump: '#36eb41' - ground heat pump: '#2fb537' - Ambient: '#98eb9d' - CHP: '#8a5751' - CHP CC: '#634643' - CHP heat: '#8a5751' - CHP electric: '#8a5751' - district heating: '#e8beac' - resistive heater: '#d8f9b8' - retrofitting: '#8487e8' - building retrofitting: '#8487e8' - # hydrogen - H2 for industry: "#f073da" - H2 for shipping: "#ebaee0" - H2: '#bf13a0' - hydrogen: '#bf13a0' - SMR: '#870c71' - SMR CC: '#4f1745' - H2 liquefaction: '#d647bd' - hydrogen storage: '#bf13a0' - H2 storage: '#bf13a0' - land transport fuel cell: '#6b3161' - H2 pipeline: '#f081dc' - H2 pipeline retrofitted: '#ba99b5' - H2 Fuel Cell: '#c251ae' - H2 Electrolysis: '#ff29d9' - # ammonia - NH3: '#46caf0' - ammonia: '#46caf0' - ammonia store: '#00ace0' - ammonia cracker: '#87d0e6' - Haber-Bosch: '#076987' - # syngas - Sabatier: '#9850ad' - methanation: '#c44ce6' - methane: '#c44ce6' - helmeth: '#e899ff' - # synfuels - Fischer-Tropsch: '#25c49a' - liquid: '#25c49a' - kerosene for aviation: '#a1ffe6' - naphtha for industry: '#57ebc4' - methanolisation: '#83d6d5' - methanol: '#468c8b' - shipping methanol: '#468c8b' - # co2 - CC: '#f29dae' - CCS: '#f29dae' - CO2 sequestration: '#f29dae' - DAC: '#ff5270' - co2 stored: '#f2385a' - co2: '#f29dae' - co2 vent: '#ffd4dc' - CO2 pipeline: '#f5627f' - # emissions - process emissions CC: '#000000' - process emissions: '#222222' - process emissions to stored: '#444444' - process emissions to atmosphere: '#888888' - oil emissions: '#aaaaaa' - shipping oil emissions: "#555555" - shipping methanol emissions: '#666666' - land transport oil emissions: '#777777' - agriculture machinery oil emissions: '#333333' - # other - shipping: '#03a2ff' - power-to-heat: '#2fb537' - power-to-gas: '#c44ce6' - power-to-H2: '#ff29d9' - power-to-liquid: '#25c49a' - gas-to-power/heat: '#ee8340' - waste: '#e3d37d' - other: '#000000' - lowT industry: "#555555" - mediumT industry: "yellow" - highT industry: "brown" - lowT industry solid biomass: "green" - lowT industry solid biomass CC: "green" - lowT industry methane: "yellow" - lowT industry methane CC: "yellow" - lowT industry H2: "blue" - gas for mediumT industry: '#333666' - gas for mediumT industry CC: '#333666' - gas for highT industry: '#333333' - gas for highT industry CC: '#333333' - hydrogen for mediumT industry: '#993666' - hydrogen for highT industry: '#993333' - lowT industry electricity: "pink" - lowT industry heat pump: "purple" - solid biomass for mediumT industry: '#009E60' - solid biomass for mediumT industry CC: '#009E60' From fd4f1ac7960143765d8530e8fb190b4d73e5ec03 Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 5 Aug 2024 11:44:26 +0200 Subject: [PATCH 10/13] remove duplicate --- scripts/prepare_sector_network.py | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 446bbb8ba1..6b5701bee7 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -145,7 +145,6 @@ def define_spatial(nodes, options): spatial.coal = SimpleNamespace() spatial.coal.nodes = ["EU coal"] spatial.coal.locations = ["EU"] - spatial.coal.locations = ["EU"] # lignite spatial.lignite = SimpleNamespace() From 1e307e8a405d79a51bb0e59611648d7b9d358d3b Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 5 Aug 2024 12:03:02 +0200 Subject: [PATCH 11/13] include pglaum feedback --- scripts/prepare_sector_network.py | 32 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 6b5701bee7..8050963be4 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -2381,16 +2381,14 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for lowT industry", bus0=spatial.biomass.nodes, bus1=nodes + " lowT industry", - bus2="co2 atmosphere", carrier="lowT industry solid biomass", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at["solid biomass boiler steam", "efficiency"], - efficiency2=costs.at["solid biomass", "CO2 intensity"] - - costs.at["solid biomass", "CO2 intensity"], capital_cost=costs.at["solid biomass boiler steam", "fixed"] * costs.at["solid biomass boiler steam", "efficiency"], marginal_cost=costs.at["solid biomass boiler steam", "VOM"], + lifetime=costs.at["solid biomass boiler steam", "lifetime"], ) n.madd( @@ -2399,8 +2397,8 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for lowT industry CC", bus0=spatial.biomass.nodes, bus1=nodes + " lowT industry", - bus2=spatial.co2.nodes, - bus3="co2 atmosphere", + bus2="co2 atmosphere", + bus3=spatial.co2, carrier="lowT industry solid biomass CC", p_nom_extendable=True, p_min_pu=must_run, @@ -2410,12 +2408,13 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): + costs.at["biomass CHP capture", "fixed"] * costs.at["solid biomass", "CO2 intensity"], marginal_cost=costs.at["solid biomass boiler steam CC", "VOM"], + efficiency2=-costs.at["solid biomass", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], efficiency3=costs.at["solid biomass", "CO2 intensity"] * (1 - costs.at["biomass CHP capture", "capture_rate"]) - costs.at["solid biomass", "CO2 intensity"], - efficiency2=costs.at["solid biomass", "CO2 intensity"] - * costs.at["biomass CHP capture", "capture_rate"], lifetime=costs.at["solid biomass boiler steam CC", "lifetime"], + ) if options["industry_t"]["low_T"]["methane"]: @@ -2434,6 +2433,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): * costs.at["gas boiler steam", "efficiency"], marginal_cost=costs.at["gas boiler steam", "VOM"], efficiency2=costs.at["gas", "CO2 intensity"], + lifetime=costs.at["gas boiler steam", "lifetime"], ) eta = ( @@ -2466,6 +2466,7 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): ) if options["industry_t"]["low_T"]["heat_pumps"]: + # high temperature industrial heat pump can heat up to 150°C eta = costs.at["industrial heat pump high temperature", "efficiency"] n.madd( "Link", @@ -2503,7 +2504,9 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): """ - Add medium temperature heat for industry. + Add medium temperature heat for industry. Medium and high temperature + heat demands are taken from today's industry methane demand and split + according to config setting. """ logger.info("Add medium temperature industry.") @@ -2533,13 +2536,10 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): suffix=" solid biomass for mediumT industry", bus0=spatial.biomass.nodes, bus1=nodes + " mediumT industry", - bus2="co2 atmosphere", carrier="solid biomass for mediumT industry", p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at["direct firing solid fuels", "efficiency"], - efficiency2=costs.at["solid biomass", "CO2 intensity"] - - costs.at["solid biomass", "CO2 intensity"], capital_cost=costs.at["direct firing solid fuels", "fixed"] * costs.at["direct firing solid fuels", "efficiency"], marginal_cost=costs.at["direct firing solid fuels", "VOM"] @@ -2567,9 +2567,8 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): + costs.at["biomass boiler", "pelletizing cost"], efficiency2=costs.at["solid biomass", "CO2 intensity"] * costs.at["biomass CHP capture", "capture_rate"], - efficiency3=costs.at["solid biomass", "CO2 intensity"] - * (1 - costs.at["biomass CHP capture", "capture_rate"]) - - costs.at["solid biomass", "CO2 intensity"], + efficiency3=-costs.at["solid biomass", "CO2 intensity"] + * costs.at["biomass CHP capture", "capture_rate"], lifetime=costs.at["direct firing solid fuels CC", "lifetime"], ) @@ -2643,7 +2642,9 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): """ - Add high temperature heat for industry. + Add high temperature heat for industry. Medium and high temperature + heat demands are taken from today's industry methane demand and split + according to config setting. """ logger.info("Add high temperature industry.") @@ -2725,6 +2726,7 @@ def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): p_nom_extendable=True, p_min_pu=must_run, efficiency=costs.at["direct firing gas", "efficiency"], + lifetime=costs.at["direct firing gas", "lifetime"], ) From 0e599fd26915cd2926c723027c816ebbca7caf9e Mon Sep 17 00:00:00 2001 From: lisazeyen Date: Mon, 5 Aug 2024 12:28:58 +0200 Subject: [PATCH 12/13] update share between medium and high t --- config/config.default.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.default.yaml b/config/config.default.yaml index d19ed1e097..49d6b997c7 100644 --- a/config/config.default.yaml +++ b/config/config.default.yaml @@ -476,10 +476,10 @@ sector: must_run: 0.8 # NB: industrial heat demand is in reality supplied at site by discrete plants # which follow the local demand and therefore cannot be dispatched too much. # Thus, p_min_pu is set to must run to avoid too much dispatch behaviour. Improvements welcome! - # share of medium and high temperature for process heat based on table 3 for EU28 in https://doi.org/10.1002/er.3436 + # share of medium and high temperature for process heat based on EU27 Fig. 5 https://www.agora-industry.org/publications/direct-electrification-of-industrial-process-heat # TODO: should be improved and split up by country and sector - share_medium: 0.36 - share_high: 0.64 + share_medium: 0.42 + share_high: 0.57 # Options in case of endogenous industry heat supply low_T: biomass: true From 2eb830a3231211eb9aee9ad3124e1a1b8bd434f8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:31:11 +0000 Subject: [PATCH 13/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- scripts/prepare_sector_network.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 33bae58cc8..942fc357ae 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -2780,12 +2780,11 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): * costs.at["solid biomass", "CO2 intensity"], marginal_cost=costs.at["solid biomass boiler steam CC", "VOM"], efficiency2=-costs.at["solid biomass", "CO2 intensity"] - * costs.at["biomass CHP capture", "capture_rate"], + * costs.at["biomass CHP capture", "capture_rate"], efficiency3=costs.at["solid biomass", "CO2 intensity"] * (1 - costs.at["biomass CHP capture", "capture_rate"]) - costs.at["solid biomass", "CO2 intensity"], lifetime=costs.at["solid biomass boiler steam CC", "lifetime"], - ) if options["industry_t"]["low_T"]["methane"]: @@ -2875,9 +2874,10 @@ def add_low_t_industry(n, nodes, industrial_demand, costs, must_run): def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): """ - Add medium temperature heat for industry. Medium and high temperature - heat demands are taken from today's industry methane demand and split - according to config setting. + Add medium temperature heat for industry. + + Medium and high temperature heat demands are taken from today's + industry methane demand and split according to config setting. """ logger.info("Add medium temperature industry.") @@ -3013,9 +3013,10 @@ def add_medium_t_industry(n, nodes, industrial_demand, costs, must_run): def add_high_t_industry(n, nodes, industrial_demand, costs, must_run): """ - Add high temperature heat for industry. Medium and high temperature - heat demands are taken from today's industry methane demand and split - according to config setting. + Add high temperature heat for industry. + + Medium and high temperature heat demands are taken from today's + industry methane demand and split according to config setting. """ logger.info("Add high temperature industry.")