Skip to content
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Changelog
- Longer lifetime (40 years) is only applied to existing gas CHPs, not new ones. Added a new config entry `existing_capacities:fill_value_gas_chp_lifetime`
- Bugfix: gas CHPs are extendable again
- Simplified scenarion definition and made `Mix` the default scenario
- 0.3: workflow is all public now, no longer requires credentials to internal data
- Allowing myopic optimization until 2050
Expand Down
5 changes: 2 additions & 3 deletions config/config.de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run
run:
prefix: 20250514_dhsubnodes
prefix: 20253006_fix_chp_lifetime
name:
# - ExPol
- KN2045_Mix
Expand Down Expand Up @@ -70,6 +70,7 @@ scenario:
existing_capacities:
grouping_years_power: [1920, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020]
grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # heat grouping years >= baseyear will be ignored
fill_value_gas_chp_lifetime: 40 # if no explicit lifetime is given use 40 years. The number was chosen s.t. the existing capacities in 2020 match with statistics.


# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#countries
Expand Down Expand Up @@ -275,8 +276,6 @@ costs:

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#sector
sector:
chp:
enable: false # This should only deactivate the CHPs from prepare_sector_network, not those from add_existing_baseyear
v2g: false
solar_thermal: false
district_heating:
Expand Down
39 changes: 28 additions & 11 deletions scripts/add_existing_baseyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
chp["lifetime"] = (chp.DateOut - chp["grouping_year"] + 1).fillna(
snakemake.params.costs["fill_values"]["lifetime"]
)
chp.loc[chp.Fueltype == "gas", "lifetime"] = (
chp.DateOut - chp["grouping_year"] + 1
).fillna(snakemake.params.existing_capacities["fill_value_gas_chp_lifetime"])
Comment thread
cpschau marked this conversation as resolved.

chp = chp.loc[
chp.grouping_year + chp.lifetime > baseyear
] # in add_brownfield this is build_year + lifetime <= baseyear
Expand Down Expand Up @@ -572,6 +576,12 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
aggfunc=lambda x: np.average(x, weights=mastr_chp.loc[x.index, "p_nom"]),
)

mastr_chp_lifetime = mastr_chp.pivot_table(
index=["grouping_year", "Fueltype"],
columns="bus",
values="lifetime",
aggfunc=lambda x: np.average(x, weights=mastr_chp.loc[x.index, "p_nom"]),
)
mastr_chp_p_nom = mastr_chp.pivot_table(
index=["grouping_year", "Fueltype"],
columns="bus",
Expand All @@ -589,12 +599,13 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
# add everything as Link
for grouping_year, generator in mastr_chp_p_nom.index:
# capacity is the capacity in MW at each node for this
p_nom = mastr_chp_p_nom.loc[grouping_year, generator].dropna()
p_nom = mastr_chp_p_nom.loc[grouping_year, generator]
threshold = snakemake.params.existing_capacities["threshold_capacity"]
p_nom = p_nom[p_nom > threshold]

efficiency_power = mastr_chp_efficiency_power.loc[grouping_year, generator]
efficiency_heat = mastr_chp_efficiency_heat.loc[grouping_year, generator]
lifetime = mastr_chp_lifetime.loc[grouping_year, generator]

for bus in p_nom.index:
# check if link already exists and set p_nom_min and efficiency
Expand Down Expand Up @@ -636,11 +647,11 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
overnight_cost=costs.at[key, "investment"]
* costs.at[key, "efficiency"],
marginal_cost=costs.at[key, "VOM"],
efficiency=efficiency_power.dropna().loc[bus],
efficiency2=efficiency_heat.dropna().loc[bus],
efficiency=efficiency_power.loc[bus],
efficiency2=efficiency_heat.loc[bus],
efficiency3=costs.at[generator, "CO2 intensity"],
build_year=grouping_year,
lifetime=costs.at[key, "lifetime"],
lifetime=lifetime.loc[bus],
)
else:
key = "central solid biomass CHP"
Expand All @@ -661,7 +672,7 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
efficiency=efficiency_power.loc[bus],
efficiency2=efficiency_heat.loc[bus],
build_year=grouping_year,
lifetime=costs.at[key, "lifetime"],
lifetime=lifetime.loc[bus],
)

# CHPs that are not from MaStR
Expand All @@ -671,10 +682,17 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
values="Capacity",
aggfunc="sum",
)
chp_nodal_lifetime = chp.pivot_table(
index=["grouping_year", "Fueltype"],
columns="bus",
values="lifetime",
aggfunc=lambda x: np.average(x, weights=chp.loc[x.index, "Capacity"]),
)
for grouping_year, generator in chp_nodal_p_nom.index:
p_nom = chp_nodal_p_nom.loc[grouping_year, generator].dropna()
p_nom = chp_nodal_p_nom.loc[grouping_year, generator]
threshold = snakemake.params.existing_capacities["threshold_capacity"]
p_nom = p_nom[p_nom > threshold]
lifetime = chp_nodal_lifetime.loc[grouping_year, generator]

for bus in p_nom.index:
# check if link already exists and set p_nom_min and efficiency
Expand Down Expand Up @@ -726,7 +744,7 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
efficiency2=costs.at[key, "efficiency"] / costs.at[key, "c_b"],
efficiency3=costs.at[generator, "CO2 intensity"],
build_year=grouping_year,
lifetime=costs.at[key, "lifetime"],
lifetime=lifetime.loc[bus],
)
else:
key = "central solid biomass CHP"
Expand All @@ -747,7 +765,7 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
efficiency=costs.at[key, "efficiency"],
efficiency2=costs.at[key, "efficiency-heat"],
build_year=grouping_year,
lifetime=costs.at[key, "lifetime"],
lifetime=lifetime.loc[bus],
)


Expand Down Expand Up @@ -1085,9 +1103,8 @@ def add_heating_capacities_installed_before_baseyear(

snakemake = mock_snakemake(
"add_existing_baseyear",
configfiles=["config/test/config.dach.yaml"],
clusters="5",
ll="v1.5",
clusters="27",
ll="vopt",
opts="",
sector_opts="none",
planning_horizons="2020",
Expand Down
6 changes: 0 additions & 6 deletions scripts/pypsa-de/modify_cost_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,6 @@ def carbon_component_fossils(costs, co2_price):
f"Scaling central water tank storage investment costs to KEA Technikkatalog: {costs.loc['central water tank storage', 'investment'].value} {costs.loc['central water tank storage', 'investment'].unit}."
)

# increase central gas CHP lifetime to 40 years
costs.at[("central gas CHP", "lifetime"), "value"] = 40
logger.info(
f"Setting lifetime of central gas CHP to {costs.at[('central gas CHP', 'lifetime'), 'value']} {costs.at[('central gas CHP', 'lifetime'), 'unit']}."
)

# decrease Fischer-Tropsch efficiency
costs.at[("Fischer-Tropsch", "efficiency"), "value"] = (
1 / costs.at[("Fischer-Tropsch", "hydrogen-input"), "value"]
Expand Down
Loading