Skip to content

Commit c287a2b

Browse files
authored
Merge branch 'main' into dependabot/github_actions/github-actions-1bd4ecb1c2
2 parents f0dcdb8 + 319732e commit c287a2b

153 files changed

Lines changed: 38520 additions & 10058 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/push-images.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ name: Push images
22

33
on:
44
push:
5-
65
branches:
76
- master
87
workflow_dispatch:
98

109
env:
1110
IMAGE_NAME: pypsa/eur-dev-env
12-
BASE_ENV: envs/linux-64.lock.yaml
1311

1412
jobs:
1513
push-image:
@@ -20,9 +18,9 @@ jobs:
2018
with:
2119
fetch-depth: 0
2220

23-
- name: 'Get relevant env'
21+
- name: 'Get last commit that changed pixi env'
2422
run: |
25-
hash_last_changed=$(git log -1 --pretty=format:%H -- ${{ env.BASE_ENV }})
23+
hash_last_changed=$(git log -1 --pretty=format:%H -- pixi.toml pixi.lock)
2624
echo "hash_last_changed=$hash_last_changed" >> $GITHUB_ENV
2725
2826
- name: 'Login to GitHub Container Registry'

.github/workflows/test.yaml

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Test workflows
1+
name: Test
22

33
on:
44
push:
@@ -17,8 +17,30 @@ concurrency:
1717
cancel-in-progress: true
1818

1919
jobs:
20-
run-tests:
21-
name: OS
20+
unit-tests:
21+
name: Unit
22+
runs-on: ubuntu-latest
23+
24+
defaults:
25+
run:
26+
shell: bash -l {0}
27+
28+
steps:
29+
- uses: actions/checkout@v6
30+
31+
- name: Setup Pixi
32+
uses: prefix-dev/setup-pixi@v0.9.4
33+
with:
34+
pixi-version: v0.59.0
35+
cache: true
36+
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'master' }}
37+
38+
- name: Run unit tests
39+
run: |
40+
pixi run unit-tests
41+
42+
integration-tests:
43+
name: Integration
2244
runs-on: ${{ matrix.os }}-latest
2345
strategy:
2446
fail-fast: false
@@ -43,7 +65,6 @@ jobs:
4365
- 'data/**'
4466
- 'Snakefile'
4567
- 'config/**'
46-
- 'test/**'
4768
- 'pixi.toml'
4869
- 'pixi.lock'
4970
- '.github/workflows/test.yaml'
@@ -58,51 +79,56 @@ jobs:
5879
sudo docker builder prune -a --force
5980
echo "Final disk space"
6081
df -h
82+
6183
- name: Skip - no source changes
62-
if: steps.filter.outputs.src != 'true' && github.event_name != 'schedule'
84+
if: steps.filter.outputs.src != 'true' && github.event_name != 'schedule' && github.event_name != 'workflow_dispatch'
6385
run: echo "Skipping tests because no source code changes detected"
6486

6587
- name: Setup Pixi
66-
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule'
88+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
6789
uses: prefix-dev/setup-pixi@v0.9.4
6890
with:
6991
pixi-version: v0.59.0
7092
cache: true
71-
# Do not cache in branches
72-
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'main' }}
93+
cache-write: ${{ github.event_name == 'push' && github.ref_name == 'master' }}
7394

7495
- name: Setup cache keys
75-
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule'
96+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
7697
run: |
77-
echo "WEEK=$(date +'%Y%U')" >> $GITHUB_ENV # data and cutouts
98+
echo "WEEK=$(date +'%Y%U')" >> $GITHUB_ENV # data
99+
echo "MONTH=$(date +'%Y%m')" >> $GITHUB_ENV # cutouts
100+
echo "VERSIONS_HASH=${{ hashFiles('data/versions.csv') }}" >> $GITHUB_ENV
78101
79102
- uses: actions/cache@v5
80-
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule'
103+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
81104
with:
82-
path: |
83-
data
84-
cutouts
85-
key: data-cutouts-${{ env.WEEK }}
105+
path: data
106+
key: data-${{ env.WEEK }}-${{ env.VERSIONS_HASH }}
107+
108+
- uses: actions/cache@v5
109+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
110+
with:
111+
path: cutouts
112+
key: cutouts-${{ env.MONTH }}
113+
114+
- name: Restore git-tracked files in data/
115+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
116+
run: git checkout HEAD -- data/
86117

87118
- name: Run pylint check on scripts
88-
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule'
119+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
89120
# check for undefined variables to reuse functions across scripts
90121
run: |
91122
pixi run pylint --disable=all --enable=E0601,E0606 --output-format=parseable scripts/add_* scripts/prepare_* scripts/solve_*
92123
93124
- name: Run snakemake test workflows
94-
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule'
125+
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
95126
env:
96127
SNAKEMAKE_STORAGE_CACHED_HTTP_CACHE: ""
97128
SNAKEMAKE_STORAGE_CACHED_HTTP_SKIP_REMOTE_CHECKS: "1"
98129
run: |
99130
pixi run integration-tests
100131
101-
- name: Run unit tests
102-
if: steps.filter.outputs.src == 'true' || github.event_name == 'schedule'
103-
run: |
104-
pixi run unit-tests
105-
106132
- name: Upload artifacts
107133
if: always()
108134
uses: actions/upload-artifact@v6

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ gurobi.log
3131
/cutouts
3232
/tmp
3333
doc/_build
34+
_build
3435

3536
/scripts/old
3637
/scripts/create_scenarios.py
@@ -65,6 +66,8 @@ d1gam3xoknrgr2.cloudfront.net/
6566

6667
*~
6768

69+
*.egg-info
70+
6871
*.pyc
6972

7073
*.xlsx

.pixi/config.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,7 @@
33
# SPDX-License-Identifier: CC0-1.0
44

55
pinning-strategy = "latest-up"
6-
run-post-link-scripts = "false" # set to "insecure" to allow running post-link scripts
6+
7+
# This aligns with default `conda` behaviour.
8+
# Set to "false" to stop post-link scripts from running.
9+
run-post-link-scripts = "insecure"

.pre-commit-config.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# SPDX-FileCopyrightText: Contributors to PyPSA-Eur <https://github.com/pypsa/pypsa-eur>
22
#
33
# SPDX-License-Identifier: CC0-1.0
4-
5-
exclude: "^LICENSES"
4+
exclude: "^LICENSES|^config/schema\\.json$|^config/config\\.default\\.yaml$"
65

76
ci:
87
autoupdate_schedule: quarterly
@@ -11,7 +10,6 @@ repos:
1110
- repo: https://github.com/pre-commit/pre-commit-hooks
1211
rev: v6.0.0
1312
hooks:
14-
- id: check-merge-conflict
1513
- id: check-added-large-files
1614
args: ["--maxkb=2000"]
1715

@@ -31,7 +29,7 @@ repos:
3129
rev: v2.4.1
3230
hooks:
3331
- id: codespell
34-
args: ['--ignore-regex="(\b[A-Z]+\b)"', '--ignore-words-list=fom,appartment,bage,ore,setis,tabacco,berfore,vor,pris,bund,GuD,Dezember,Juni,Juli,Produktion,WorstCase'] # Ignore capital case words, e.g. country codes
32+
args: ['--ignore-regex="(\b[A-Z]+\b)"', '--ignore-words-list=fom,appartment,bage,ore,setis,tabacco,berfore,vor,pris,bund,ons,GuD,Dezember,Juni,Juli,Produktion,WorstCase'] # Ignore capital case words, e.g. country codes
3533
types_or: [python, rst, markdown]
3634
files: ^(scripts|doc)/
3735

CITATION.cff

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ preferred-citation:
2828
references:
2929
- title: "PyPSA-Eur: An open sector-coupled optimisation model of the European energy system"
3030
repository: https://github.com/pypsa/pypsa-eur
31-
version: v2025.07.0
31+
version: v2026.02.0
3232
license: MIT
3333
authors:
3434
- family-names: Brown

README.md

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,11 @@ SPDX-License-Identifier: CC-BY-4.0
121121
# PyPSA-Eur: A Sector-Coupled Open Optimisation Model of the European Energy System
122122

123123
PyPSA-Eur is an open model dataset of the European energy system at the
124-
transmission network level that covers the full ENTSO-E area. The model is suitable both for operational studies and generation and transmission expansion planning studies.
125-
The continental scope and highly resolved spatial scale enables a proper description of the long-range
126-
smoothing effects for renewable power generation and their varying resource availability.
124+
transmission network level that covers the full ENTSO-E area and all energy sectors, including transport, heating, biomass, industry, and agriculture.
125+
Besides the power grid, pipeline networks for gas, hydrogen, carbon dioxide, and liquid fuels are included.
126+
The model is suitable both for planning studies and operational studies.
127+
The model is built from open data using a Snakemake workflow and fully open source.
128+
It is designed to be imported into the open-source energy system modelling framework [PyPSA](www.pypsa.org).
127129

128130
The model is described in the [documentation](https://pypsa-eur.readthedocs.io)
129131
and in the paper
@@ -144,64 +146,55 @@ The model is designed to be imported into the open toolbox
144146
> Institute of Technology](http://www.kit.edu/english/index.php) funded by the
145147
> [Helmholtz Association](https://www.helmholtz.de/en/).
146148
147-
> [!WARNING]
148-
> PyPSA-Eur is under active development and has several
149-
> [limitations](https://pypsa-eur.readthedocs.io/en/latest/limitations.html) which
150-
> you should understand before using the model. The github repository
151-
> [issues](https://github.com/PyPSA/pypsa-eur/issues) collect known topics we are
152-
> working on (please feel free to help or make suggestions). The
153-
> [documentation](https://pypsa-eur.readthedocs.io/) remains somewhat patchy. You
154-
> can find showcases of the model's capabilities in the Joule paper [The potential
155-
> role of a hydrogen network in
156-
> Europe](https://doi.org/10.1016/j.joule.2023.06.016), another [paper in Joule
157-
> with a description of the industry
158-
> sector](https://doi.org/10.1016/j.joule.2022.04.016), or in [a 2021 presentation
159-
> at EMP-E](https://nworbmot.org/energy/brown-empe.pdf). We do not recommend to
160-
> use the full resolution network model for simulations. At high granularity the
161-
> assignment of loads and generators to the nearest network node may not be a
162-
> correct assumption, depending on the topology of the underlying distribution
163-
> grid, and local grid bottlenecks may cause unrealistic load-shedding or
164-
> generator curtailment. We recommend to cluster the network to a couple of
165-
> hundred nodes to remove these local inconsistencies. See the discussion in
166-
> Section 3.4 "Model validation" of the paper.
167-
168-
![PyPSA-Eur Grid Model](doc/img/elec.png)
169-
170-
The dataset consists of:
171-
172-
- A grid model based on a modified [GridKit](https://github.com/bdw/GridKit)
173-
extraction of the [ENTSO-E Transmission System
174-
Map](https://www.entsoe.eu/data/map/). The grid model contains 7072 lines
175-
(alternating current lines at and above 220kV voltage level and all high
176-
voltage direct current lines) and 3803 substations.
149+
150+
Among many other things, the dataset consists of:
151+
152+
- A power grid model based on [OpenStreetMap](https://zenodo.org/records/18619025) for voltage levels above 220kV (optional above 60kV).
177153
- The open power plant database
178154
[powerplantmatching](https://github.com/PyPSA/powerplantmatching).
179-
- Electrical demand time series from the
180-
[OPSD project](https://open-power-system-data.org/).
181-
- Renewable time series based on ERA5 and SARAH, assembled using the [atlite tool](https://github.com/PyPSA/atlite).
182-
- Geographical potentials for wind and solar generators based on land use (CORINE) and excluding nature reserves (Natura2000) are computed with the [atlite library](https://github.com/PyPSA/atlite).
155+
- Electrical demand time series from the [ENTSO-E Transparency Platform](https://transparency.entsoe.eu/).
156+
- Renewable time series based on ERA5 and SARAH-3, assembled using [atlite](https://github.com/PyPSA/atlite).
157+
- Geographical potentials for wind and solar generators based land eligibility analysis in [atlite](https://github.com/PyPSA/atlite).
158+
- Energy balances compiled from Eurostat and JRC-IDEES datasets.
159+
160+
The high-voltage grid and the power plant fleet are shown in this map of the unclustered model (as of 1 January 2026):
183161

184-
A sector-coupled extension adds demand
185-
and supply for the following sectors: transport, space and water
186-
heating, biomass, industry and industrial feedstocks, agriculture,
187-
forestry and fishing. This completes the energy system and includes
188-
all greenhouse gas emitters except waste management and land use.
162+
![PyPSA-Eur Unclustered](doc/img/base.png)
163+
164+
165+
For computational reasons the model is usually clustered down
166+
to 50-250 nodes. The image below shows the electricity network and power plants clustered to NUTS2 regions:
167+
168+
![network diagram](doc/img/elec.png)
189169

190170
This diagram gives an overview of the sectors and the links between
191-
them:
171+
them within each model region:
192172

193173
![sector diagram](doc/img/multisector_figure.png)
194174

195-
Each of these sectors is built up on the transmission network nodes
196-
from [PyPSA-Eur](https://github.com/PyPSA/pypsa-eur):
197175

198-
![network diagram](https://github.com/PyPSA/pypsa-eur/blob/master/doc/img/base.png?raw=true)
199-
200-
For computational reasons the model is usually clustered down
201-
to 50-200 nodes.
202176

203-
Already-built versions of the model can be found in the accompanying [Zenodo
204-
repository](https://doi.org/10.5281/zenodo.3601881).
177+
# Warnings
178+
179+
PyPSA-Eur is under active development and has several
180+
[limitations](https://pypsa-eur.readthedocs.io/en/latest/limitations.html) which
181+
you should understand before using the model. The github repository
182+
[issues](https://github.com/PyPSA/pypsa-eur/issues) collect known topics we are
183+
working on (please feel free to help or make suggestions). The
184+
[documentation](https://pypsa-eur.readthedocs.io/) remains somewhat patchy. You
185+
can find showcases of the model's capabilities in the Joule paper [The potential
186+
role of a hydrogen network in
187+
Europe](https://doi.org/10.1016/j.joule.2023.06.016), another [paper in Joule
188+
with a description of the industry
189+
sector](https://doi.org/10.1016/j.joule.2022.04.016), or in [a 2021 presentation
190+
at EMP-E](https://nworbmot.org/energy/brown-empe.pdf). We do not recommend to
191+
use the full resolution network model for simulations. At high granularity the
192+
assignment of loads and generators to the nearest network node may not be a
193+
correct assumption, depending on the topology of the underlying distribution
194+
grid, and local grid bottlenecks may cause unrealistic load-shedding or
195+
generator curtailment. We recommend to cluster the network to a couple of
196+
hundred nodes to remove these local inconsistencies. See the discussion in
197+
Section 3.4 "Model validation" of the paper.
205198

206199
# Contributing and Support
207200

REUSE.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ SPDX-PackageDownloadLocation = "https://github.com/pypsa/pypsa-eur"
55

66
[[annotations]]
77
path = [
8-
"doc/configtables/*",
98
"doc/data_inventory.csv",
109
"doc/img/*",
1110
"test/test_data/*",
@@ -20,7 +19,9 @@ path = [
2019
"pixi.lock",
2120
"matplotlibrc",
2221
"envs/*.pin.txt",
23-
"envs/environment.yaml"
22+
"envs/environment.yaml",
23+
"config/config.default.yaml",
24+
"config/schema.default.json"
2425
]
2526
SPDX-FileCopyrightText = "The PyPSA-Eur Authors"
2627
SPDX-License-Identifier = "CC0-1.0"
@@ -41,7 +42,6 @@ path = [
4142
"data/parameter_corrections.yaml",
4243
"data/retro/window_assumptions.csv",
4344
"data/retro/retro_cost_germany.csv",
44-
"data/switzerland-new_format-all_years.csv",
4545
"data/transmission_projects/**",
4646
"data/unit_commitment.csv",
4747
"data/versions.csv",

0 commit comments

Comments
 (0)