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:
parent
7e6c7b3dd3
commit
8c196a7a21
0
config.default.yaml
Executable file → Normal file
0
config.default.yaml
Executable file → Normal file
@ -58,8 +58,13 @@ def add_brownfield(n, n_p, year):
|
||||
c.df.index[c.df.build_year + c.df.lifetime < year])
|
||||
|
||||
#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,
|
||||
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_opt"] < snakemake.config['existing_capacities']['threshold_capacity']])
|
||||
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
|
||||
c.df[attr + "_nom"] = c.df[attr + "_nom_opt"]
|
||||
|
26
scripts/prepare_sector_network.py
Executable file → Normal file
26
scripts/prepare_sector_network.py
Executable file → Normal file
@ -52,11 +52,11 @@ def add_lifetime_wind_solar(n):
|
||||
if carrier in index], 'lifetime']=costs.at[carrier_name,'lifetime']
|
||||
def update_wind_solar_costs(n,costs):
|
||||
"""
|
||||
Update costs for wind and solar generators added with pypsa-eur to those
|
||||
Update costs for wind and solar generators added with pypsa-eur to those
|
||||
cost in the planning year
|
||||
|
||||
"""
|
||||
|
||||
|
||||
#assign clustered bus
|
||||
#map initial network -> simplified network
|
||||
busmap_s = pd.read_hdf(snakemake.input.clustermaps,
|
||||
@ -72,13 +72,13 @@ def update_wind_solar_costs(n,costs):
|
||||
profile = snakemake.input.profile_offwind_dc if tech=='offwind-dc' else snakemake.input.profile_offwind_ac
|
||||
with xr.open_dataset(profile) as ds:
|
||||
underwater_fraction = ds['underwater_fraction'].to_pandas().to_frame()
|
||||
underwater_fraction["cluster_bus"] = underwater_fraction.index.map(clustermaps)
|
||||
underwater_fraction["cluster_bus"] = underwater_fraction.index.map(clustermaps)
|
||||
u_f = underwater_fraction.groupby("cluster_bus").mean()
|
||||
|
||||
|
||||
average_distance = ds['average_distance'].to_pandas().to_frame()
|
||||
average_distance["cluster_bus"] = average_distance.index.map(clustermaps)
|
||||
average_distance["cluster_bus"] = average_distance.index.map(clustermaps)
|
||||
a_d = average_distance.groupby("cluster_bus").mean()
|
||||
|
||||
|
||||
connection_cost = (snakemake.config['costs']['lines']['length_factor'] *
|
||||
a_d*
|
||||
(u_f *
|
||||
@ -90,16 +90,16 @@ def update_wind_solar_costs(n,costs):
|
||||
connection_cost)
|
||||
logger.info("Added connection cost of {:0.0f}-{:0.0f} Eur/MW/a to {}"
|
||||
.format(connection_cost[0].min(), connection_cost[0].max(), tech))
|
||||
capital_cost.rename(index=lambda node: node + ' ' + tech, inplace=True)
|
||||
n.generators.loc[n.generators.index[n.generators.carrier==tech],'capital_cost']=capital_cost[0]
|
||||
|
||||
capital_cost.rename(index=lambda node: node + ' ' + tech, inplace=True)
|
||||
n.generators.loc[n.generators.index[n.generators.carrier==tech],'capital_cost']=capital_cost[0]
|
||||
|
||||
elif suptech == 'solar':
|
||||
capital_cost = costs.at['solar-utility', 'fixed']
|
||||
capital_cost = costs.at['solar-utility', 'fixed']
|
||||
n.generators.loc[n.generators.index[n.generators.carrier==tech],'capital_cost']=capital_cost
|
||||
else:
|
||||
capital_cost = costs.at['onwind', 'fixed']
|
||||
capital_cost = costs.at['onwind', 'fixed']
|
||||
n.generators.loc[n.generators.index[n.generators.carrier==tech],'capital_cost']=capital_cost
|
||||
|
||||
|
||||
def add_carrier_buses(n, carriers):
|
||||
"""
|
||||
Add buses to connect e.g. coal, nuclear and oil plants
|
||||
@ -1683,7 +1683,7 @@ if __name__ == "__main__":
|
||||
clustered_pop_layout='pypsa-eur-sec/resources/pop_layout_{network}_s{simpl}_{clusters}.csv',
|
||||
costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv',
|
||||
profile_offwind_ac='pypsa-eur/resources/profile_offwind-ac.nc',
|
||||
profile_offwind_dc='pypsa-eur/resources/profile_offwind-dc.nc',
|
||||
profile_offwind_dc='pypsa-eur/resources/profile_offwind-dc.nc',
|
||||
clustermaps="pypsa-eur/resources/clustermaps_{network}_s{simpl}_{clusters}.h5",
|
||||
cop_air_total='pypsa-eur-sec/resources/cop_air_total_{network}_s{simpl}_{clusters}.nc',
|
||||
cop_soil_total='pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc',
|
||||
|
@ -123,21 +123,36 @@ def add_battery_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")]
|
||||
heat = n.links.index[n.links.index.str.contains("urban central") & n.links.index.str.contains("CHP") & n.links.index.str.contains("heat")]
|
||||
electric_bool = (n.links.index.str.contains("urban central")
|
||||
& 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")
|
||||
|
||||
#ratio of output heat to electricity set by p_nom_ratio
|
||||
lhs = linexpr((n.links.loc[electric,"efficiency"]
|
||||
*n.links.loc[electric,'p_nom_ratio'],
|
||||
link_p_nom[electric]),
|
||||
(-n.links.loc[heat,"efficiency"].values,
|
||||
link_p_nom[heat].values))
|
||||
lhs = linexpr((n.links.loc[electric_ext,"efficiency"]
|
||||
*n.links.loc[electric_ext,'p_nom_ratio'],
|
||||
link_p_nom[electric_ext]),
|
||||
(-n.links.loc[heat_ext,"efficiency"].values,
|
||||
link_p_nom[heat_ext].values))
|
||||
define_constraints(n, lhs, "=", 0, 'chplink', 'fix_p_nom_ratio')
|
||||
|
||||
|
||||
if not electric.empty:
|
||||
|
||||
link_p = get_var(n, "Link", "p")
|
||||
|
||||
#backpressure
|
||||
@ -149,12 +164,29 @@ def add_chp_constraints(n):
|
||||
|
||||
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):
|
||||
for carrier in ['solar', 'onwind', 'offwind-ac', 'offwind-dc']:
|
||||
|
Loading…
Reference in New Issue
Block a user