Take care of CHPs when doing p_nom < threshold & extra_functionality

- add_brownfield.py: Have to make sure that for each CHP there is both
  a heat and electric link, but they have different p_nom for each
  CHP, so have to make sure we don't remove one without the other.

- solve_network.py: Make sure extra_functionality constraints for CHP
  power-heat feasibility graph also work for non-extendable CHPs.
This commit is contained in:
Tom Brown 2020-08-14 09:11:19 +02:00
parent 7e6c7b3dd3
commit 8c196a7a21
5 changed files with 64 additions and 27 deletions

0
Snakefile Executable file → Normal file
View File

0
config.default.yaml Executable file → Normal file
View File

View File

@ -58,8 +58,13 @@ def add_brownfield(n, n_p, year):
c.df.index[c.df.build_year + c.df.lifetime < year]) c.df.index[c.df.build_year + c.df.lifetime < year])
#remove assets if their optimized nominal capacity is lower than a threshold #remove assets if their optimized nominal capacity is lower than a threshold
#since CHP heat Link is proportional to CHP electric Link, make sure threshold is compatible
chp_heat = c.df.index[c.df[attr + "_nom_extendable"] & c.df.index.str.contains("urban central") & c.df.index.str.contains("CHP") & c.df.index.str.contains("heat")]
if not chp_heat.empty:
n_p.mremove(c.name, n_p.mremove(c.name,
c.df.index[c.df[attr + "_nom_opt"] < snakemake.config['existing_capacities']['threshold_capacity']]) chp_heat[c.df.loc[chp_heat, attr + "_nom_opt"] < snakemake.config['existing_capacities']['threshold_capacity']*c.df.efficiency[chp_heat.str.replace("heat","electric")].values*c.df.p_nom_ratio[chp_heat.str.replace("heat","electric")].values/c.df.efficiency[chp_heat].values])
n_p.mremove(c.name,
c.df.index[c.df[attr + "_nom_extendable"] & ~c.df.index.isin(chp_heat) & (c.df[attr + "_nom_opt"] < snakemake.config['existing_capacities']['threshold_capacity'])])
#copy over assets but fix their capacity #copy over assets but fix their capacity
c.df[attr + "_nom"] = c.df[attr + "_nom_opt"] c.df[attr + "_nom"] = c.df[attr + "_nom_opt"]

0
scripts/prepare_sector_network.py Executable file → Normal file
View File

View File

@ -123,21 +123,36 @@ def add_battery_constraints(n):
def add_chp_constraints(n): def add_chp_constraints(n):
electric = n.links.index[n.links.index.str.contains("urban central") & n.links.index.str.contains("CHP") & n.links.index.str.contains("electric")] electric_bool = (n.links.index.str.contains("urban central")
heat = n.links.index[n.links.index.str.contains("urban central") & n.links.index.str.contains("CHP") & n.links.index.str.contains("heat")] & n.links.index.str.contains("CHP")
& n.links.index.str.contains("electric"))
heat_bool = (n.links.index.str.contains("urban central")
& n.links.index.str.contains("CHP")
& n.links.index.str.contains("heat"))
if not electric.empty: electric = n.links.index[electric_bool]
heat = n.links.index[heat_bool]
electric_ext = n.links.index[electric_bool & n.links.p_nom_extendable]
heat_ext = n.links.index[heat_bool & n.links.p_nom_extendable]
electric_fix = n.links.index[electric_bool & ~n.links.p_nom_extendable]
heat_fix = n.links.index[heat_bool & ~n.links.p_nom_extendable]
if not electric_ext.empty:
link_p_nom = get_var(n, "Link", "p_nom") link_p_nom = get_var(n, "Link", "p_nom")
#ratio of output heat to electricity set by p_nom_ratio #ratio of output heat to electricity set by p_nom_ratio
lhs = linexpr((n.links.loc[electric,"efficiency"] lhs = linexpr((n.links.loc[electric_ext,"efficiency"]
*n.links.loc[electric,'p_nom_ratio'], *n.links.loc[electric_ext,'p_nom_ratio'],
link_p_nom[electric]), link_p_nom[electric_ext]),
(-n.links.loc[heat,"efficiency"].values, (-n.links.loc[heat_ext,"efficiency"].values,
link_p_nom[heat].values)) link_p_nom[heat_ext].values))
define_constraints(n, lhs, "=", 0, 'chplink', 'fix_p_nom_ratio') define_constraints(n, lhs, "=", 0, 'chplink', 'fix_p_nom_ratio')
if not electric.empty:
link_p = get_var(n, "Link", "p") link_p = get_var(n, "Link", "p")
#backpressure #backpressure
@ -149,12 +164,29 @@ def add_chp_constraints(n):
define_constraints(n, lhs, "<=", 0, 'chplink', 'backpressure') define_constraints(n, lhs, "<=", 0, 'chplink', 'backpressure')
#top_iso_fuel_line
lhs = linexpr((1,link_p[heat]),
(1,link_p[electric].values),
(-1,link_p_nom[electric].values))
define_constraints(n, lhs, "<=", 0, 'chplink', 'top_iso_fuel_line') if not electric_ext.empty:
link_p_nom = get_var(n, "Link", "p_nom")
link_p = get_var(n, "Link", "p")
#top_iso_fuel_line for extendable
lhs = linexpr((1,link_p[heat_ext]),
(1,link_p[electric_ext].values),
(-1,link_p_nom[electric_ext].values))
define_constraints(n, lhs, "<=", 0, 'chplink', 'top_iso_fuel_line_ext')
if not electric_fix.empty:
link_p = get_var(n, "Link", "p")
#top_iso_fuel_line for fixed
lhs = linexpr((1,link_p[heat_fix]),
(1,link_p[electric_fix].values))
define_constraints(n, lhs, "<=", n.links.loc[electric_fix,"p_nom"].values, 'chplink', 'top_iso_fuel_line_fix')
def add_land_use_constraint(n): def add_land_use_constraint(n):
for carrier in ['solar', 'onwind', 'offwind-ac', 'offwind-dc']: for carrier in ['solar', 'onwind', 'offwind-ac', 'offwind-dc']: