Skip to content

remove data/hydro_capacities.csv with untraceable source #1279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ renewable:
cutout: europe-2013-sarah3-era5
carriers: [ror, PHS, hydro]
PHS_max_hours: 6
hydro_max_hours: "energy_capacity_totals_by_country" # one of energy_capacity_totals_by_country, estimate_by_large_installations or a float
hydro_max_hours_quantile: 0.1
flatten_dispatch: false
flatten_dispatch_buffer: 0.2
clip_min_inflow: 1.0
Expand Down
31 changes: 0 additions & 31 deletions data/hydro_capacities.csv

This file was deleted.

2 changes: 1 addition & 1 deletion doc/configtables/hydro.csv
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
cutout,--,Must be 'europe-2013-sarah3-era5',Specifies the directory where the relevant weather data ist stored.
carriers,--,"Any subset of {'ror', 'PHS', 'hydro'}","Specifies the types of hydro power plants to build per-unit availability time series for. 'ror' stands for run-of-river plants, 'PHS' represents pumped-hydro storage, and 'hydro' stands for hydroelectric dams."
PHS_max_hours,h,float,Maximum state of charge capacity of the pumped-hydro storage (PHS) in terms of hours at full output capacity ``p_nom``. Cf. `PyPSA documentation <https://pypsa.readthedocs.io/en/latest/components.html#storage-unit>`_.
hydro_max_hours,h,"Any of {float, 'energy_capacity_totals_by_country', 'estimate_by_large_installations'}",Maximum state of charge capacity of the pumped-hydro storage (PHS) in terms of hours at full output capacity ``p_nom`` or heuristically determined. Cf. `PyPSA documentation <https://pypsa.readthedocs.io/en/latest/components.html#storage-unit>`_.
hydro_max_hours_quantile,-,"[0, 1]","Quantile of hydro reservoir storage durations with data per country to use as a fill-value for missing datapoints. Defaults to 10% quantile, assuming reservoirs with large capacities have data. If no hydro reservoir has a storage duration given, a duration of 24 hours is assumed."
flatten_dispatch,bool,"{true, false}",Consider an upper limit for the hydro dispatch. The limit is given by the average capacity factor plus the buffer given in ``flatten_dispatch_buffer``
flatten_dispatch_buffer,--,float,"If ``flatten_dispatch`` is true, specify the value added above the average capacity factor."
clip_min_inflow,MW,float,"To avoid too small values in the inflow time series, values below this threshold are set to zero."
Expand Down
8 changes: 8 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ Release Notes
rules. This simplifies the use of ``mock_snakemake`` and places downloaded
data more transparently into the ``data`` directory.

* Removed use of ``data/hydro_capacities.csv`` for hydro energy storage
capacities because its source is untraceable. Many larger hydro reservoirs
from ``powerplantmatching`` have storage capacities given. The storage
capacity of hydro-electric plants with missing storage capacities is now
approximated through a configurable quantile of the storage durations of hydro
reservoirs with data, seperately for each country. The default is the 10%
quantile, assuming that missing data points are rather smaller reservoirs.

PyPSA-Eur 0.12.0 (30th August 2024)
===================================

Expand Down
1 change: 0 additions & 1 deletion rules/build_electricity.smk
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,6 @@ rule add_electricity:
),
regions=resources("regions_onshore.geojson"),
powerplants=resources("powerplants.csv"),
hydro_capacities=ancient("data/hydro_capacities.csv"),
unit_commitment="data/unit_commitment.csv",
fuel_price=lambda w: (
resources("monthly_fuel_price.csv")
Expand Down
29 changes: 5 additions & 24 deletions scripts/add_electricity.py
Original file line number Diff line number Diff line change
Expand Up @@ -616,41 +616,22 @@ def attach_hydro(n, costs, ppl, profile_hydro, hydro_capacities, carriers, **par
)

if "hydro" in carriers and not hydro.empty:
hydro_max_hours = params.get("hydro_max_hours")
hydro_max_hours_quantile = params.get("hydro_max_hours_quantile", 0.1)

assert hydro_max_hours is not None, "No path for hydro capacities given."

hydro_stats = pd.read_csv(
hydro_capacities, comment="#", na_values="-", index_col=0
max_hours_country = hydro.groupby("country").max_hours.quantile(
hydro_max_hours_quantile
)
e_target = hydro_stats["E_store[TWh]"].clip(lower=0.2) * 1e6
e_installed = hydro.eval("p_nom * max_hours").groupby(hydro.country).sum()
e_missing = e_target - e_installed
missing_mh_i = hydro.query("max_hours.isnull()").index

if hydro_max_hours == "energy_capacity_totals_by_country":
# watch out some p_nom values like IE's are totally underrepresented
max_hours_country = (
e_missing / hydro.loc[missing_mh_i].groupby("country").p_nom.sum()
)

elif hydro_max_hours == "estimate_by_large_installations":
max_hours_country = (
hydro_stats["E_store[TWh]"] * 1e3 / hydro_stats["p_nom_discharge[GW]"]
)

max_hours_country.clip(0, inplace=True)

missing_countries = pd.Index(hydro["country"].unique()).difference(
max_hours_country.dropna().index
)
if not missing_countries.empty:
logger.warning(
f'Assuming max_hours=6 for hydro reservoirs in the countries: {", ".join(missing_countries)}'
f'Assuming max_hours=24 for hydro reservoirs in the countries: {", ".join(missing_countries)}'
)
hydro_max_hours = hydro.max_hours.where(
hydro.max_hours > 0, hydro.country.map(max_hours_country)
).fillna(6)
).fillna(24)

if params.get("flatten_dispatch", False):
buffer = params.get("flatten_dispatch_buffer", 0.2)
Expand Down
Loading