add H2 boiler and constraint to avoid existing gas boiler back up

This commit is contained in:
lisazeyen 2023-08-28 13:31:02 +02:00
parent 369eaf3457
commit abb584de45
3 changed files with 86 additions and 11 deletions

View File

@ -20,7 +20,7 @@ remote:
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run
run:
name: "test_co2limit"
name: "test_h2_retrofit"
disable_progressbar: false
shared_resources: true
shared_cutouts: true
@ -35,7 +35,7 @@ scenario:
- ''
ll:
- v1.0
- v1.5
# - v1.5
clusters:
- 37
# - 128
@ -45,7 +45,9 @@ scenario:
opts:
- ''
sector_opts:
- 4380H-T-H-B-I-A-solar+p3-dist1
- 1p7-4380H-T-H-B-I-A-solar+p3-dist1
- 1p5-4380H-T-H-B-I-A-solar+p3-dist1
- 2p0-4380H-T-H-B-I-A-solar+p3-dist1
planning_horizons:
- 2020
- 2030
@ -69,7 +71,7 @@ enable:
retrieve_sector_databundle: true
retrieve_cost_data: true
build_cutout: false
retrieve_cutout: false
retrieve_cutout: true
build_natura_raster: false
retrieve_natura_raster: true
custom_busmap: false
@ -133,7 +135,7 @@ electricity:
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#atlite
atlite:
default_cutout: europe-2013-era5
nprocesses: 4
nprocesses: 1
show_progress: false
cutouts:
# use 'base' to determine geographical bounds and time span from config
@ -916,6 +918,7 @@ plotting:
H2 for shipping: "#ebaee0"
H2: '#bf13a0'
hydrogen: '#bf13a0'
retrofitted H2 boiler: '#e5a0d9'
SMR: '#870c71'
SMR CC: '#4f1745'
H2 liquefaction: '#d647bd'

View File

@ -306,6 +306,29 @@ def adjust_CO2_glc(n):
n.df(c).loc[mask, "type"] = "co2_limit"
return n
def add_H2_boilers(n):
c = "Link"
logger.info("Add H2 boilers.")
# existing gas boilers
mask = n.links.carrier.str.contains("gas boiler") & ~n.links.p_nom_extendable
gas_i = n.links[mask].index
df = n.links.loc[gas_i]
# adjust bus 0
df["bus0"] = df.bus1.map(n.buses.location) + " H2"
# rename carrier and index
df["carrier"] = df.carrier.apply(lambda x: x.replace("gas boiler", "retrofitted H2 boiler"))
df.rename(index = lambda x: x.replace("gas boiler", "retrofitted H2 boiler"), inplace=True)
# todo, costs for retrofitting
df["capital_costs"] = 100
# set existing capacity to zero
df["p_nom"] = 0
df["p_nom_extendable"] = True
# add H2 boilers to network
import_components_from_dataframe(n, df, c)
# %%
if __name__ == "__main__":
if "snakemake" not in globals():
@ -339,14 +362,17 @@ if __name__ == "__main__":
n = concat_networks(years)
# adjust global constraints lv limit if the same for all years
n = adjust_lvlimit(n)
n = adjust_lvlimit(n)
# adjust global constraints CO2 limit
n = adjust_CO2_glc(n)
# set phase outs
set_all_phase_outs(n)
# adjust stores to multi period investment
n = adjust_stores(n)
# set phase outs
set_all_phase_outs(n)
# add H2 boiler
add_H2_boilers(n)
# set carbon constraints
opts = snakemake.wildcards.sector_opts.split("-")

View File

@ -32,7 +32,7 @@ import re
import numpy as np
import pandas as pd
import pypsa
from pypsa.descriptors import nominal_attrs
from pypsa.descriptors import nominal_attrs, get_activity_mask
import xarray as xr
from _helpers import configure_logging, update_config_with_sector_opts
@ -41,6 +41,7 @@ from vresutils.benchmark import memory_logger
logger = logging.getLogger(__name__)
pypsa.pf.logger.setLevel(logging.WARNING)
from pypsa.descriptors import get_switchable_as_dense as get_as_dense
from pypsa.io import import_components_from_dataframe
from linopy.expressions import merge
from numpy import isnan
@ -276,7 +277,51 @@ def add_max_growth(n, config):
n.carriers.loc[carrier, "max_relative_growth"] = max_r_per_period
return n
def add_retrofit_gas_boiler_constraint(n, snapshots):
"""Allow retrofitting of existing gas boilers to H2 boilers.
"""
c = "Link"
logger.info("Add constraint for retrofitting gas boilers to H2 boilers.")
# existing gas boilers
mask = n.links.carrier.str.contains("gas boiler") & ~n.links.p_nom_extendable
gas_i = n.links[mask].index
mask = n.links.carrier.str.contains("retrofitted H2 boiler")
h2_i = n.links[mask].index
n.links.loc[gas_i, "p_nom_extendable"] = True
p_nom = n.links.loc[gas_i, "p_nom"]
n.links.loc[gas_i, "p_nom"] = 0
# heat profile
cols = n.loads_t.p_set.columns[n.loads_t.p_set.columns.str.contains("heat")
& ~n.loads_t.p_set.columns.str.contains("industry")
& ~n.loads_t.p_set.columns.str.contains("agriculture")]
profile = n.loads_t.p_set[cols].div(n.loads_t.p_set[cols].groupby(level=0).max(), level=0)
# to deal if max value is zero
profile.fillna(0, inplace=True)
profile.rename(columns=n.loads.bus.to_dict(), inplace=True)
profile = profile.reindex(columns=n.links.loc[gas_i, "bus1"])
profile.columns = gas_i
rhs = profile.mul(p_nom)
dispatch = n.model["Link-p"]
active = get_activity_mask(n, c, snapshots, gas_i)
rhs = rhs[active]
p_gas = dispatch.sel(Link=gas_i)
p_h2 = dispatch.sel(Link=h2_i)
lhs = p_gas + p_h2
n.model.add_constraints(lhs == rhs, name="gas_retrofit")
def prepare_network(
n,
solve_opts=None,
@ -740,6 +785,7 @@ def extra_functionality(n, snapshots):
if n._multi_invest:
add_carbon_constraint(n, snapshots)
add_carbon_budget_constraint(n, snapshots)
add_retrofit_gas_boiler_constraint(n, snapshots)
def solve_network(n, config, solving, opts="", **kwargs):