Skip to content

feat: pandapower interop — IEC 60909 short-circuit + AC validation of the optimiser#13

Open
harrysalmon wants to merge 4 commits into
vfinel:developfrom
harrysalmon:feat/pandapower-interop
Open

feat: pandapower interop — IEC 60909 short-circuit + AC validation of the optimiser#13
harrysalmon wants to merge 4 commits into
vfinel:developfrom
harrysalmon:feat/pandapower-interop

Conversation

@harrysalmon
Copy link
Copy Markdown

Summary

Adds an opt-in pandapower interop layer (src/nopywer/pp_interop/) that:

  1. Converts a PowerGrid to a pandapowerNet via to_pandapower(grid) — the conversion runs once and produces a PandapowerGrid handle that subsequent calc functions reuse.
  2. Computes IEC 60909 prospective short-circuit current at every bus (compute_short_circuit) — useful for sizing breaker breaking capacity and verifying RCD/breaker trip conditions.
  3. Runs balanced AC power flow (compute_power_flow) and a side-by-side compare_with_tree_walk helper that diffs the existing analyze.py tree walk against pandapower's Newton-Raphson AC truth.

Pandapower is an optional dependency (pip install nopywer[pandapower]); import nopywer works without it. A modern extra is added for users who want pandas≥3.0 / numpy≥2.4 without pandapower (the two extras are declared as conflicting in [tool.uv] because pandapower 3.4 caps both).

Reading order for reviewers

research/pandapower/REVIEWING.md is a 25-min reader's guide with reading order, run-it-yourself recipe, and a "decisions worth pushing back on" section that pre-empts the eight design choices most likely to provoke a comment (git pin, dep floors, module name, GeoJSON schema, etc.).

The 7 numbered docs in research/pandapower/ cover background, intersection between the two domain models, porting tradeoffs, the wider opportunity menu, and the findings from running the validator on the 2025 fixture.

Headline finding

Running the validator on tests/fixtures/input_nodes.geojson (the 2025 event, 51 nodes / 50 cables) shows the tree-walk under-reports voltage drop by up to 12 percentage points at high-stress nodes:

Node Tree-walk vdrop AC vdrop Δ
glitch 26.91 % 39.09 % +12.18 pp
oasis_playground 26.52 % 38.53 % +12.01 pp
belly_town 26.17 % 37.91 % +11.74 pp

Mean voltage Δ across all 51 buses: 7.8 V; max 28 V at glitch.

The gap is one-sided (tree walk always under-reports) and grows with drop magnitude. Cause: constant-power loads at low voltage draw more current → bigger drop → more current → … The tree walk computes I at nominal V₀ and never sees the feedback. AC iterates to the equilibrium.

This is exactly the validator that PR #5's MILP optimiser docstring asks for: "validate critical layouts with a detailed power-flow check". Full write-up in research/pandapower/07_optimiser_validation_findings.md.

Commits

  1. docs(research) — 9 research docs (~1100 lines), no code.
  2. feat(pp_interop) — conversion layer + IEC 60909 short-circuit. Adds i_sc_ka field to PowerNode. SC tests.
  3. feat(pp_interop) — AC power flow + tree-walk validator. Loads in to_pandapower. End-to-end script under scripts/. PF tests.
  4. chore(deps) — pins pandapower to the merge commit of e2nIEE/pandapower#2860 which fixes a CoW/read-only bug breaking runpp under pandas≥2.3. Released 3.4.0 is one day too old; no 3.4.1 yet.

Each commit leaves the tree in a working state.

Test plan

  • uv sync --extra pandapower && uv run pytest — 44/44 pass (33 existing untouched + 11 new)
  • uv run python scripts/validate_optimiser_with_runpp.py — converges, reports the divergence above
  • uv sync --extra modern — installs cleanly without pandapower, gives pandas 3.x / numpy 2.4+
  • import nopywer works without the pandapower extra installed (lazy import inside pp_interop)
  • Existing tests unchanged — only added

What this PR does NOT do

  • No CLI flag — validation runs through the script. Folding into nopywer-analyze is a thin wrapper, deliberately deferred.
  • No frontend changes — GeoJSON gains an i_sc_ka field (default 0.0) that app.js ignores.
  • No optimiser changes — validation runs after the optimiser, doesn't feed back into it. Closing that loop is in research/pandapower/06_extended_opportunities.md.
  • No runpp_3ph (per-phase asymmetric flow). Balanced runpp is enough to demonstrate the linearisation gap. Asymmetric is opportunity §3 in the same doc.

🤖 Generated with Claude Code

Survey of how pandapower could augment nopywer's power calculations.
Six numbered docs cover the library overview, what nopywer's tree walk
actually computes, the concept-by-concept intersection, three porting
strategies with tradeoffs, references, and a wider opportunity menu.
A seventh doc records what was built for opportunity §1 (AC validation
of the optimiser) and what running it on the 2025 fixture revealed.

REVIEWING.md is a reading-order guide for whoever picks up this branch.

No code changes.
Optional feature, opt-in via `pip install nopywer[pandapower]`.

Adds a two-step pandapower interop module:

  to_pandapower(grid)               -> PandapowerGrid (the handle)
  compute_short_circuit(pp_grid)    -> {name: i_sc_ka}

PandapowerGrid bundles the pandapowerNet, name->bus_idx, and a back-ref
to the source PowerGrid for write-back. The same handle is reused
across calc functions; future ones (power flow, OPF, runpp_3ph) hang
off the same conversion.

PowerNode gains an `i_sc_ka` field (rounded, emitted in to_geojson).
All defaults and modelling assumptions live in pp_interop/config.py
(generator Sn/X''d, cable X, voltage convention, fault type).

A `modern` extra restores the original pandas>=3.0 / numpy>=2.4 floors
for users who don't want pandapower; declared as conflicting with the
pandapower extra in [tool.uv].
Adds two new entry points on top of the conversion layer:

  compute_power_flow(pp_grid)       -> PowerFlowResults (V, I per bus/line)
  compare_with_tree_walk(grid)      -> TreeWalkVsAcDiff (tree, ac, Δ)

compute_power_flow runs pp.runpp (Newton-Raphson) and returns results in
nopywer-native units (volts P-N, amps, percent). compare_with_tree_walk
runs analyze() and the AC flow side-by-side and reports per-node /
per-cable diffs, with helpers for the worst disagreement.

to_pandapower now also creates net.load entries for every consumer
(P from power_watts, Q from PF). Loads are required by runpp and are
inert for IEC 60909 calc_sc max-case (which ignores prefault load).

scripts/validate_optimiser_with_runpp.py runs the validator end-to-end
on the 2025 event fixture. Findings are written up in
research/pandapower/07_optimiser_validation_findings.md.
Pandapower 3.4.0 (released 2026-02-09) ships a bug that breaks runpp
under pandas>=2.3 with read-only numpy buffers. The fix landed in
e2nIEE/pandapower#2860 on 2026-02-10 — one day too late. No 3.4.1 yet.

Without this pin compute_power_flow is unusable. compute_short_circuit
is unaffected because calc_sc doesn't traverse the buggy code path.

Switch back to a PyPI version constraint once 3.4.1 ships. Search the
pyproject.toml comment for the PR link to find the spot.
@harrysalmon harrysalmon marked this pull request as draft May 10, 2026 19:08
Comment thread src/nopywer/pp_interop/_conversion.py
Comment thread src/nopywer/pp_interop/_conversion.py
Comment thread src/nopywer/pp_interop/_conversion.py
Comment thread src/nopywer/pp_interop/_powerflow.py
Comment thread src/nopywer/pp_interop/config.py
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.

1 participant