Skip to content

SLD readability & loading coherence on PyPSA grids (3 fixes)#180

Merged
marota merged 2 commits into
mainfrom
claude/pypsa-sld-diagram-display-g0y5ez
Jul 1, 2026
Merged

SLD readability & loading coherence on PyPSA grids (3 fixes)#180
marota merged 2 commits into
mainfrom
claude/pypsa-sld-diagram-display-g0y5ez

Conversation

@marota

@marota marota commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Summary

Three coordinated fixes for the Single Line Diagram on PyPSA-EUR grids, where equipment carries both a raw IIDM id (relation_8423569-225) and a friendly operator name (MARSIL61PRAGN). These changes make the SLD honest and readable while fixing overload-halo visibility and explaining the physics of half-open lines.

Key Changes

1. Feeders labelled by far-end voltage level (Issue 1)

  • Backend: Added build_feeder_labels(network, vl_id) in sld_render.py that returns {equipment_id: {name, other_vl, label}} for every line/2-winding transformer touching a voltage level
    • label = far-end VL friendly name, disambiguated with 1-based index for parallel circuits (LANNEMEZAN 225kV 1 / … 2)
    • Falls back to branch's own friendly name, then to raw id (preserves readability on non-PyPSA grids)
    • Includes helper _vl_name_map() and _collect_vl_branches() with defensive exception handling
  • Frontend: New hook useSldFeederRelabel + utility applyFeederRelabels() in utils/svg/feederLabels.ts that swaps matching <text> content, idempotently restoring on tab/VL switch
  • Tests: Comprehensive test suite in test_feeder_labels.py covering single/parallel branches, unnamed far-ends, and fallback logic

2. Overload halo now visible on extremity SLD (Issue 2)

  • Root cause: Overload names arrive as grid2op/operator friendly names (MARSIL61PRAGN) but SLD cells are keyed by IIDM id (relation_8423569-225) — direct lookup missed
  • Solution: New utilities buildFriendlyToEquip() and overloadCandidates() in feederLabels.ts bridge friendly name → IIDM id via the feeder_labels map
  • Frontend: Updated SldOverlay.tsx overload-highlight pass to resolve through the bridge before findCellForEquipment, with fallback to raw value (covers id-keyed overload lists)
  • Tests: Added test cases in SldOverlay.test.tsx verifying halo lands on correct feeder when friendly name is mapped

3. Annotate charging-current loading of half-open lines (Issue 3)

  • Backend: New build_half_open_reactive(network) in simulation_helpers.py returns {branch_id_or_name: live_end_reactive_mvar} for lines/transformers open at exactly one terminal
    • Physically correct: a line open at one end is out of service for active power (p ≈ 0) but its capacitance draws reactive charging current from the live end
    • Current-based loading rho reads non-zero (e.g. ~33%) — not a bug, but easy to misread as residual overload
    • Keys cover both IIDM id and friendly name for grid2op lookup
  • Backend: New half_open_overload_notes() in simulation_helpers.py gates annotation to lines still "overloaded" (loading > ~1%) after action, returning reactive power for UI explanation
  • Backend: New half_open_branch_reactive_from_obs() in simulation_helpers.py reads post-action variant via network manager, with proper variant restoration
  • Frontend: Updated ActionCard.tsx to display annotation when half_open_overloads present, explaining the loading as charging current
  • Types: Added half_open_overloads?: Record<string, number> to ActionDetail interface
  • Tests: New test file test_half_open_overload.py covering variant switching, reactive power extraction, and annotation gating

Implementation Details

  • Defensive exception handling: All new backend functions grac

https://claude.ai/code/session_01TXqGodvLG69petEgm4GPrR

claude added 2 commits June 30, 2026 13:19
Three related fixes for the SLD overlay on the PyPSA-EUR grids, where
equipment carries both a raw IIDM id (relation_8423569-225) and a friendly
operator name (MARSIL61PRAGN):

1. Feeders labelled by the far-end voltage level. Every SLD endpoint now
   returns a `feeder_labels` map (build_feeder_labels) and the frontend
   relabels each branch feeder with the name of the VL at the OTHER end of
   the line (e.g. "MARSILLON 225kV") instead of the raw IIDM branch id,
   keeping a 1/2 index for parallel circuits. Falls back to the branch's own
   name, then the raw id, so already-readable grids are untouched.

2. Overload halo on the extremity SLD. The N-1 overload halo was missing
   because the overload list uses grid2op friendly names while the SLD cells
   are keyed by IIDM id; the feeder_labels `name` now bridges the two so the
   halo lands on the right feeder.

3. Disconnected-overload loading coherence. When an action disconnects the
   overloaded line itself, the card showed a stale grid2op loading (e.g.
   33 %) while the SLD/NAD correctly drew zero flow. compute_action_metrics
   now reads connectivity from the post-action pypowsybl variant
   (build_branch_connectivity / disconnected_branch_names_from_obs) and
   reports 0 % for disconnected branches, so card and diagrams agree.

The two large SLD label passes (feeder relabel + injection name buttons)
were extracted into hooks/utils to keep SldOverlay under the LoC ceiling.

Tests: feeder labels, branch connectivity, disconnected-overload zeroing
(backend); feeder relabel + friendly-name overload halo (frontend).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TXqGodvLG69petEgm4GPrR
Follow-up to the SLD readability work. The "33% loading after disconnecting
the overloaded line" turned out NOT to be a bug: reproducing the exact
scenario against expert_op4grid_recommender's PypowsyblObservation on the
real grid showed the line, once opened at one end, carries i1≈43A with
q1≈-16.8 MVAr and p1=0 — i.e. real reactive CHARGING current of a line whose
capacitance stays energised from the live end. rho = 43/130 ≈ 33% is
therefore physically correct; the diagrams just show active power (p=0).

So instead of suppressing the value we keep it and explain it:

- Revert the compute_action_metrics zeroing and its build_branch_connectivity
  / disconnected_branch_names_from_obs helpers.
- Add build_half_open_reactive / half_open_branch_reactive_from_obs /
  half_open_overload_notes: for a still-"overloaded" line left open at one
  end with loading >1%, capture the live-end reactive power (MVAr).
- simulate_manual_action attaches it as `half_open_overloads` on the result
  (serialized + carried through the save/reload triad).
- ActionCard annotates the loading: "open one end · 16.8 MVAr capacitive",
  with a tooltip explaining it is charging current, not real flow.

The recommender library is correct and was left unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TXqGodvLG69petEgm4GPrR
@marota marota merged commit c3f9c00 into main Jul 1, 2026
9 of 10 checks passed
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