Skip to content

Commit 37c5554

Browse files
author
Micha
authored
use higher lifetime only for existing German gas CHPs (#90)
* use higher lifetime only for existing German gas CHPs * actually use adjusted lifetime when asset is created * Revert "disable chps from prepare_sector_network" This reverts commit ea88245. * use pivot_table weighted by capacity to determine lifetimes * remove old comments * remove unused dropna * make NA values for existing gas CHPs a config setting * add changelog note * use all lower case for config
1 parent 8f314bd commit 37c5554

File tree

4 files changed

+32
-20
lines changed

4 files changed

+32
-20
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# Changelog
2+
- 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`
3+
- Bugfix: gas CHPs are extendable again
24
- Simplified scenarion definition and made `Mix` the default scenario
35
- 0.3: workflow is all public now, no longer requires credentials to internal data
46
- Allowing myopic optimization until 2050

config/config.de.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#run
66
run:
7-
prefix: 20250514_dhsubnodes
7+
prefix: 20253006_fix_chp_lifetime
88
name:
99
# - ExPol
1010
- KN2045_Mix
@@ -70,6 +70,7 @@ scenario:
7070
existing_capacities:
7171
grouping_years_power: [1920, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020]
7272
grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # heat grouping years >= baseyear will be ignored
73+
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.
7374

7475

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

276277
# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#sector
277278
sector:
278-
chp:
279-
enable: false # This should only deactivate the CHPs from prepare_sector_network, not those from add_existing_baseyear
280279
v2g: false
281280
solar_thermal: false
282281
district_heating:

scripts/add_existing_baseyear.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,10 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
510510
chp["lifetime"] = (chp.DateOut - chp["grouping_year"] + 1).fillna(
511511
snakemake.params.costs["fill_values"]["lifetime"]
512512
)
513+
chp.loc[chp.Fueltype == "gas", "lifetime"] = (
514+
chp.DateOut - chp["grouping_year"] + 1
515+
).fillna(snakemake.params.existing_capacities["fill_value_gas_chp_lifetime"])
516+
513517
chp = chp.loc[
514518
chp.grouping_year + chp.lifetime > baseyear
515519
] # in add_brownfield this is build_year + lifetime <= baseyear
@@ -572,6 +576,12 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
572576
aggfunc=lambda x: np.average(x, weights=mastr_chp.loc[x.index, "p_nom"]),
573577
)
574578

579+
mastr_chp_lifetime = mastr_chp.pivot_table(
580+
index=["grouping_year", "Fueltype"],
581+
columns="bus",
582+
values="lifetime",
583+
aggfunc=lambda x: np.average(x, weights=mastr_chp.loc[x.index, "p_nom"]),
584+
)
575585
mastr_chp_p_nom = mastr_chp.pivot_table(
576586
index=["grouping_year", "Fueltype"],
577587
columns="bus",
@@ -589,12 +599,13 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
589599
# add everything as Link
590600
for grouping_year, generator in mastr_chp_p_nom.index:
591601
# capacity is the capacity in MW at each node for this
592-
p_nom = mastr_chp_p_nom.loc[grouping_year, generator].dropna()
602+
p_nom = mastr_chp_p_nom.loc[grouping_year, generator]
593603
threshold = snakemake.params.existing_capacities["threshold_capacity"]
594604
p_nom = p_nom[p_nom > threshold]
595605

596606
efficiency_power = mastr_chp_efficiency_power.loc[grouping_year, generator]
597607
efficiency_heat = mastr_chp_efficiency_heat.loc[grouping_year, generator]
608+
lifetime = mastr_chp_lifetime.loc[grouping_year, generator]
598609

599610
for bus in p_nom.index:
600611
# check if link already exists and set p_nom_min and efficiency
@@ -636,11 +647,11 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
636647
overnight_cost=costs.at[key, "investment"]
637648
* costs.at[key, "efficiency"],
638649
marginal_cost=costs.at[key, "VOM"],
639-
efficiency=efficiency_power.dropna().loc[bus],
640-
efficiency2=efficiency_heat.dropna().loc[bus],
650+
efficiency=efficiency_power.loc[bus],
651+
efficiency2=efficiency_heat.loc[bus],
641652
efficiency3=costs.at[generator, "CO2 intensity"],
642653
build_year=grouping_year,
643-
lifetime=costs.at[key, "lifetime"],
654+
lifetime=lifetime.loc[bus],
644655
)
645656
else:
646657
key = "central solid biomass CHP"
@@ -661,7 +672,7 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
661672
efficiency=efficiency_power.loc[bus],
662673
efficiency2=efficiency_heat.loc[bus],
663674
build_year=grouping_year,
664-
lifetime=costs.at[key, "lifetime"],
675+
lifetime=lifetime.loc[bus],
665676
)
666677

667678
# CHPs that are not from MaStR
@@ -671,10 +682,17 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
671682
values="Capacity",
672683
aggfunc="sum",
673684
)
685+
chp_nodal_lifetime = chp.pivot_table(
686+
index=["grouping_year", "Fueltype"],
687+
columns="bus",
688+
values="lifetime",
689+
aggfunc=lambda x: np.average(x, weights=chp.loc[x.index, "Capacity"]),
690+
)
674691
for grouping_year, generator in chp_nodal_p_nom.index:
675-
p_nom = chp_nodal_p_nom.loc[grouping_year, generator].dropna()
692+
p_nom = chp_nodal_p_nom.loc[grouping_year, generator]
676693
threshold = snakemake.params.existing_capacities["threshold_capacity"]
677694
p_nom = p_nom[p_nom > threshold]
695+
lifetime = chp_nodal_lifetime.loc[grouping_year, generator]
678696

679697
for bus in p_nom.index:
680698
# check if link already exists and set p_nom_min and efficiency
@@ -726,7 +744,7 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
726744
efficiency2=costs.at[key, "efficiency"] / costs.at[key, "c_b"],
727745
efficiency3=costs.at[generator, "CO2 intensity"],
728746
build_year=grouping_year,
729-
lifetime=costs.at[key, "lifetime"],
747+
lifetime=lifetime.loc[bus],
730748
)
731749
else:
732750
key = "central solid biomass CHP"
@@ -747,7 +765,7 @@ def add_chp_plants(n, grouping_years, costs, baseyear):
747765
efficiency=costs.at[key, "efficiency"],
748766
efficiency2=costs.at[key, "efficiency-heat"],
749767
build_year=grouping_year,
750-
lifetime=costs.at[key, "lifetime"],
768+
lifetime=lifetime.loc[bus],
751769
)
752770

753771

@@ -1085,9 +1103,8 @@ def add_heating_capacities_installed_before_baseyear(
10851103

10861104
snakemake = mock_snakemake(
10871105
"add_existing_baseyear",
1088-
configfiles=["config/test/config.dach.yaml"],
1089-
clusters="5",
1090-
ll="v1.5",
1106+
clusters="27",
1107+
ll="vopt",
10911108
opts="",
10921109
sector_opts="none",
10931110
planning_horizons="2020",

scripts/pypsa-de/modify_cost_data.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,6 @@ def carbon_component_fossils(costs, co2_price):
140140
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}."
141141
)
142142

143-
# increase central gas CHP lifetime to 40 years
144-
costs.at[("central gas CHP", "lifetime"), "value"] = 40
145-
logger.info(
146-
f"Setting lifetime of central gas CHP to {costs.at[('central gas CHP', 'lifetime'), 'value']} {costs.at[('central gas CHP', 'lifetime'), 'unit']}."
147-
)
148-
149143
# decrease Fischer-Tropsch efficiency
150144
costs.at[("Fischer-Tropsch", "efficiency"), "value"] = (
151145
1 / costs.at[("Fischer-Tropsch", "hydrogen-input"), "value"]

0 commit comments

Comments
 (0)