Group the generators existing before base year into categories and add them to the network as e.g. solar-2005, solar-2010, solar-2015
This commit is contained in:
parent
17a348d1e6
commit
4523f324cd
@ -46,6 +46,9 @@ biomass:
|
|||||||
year: 2030
|
year: 2030
|
||||||
scenario: "Med"
|
scenario: "Med"
|
||||||
|
|
||||||
|
existing_capacities:
|
||||||
|
grouping_years: ['1980', '1985', '1990', '1995', '2000','2005','2010','2015', '2019']
|
||||||
|
threshold_capacity: 10
|
||||||
|
|
||||||
sector:
|
sector:
|
||||||
'central' : True
|
'central' : True
|
||||||
|
@ -20,10 +20,6 @@ import pytz
|
|||||||
|
|
||||||
from vresutils.costdata import annuity
|
from vresutils.costdata import annuity
|
||||||
|
|
||||||
from add_existing_baseyear import add_power_capacities_installed_before_baseyear
|
|
||||||
|
|
||||||
from add_existing_baseyear import add_heating_capacities_installed_before_baseyear
|
|
||||||
|
|
||||||
from prepare_sector_network import prepare_costs
|
from prepare_sector_network import prepare_costs
|
||||||
|
|
||||||
#First tell PyPSA that links can have multiple outputs by
|
#First tell PyPSA that links can have multiple outputs by
|
||||||
@ -39,7 +35,12 @@ override_component_attrs["Link"].loc["efficiency3"] = ["static or series","per u
|
|||||||
override_component_attrs["Link"].loc["p2"] = ["series","MW",0.,"2nd bus output","Output"]
|
override_component_attrs["Link"].loc["p2"] = ["series","MW",0.,"2nd bus output","Output"]
|
||||||
override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output","Output"]
|
override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output","Output"]
|
||||||
|
|
||||||
|
override_component_attrs["Link"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Link"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Generator"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Generator"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Store"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Store"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
|
||||||
def add_brownfield(n, n_p, year):
|
def add_brownfield(n, n_p, year):
|
||||||
print("adding brownfield")
|
print("adding brownfield")
|
||||||
@ -66,19 +67,21 @@ def add_brownfield(n, n_p, year):
|
|||||||
|
|
||||||
previous_timestep=snakemake.config['scenario']['planning_horizons'][snakemake.config['scenario']['planning_horizons'].index(year)-1]
|
previous_timestep=snakemake.config['scenario']['planning_horizons'][snakemake.config['scenario']['planning_horizons'].index(year)-1]
|
||||||
previous_timesteps=snakemake.config['scenario']['planning_horizons'][0:snakemake.config['scenario']['planning_horizons'].index(year)]
|
previous_timesteps=snakemake.config['scenario']['planning_horizons'][0:snakemake.config['scenario']['planning_horizons'].index(year)]
|
||||||
|
grouping_years=snakemake.config['existing_capacities']['grouping_years']
|
||||||
|
|
||||||
# generators installed before baseyear are removed,
|
|
||||||
# they are added again by add_power_capacities_installed_before_baseyear()
|
|
||||||
# with updated capacities (some of them have been decomissioned)
|
|
||||||
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list() if '<'+snakemake.config['scenario']['planning_horizons'][0] in index])
|
|
||||||
|
|
||||||
|
### GENERATORS ###
|
||||||
# generators whose build_year + lifetime < year are removed
|
# generators whose build_year + lifetime < year are removed
|
||||||
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
|
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
|
||||||
if (n_p.generators.loc[index, 'build_year'] in previous_timesteps)
|
if (n_p.generators.loc[index, 'build_year']+n_p.generators.loc[index, 'lifetime'] < int(year))])
|
||||||
and (n_p.generators.loc[index, 'build_year']+n_p.generators.loc[index, 'lifetime'] < int(year))])
|
|
||||||
|
|
||||||
# generators whose capacity was optimized in the previous year are renamed
|
# remove generators if their optimized nominal capacity is lower than a threshold
|
||||||
n_p.generators.index=np.where(n_p.generators.index.str[-4:].isin(previous_timesteps)==False,
|
n_p.mremove("Generator", [index for index in n_p.generators.index.to_list()
|
||||||
|
if (n_p.generators.loc[index, 'p_nom_opt'] < snakemake.config['existing_capacities']['threshold_capacity'])])
|
||||||
|
|
||||||
|
|
||||||
|
# generators whose capacity was optimized in the previous year are renamed and build year is added
|
||||||
|
n_p.generators.index=np.where(n_p.generators.index.str[-4:].isin(previous_timesteps+grouping_years)==False,
|
||||||
n_p.generators.index + '-' + previous_timestep,
|
n_p.generators.index + '-' + previous_timestep,
|
||||||
n_p.generators.index)
|
n_p.generators.index)
|
||||||
n_p.generators.loc[[index for index in n_p.generators.index.to_list()
|
n_p.generators.loc[[index for index in n_p.generators.index.to_list()
|
||||||
@ -97,19 +100,22 @@ def add_brownfield(n, n_p, year):
|
|||||||
build_year=n_p.generators.build_year,
|
build_year=n_p.generators.build_year,
|
||||||
lifetime=n_p.generators.lifetime)
|
lifetime=n_p.generators.lifetime)
|
||||||
|
|
||||||
#add stores from previous steps
|
### STORES ###
|
||||||
|
|
||||||
# stores whose installationYear + lifetime < year are removed
|
# stores whose installationYear + lifetime < year are removed
|
||||||
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
|
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
|
||||||
if (n_p.stores.loc[index, 'build_year'] in previous_timesteps)
|
if (n_p.stores.loc[index, 'build_year']+n_p.stores.loc[index, 'lifetime'] < int(year))])
|
||||||
and (n_p.stores.loc[index, 'build_year']+n_p.stores.loc[index, 'lifetime'] < int(year))])
|
|
||||||
|
|
||||||
# stores whose capacity was optimized in the previous year are renamed
|
# remove stores if their optimized nominal capacity is lower than a threshold
|
||||||
n_p.stores.index=np.where(n_p.stores.index.str[-4:].isin(previous_timesteps)==False,
|
n_p.mremove("Store", [index for index in n_p.stores.index.to_list()
|
||||||
|
if (n_p.stores.loc[index, 'e_nom_opt'] < snakemake.config['existing_capacities']['threshold_capacity'])])
|
||||||
|
|
||||||
|
# stores whose capacity was optimized in the previous year are renamed and the build year is added
|
||||||
|
n_p.stores.index=np.where(n_p.stores.index.str[-4:].isin(previous_timesteps+grouping_years)==False,
|
||||||
n_p.stores.index + '-' + previous_timestep,
|
n_p.stores.index + '-' + previous_timestep,
|
||||||
n_p.stores.index)
|
n_p.stores.index)
|
||||||
n_p.stores.loc[[index for index in n_p.stores.index.to_list()
|
n_p.stores.loc[[index for index in n_p.stores.index.to_list()
|
||||||
if previous_timestep in index], 'build_year']=int(previous_timestep)
|
if previous_timestep in index], 'build_year']=int(previous_timestep)
|
||||||
|
#add stores from previous steps
|
||||||
n.madd("Store",
|
n.madd("Store",
|
||||||
n_p.stores.index,
|
n_p.stores.index,
|
||||||
bus=n_p.stores.bus,
|
bus=n_p.stores.bus,
|
||||||
@ -120,22 +126,25 @@ def add_brownfield(n, n_p, year):
|
|||||||
build_year=n_p.stores.build_year,
|
build_year=n_p.stores.build_year,
|
||||||
lifetime=n_p.stores.lifetime)
|
lifetime=n_p.stores.lifetime)
|
||||||
|
|
||||||
## add links from previous steps
|
### LINKS ###
|
||||||
# TODO: add_chp_constraint() in solve_network needs to be adjusted
|
# TODO: add_chp_constraint() in solve_network needs to be adjusted
|
||||||
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if '<'+snakemake.config['scenario']['planning_horizons'][0] in index])
|
|
||||||
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'CHP' in index])
|
n_p.mremove("Link", [index for index in n_p.links.index.to_list() if 'CHP' in index])
|
||||||
|
|
||||||
# stores whose installationYear + lifetime < year are removed
|
|
||||||
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
|
|
||||||
if (n_p.links.loc[index, 'build_year'] in previous_timesteps)
|
|
||||||
and (n_p.links.loc[index, 'build_year']+n_p.links.loc[index, 'lifetime'] < int(year))])
|
|
||||||
|
|
||||||
# links whose installationYear + lifetime < year are removed
|
# links whose installationYear + lifetime < year are removed
|
||||||
n_p.links.index=np.where(n_p.links.index.str[-4:].isin(previous_timesteps)==False,
|
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
|
||||||
|
if (n_p.links.loc[index, 'build_year']+n_p.links.loc[index, 'lifetime'] < int(year))])
|
||||||
|
|
||||||
|
# delete links if their optimized nominal capacity is lower than a threshold
|
||||||
|
n_p.mremove("Link", [index for index in n_p.links.index.to_list()
|
||||||
|
if (n_p.links.loc[index, 'p_nom_opt'] < snakemake.config['existing_capacities']['threshold_capacity'])])
|
||||||
|
|
||||||
|
# links whose capacity was optimized in the previous year are renamed and the build year is added
|
||||||
|
n_p.links.index=np.where(n_p.links.index.str[-4:].isin(previous_timesteps+grouping_years)==False,
|
||||||
n_p.links.index + '-' + previous_timestep,
|
n_p.links.index + '-' + previous_timestep,
|
||||||
n_p.links.index)
|
n_p.links.index)
|
||||||
n_p.links.loc[[index for index in n_p.links.index.to_list()
|
n_p.links.loc[[index for index in n_p.links.index.to_list()
|
||||||
if previous_timestep in index], 'build_year']=int(previous_timestep)
|
if previous_timestep in index], 'build_year']=int(previous_timestep)
|
||||||
|
#add links from previous steps
|
||||||
n.madd("Link",
|
n.madd("Link",
|
||||||
n_p.links.index,
|
n_p.links.index,
|
||||||
bus0=n_p.links.bus0,
|
bus0=n_p.links.bus0,
|
||||||
@ -159,9 +168,9 @@ if __name__ == "__main__":
|
|||||||
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
|
wildcards=dict(network='elec', simpl='', clusters='37', lv='1.0',
|
||||||
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1',
|
sector_opts='Co2L0-168H-T-H-B-I-solar3-dist1',
|
||||||
co2_budget_name='go',
|
co2_budget_name='go',
|
||||||
planning_horizons='2050'),
|
planning_horizons='2030'),
|
||||||
input=dict(network='pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
|
input=dict(network='pypsa-eur-sec/results/test/prenetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_{planning_horizons}.nc',
|
||||||
network_p='pypsa-eur-sec/results/test/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_2040.nc',
|
network_p='pypsa-eur-sec/results/test/postnetworks/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{co2_budget_name}_2020.nc',
|
||||||
costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv',
|
costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv',
|
||||||
cop_air_total="pypsa-eur-sec/resources/cop_air_total_{network}_s{simpl}_{clusters}.nc",
|
cop_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"),
|
cop_soil_total="pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc"),
|
||||||
@ -196,15 +205,6 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
baseyear = snakemake.config['scenario']["planning_horizons"][0]
|
baseyear = snakemake.config['scenario']["planning_horizons"][0]
|
||||||
|
|
||||||
add_power_capacities_installed_before_baseyear(n, year, baseyear, costs) # only the capacities with YearDecomissioning > year are added
|
|
||||||
|
|
||||||
if "H" in opts:
|
|
||||||
time_dep_hp_cop = options["time_dep_hp_cop"]
|
|
||||||
ashp_cop = xr.open_dataarray(snakemake.input.cop_air_total).T.to_pandas().reindex(index=n.snapshots)
|
|
||||||
gshp_cop = xr.open_dataarray(snakemake.input.cop_soil_total).T.to_pandas().reindex(index=n.snapshots)
|
|
||||||
default_lifetime = snakemake.config['costs']['lifetime']
|
|
||||||
add_heating_capacities_installed_before_baseyear(n, year, baseyear, ashp_cop, gshp_cop, time_dep_hp_cop, costs,
|
|
||||||
default_lifetime) # only the capacities with YearDecomissioning > year are added
|
|
||||||
|
|
||||||
n.export_to_netcdf(snakemake.output[0])
|
n.export_to_netcdf(snakemake.output[0])
|
||||||
|
|
||||||
|
@ -35,18 +35,22 @@ override_component_attrs["Link"].loc["efficiency3"] = ["static or series","per u
|
|||||||
override_component_attrs["Link"].loc["p2"] = ["series","MW",0.,"2nd bus output","Output"]
|
override_component_attrs["Link"].loc["p2"] = ["series","MW",0.,"2nd bus output","Output"]
|
||||||
override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output","Output"]
|
override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output","Output"]
|
||||||
|
|
||||||
|
override_component_attrs["Link"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Link"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Generator"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Generator"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Store"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Store"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
|
||||||
def add_power_capacities_installed_before_baseyear(n, year, baseyear, costs):
|
def add_power_capacities_installed_before_baseyear(n, grouping_years, costs):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
n : network
|
n : network
|
||||||
year : capacity that fulfills YearDecomissioning > year is added
|
|
||||||
|
|
||||||
baseyear : capacity name will be e.g. "solar <baseyear"
|
grouping_years : intervals to group existing capacities
|
||||||
this allows adding the solar capacity that was installed before
|
|
||||||
2020 (baseyear) and is still alive in 2030 (year)
|
|
||||||
costs : to read lifetime to estimate YearDecomissioning
|
costs : to read lifetime to estimate YearDecomissioning
|
||||||
|
|
||||||
|
|
||||||
@ -111,23 +115,19 @@ def add_power_capacities_installed_before_baseyear(n, year, baseyear, costs):
|
|||||||
'YearDecommissioning':int(float(year)+costs.at[tech, 'lifetime'])},
|
'YearDecommissioning':int(float(year)+costs.at[tech, 'lifetime'])},
|
||||||
ignore_index=True)
|
ignore_index=True)
|
||||||
|
|
||||||
# powerplants already include an estimated decommissining year wich has been
|
nodes=set([node[0:2] for node in n.buses.index[n.buses.carrier == "AC"]])
|
||||||
# calculated based on pm config, check if we want to make this calculation more
|
|
||||||
# transparent, e.g., by loading lifetime assumptions from costs.csv into pm config
|
|
||||||
# check how pm is dealing with retrofitting
|
#TODO: Check if we want to change YearCommisioned into YearRetrofited
|
||||||
# pm.get_config()['fuel_to_lifetime']
|
for i,grouping_year in enumerate(grouping_years):
|
||||||
# index = df_agg.Fueltype.map(lf)+df_agg.YearCommissioned > 2020
|
if i==0:
|
||||||
|
index = df_agg.YearCommissioned < int(grouping_year)
|
||||||
|
else:
|
||||||
|
index = (int(grouping_years[i-1]) < df_agg.YearCommissioned) & (df_agg.YearCommissioned < int(grouping_year))
|
||||||
|
|
||||||
index=df_agg.YearDecommissioning > int(year)
|
|
||||||
df = df_agg[index].pivot_table(index='Country', columns='Fueltype',
|
df = df_agg[index].pivot_table(index='Country', columns='Fueltype',
|
||||||
values='Capacity', aggfunc='sum')
|
values='Capacity', aggfunc='sum')
|
||||||
|
|
||||||
nodes=set([node[0:2] for node in n.buses.index[n.buses.carrier == "AC"]])
|
|
||||||
|
|
||||||
for carrier in ['coal', 'oil', 'uranium']:
|
|
||||||
n.add("Bus",
|
|
||||||
"EU " + carrier,
|
|
||||||
carrier=carrier)
|
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
#if a country has more than one node, selects the first one
|
#if a country has more than one node, selects the first one
|
||||||
@ -137,9 +137,10 @@ def add_power_capacities_installed_before_baseyear(n, year, baseyear, costs):
|
|||||||
("coal", "coal"),
|
("coal", "coal"),
|
||||||
("oil","oil"),
|
("oil","oil"),
|
||||||
("nuclear","uranium")]:
|
("nuclear","uranium")]:
|
||||||
|
try:
|
||||||
if node in df.index and not np.isnan(df.loc[node, generator]):
|
if node in df.index and not np.isnan(df.loc[node, generator]):
|
||||||
n.add("Link",
|
n.add("Link",
|
||||||
bus_selected + " " + generator +" <" + baseyear,
|
bus_selected + " " + generator +"-" + grouping_year,
|
||||||
bus0="EU " + carrier,
|
bus0="EU " + carrier,
|
||||||
bus1=bus_selected,
|
bus1=bus_selected,
|
||||||
bus2="co2 atmosphere",
|
bus2="co2 atmosphere",
|
||||||
@ -147,7 +148,11 @@ def add_power_capacities_installed_before_baseyear(n, year, baseyear, costs):
|
|||||||
capital_cost=costs.at[generator,'efficiency']*costs.at[generator,'fixed'], #NB: fixed cost is per MWel
|
capital_cost=costs.at[generator,'efficiency']*costs.at[generator,'fixed'], #NB: fixed cost is per MWel
|
||||||
p_nom=df.loc[node, generator],
|
p_nom=df.loc[node, generator],
|
||||||
efficiency=costs.at[generator,'efficiency'],
|
efficiency=costs.at[generator,'efficiency'],
|
||||||
efficiency2=costs.at[carrier,'CO2 intensity'])
|
efficiency2=costs.at[carrier,'CO2 intensity'],
|
||||||
|
build_year=int(grouping_year),
|
||||||
|
lifetime=costs.at[generator,'lifetime'])
|
||||||
|
except:
|
||||||
|
print("No capacity installed around " + grouping_year + " of " + generator + " in node " + node)
|
||||||
|
|
||||||
for generator in ['solar', 'onwind', 'offwind']:
|
for generator in ['solar', 'onwind', 'offwind']:
|
||||||
try:
|
try:
|
||||||
@ -158,32 +163,34 @@ def add_power_capacities_installed_before_baseyear(n, year, baseyear, costs):
|
|||||||
p_max_pu=n.generators_t.p_max_pu[bus_selected + ' ' + generator]
|
p_max_pu=n.generators_t.p_max_pu[bus_selected + ' ' + generator]
|
||||||
|
|
||||||
n.add("Generator",
|
n.add("Generator",
|
||||||
bus_selected + ' ' + generator +" <"+ baseyear,
|
bus_selected + ' ' + generator +"-"+ grouping_year,
|
||||||
bus=bus_selected,
|
bus=bus_selected,
|
||||||
carrier=generator,
|
carrier=generator,
|
||||||
p_nom=df.loc[node, generator],
|
p_nom=df.loc[node, generator],
|
||||||
marginal_cost=costs.at[generator,'VOM'],
|
marginal_cost=costs.at[generator,'VOM'],
|
||||||
capital_cost=costs.at[generator,'fixed'],
|
capital_cost=costs.at[generator,'fixed'],
|
||||||
efficiency=costs.at[generator, 'efficiency'],
|
efficiency=costs.at[generator, 'efficiency'],
|
||||||
p_max_pu=p_max_pu)
|
p_max_pu=p_max_pu,
|
||||||
|
build_year=int(grouping_year),
|
||||||
|
lifetime=costs.at[generator,'lifetime'])
|
||||||
except:
|
except:
|
||||||
print("No capacity installed before base year of " + generator + " is alive in node " + node)
|
print("No capacity installed around " + grouping_year + " of " + generator + " in node " + node)
|
||||||
|
|
||||||
# delete generators if their lifetime is over and p_nom=0
|
# delete generators if their lifetime is over and p_nom=0
|
||||||
n.mremove("Generator", [index for index in n.generators.index.to_list() if '<'+baseyear in index and n.generators.p_nom[index]==0])
|
n.mremove("Generator", [index for index in n.generators.index.to_list() if grouping_year in index and n.generators.p_nom[index] < snakemake.config['existing_capacities']['threshold_capacity']])
|
||||||
n.mremove("Link", [index for index in n.links.index.to_list() if '<'+baseyear in index and n.links.p_nom[index]==0])
|
n.mremove("Link", [index for index in n.links.index.to_list() if grouping_year in index and n.links.p_nom[index] < snakemake.config['existing_capacities']['threshold_capacity']])
|
||||||
|
|
||||||
def add_heating_capacities_installed_before_baseyear(n, year, baseyear, ashp_cop, gshp_cop, time_dep_hp_cop, costs, default_lifetime):
|
def add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years, ashp_cop, gshp_cop, time_dep_hp_cop, costs, default_lifetime):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
n : network
|
n : network
|
||||||
year : capacity that fulfills YearDecomissioning > year is added
|
|
||||||
baseyear : capacity name will be e.g. "gas boiler <baseyear"
|
baseyear: last year covered in the existing capacities database
|
||||||
this allows adding the gas boiler capacity that was installed
|
|
||||||
before 2020 (baseyear) and is still alive in 2030 (year)
|
grouping_years : intervals to group existing capacities
|
||||||
|
|
||||||
linear decomissioning of heating capacities from 2020 to 2045 is
|
linear decomissioning of heating capacities from 2020 to 2045 is
|
||||||
currently assumed
|
currently assumed
|
||||||
@ -266,32 +273,42 @@ def add_heating_capacities_installed_before_baseyear(n, year, baseyear, ashp_cop
|
|||||||
|
|
||||||
cop = {"air" : ashp_cop, "ground" : gshp_cop}
|
cop = {"air" : ashp_cop, "ground" : gshp_cop}
|
||||||
efficiency = cop[heat_pump_type][nodes[name]] if time_dep_hp_cop else costs.at[costs_name,'efficiency']
|
efficiency = cop[heat_pump_type][nodes[name]] if time_dep_hp_cop else costs.at[costs_name,'efficiency']
|
||||||
|
for i,grouping_year in enumerate(grouping_years):
|
||||||
|
if int(grouping_year) + default_lifetime <= int(baseyear):
|
||||||
|
ratio=0
|
||||||
|
else:
|
||||||
|
#installation is assumed to be linear for the past 25 years (default lifetime)
|
||||||
|
ratio = (int(grouping_year)-int(grouping_years[i-1]))/default_lifetime
|
||||||
|
print(grouping_year + ' ratio ' + str(ratio))
|
||||||
n.madd("Link",
|
n.madd("Link",
|
||||||
nodes[name],
|
nodes[name],
|
||||||
suffix=" {} {} heat pump <{}".format(name,heat_pump_type, baseyear),
|
suffix=" {} {} heat pump-{}".format(name,heat_pump_type, grouping_year),
|
||||||
bus0=nodes[name],
|
bus0=nodes[name],
|
||||||
bus1=nodes[name] + " " + name + " heat",
|
bus1=nodes[name] + " " + name + " heat",
|
||||||
carrier="{} {} heat pump".format(name,heat_pump_type),
|
carrier="{} {} heat pump".format(name,heat_pump_type),
|
||||||
efficiency=efficiency,
|
efficiency=efficiency,
|
||||||
capital_cost=costs.at[costs_name,'efficiency']*costs.at[costs_name,'fixed'],
|
capital_cost=costs.at[costs_name,'efficiency']*costs.at[costs_name,'fixed'],
|
||||||
p_nom=p_nom[name]*max(0,(int(baseyear)+default_lifetime-int(year))/default_lifetime)) #decomissioning happens lineary from now to 25 years lter
|
p_nom=p_nom[name]*ratio,
|
||||||
|
build_year=int(grouping_year),
|
||||||
|
lifetime=costs.at[costs_name,'lifetime'])
|
||||||
|
|
||||||
# add resistive heater, gas boilers and oil boilers
|
# add resistive heater, gas boilers and oil boilers
|
||||||
# (50% capacities to rural buses, 50% to urban buses)
|
# (50% capacities to rural buses, 50% to urban buses)
|
||||||
n.madd("Link",
|
n.madd("Link",
|
||||||
nodes[name],
|
nodes[name],
|
||||||
suffix= " " + name + " resistive heater <{}".format(baseyear),
|
suffix= " " + name + " resistive heater-{}".format(grouping_year),
|
||||||
bus0=nodes[name],
|
bus0=nodes[name],
|
||||||
bus1=nodes[name] + " " + name + " heat",
|
bus1=nodes[name] + " " + name + " heat",
|
||||||
carrier=name + " resistive heater",
|
carrier=name + " resistive heater",
|
||||||
efficiency=costs.at[name_type + ' resistive heater','efficiency'],
|
efficiency=costs.at[name_type + ' resistive heater','efficiency'],
|
||||||
capital_cost=costs.at[name_type + ' resistive heater','efficiency']*costs.at[name_type + ' resistive heater','fixed'],
|
capital_cost=costs.at[name_type + ' resistive heater','efficiency']*costs.at[name_type + ' resistive heater','fixed'],
|
||||||
p_nom=0.5*df['{} resistive heater'.format(heat_type)][nodes[name]]*max(0,(int(baseyear)+default_lifetime-int(year))/default_lifetime))
|
p_nom=0.5*df['{} resistive heater'.format(heat_type)][nodes[name]]*ratio,
|
||||||
|
build_year=int(grouping_year),
|
||||||
|
lifetime=costs.at[costs_name,'lifetime'])
|
||||||
|
|
||||||
n.madd("Link",
|
n.madd("Link",
|
||||||
nodes[name],
|
nodes[name],
|
||||||
suffix= " " + name + " gas boiler <{}".format(baseyear),
|
suffix= " " + name + " gas boiler-{}".format(grouping_year),
|
||||||
bus0=["EU gas"]*len(nodes[name]),
|
bus0=["EU gas"]*len(nodes[name]),
|
||||||
bus1=nodes[name] + " " + name + " heat",
|
bus1=nodes[name] + " " + name + " heat",
|
||||||
bus2="co2 atmosphere",
|
bus2="co2 atmosphere",
|
||||||
@ -299,11 +316,12 @@ def add_heating_capacities_installed_before_baseyear(n, year, baseyear, ashp_cop
|
|||||||
efficiency=costs.at[name_type + ' gas boiler','efficiency'],
|
efficiency=costs.at[name_type + ' gas boiler','efficiency'],
|
||||||
efficiency2=costs.at['gas','CO2 intensity'],
|
efficiency2=costs.at['gas','CO2 intensity'],
|
||||||
capital_cost=costs.at[name_type + ' gas boiler','efficiency']*costs.at[name_type + ' gas boiler','fixed'],
|
capital_cost=costs.at[name_type + ' gas boiler','efficiency']*costs.at[name_type + ' gas boiler','fixed'],
|
||||||
p_nom=0.5*df['{} gas boiler'.format(heat_type)][nodes[name]]*max(0,(int(baseyear)+default_lifetime-int(year))/default_lifetime))
|
p_nom=0.5*df['{} gas boiler'.format(heat_type)][nodes[name]]*ratio,
|
||||||
|
build_year=int(grouping_year),
|
||||||
|
lifetime=costs.at[name_type + ' gas boiler','lifetime'])
|
||||||
n.madd("Link",
|
n.madd("Link",
|
||||||
nodes[name],
|
nodes[name],
|
||||||
suffix=" " + name + " oil boiler <{}".format(baseyear),
|
suffix=" " + name + " oil boiler-{}".format(grouping_year),
|
||||||
bus0=["EU oil"]*len(nodes[name]),
|
bus0=["EU oil"]*len(nodes[name]),
|
||||||
bus1=nodes[name] + " " + name + " heat",
|
bus1=nodes[name] + " " + name + " heat",
|
||||||
bus2="co2 atmosphere",
|
bus2="co2 atmosphere",
|
||||||
@ -311,13 +329,16 @@ def add_heating_capacities_installed_before_baseyear(n, year, baseyear, ashp_cop
|
|||||||
efficiency=costs.at['decentral oil boiler','efficiency'],
|
efficiency=costs.at['decentral oil boiler','efficiency'],
|
||||||
efficiency2=costs.at['oil','CO2 intensity'],
|
efficiency2=costs.at['oil','CO2 intensity'],
|
||||||
capital_cost=costs.at['decentral oil boiler','efficiency']*costs.at['decentral oil boiler','fixed'],
|
capital_cost=costs.at['decentral oil boiler','efficiency']*costs.at['decentral oil boiler','fixed'],
|
||||||
p_nom=0.5*df['{} oil boiler'.format(heat_type)][nodes[name]]*max(0,(int(baseyear)+default_lifetime-int(year))/default_lifetime))
|
p_nom=0.5*df['{} oil boiler'.format(heat_type)][nodes[name]]*ratio,
|
||||||
|
build_year=int(grouping_year),
|
||||||
|
lifetime=costs.at[name_type + ' gas boiler','lifetime'])
|
||||||
|
|
||||||
# delete links with p_nom=nan corresponding to extra nodes in country
|
# delete links with p_nom=nan corresponding to extra nodes in country
|
||||||
n.mremove("Link", [index for index in n.links.index.to_list() if baseyear in index and np.isnan(n.links.p_nom[index])])
|
n.mremove("Link", [index for index in n.links.index.to_list() if grouping_year in index and np.isnan(n.links.p_nom[index])])
|
||||||
|
|
||||||
# delete links if their lifetime is over and p_nom=0
|
# delete links if their lifetime is over and p_nom=0
|
||||||
n.mremove("Link", [index for index in n.links.index.to_list() if '<'+baseyear in index and n.links.p_nom[index]==0])
|
n.mremove("Link", [index for index in n.links.index.to_list() if grouping_year in index and n.links.p_nom[index]<snakemake.config['existing_capacities']['threshold_capacity']])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Detect running outside of snakemake and mock snakemake for testing
|
# Detect running outside of snakemake and mock snakemake for testing
|
||||||
@ -332,7 +353,7 @@ if __name__ == "__main__":
|
|||||||
costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv',
|
costs='pypsa-eur-sec/data/costs/costs_{planning_horizons}.csv',
|
||||||
cop_air_total="pypsa-eur-sec/resources/cop_air_total_{network}_s{simpl}_{clusters}.nc",
|
cop_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"),
|
cop_soil_total="pypsa-eur-sec/resources/cop_soil_total_{network}_s{simpl}_{clusters}.nc"),
|
||||||
output=['pypsa-eur-sec/results/test/prenetworks_bf/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc'],
|
output=['pypsa-eur-sec/results/test/prenetworks_brownfield/{network}_s{simpl}_{clusters}_lv{lv}__{sector_opts}_{planning_horizons}.nc'],
|
||||||
)
|
)
|
||||||
import yaml
|
import yaml
|
||||||
with open('config.yaml') as f:
|
with open('config.yaml') as f:
|
||||||
@ -355,15 +376,15 @@ if __name__ == "__main__":
|
|||||||
snakemake.config['costs']['discountrate'],
|
snakemake.config['costs']['discountrate'],
|
||||||
Nyears)
|
Nyears)
|
||||||
|
|
||||||
|
grouping_years=snakemake.config['existing_capacities']['grouping_years']
|
||||||
add_power_capacities_installed_before_baseyear(n, baseyear, baseyear, costs)
|
add_power_capacities_installed_before_baseyear(n, grouping_years, costs)
|
||||||
|
|
||||||
if "H" in opts:
|
if "H" in opts:
|
||||||
time_dep_hp_cop = options["time_dep_hp_cop"]
|
time_dep_hp_cop = options["time_dep_hp_cop"]
|
||||||
ashp_cop = xr.open_dataarray(snakemake.input.cop_air_total).T.to_pandas().reindex(index=n.snapshots)
|
ashp_cop = xr.open_dataarray(snakemake.input.cop_air_total).T.to_pandas().reindex(index=n.snapshots)
|
||||||
gshp_cop = xr.open_dataarray(snakemake.input.cop_soil_total).T.to_pandas().reindex(index=n.snapshots)
|
gshp_cop = xr.open_dataarray(snakemake.input.cop_soil_total).T.to_pandas().reindex(index=n.snapshots)
|
||||||
default_lifetime = snakemake.config['costs']['lifetime']
|
default_lifetime = snakemake.config['costs']['lifetime']
|
||||||
add_heating_capacities_installed_before_baseyear(n, baseyear, baseyear, ashp_cop, gshp_cop, time_dep_hp_cop, costs, default_lifetime)
|
add_heating_capacities_installed_before_baseyear(n, baseyear, grouping_years, ashp_cop, gshp_cop, time_dep_hp_cop, costs, default_lifetime)
|
||||||
|
|
||||||
n.export_to_netcdf(snakemake.output[0])
|
n.export_to_netcdf(snakemake.output[0])
|
||||||
|
|
||||||
|
@ -35,7 +35,31 @@ override_component_attrs["Link"].loc["efficiency3"] = ["static or series","per u
|
|||||||
override_component_attrs["Link"].loc["p2"] = ["series","MW",0.,"2nd bus output","Output"]
|
override_component_attrs["Link"].loc["p2"] = ["series","MW",0.,"2nd bus output","Output"]
|
||||||
override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output","Output"]
|
override_component_attrs["Link"].loc["p3"] = ["series","MW",0.,"3rd bus output","Output"]
|
||||||
|
|
||||||
|
override_component_attrs["Link"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Link"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Generator"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Generator"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Store"].loc["build_year"] = ["integer","year",np.nan,"build year","Input (optional)"]
|
||||||
|
override_component_attrs["Store"].loc["lifetime"] = ["float","years",np.nan,"build year","Input (optional)"]
|
||||||
|
|
||||||
|
def add_lifetime_wind_solar(n):
|
||||||
|
"""
|
||||||
|
Add lifetime for solar and wind generators
|
||||||
|
"""
|
||||||
|
for carrier in ['solar', 'onwind', 'offwind-dc', 'offwind-ac']:
|
||||||
|
carrier_name='offwind' if carrier in ['offwind-dc', 'offwind-ac'] else carrier
|
||||||
|
n.generators.loc[[index for index in n.generators.index.to_list()
|
||||||
|
if carrier in index], 'lifetime']=costs.at[carrier_name,'lifetime']
|
||||||
|
|
||||||
|
def add_coal_oil_uranium_buses(n):
|
||||||
|
"""
|
||||||
|
Add buses to connect coal, nuclear and oil plants
|
||||||
|
"""
|
||||||
|
|
||||||
|
for carrier in ['coal', 'oil', 'uranium']:
|
||||||
|
n.add("Bus",
|
||||||
|
"EU " + carrier,
|
||||||
|
carrier=carrier)
|
||||||
|
|
||||||
def remove_elec_base_techs(n):
|
def remove_elec_base_techs(n):
|
||||||
"""remove conventional generators (e.g. OCGT) and storage units (e.g. batteries and H2)
|
"""remove conventional generators (e.g. OCGT) and storage units (e.g. batteries and H2)
|
||||||
@ -1615,19 +1639,10 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
n.loads["carrier"] = "electricity"
|
n.loads["carrier"] = "electricity"
|
||||||
|
|
||||||
# Add lifetime and build_year attributes to generators, links and stores
|
|
||||||
n.generators["lifetime"]=np.nan
|
|
||||||
n.generators["build_year"]=np.nan
|
|
||||||
n.links["lifetime"]=np.nan
|
|
||||||
n.links["build_year"]=np.nan
|
|
||||||
n.stores["lifetime"]=np.nan
|
|
||||||
|
|
||||||
# Add lifetime for solar and wind generators
|
|
||||||
for carrier in ['solar', 'onwind', 'offwind-dc', 'offwind-ac']:
|
|
||||||
carrier_name='offwind' if carrier in ['offwind-dc', 'offwind-ac'] else carrier
|
|
||||||
n.generators.loc[[index for index in n.generators.index.to_list()
|
|
||||||
if carrier in index], 'lifetime']=costs.at[carrier_name,'lifetime']
|
|
||||||
|
|
||||||
|
if snakemake.config["foresight"]=='myopic':
|
||||||
|
add_lifetime_wind_solar(n)
|
||||||
|
add_coal_oil_uranium_buses(n)
|
||||||
|
|
||||||
add_co2_tracking(n)
|
add_co2_tracking(n)
|
||||||
|
|
||||||
@ -1715,5 +1730,4 @@ if __name__ == "__main__":
|
|||||||
if snakemake.config["sector"]['electricity_grid_connection']:
|
if snakemake.config["sector"]['electricity_grid_connection']:
|
||||||
add_electricity_grid_connection(n)
|
add_electricity_grid_connection(n)
|
||||||
|
|
||||||
n.stores["build_year"]=np.nan
|
|
||||||
n.export_to_netcdf(snakemake.output[0])
|
n.export_to_netcdf(snakemake.output[0])
|
||||||
|
Loading…
Reference in New Issue
Block a user