Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
1cf34a9
feat: skip tyndp_renewable_profile technologies in workflow and build…
daniel-rdt May 23, 2025
3be60a1
feat: clean pecd data for years 2030, 2040, 2050 and build_renewable_…
daniel-rdt May 27, 2025
9f0b674
feat: add pecd profiles as input to prepare_sector_network and add_br…
daniel-rdt May 27, 2025
c0ce59f
fix: add hotfix for add_existing_baseyear existing renewable capaciti…
daniel-rdt May 27, 2025
cabc766
fix: fix pylint
daniel-rdt May 27, 2025
686df43
fix: fix pylint better
daniel-rdt May 27, 2025
4162538
fix: add electricity param for add_existing_baseyear rule in perfect …
daniel-rdt May 27, 2025
79526a7
feat: improve workflow implementation for more efficient execution of…
daniel-rdt May 28, 2025
ba5458d
fix: hotfix for add_brownfield p_max_pu until tyndp generators are ad…
daniel-rdt May 28, 2025
81402fe
doc: add description of new configuration option to configtables
daniel-rdt May 28, 2025
c1fbe13
doc: add release note
daniel-rdt May 28, 2025
b684567
feat: add retrieval rule for PECD data from google drive until data o…
daniel-rdt May 28, 2025
c33f5a3
fix: fix ruleorder statement
daniel-rdt May 28, 2025
16f9c16
fix: remove unneeded inputs to build_renewable_profiles_pecd and upda…
daniel-rdt May 28, 2025
d5bc7ea
doc: update license identifier
daniel-rdt Jun 2, 2025
500082c
feat: update pecd retrieval to use gcp storage
daniel-rdt Jun 3, 2025
540609e
Merge branch 'master' into feat/49-pecd-offshore
tgilon Jun 4, 2025
4cdfe9d
refactor: use tyndp specific renewable carriers and differentiate bet…
daniel-rdt Jun 12, 2025
4244dd3
Merge remote-tracking branch 'origin/feat/49-pecd-offshore' into feat…
daniel-rdt Jun 12, 2025
f2af81b
bugfix: include missing offshore node PECD data as empty columns and …
daniel-rdt Jun 12, 2025
cf11da3
bugfix: fix pylint and remove hydro from test config
daniel-rdt Jun 13, 2025
d84159f
bugfix: add existing res dependent on renewable carriers list
daniel-rdt Jun 13, 2025
e0635cb
feature: add 2050 pecd renewable profiles explicitly and filter for s…
daniel-rdt Jun 13, 2025
7b297a3
bugfix: fix params for add_existing_baseyear solve_perfect
daniel-rdt Jun 13, 2025
fe8cb52
bugfix: change year in renewable profile pecd back to integer
daniel-rdt Jun 16, 2025
67c84ce
bugfix: fix year dimension for 2035 an 2045 steps
daniel-rdt Jun 19, 2025
3bf3eb7
Merge remote-tracking branch 'origin/master' into feat/49-pecd-offshore
tgilon Jun 19, 2025
225de71
Apply suggestions from code review
daniel-rdt Jun 26, 2025
faf71b5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 26, 2025
8136121
fix: import chain from itertools
daniel-rdt Jun 26, 2025
a67fb07
refactor: generalize get tyndp renewable carriers
daniel-rdt Jun 26, 2025
dbccb1b
Merge branch 'master' into feat/49-pecd-offshore
tgilon Jun 26, 2025
b193122
fix: remove placeholder for renewable technology max capacities in bu…
daniel-rdt Jun 27, 2025
fed98dd
doc: add information about PECD Version 3.1 to documentation
daniel-rdt Jun 27, 2025
0a36daa
fix: remove unnecessary params from pecd rules
daniel-rdt Jun 27, 2025
b98eccc
feat: change fn_pecd to dir_pecd and add comment on skiprows
daniel-rdt Jun 27, 2025
580eaaa
refactor: change to if not continue style to reduce diff
daniel-rdt Jun 27, 2025
a55cfbf
feat: improve pecd profile configuration by making profile names expl…
daniel-rdt Jun 27, 2025
decd186
refactor: simplify tyndp_renewable_carriers also in smk files
daniel-rdt Jun 27, 2025
ad42364
Apply suggestions from code review
daniel-rdt Jul 1, 2025
3a10294
feat: adjust mock snakemake for changed first level config of pecd pr…
daniel-rdt Jul 1, 2025
a4d8cf1
feat: harmonize order of config options to default config
daniel-rdt Jul 1, 2025
b604850
refactor: move get_tyndp_res_carriers to _helpers.py
daniel-rdt Jul 1, 2025
8bd32c8
doc: add CSP to list of PECD profile names
daniel-rdt Jul 1, 2025
ba9a7e4
Merge branch 'master' into feat/49-pecd-offshore
daniel-rdt Jul 2, 2025
0c63140
doc: add todo for pecd data retrieval
daniel-rdt Jul 2, 2025
3e4b3f8
Apply suggestions from code review
daniel-rdt Jul 2, 2025
76c8cc8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 2, 2025
86d955e
doc: improve documentation of pecd_renewable_profiles option
daniel-rdt Jul 2, 2025
f068db4
Add missing input, use branch
coroa Jul 3, 2025
d6f3ae1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 3, 2025
94d074c
Merge remote-tracking branch 'origin/feat/49-pecd-offshore' into feat…
daniel-rdt Jul 3, 2025
48ab5d5
feat: make estimate renewable capacities explicit from config for sel…
daniel-rdt Jul 3, 2025
5e8d619
feat: split up tyndp renewable carriers into separate list
daniel-rdt Jul 3, 2025
f191c28
refactor: consistent naming convention of pecd_techs and tyndp_renewa…
daniel-rdt Jul 3, 2025
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
7 changes: 7 additions & 0 deletions config/config.default.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,13 @@ electricity:
conventional_carriers: [nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass]
renewable_carriers: [solar, solar-hsat, onwind, offwind-ac, offwind-dc, offwind-float, hydro]

tyndp_renewable_profiles:
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
enable: false
technologies:
- offwind-ac
- offwind-dc
- offwind-float

estimate_renewable_capacities:
enable: true
from_gem: true
Expand Down
6 changes: 6 additions & 0 deletions config/config.tyndp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ co2_budget:
electricity:
base_network: tyndp-raw
transmission_limit: v1.0
tyndp_renewable_profiles:
enable: true
technologies:
- offwind-ac
- offwind-dc
- offwind-float

links:
p_max_pu: 1.0
Expand Down
6 changes: 6 additions & 0 deletions config/test/config.tyndp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ co2_budget:
electricity:
base_network: tyndp-raw
transmission_limit: v1.0
tyndp_renewable_profiles:
enable: true
technologies:
- offwind-ac
- offwind-dc
- offwind-float

extendable_carriers:
Generator: [OCGT]
Expand Down
3 changes: 3 additions & 0 deletions doc/configtables/electricity.csv
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ everywhere_powerplants,--,"Any subset of {nuclear, oil, OCGT, CCGT, coal, lignit
conventional_carriers,--,"Any subset of {nuclear, oil, OCGT, CCGT, coal, lignite, geothermal, biomass}","List of conventional power plants to include in the model from ``resources/powerplants_s_{clusters}.csv``. If an included carrier is also listed in ``extendable_carriers``, the capacity is taken as a lower bound."
,,,
renewable_carriers,--,"Any subset of {solar, onwind, offwind-ac, offwind-dc, offwind-float, hydro}",List of renewable generators to include in the model.
tyndp_renewable_profiles,,,
-- enable,,bool,Activate PECD renewable profiles from 2024 TYNDP instead of default renewable profiles for specified renewable technologies below.
-- technologies,--,list,Select the renewable technologies for which PECD renewable profiles are used. Carriers not listed use default renewable profiles.
estimate_renewable_capacities,,,
-- enable,,bool,Activate routine to estimate renewable capacities in rule :mod:`add_electricity`. This option should not be used in combination with pathway planning ``foresight: myopic`` or ``foresight: perfect`` as renewable capacities are added differently in :mod:`add_existing_baseyear`.
-- from_gem,--,bool,Add renewable capacities from `Global Energy Monitor's Global Solar Power Tracker <https://globalenergymonitor.org/projects/global-solar-power-tracker/>`_ and `Global Energy Monitor's Global Wind Power Tracker <https://globalenergymonitor.org/projects/global-wind-power-tracker/>`_.
Expand Down
2 changes: 2 additions & 0 deletions doc/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Release Notes

**Changes**

* Add processing and preparation of TYNDP 2024 PECD renewable profiles instead of default renewable profiles using atlite (https://github.com/open-energy-transition/open-tyndp/pull/53). Initial implementation first addresses profiles for offshore technologies.
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated

* Add TYNDP hydrogen import potentials and corridors from outside of the modelled countries (https://github.com/open-energy-transition/open-tyndp/pull/36). Notably this includes pipelines and shipping imports from North Africa, Ukraine and Norway. Different import potentials are available for each of the planning years which are differentiated by wildcards.

* Add the TYNDP electricity demand as an exogenously set demand (https://github.com/open-energy-transition/open-tyndp/pull/14). This requires the default PyPSA-Eur modelling to be explicitly disabled. The TYNDP electricity demand depends on the planning year, necessitating a different approach to the default PyPSA-Eur one. Wildcards are introduced and load is attached in `prepare_sector_network`.
Expand Down
71 changes: 70 additions & 1 deletion rules/build_electricity.smk
Comment thread
daniel-rdt marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,65 @@ rule build_renewable_profiles:
"../scripts/build_renewable_profiles.py"


def input_data_pecd(w):
return {
f"pecd_data_{pyear}": resources("pecd_data_{technology}_" + str(pyear) + ".csv")
for pyear in set(
config_provider("scenario", "planning_horizons")(w)
).intersection([2030, 2040])
# Complete PECD data is only available for the years 2030, 2040
# TODO: adjust if udpated 2050 data available
}


rule build_renewable_profiles_pecd:
params:
snapshots=config_provider("snapshots"),
drop_leap_day=config_provider("enable", "drop_leap_day"),
renewable=config_provider("renewable"),
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
planning_horizons=config_provider("scenario", "planning_horizons"),
input:
unpack(input_data_pecd),
output:
profile=resources("profile_pecd_{clusters}_{technology}.nc"),
log:
logs("build_renewable_profile_pecd_{clusters}_{technology}.log"),
benchmark:
benchmarks("build_renewable_profile_pecd_{clusters}_{technology}")
threads: 1
resources:
mem_mb=4000,
wildcard_constraints:
technology="(?!hydro).*", # Any technology other than hydro
conda:
"../envs/environment.yaml"
script:
"../scripts/build_renewable_profiles_pecd.py"


rule clean_pecd_data:
params:
scenario=config_provider("tyndp_scenario"),
snapshots=config_provider("snapshots"),
input:
offshore_buses="data/tyndp_2024_bundle/Offshore hubs/NODE.xlsx",
onshore_buses=resources("busmap_base_s_all.csv"),
fn_pecd="data/tyndp_2024_bundle/PECD",
output:
pecd_data_clean=resources("pecd_data_{technology}_{planning_horizons}.csv"),
log:
logs("clean_pecd_data_{technology}_{planning_horizons}.log"),
benchmark:
benchmarks("clean_pecd_data_{technology}_{planning_horizons}")
threads: 4
resources:
mem_mb=4000,
conda:
"../envs/environment.yaml"
script:
"../scripts/clean_pecd_data.py"


rule build_monthly_prices:
input:
co2_price_raw="data/validation/emission-spot-primary-market-auction-report-2019-data.xls",
Expand Down Expand Up @@ -545,6 +604,7 @@ def input_class_regions(w):
)
for tech in set(config_provider("electricity", "renewable_carriers")(w))
- {"hydro"}
- set(tyndp_renewable_profiles(w))
}


Expand Down Expand Up @@ -729,14 +789,23 @@ rule cluster_network:
"../scripts/cluster_network.py"


def tyndp_renewable_profiles(w):
return (
config_provider("electricity", "tyndp_renewable_profiles", "technologies")(w)
if config_provider("electricity", "tyndp_renewable_profiles", "enable")(w)
else []
)


def input_profile_tech(w):
return {
f"profile_{tech}": resources(
"profile_{clusters}_" + tech + ".nc"
if tech != "hydro"
else f"profile_{tech}.nc"
)
for tech in config_provider("electricity", "renewable_carriers")(w)
for tech in set(config_provider("electricity", "renewable_carriers")(w))
- set(tyndp_renewable_profiles(w))
}


Expand Down
9 changes: 9 additions & 0 deletions rules/build_sector.smk
Original file line number Diff line number Diff line change
Expand Up @@ -1228,6 +1228,14 @@ def input_profile_offwind(w):
f"profile_{tech}": resources("profile_{clusters}_" + tech + ".nc")
for tech in ["offwind-ac", "offwind-dc", "offwind-float"]
if (tech in config_provider("electricity", "renewable_carriers")(w))
and (tech not in tyndp_renewable_profiles(w))
}


def input_profile_pecd(w):
return {
f"profile_pecd_{tech}": resources("profile_pecd_{clusters}_" + tech + ".nc")
for tech in tyndp_renewable_profiles(w)
}


Expand Down Expand Up @@ -1379,6 +1387,7 @@ rule prepare_sector_network:
scaling_factor=config_provider("load", "scaling_factor"),
input:
unpack(input_profile_offwind),
unpack(input_profile_pecd),
unpack(input_heat_source_power),
**rules.cluster_gas_network.output,
**rules.build_gas_input_locations.output,
Expand Down
14 changes: 14 additions & 0 deletions rules/retrieve.smk
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,20 @@ if config["enable"]["retrieve"] and config["enable"].get("retrieve_tyndp_bundle"
script:
"../scripts/retrieve_tyndp_bundle.py"

rule retrieve_tyndp_pecd_data:
params:
tyndp_bundle="data/tyndp_2024_bundle",
# TODO Integrate into Zenodo tyndp data bundle
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
output:
dir=directory("data/tyndp_2024_bundle/PECD"),
log:
"logs/retrieve_tyndp_pecd_data.log",
retries: 2
script:
"../scripts/retrieve_tyndp_pecd_data.py"

ruleorder: retrieve_tyndp_bundle > retrieve_tyndp_pecd_data > clean_pecd_data
Comment thread
daniel-rdt marked this conversation as resolved.

rule retrieve_countries_centroids:
output:
"data/countries_centroids.geojson",
Expand Down
15 changes: 14 additions & 1 deletion rules/solve_myopic.smk
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ rule add_existing_baseyear:
params:
baseyear=config_provider("scenario", "planning_horizons", 0),
sector=config_provider("sector"),
electricity=config_provider("electricity"),
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
existing_capacities=config_provider("existing_capacities"),
costs=config_provider("costs"),
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
Expand Down Expand Up @@ -59,11 +60,21 @@ rule add_existing_baseyear:
def input_profile_tech_brownfield(w):
return {
f"profile_{tech}": resources("profile_{clusters}_" + tech + ".nc")
for tech in config_provider("electricity", "renewable_carriers")(w)
for tech in (
set(config_provider("electricity", "renewable_carriers")(w))
- set(tyndp_renewable_profiles(w))
)
if tech != "hydro"
}


def input_profile_tech_brownfied_pecd(w):
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
return {
f"profile_{tech}": resources("profile_pecd_{clusters}_" + tech + ".nc")
for tech in tyndp_renewable_profiles(w)
}


rule add_brownfield:
params:
H2_retrofit=config_provider("sector", "H2_retrofit"),
Expand All @@ -72,6 +83,7 @@ rule add_brownfield:
),
threshold_capacity=config_provider("existing_capacities", "threshold_capacity"),
snapshots=config_provider("snapshots"),
electricity=config_provider("electricity"),
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
drop_leap_day=config_provider("enable", "drop_leap_day"),
carriers=config_provider("electricity", "renewable_carriers"),
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
Expand All @@ -81,6 +93,7 @@ rule add_brownfield:
),
input:
unpack(input_profile_tech_brownfield),
unpack(input_profile_tech_brownfied_pecd),
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
simplify_busmap=resources("busmap_base_s.csv"),
cluster_busmap=resources("busmap_base_s_{clusters}.csv"),
network=resources(
Expand Down
1 change: 1 addition & 0 deletions rules/solve_perfect.smk
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ rule add_existing_baseyear:
params:
baseyear=config_provider("scenario", "planning_horizons", 0),
sector=config_provider("sector"),
electricity=config_provider("electricity"),
Comment thread
daniel-rdt marked this conversation as resolved.
Outdated
existing_capacities=config_provider("existing_capacities"),
costs=config_provider("costs"),
heat_pump_sources=config_provider("sector", "heat_pump_sources"),
Expand Down
7 changes: 5 additions & 2 deletions scripts/add_brownfield.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Contributors to PyPSA-Eur <https://github.com/pypsa/pypsa-eur>
# SPDX-FileCopyrightText: Open Energy Transition gGmbH and contributors to PyPSA-Eur <https://github.com/pypsa/pypsa-eur>
#
# SPDX-License-Identifier: MIT
"""
Expand Down Expand Up @@ -218,7 +218,10 @@ def adjust_renewable_profiles(n, input_profiles, params, year):
pd.Series(dr, index=dr).where(lambda x: x.isin(n.snapshots), pd.NA).ffill()
)

for carrier in params["carriers"]:
# TODO: hotfix remove filter for tyndp_renewable_profiles after tyndp generators are added
for carrier in set(params["carriers"]) - set(
params["electricity"]["tyndp_renewable_profiles"]["technologies"]
):
if carrier == "hydro":
continue

Expand Down
23 changes: 21 additions & 2 deletions scripts/add_electricity.py
Original file line number Diff line number Diff line change
Expand Up @@ -1212,7 +1212,22 @@ def attach_stores(
params.link_length_factor,
)

renewable_carriers = set(params.electricity["renewable_carriers"])
tyndp_renewable_profiles = (
params.electricity["tyndp_renewable_profiles"]["technologies"]
if params.electricity["tyndp_renewable_profiles"]["enable"]
else []
)
if len(tyndp_renewable_profiles) > 0:
logger.info(
f"Skipping renewable carriers '{', '.join(tyndp_renewable_profiles)}'. They will be attached later on with TYNDP data."
)
Comment thread
daniel-rdt marked this conversation as resolved.
renewable_carriers = set(
[
carrier
for carrier in params.electricity["renewable_carriers"]
if carrier not in tyndp_renewable_profiles
]
)
extendable_carriers = params.electricity["extendable_carriers"]
conventional_carriers = params.electricity["conventional_carriers"]
conventional_inputs = {
Expand Down Expand Up @@ -1276,7 +1291,11 @@ def attach_stores(
"in rule `add_existing_baseyear` with foresight mode 'myopic'."
)
else:
tech_map = estimate_renewable_caps["technology_mapping"]
tech_map = {
key: value
for key, value in estimate_renewable_caps["technology_mapping"].items()
if value not in tyndp_renewable_profiles
}
expansion_limit = estimate_renewable_caps["expansion_limit"]
year = estimate_renewable_caps["year"]

Expand Down
21 changes: 21 additions & 0 deletions scripts/add_existing_baseyear.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def add_existing_renewables(
costs: pd.DataFrame,
df_agg: pd.DataFrame,
countries: list[str],
tyndp_renewable_profiles: list[str],
) -> None:
"""
Add existing renewable capacities to conventional power plant data.
Expand All @@ -82,13 +83,22 @@ def add_existing_renewables(
Network containing topology and generator data
countries : list
List of country codes to consider
tyndp_renewable_profiles: list
List of renewable profile technologies taken from tyndp PECD

Returns
-------
None
Modifies df_agg in-place
"""
tech_map = {"solar": "PV", "onwind": "Onshore", "offwind-ac": "Offshore"}
# TODO: remove when TYNDP renewable generators are added
if len(tyndp_renewable_profiles) > 0:
logger.info(
f"Hotfix until TYNDP renewable carriers are added. Skipping renewable carriers '{', '.join(tyndp_renewable_profiles)}'."
)
for k in tyndp_renewable_profiles:
tech_map.pop(k, None)

irena = pm.data.IRENASTAT().powerplant.convert_country_to_alpha2()
irena = irena.query("Country in @countries")
Expand Down Expand Up @@ -149,6 +159,7 @@ def add_power_capacities_installed_before_baseyear(
countries: list[str],
capacity_threshold: float,
lifetime_values: dict[str, float],
tyndp_renewable_profiles: list[str],
) -> None:
"""
Add power generation capacities installed before base year.
Expand All @@ -171,6 +182,8 @@ def add_power_capacities_installed_before_baseyear(
Minimum capacity threshold
lifetime_values : dict
Default values for missing data
tyndp_renewable_profiles: list
List of renewable profile technologies taken from tyndp PECD
"""
logger.debug(f"Adding power capacities installed before {baseyear}")

Expand Down Expand Up @@ -223,6 +236,7 @@ def add_power_capacities_installed_before_baseyear(
costs=costs,
n=n,
countries=countries,
tyndp_renewable_profiles=tyndp_renewable_profiles,
)
# drop assets which are already phased out / decommissioned
phased_out = df_agg[df_agg["DateOut"] < baseyear].index
Expand Down Expand Up @@ -727,6 +741,12 @@ def add_heating_capacities_installed_before_baseyear(

options = snakemake.params.sector

tyndp_renewable_profiles = (
snakemake.params.electricity["tyndp_renewable_profiles"]["technologies"]
if snakemake.params.electricity["tyndp_renewable_profiles"]["enable"]
else []
)

baseyear = snakemake.params.baseyear

n = pypsa.Network(snakemake.input.network)
Expand All @@ -753,6 +773,7 @@ def add_heating_capacities_installed_before_baseyear(
countries=snakemake.config["countries"],
capacity_threshold=snakemake.params.existing_capacities["threshold_capacity"],
lifetime_values=snakemake.params.costs["fill_values"],
tyndp_renewable_profiles=tyndp_renewable_profiles,
)

if options["heating"]:
Expand Down
Loading