Skip to content

feat: PyPSA-EUR pipeline consolidation, fr225_400 dataset, full test coverage - #112

Merged
marota merged 6 commits into
mainfrom
feat/pypsa-eur-network-scripts
Apr 24, 2026
Merged

marota merged 6 commits into
mainfrom
feat/pypsa-eur-network-scripts

Conversation

@marota

@marota marota commented Apr 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Consolidates the PyPSA-EUR OSM→XIIDM conversion pipeline into scripts/pypsa_eur/, ships the canonical pypsa_eur_fr225_400 dataset, and adds end-to-end test coverage so the pipeline can be iterated on without regressing silently.

Three logical changes, in three commits plus a merge from main:

  1. Layout regeneration fix (82b34f1) — grid_layout.json was produced with inconsistent projection / VL key assumptions. Regenerated with correct Mercator math so layouts line up with the XIIDM VL IDs.
  2. Pipeline modularization (4680689) — convert_pypsa_to_xiidm.py is rewritten as a 5-step pipeline with a shared PipelineContext (load → network → calibrate → n1verify → metadata). fetch_osm_names.py is parameterized with --voltages, --output-dir, --cache-from. New regenerate_grid_layout.py + 37-test suite covers Mercator math, key matching, and cross-network consistency.
  3. Consolidation + coverage + dataset (0baa3e2) — every PyPSA-EUR script now lives under scripts/pypsa_eur/, a top-level build_pipeline.py orchestrator chains the five steps, and thermal calibration + N-1 overload reporting are extracted into their own tools. Hardcoded /home/marotant/... paths are gone.

Pipeline layout (post-merge)

scripts/pypsa_eur/
├── build_pipeline.py              # orchestrator — chains 5 steps, CLI flags propagate
├── fetch_osm_names.py             # step 1 — OSM Overpass query for substation names
├── convert_pypsa_to_xiidm.py      # step 2 — PyPSA network → XIIDM
├── calibrate_thermal_limits.py    # step 3 — N-1 peak-driven thermal-limit calibration
├── add_detailed_topology.py       # step 4 — double-busbar topology + coupler actions
├── generate_n1_overloads.py       # step 5 — N-1 security-analysis report
├── regenerate_grid_layout.py      # standalone layout regen (Mercator)
├── build_pypsa_eur_network.py     # upstream PyPSA-EUR invocation
├── verify_detailed_topology.py    # topology sanity check
├── add_limits_and_overloads.py    # legacy combined tool (kept)
├── conftest.py                    # shared pytest fixtures (network-agnostic)
└── test_*.py                      # see test matrix below

Top-level entrypoint:

python scripts/pypsa_eur/build_pipeline.py \
    --voltages 225,400 \
    --n1-peak-pct 130 \
    --min-branches 3
# → writes to data/pypsa_eur_fr225_400/ by default

Test coverage

All tests live under scripts/pypsa_eur/ and share a single conftest.py so no file re-defines the network / contingencies / layout fixtures. Counts are derived from artifacts on disk via an expected_counts fixture — nothing is hard-coded to 398 or 192 anymore, so the suite works on both pypsa_eur_fr400 and pypsa_eur_fr225_400 via --pypsa-network <name>.

File Tests What it covers
test_pipeline.py end-to-end XIIDM integrity, bus / generator / load counts, VL mapping, dispatch distribution
test_n1_calibration.py calibration 130 % peak invariant, convergence rate, line-count parity
test_grid_layout.py layout VL coverage, coordinate bounds, key-format match to XIIDM
test_regenerate_grid_layout.py Mercator 37 tests — projection math, key matching, cross-network consistency
test_build_pipeline.py orchestrator step selection (--steps, --from-step, --skip-osm), arg propagation, failure handling, --help
test_calibrate_thermal_limits.py XIIDM rewriter _patch_xiidm_limits regex, XML parseability, _overload_fraction counting
test_generate_n1_overloads.py N-1 reporter _get_line_limits_from_xml, module constants, CLI surface

207 passed on the non-slow subset against pypsa_eur_fr225_400.

pypsa_eur_fr225_400 dataset

Force-added (the data/ rule in .gitignore would otherwise drop it) so the canonical network ships with the repo:

  • 1196 buses · 1861 lines · 361 couplers · 2351 actions
  • 130 % N-1 peak loading (calibrated)
  • Includes actions.json, bus_id_mapping.json, grid_layout.json, line_id_names.json, n1_overload_contingencies.json, network.xiidm, osm_names.json, vl_next_node.json

Merge note

This branch is behind main by 138 non-pypsa commits; merged origin/main with -X ours so our pypsa work wins on the five overlap points (data/pypsa_eur_fr400/actions.json, data/pypsa_eur_fr400/network.xiidm, docs/data/pypsa-eur-osm-to-xiidm.md, scripts/pypsa_eur/build_pypsa_eur_network.py), and took our side on two modify/delete conflicts (scripts/convert_pypsa_to_xiidm.py, scripts/test_grid_layout.py — both moved to scripts/pypsa_eur/). Non-pypsa main changes (backend refactor, frontend tests, docs reorganization, parity scripts, code-quality gate, …) flow through unchanged.

Test plan

  • pytest scripts/pypsa_eur/ -m "not slow" — expect 207 passed
  • pytest scripts/pypsa_eur/ -m slow — expect all passing (pypowsybl-heavy, ~several minutes)
  • python scripts/pypsa_eur/build_pipeline.py --help — expect usage with --voltages, --steps, --from-step, --skip-osm, --n1-peak-pct, --min-branches
  • python scripts/pypsa_eur/build_pipeline.py --voltages 400 --steps 5 on an existing data/pypsa_eur_fr400/ — expect fresh n1_overload_contingencies.json
  • Backend smoke: load data/pypsa_eur_fr225_400/network.xiidm via the React UI, run a single contingency, confirm overloads render
  • CI green on the merged tree (no regression in the 138 upstream commits)

🤖 Generated with Claude Code

Antoine and others added 6 commits April 17, 2026 22:17
- Rewrite convert_pypsa_to_xiidm.py into 5-step pipeline with PipelineContext:
  load → network → calibrate → n1verify → metadata
  CLI options: --steps, --from-step, --skip-n1 for selective execution
- Parameterize fetch_osm_names.py with --voltages, --output-dir, --cache-from
- Add regenerate_grid_layout.py for standalone layout regeneration
- Add test_regenerate_grid_layout.py with 37 tests (Mercator math, key matching, cross-network consistency)
- Regenerate both grid_layout.json files with correct Mercator projection and VL key matching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…25_400

Move all PyPSA-EUR scripts under scripts/pypsa_eur/, add a build_pipeline.py
orchestrator that chains the five conversion steps, and extract the thermal
calibration + N-1 overload reporting into their own tools. Drop hardcoded
/home/marotant/... paths so everything works from any checkout.

Tests are consolidated behind a shared conftest.py that exposes the network,
contingency, and layout fixtures plus an expected_counts derivation — so the
suite is network-agnostic and runs against pypsa_eur_fr225_400 (new default)
or pypsa_eur_fr400 via --pypsa-network. New unit-test files exercise
build_pipeline.py, calibrate_thermal_limits.py, and generate_n1_overloads.py
without depending on the full pypowsybl stack.

pypsa_eur_fr225_400 dataset (1196 buses, 1861 lines, 361 couplers, 2351
actions, 130% N-1 peak) is force-added so the canonical network ships with
the repo.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…k-scripts

# Conflicts:
#	scripts/convert_pypsa_to_xiidm.py
#	scripts/test_grid_layout.py
Resolves ruff F541 on four f-strings without placeholders in the PyPSA-EUR
helper scripts, and adds the missing `import sys` in verify_detailed_topology
(F821) so its final `sys.exit` works.

https://claude.ai/code/session_016ovnGnHPKUJ9jxdgiZRCec
…Mh5N

Remove unnecessary f-string prefixes from static strings
@marota
marota merged commit 5ff3907 into main Apr 24, 2026
8 checks passed
marota added a commit that referenced this pull request May 5, 2026
Sixteen merged PRs (#112–#127) plus the polish landed on
``claude/interactive-overflow-analysis``. Headlined by the
interactive overflow analysis tab, the PyPSA-EUR European-wide
grid pipeline, and the design-token migration. See CHANGELOG.md
section 0.7.0 for the full entry; README badge + reference table
bumped accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants