Skip to content

Match PSS(e) zero-impedance branch handling (per-branch L2 norm)#329

Open
luke-kiernan wants to merge 4 commits into
mainfrom
fix/zibr-per-branch-l2
Open

Match PSS(e) zero-impedance branch handling (per-branch L2 norm)#329
luke-kiernan wants to merge 4 commits into
mainfrom
fix/zibr-per-branch-l2

Conversation

@luke-kiernan

@luke-kiernan luke-kiernan commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Fixes items 1 and 2 of #322.

Problem

ZeroImpedanceBranchReduction's get_reduction scanned the assembled Ybus
off-diagonals and merged a bus pair only when
real(Y[i,j]) == 0 && abs(imag(Y[i,j])) >= susceptance_threshold, diverging from
PSS(e):

  1. L2 norm. The iszero(real(Y)) gate skipped near-shorts with a small
    resistive part. PSS(e) uses abs(y) >= threshold.
  2. Per-branch, not summed. PSS(e) examines each branch; we examined the
    combined parallel entry, so a single near-zero-impedance branch hidden by an
    anti-parallel member that cancels it in the sum was not merged.

Change

get_reduction now iterates the direct and parallel branch maps and tests each
branch's series admittance. An arc is treated as zero-impedance when either
some individual non-transformer branch clears the threshold (PSS(e)'s per-branch
L2 rule — fixes items 1 & 2) or the combined off-diagonal entry clears it.
Item 3 (two sub-threshold branches whose sum clears the threshold) is left
merging via the combined term, pending confirmation of PSS(e)'s behavior
there.

The merge arc_key is read directly as the branch-map key (identical to the old
reverse-lookup), so removed_arcs and the merge maps are unchanged. The loop
iterates only the direct and parallel maps; it no longer consults
series_branch_map, which is empty when ZIBR runs (it is always the first
reduction).

Tests

  • Regression tests for items 1, 2, 3, and the all-below-threshold case.
  • MATPOWER (makeYbus, unreduced) and the Eastern PSS(e) export (no
    zero-impedance section) are compared against the unreduced PNM matrix
    (susceptance_threshold = Inf); the other PSS(e) cases keep their
    zero-impedance groups and still validate that PNM matches PSS(e)'s merges.

🤖 Generated with Claude Code

Fixes items 1 and 2 of #322. ZIBR `get_reduction` previously scanned the
assembled Ybus off-diagonals and merged a bus pair only when
`real(Y[i,j]) == 0 && abs(imag(Y[i,j])) >= threshold`. This diverged from
PSS(e):

  1. It gated on `iszero(real(Y))` instead of the L2 norm `abs(Y)`, so a
     near-short with a small resistive part was skipped.
  2. It tested the *summed* parallel-branch entry, so a single near-zero-
     impedance branch (e.g. 1e4im) hidden by an anti-parallel member that
     cancels it in the sum (e.g. -10im) was not merged.

Rework `get_reduction` to iterate the direct and parallel branch maps (the
only arc sources at ZIBR time, the first reduction) and test each branch's
series admittance. An arc merges when either any individual non-transformer
branch clears the threshold (PSS(e)'s per-branch rule) or the combined entry
does (item 3 — kept as the numerically robust coupling measure, since whether
PSS(e)/correctness wants a merge there is unresolved). The union is a superset
of the old combined-only test, so item 3 behavior is unchanged.

The merge `arc_key` is now obtained directly as the branch-map key rather than
reverse-looked-up from Ybus indices via `_find_zero_impedance_arc_key`; the
tuple is identical, so `removed_arcs` and the merge maps are unchanged. This
also drops the `_build_transformer_arc_set` scan, with transformer exclusion
kept via `_is_transformer`/`_any_transformer`.

Adds regression tests for items 1, 2, 3, and the all-below-threshold case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates ZeroImpedanceBranchReduction (ZIBR) to more closely match PSS(e) by detecting zero-impedance merges using per-branch admittance magnitude (L2 norm), while still optionally merging based on the combined off-diagonal coupling for parallel groups.

Changes:

  • Reworks ZIBR detection to iterate direct/parallel branch maps and apply per-branch abs(y) >= threshold logic (plus a combined-entry fallback for parallel groups).
  • Updates ZIBR documentation to reflect the new per-branch + combined-entry criteria.
  • Adds regression tests covering near-short cancellation in parallel groups, combined-entry-only merges, and L2 detection with nonzero resistance.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/apply_zero_impedance_reduction.jl Implements per-arc/per-branch ZIBR detection and merge logic.
src/zero_impedance_branch_reduction.jl Updates docstring/spec to describe the revised ZIBR rule.
test/test_ybus_reductions.jl Adds targeted regression tests for the updated ZIBR behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/apply_zero_impedance_reduction.jl Outdated
Comment thread src/apply_zero_impedance_reduction.jl
@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

Performance Results

Precompile Time

Main This Branch Delta
2.1 s 2.1 s -0.2%

Execution Time

Cells show median (min–max) over 5 samples; delta compares medians.

Test Main This Branch Delta
matpower_ACTIVSg2000_sys-Build Ybus 9.1 (8.8–10.6) ms 9.3 (9.3–10.0) ms +3.2%
matpower_ACTIVSg2000_sys-Build PTDF 69.2 (68.6–69.6) ms 70.3 (69.3–71.1) ms +1.7%
matpower_ACTIVSg2000_sys-Build LODF 140.1 (139.1–144.2) ms 140.0 (139.8–143.4) ms -0.1%
matpower_ACTIVSg2000_sys-Build VirtualMODF 102.8 (101.5–105.3) ms 1.1 (1.1–1.1) s +986.3%
matpower_ACTIVSg2000_sys-VirtualMODF Query 10 rows 0.6 (0.5–1.2) ms 0.6 (0.6–1.3) ms +4.7%
matpower_ACTIVSg2000_sys-Radial network reduction 0.7 (0.7–0.9) ms 0.8 (0.7–1.0) ms +7.3%
matpower_ACTIVSg2000_sys-Degree two network reduction 0.8 (0.8–1.2) ms 0.8 (0.8–1.3) ms +2.0%
Base_Eastern_Interconnect_515GW-Build Ybus 500.3 (492.7–507.4) ms 632.1 (628.7–654.0) ms +26.4%
Base_Eastern_Interconnect_515GW-Build VirtualPTDF 724.2 (721.1–741.4) ms 853.2 (851.5–859.0) ms +17.8%
Base_Eastern_Interconnect_515GW-VirtualPTDF Query 10 rows 21.5 (21.1–22.2) ms 21.7 (21.6–22.6) ms +0.8%
Base_Eastern_Interconnect_515GW-Build VirtualMODF 726.4 (721.8–732.4) ms 948.3 (944.5–948.7) ms +30.5%
Base_Eastern_Interconnect_515GW-VirtualMODF Query 10 rows 26.0 (25.5–26.6) ms 26.6 (26.0–27.2) ms +2.3%
Base_Eastern_Interconnect_515GW-Radial network reduction 31.3 (31.1–32.7) ms 31.2 (30.9–32.4) ms -0.5%
Base_Eastern_Interconnect_515GW-Degree two network reduction 43.1 (42.7–43.7) ms 42.8 (42.2–43.5) ms -0.8%

Per CoPilot review on #329: the merge predicate called `ybus_branch_entries`,
re-emitting its `r == x == 0` warning (assembly already emitted it) and
rebuilding the 2x2; and the parallel combined term used
`ybus_branch_entries(group, nr)`, which ignores `min_x_eps`. Compute
`Y_l = 1/(r + x im)` directly from `(r, x)` with the same `min_x_eps`
substitution, and form the combined entry as `sum(Y_l)` (members are symmetric).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@luke-kiernan

luke-kiernan commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator Author

2 comments:

  1. Test failures. I'm guessing they're tests I need to adjust for changed behavior, not actual bugs, but will look into it.
  2. Performance: ~50% longer ybus build time on both the EI and the 2k test system. Current implementation is doing structural insertions on the assembled sparse matrix (slow)--fixable, but requires more restructuring. Opening a stacked PR for it.

edit: first round of behavioral changes fixed

luke-kiernan and others added 2 commits June 18, 2026 13:24
The per-branch L2 criterion now merges zero-impedance branches that the old
`iszero(real(Y))` gate skipped (e.g. 228 buses on CATS), so the default Ybus no
longer matches MATPOWER's `makeYbus`, which does no bus merging. Disable the
auto-applied ZeroImpedanceBranchReduction (susceptance_threshold = Inf) in the
MATPOWER comparison tests so they validate raw assembly against an unreduced
baseline; bus-merging behavior is covered in test_ybus_reductions.jl.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Base_Eastern_Interconnect_515GW PSS(e) export has no "ZERO IMPEDANCE LINE
CONNECTED BUSES" section, so its baseline is unreduced. The per-branch L2
criterion now merges 28 low-impedance branches PSS(e) left in place here, so
build with susceptance_threshold = Inf to compare unreduced matrices. The other
PSS(e) cases do list zero-impedance groups and still validate that PNM matches
PSS(e)'s merges, so they are left unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@luke-kiernan luke-kiernan force-pushed the fix/zibr-per-branch-l2 branch from 4b86712 to c919d37 Compare June 18, 2026 22:08
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