Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,8 @@ solar_thermal:

# docs in https://pypsa-eur.readthedocs.io/en/latest/configuration.html#existing-capacities
existing_capacities:
grouping_years_power: [1920, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020, 2025]
grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # heat grouping years >= baseyear will be ignored
grouping_years_power: [1920, 1950, 1955, 1960, 1965, 1970, 1975, 1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2020, 2025] # power grouping years > baseyear will be ignored
grouping_years_heat: [1980, 1985, 1990, 1995, 2000, 2005, 2010, 2015, 2019] # heat grouping years > baseyear will be ignored
threshold_capacity: 10
default_heating_lifetime: 20
conventional_carriers:
Expand Down
65 changes: 37 additions & 28 deletions scripts/add_existing_baseyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"""

import logging
from collections.abc import Sequence
from types import SimpleNamespace

import country_converter as coco
Expand Down Expand Up @@ -464,6 +465,25 @@ def get_efficiency(
return efficiency


def valid_grouping_years(
grouping_years: Sequence[int] | pd.Index,
baseyear: int,
max_lifetime: float | None = None,
) -> pd.Index:
grouping_years = pd.Index(sorted(grouping_years)).astype(int)

valid = grouping_years <= baseyear
if max_lifetime is not None:
valid &= grouping_years + max_lifetime >= baseyear
if not valid.all():
logger.warning(
"Only grouping years between [baseyear - max. lifetime, baseyear] are used."
f"Dropping {grouping_years[~valid]}."
)

return grouping_years[valid]


def add_heating_capacities_installed_before_baseyear(
n: pypsa.Network,
costs: pd.DataFrame,
Expand All @@ -490,7 +510,7 @@ def add_heating_capacities_installed_before_baseyear(
Technology costs
baseyear : int
Base year for analysis
grouping_years : list
grouping_years : pd.Index
Intervals to group capacities
heat_pump_cop : xr.DataArray
Heat pump coefficients of performance
Expand Down Expand Up @@ -532,32 +552,14 @@ def add_heating_capacities_installed_before_baseyear(
else:
nodes_elec = nodes

too_large_grouping_years = [
gy for gy in grouping_years if gy >= int(baseyear)
]
if too_large_grouping_years:
logger.warning(
f"Grouping years >= baseyear are ignored. Dropping {too_large_grouping_years}."
)
valid_grouping_years = pd.Series(
[
int(grouping_year)
for grouping_year in grouping_years
if int(grouping_year) + default_lifetime > int(baseyear)
and int(grouping_year) < int(baseyear)
]
)

assert valid_grouping_years.is_monotonic_increasing

# get number of years of each interval
_years = valid_grouping_years.diff()
# Fill NA from .diff() with value for the first interval
_years[0] = valid_grouping_years[0] - baseyear + default_lifetime
# Installation is assumed to be linear for the past
ratios = _years / _years.sum()
# get number of years of each interval
_years = pd.Index([grouping_years[0] - baseyear + default_lifetime]).append(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am a bit confused about this expression here, this can be a negative number or? If grouping_year[0] == 1990 and baseyear == 2020 and lifetime == 20 for example.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit, i did not think about this. It is a literal port of Amos':

# Fill NA from .diff() with value for the first interval
_years[0] = valid_grouping_years[0] - baseyear + default_lifetime

Copy link
Member Author

@coroa coroa Mar 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, sorry, Amos, i was wrongly blaming you. The origin story of that expression is complicated.

@lisazeyen came up with:
https://github.com/PyPSA/pypsa-eur/blame/a72388b989d1d667ec7e44d66f6c3b494b46d000/scripts/add_existing_baseyear.py#L466-L467

         _years = (valid_grouping_years.diff().shift(-1)
                  .fillna(baseyear-valid_grouping_years.iloc[-1]))

ie. (baseyear - last of grouping_years) which sounds quite sensible (for an interval, unless the last grouping year is the same as the baseyear).

and then @lindnemi changed it to:

# Fill NA from .diff() with value for the first interval
_years[0] = valid_grouping_years[0] - baseyear + default_lifetime

in #1102 with associated discussion in #1091 .

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds like there was some back and forth, i'll not try to understand this fully now, maybe its best to have a short discussion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late reply @coroa! I think I only made some small refactoring changes here. I'll be OOO for a week but happy to discuss this further then, if helpful.

grouping_years.diff()
)
# Installation is assumed to be linear for the past
ratios = _years / np.sum(_years)

for ratio, grouping_year in zip(ratios, valid_grouping_years):
for ratio, grouping_year in zip(ratios, grouping_years):
# Add heat pumps
for heat_source in heat_pump_source_types[heat_system.system_type.value]:
costs_name = heat_system.heat_pump_costs_name(heat_source)
Expand Down Expand Up @@ -732,8 +734,10 @@ def add_heating_capacities_installed_before_baseyear(
Nyears,
)

grouping_years_power = snakemake.params.existing_capacities["grouping_years_power"]
grouping_years_heat = snakemake.params.existing_capacities["grouping_years_heat"]
grouping_years_power = valid_grouping_years(
snakemake.params.existing_capacities["grouping_years_power"],
baseyear,
)
add_power_capacities_installed_before_baseyear(
n=n,
costs=costs,
Expand All @@ -751,6 +755,11 @@ def add_heating_capacities_installed_before_baseyear(
year = int(snakemake.params["energy_totals_year"])
heating_efficiencies = pd.read_csv(fn, index_col=[1, 0]).loc[year]

grouping_years_heat = valid_grouping_years(
snakemake.params.existing_capacities["grouping_years_heat"],
baseyear,
snakemake.params.existing_capacities["default_heating_lifetime"],
)
add_heating_capacities_installed_before_baseyear(
n=n,
costs=costs,
Expand Down
Loading