Sparlectra.jl MATPOWER Case Diagnostics Matrix

Date: 2026-07-14 Sparlectra versions covered: 0.7.7–0.8.9 Purpose: compact tracking table for MATPOWER import, reference-data consistency, and solver diagnostics.

Data and license note The MATPOWER case files referenced here are publicly available from the MATPOWER project or related public benchmark-data sources. This document does not redistribute those case files. It only records diagnostic observations from local Sparlectra.jl runs. MATPOWER itself is distributed under the 3-clause BSD license, but the case files included with MATPOWER may have their own origin, citation requests, or permission conditions. Before redistributing case data or derived data sets, check the header comments of the corresponding case file and the applicable MATPOWER documentation.

Non-binding diagnostic note The observations in this matrix are engineering diagnostics from specific Sparlectra.jl runs and configuration states. They are not legal advice, not a formal validation certificate, and not a legally binding assessment of the correctness, licensing status, or benchmark suitability of the referenced data sets.

This note is intended as a living diagnostic matrix. Add one row per MATPOWER case and keep the findings short.

The matrix distinguishes solver convergence failures, wrong Newton solution branches, Sparlectra import/Y-bus mismatches, and inconsistent stored MATPOWER reference data. When a large fixed-reference residual is already reproducible with a raw MATPOWER-style Y-bus using the stored VM/VA values and branch data, classify the case as a reference-data consistency diagnostic rather than as a clean solver benchmark failure.

Latest addition: case_SyntheticUSA.m in v0.8.9

case_SyntheticUSA.m is documented from a successful v0.8.9 Web UI/API-path run. The network has 82,000 buses split across three disconnected AC islands: island 1 has 70,000 buses and 88,209 active AC branches, island 2 has 10,000 buses and 12,706 active AC branches, and island 3 has 2,000 buses and 3,206 active AC branches. The case contains nine active mpc.dcline rows. Each active DC-line row is imported as two fixed terminal injections; this steady-state PF injection approximation does not create an AC branch, dummy admittance, impedance bridge, or complete HVDC control/OPF model, and it does not electrically merge the AC Y-bus components.

Validated robust profile:

power_flow:
  tol: 1.0e-5
  max_iter: 80
  autodamp: true
  autodamp_min: 0.01
  islands:
    enabled: true
    mode: solve_independent
    diagnostic_continue_after_failure: true
  start_mode:
    angle_mode: dc
    voltage_mode: profile_blend
    profile_source: matpower_reference
  qlimits:
    enabled: false
  start_current_iteration:
    enabled: false

matpower_import:
  matpower_dcline_mode: pf_injections
  auto_profile: apply

Verified result: Web UI/API status succeeded, all three islands converged, aggregate iteration count was 68, and final mismatch was approximately 5.597176064853215e-6. Island 1 used reference bus 30902 and converged in 29 iterations with final mismatch approximately 5.597176064853215e-6; island 2 promoted bus 70684 and converged in 32 iterations with final mismatch approximately 9.838130310413362e-12; island 3 promoted bus 80004 and converged in 7 iterations with final mismatch approximately 9.086420504900161e-11.

A diagnostic run with autodamp=false, Q-limits disabled, and current-iteration start disabled produced nr_nonfinite on islands 1 and 2 while island 3 converged. Use the validated autodamped profile above for reproducibility.

Merit-function line search validation and a classic/classic start anti-pattern (v0.8.14, Issue #196)

Web UI testing of power_flow.merit.enabled=true on case_SyntheticUSA.m with power_flow.autodamp_min=0.001 and start_mode.angle_mode/voltage_mode left at classic/classic (i.e. deviating from the validated profile above) produced island 1: not_converged, iterations=80, final_mismatch≈378.5 while islands 2 and 3 converged. This surfaced two things worth recording:

  1. A real pre-existing bug, now fixed: independently solved AC islands shared one performance_profile/output_dir, so fixed-name diagnostic artifacts (merit_linesearch.log, trust_region.log, current_iteration_start.log, apslf_start.log) were silently overwritten by whichever island solved last. The surviving merit_linesearch.log reflected island 3 (converged, 7 iterations), not island 1 (the one that actually failed), which initially looked like a merit-function anomaly. These artifacts are now prefixed ac_island_<id>_ during multi-island runs (e.g. ac_island_1_merit_linesearch.log), so each island's own diagnostics are preserved.
  2. Root cause of the island 1 failure, confirmed by direct A/B test: with the correctly-scoped ac_island_1_mismatch_history.csv and ac_island_1_merit_linesearch.log, the failing run shows a slow monotonic mismatch decrease for ~36 iterations, then sudden jumps (240→257 at iteration 46→47, 260→375 at iteration 55→56) — each occurring at accept_reason=fallback_conservative, accepted_alpha=0.001 (the autodamp floor), not at an armijo-accepted step. This means the merit-function acceptance criterion was not the cause; the classic autodamp fallback (pre-existing behavior, unrelated to merit) always takes a step of at least autodamp_min even when no trial improves the mismatch, and at this point in the classic/classic start trajectory the Newton direction itself had stopped being a useful local descent direction. Re-running the identical case with only start_mode.angle_mode: dc and voltage_mode: profile_blend (the validated profile above, matching Sparlectra's own matpower_import.auto_profile=recommend advice, which had recommended exactly this change and was not applied in the failing run) converged cleanly: overall iterations=76; island 1 converged in 38 iterations with a monotonic mismatch decrease from 132.7 to 1.49e-6, no jumps; islands 2 and 3 converged as before (final_mismatch≈1.3e-10 / ≈9.1e-11).

Conclusion: power_flow.merit.enabled=true is validated as working correctly on this case when combined with the recommended dc/profile_blend start profile; it is not a source of the observed non-convergence. The classic/classic start mode on this size/structure of case is an anti-pattern that should be avoided — always follow the matpower_import.auto_profile recommendation (or set auto_profile: apply) on large/fragile cases rather than leaving start_mode at its classic defaults.

case300.m classical Q-limit outer-loop diagnostic-overwrite bugs and a classic_simultaneous reference-bus cascade (v0.8.14)

Web UI testing of case300.m with a deliberately hard, flat-start profile —

power_flow:
  autodamp: false
  trust_region:
    enabled: true
    step_mode: dogleg
  qlimits:
    enforcement_mode: classic_simultaneous
  start_mode:
    angle_mode: classic
    voltage_mode: classic
  tol: 1.0e-5
  islands:
    enabled: true

— converged (iterations=20), but the console log showed six consecutive "Classical Q-limit enforcement changed reference bus" messages (internal indices 257→8→10→19→55→63→69), and trust_region.log/ac_island_1_mismatch_history.csv only showed 7–8 of the 20 total Newton iterations. This surfaced two real, now-fixed bugs and one now-corrected initial misreading:

  1. qLimitLog reset-clobbering (fixed): the classical Q-limit outer loop (_run_q_limits_matpower_outer_loop!) re-invokes the single-solve rectangular driver once per outer round. That inner driver unconditionally called resetQLimitLog!(net) on every invocation, so only a violation-free final round's (by definition empty) log ever survived — q_limit_pv_to_pq_events reported 0 even though real PV/Slack→PQ switching happened. Fixed by skipping the reset for inner classical-outer-loop calls (detected via the existing qlimit_lock_reason === :classical_outer_loop marker), so the log now correctly accumulates across rounds.
  2. Diagnostic-artifact overwrite across outer rounds (fixed): each outer round's trust_region.log/merit_linesearch.log/current_iteration_start.log/mismatch-history CSV shared one filename, so each round silently overwrote the previous round's file — the same bug class already fixed for AC islands (ac_island_<id>_ prefix), just not yet applied to the classical Q-limit outer loop. Fixed with a qlimit_outer_<n>_ diagnostic-artifact prefix per round, composing correctly with an enclosing AC-island prefix (e.g. ac_island_2_qlimit_outer_3_trust_region.log) via a try/finally restore.
  3. Reference-bus cascade, root-caused (not a bug): with the fixes in place, net.qLimitLog for this run shows 19 total PV/Slack→PQ conversions in a single outer round, six of which are the buses cited in the reference-bus-change messages. classic_simultaneous mode processes all currently-violating buses in one outer round, and _select_new_reference_bus! picks the first PV-typed bus in net.nodeVec enumeration order without checking whether that candidate is itself already flagged as violating in the same round's (pre-computed) violation list. When several buses violate simultaneously — as here — reassignment cascades through each newly-appointed reference bus until one is found that wasn't already violating. This is a real, if naive, limitation of the reassignment heuristic (in the worst case, if every PV bus is simultaneously violating, it returns :no_reference_bus_remaining), but it is not a correctness bug: the run still converges correctly.

Correction versus an initial reading: before these fixes, only the last outer round's trust_region.log was visible, showing 7 accepted dogleg steps with healthy rho (0.63–1.0), which looked like dogleg actively earning its keep. With the fix, the full picture is visible, and a direct step_mode=scaled vs. step_mode=dogleg A/B run on the identical config produces identical results: 20 total iterations and the same 19-event Q-limit switching sequence in the same order. Dogleg shows no measurable benefit on this case, because scaled does not collapse on it either — consistent with dogleg's documented framing as graceful degradation for a Newton direction that has become a poor descent direction, not a general accelerant. The reference-bus cascade itself is a classic_simultaneous-mode/_select_new_reference_bus! characteristic, independent of trust_region.step_mode.

Conclusion: do not attribute the reference-bus cascade or this case's convergence to the choice of trust_region.step_mode — both modes behave identically here. Do not read the (now-fixed) apparently-clean 7-step trust_region.log from an unpatched Sparlectra build as evidence of anything; always confirm the diagnostic artifact actually reflects the full run (check tr_step_count/q_limit_pv_to_pq_events against the total iterations reported) before drawing conclusions from a partial log on any case that goes through the classical Q-limit outer loop.

case13659pegase.m now converges: the start profile, not the step-control mode, was the blocker (v0.8.14)

Earlier verification of this case stopped at the branch-convention scan (see the case13659pegase.m row below); full NR had not been completed locally. Follow-up Web UI testing with the documented PEGASE convention (shift_unit=rad, shift_sign=-1.0, ratio=normal) but the dc/profile_blend start (the profile validated as robust for other large cases, e.g. case_SyntheticUSA.m) diverged: classic autodamp produced a "staircase" divergence (small local improvement, then a jump to a worse plateau, repeated) driven by autodamp_floor_hits=57/80 — the classic autodamp fallback always takes at least autodamp_min, even on a non-improving trial. Switching to power_flow.trust_region.step_mode=dogleg (still dc/profile_blend start) fixed the divergence — mismatch_history_trend became monotonic, no more staircase jumps — but the run still plateaued around final_mismatch≈58-60 (verified stable up to max_iter=300, not a slow-convergence artifact) and never reached tol=1e-5.

Root cause, found via the fixed-reference self-check: evaluating the mismatch at the case's own stored VM/VA operating point (start_mode.angle_mode=matpower_va, voltage_mode=all_bus_vm, start_projection=false, one Newton iteration only) gives initial_mismatch≈1.474 pu (≈147 MW/MVAr — matching the auto-profile scan's score≈1.473797 pu in the table row below) at a different set of buses than the ones dominating the dc/profile_blend divergence. The stored reference point is much closer to a real solution (147 MW residual) than where the dc/profile_blend start was landing (≈6000 MW residual at buses 2792/7003/10205/8646/6522/437/12854/3170). This means, for this specific case, the case's own stored operating point is a better Newton seed than the DC-angle/profile-blend estimate — the opposite of the general large-case guidance.

Validated profile — starting from the case's own reference instead of dc/profile_blend:

power_flow:
  tol: 1.0e-5
  max_iter: 80
  start_mode:
    angle_mode: matpower_va
    voltage_mode: all_bus_vm
    start_projection: true
  qlimits:
    enabled: false

matpower_import:
  auto_profile: off
  shift_sign: -1.0
  shift_unit: rad
  ratio: normal

With this start, plain power_flow.autodamp=true (Sparlectra's long-standing default, no merit, no trust-region) converges cleanly in 6 iterations, final_mismatch≈6.3e-11. Direct A/B comparison on the identical start:

Step controlIterationsFinal mismatch
autodamp (default)66.3e-11
merit.enabled=true66.3e-11 (bit-identical to plain autodamp — never needs to intervene)
trust_region.step_mode=scaled95.5e-7
trust_region.step_mode=dogleg95.0e-7

Conclusion: the new merit-function/trust-region options are not what fixes this case — the start profile is. dc/profile_blend (recommended for other large/fragile cases such as case_SyntheticUSA.m) is an anti-pattern here; matpower_va/all_bus_vm (using the case's own stored reference directly, undiluted by DC-angle/blend estimation) is what makes it solvable, and once solvable, plain default autodamp is both the simplest and the fastest of the options tried. Trust-region dogleg is still a genuine, separately useful result on this case: it turns the dc/profile_blend start's divergence into stable (non-converging but non-exploding) behavior, which is exactly its documented "graceful degradation" role — it is just not a substitute for fixing the start profile. Do not generalize "dc/profile_blend is the robust large-case start" beyond what has actually been validated per case; check the fixed-reference self-check (angle_mode=matpower_va, voltage_mode=all_bus_vm, max_iter=1) early when a large case's usual start profile stalls.

Latest addition: case_ACTIVSg25k.m

case_ACTIVSg25k.m now converges successfully with the strengthened Q-limit guard profile. The final documented run reports numerical_solution=OK, q_limit_active_set=OK, final_converged=true, iterations=8, pv2pq_events=2004, guarded narrow-Q PV buses=960, and compare=OK. The remaining active PV/REF Q-limit violations are zero. This confirms that the earlier failure mode was primarily a Q-limit active-set stabilization issue, not a classical Newton divergence.

Latest addition: case_ACTIVSg10k.m wrong-branch follow-up in v0.8.2

The historical ACTIVSg10k wrong-branch observation remains important, but it should now be classified as a historical solver-path issue, not as a currently reproducible natural wrong-branch case with the latest rectangular solver path.

In the current v0.8.2 checks, several default-near and degraded start configurations were tested without artificial branch-angle threshold tightening:

  • profile_blend / MATPOWER reference voltage starts converge to a healthy solution.
  • classic / classic voltage-angle starts no longer produce a formally converged wrong branch; they fail before numerical convergence with active-set instability.
  • Delayed or disabled Q-limit variants either converge to the same healthy solution or fail Q-limit validation, but do not show wrong-branch quality warnings.
  • No tested configuration with normal wrong_branch_max_branch_angle_deg = 90.0, normal shift_sign = 1.0, shift_unit = deg, and ratio = normal reproduced the old low-voltage wrong-branch solution.

The current observed healthy ACTIVSg10k branch-quality metrics are approximately:

min_vm_pu                      ≈ 0.9234 … 0.9460
max_vm_pu                      ≈ 1.0889 … 1.1087
wrong_branch_angle_spread_deg  ≈ 107.1 … 107.7
wrong_branch_worst_branch_deg  ≈ 21.75 … 22.94
wrong_branch_status            = ok

The v0.8.2 wrong-branch configuration forwarding was separately validated with a forced threshold test on the same solved case:

  • With wrong_branch_max_branch_angle_deg = 90.0, the status is ok.
  • With wrong_branch_max_branch_angle_deg = 20.0 and wrong_branch_detection = warn, the status becomes warn, reason branch_angle_exceeded, with 3 branch-angle violations.
  • With the same 20.0 threshold and wrong_branch_detection = fail, the numerical solve still converges, but the final PF status becomes wrong_branch_detected and final_converged = false.

This forced-threshold test proves that the wrong_branch_* YAML values are now forwarded into the rectangular solver and that warn/fail final-status handling works. It is not evidence that the physical ACTIVSg10k case naturally lands on a wrong branch in v0.8.2.

Case matrix

CaseSize / typeStatus in SparlectraRecommended YAML profileMain findingsCase-specific anomalies / deviationsWrong-branch riskOpen checks
case_SyntheticUSA.m82,000 buses; three disconnected AC islands; nine active mpc.dcline rowsv0.8.9 Web UI/API path succeeds with independent island solving and PF-injection DC-line import: all islands converged, aggregate iterations 68, final mismatch ≈5.597176064853215e-6. v0.8.14 re-verification with power_flow.merit.enabled=true on the same validated dc/profile_blend profile also converges cleanly: aggregate iterations 76, island 1 (70,000 buses) converges in 38 iterations from 132.7 to 1.49e-6 with no jumps; islands 2/3 converge as before.Validated robust SyntheticUSA profile documented above (now also validated with power_flow.merit.enabled=true)Active DC lines are fixed terminal P/Q injections only; no AC branch or Y-bus bridge is created. Reference buses: 30902, promoted 70684, promoted 80004.Low with autodamping. Non-autodamped diagnostic produced nr_nonfinite on islands 1 and 2. Anti-pattern (v0.8.14): leaving start_mode at classic/classic on this case (i.e. not applying the matpower_import.auto_profile=recommend advice) makes island 1 fail after 80 iterations (final_mismatch≈378.5) with the Newton direction degrading around iteration 46, regardless of power_flow.merit.enabled or autodamp_min; use dc/profile_blend as documented above.Do not redistribute the case file; keep MATPOWER/case licensing checks external.
case_ACTIVSg10k.m10,000 buses; large synthetic transmission caseCurrent v0.8.2 file-based MATPOWER runs converge to a healthy rectangular solution with profile-blend/MATPOWER-reference starts. Typical status: status=converged, numerical_converged=true, final_converged=true, final_mismatch≈5e-8 or smaller, and wrong_branch_status=ok.large_flatstart_dc_blend for robust production runs; activsg10k_wrong_branch_historical_scan only for manual diagnosticsMATPOWER import conventions confirmed: shift_sign=1.0, shift_unit=deg, ratio=normal, bus_shunt_model=admittance. Branch-shift scan strongly rejects opposite sign, radians, and reciprocal ratio. Bus shunts are required for reactive balance. Current healthy runs show approximately min_vm_pu≈0.9234…0.9460, max_vm_pu≈1.0889…1.1087, angle_spread≈107°, and worst active branch angle ≈22°.273 PV/REF buses have no online generator; fallback to BUS.VM is required. Many PV buses have Qmin=0 or Qmax=0. Large number of PV→PQ switches can occur when Q-limits are enforced. A delayed-Q-limit scan can produce converged_limits_failed due to remaining PV Q-limit violations while branch-quality metrics remain ok.Historical, not currently reproduced. An earlier classic flat-start run converged formally to a low-voltage / wrong-branch solution with `maxdVm
case_ACTIVSg25k.m25,000 buses; large ACTIVSg synthetic transmission case; 32,230 branchesRectangular NR converges with strengthened Q-limit guard. Successful run: numerical_solution=OK, q_limit_active_set=OK, final_converged=true, status=converged, iterations=8, PF time ≈74.55 s, total example runtime ≈85.11 s, final mismatch ≈4.651e-08.activsg25k_q_limit_guard + large_flatstart_dc_blendMATPOWER fixed-reference self-check is good for this size: `maxΔP≈7.118 MW,maxΔQ
case300.m300 buses; medium test caseRectangular NR converges in about 5 iterations with 3 PV→PQ switches. Final voltage magnitudes are close, but angle comparison fails mainly around the BUS_I 196 / 2040 area. v0.8.14 re-verification with a hard classic/classic flat start, autodamp=false, trust_region.enabled=true, and qlimits.enforcement_mode=classic_simultaneous also converges (iterations=20); see the dedicated subsection above.large_flatstart_dc_blend + diagnostic_import_scanThe MATPOWER fixed-reference self-check is not power-balanced around BUS_I 196 / 2040. The dominant mismatch is already reproducible with a MATPOWER-style Y-bus using the stored VM/VA values and raw branch data. Main residual: about 926.9 MW at BUS_I 2040 and BUS_I 196.Not classified as a Sparlectra Newton wrong-branch issue. The dominant mismatch appears to be caused by the stored case reference angles together with a low-reactance active branch 196 -> 2040 (x = 0.02, TAP = 1, SHIFT = 0). Treat this case as a reference-data consistency diagnostic, not as a clean pass/fail solver benchmark. v0.8.14: under classic_simultaneous Q-limit enforcement, a single outer round can cascade the reference bus through several PV buses (_select_new_reference_bus! picks naively, without checking whether the candidate is itself already violating); this is a mode characteristic, not a bug, and is independent of trust_region.step_mode (scaled and dogleg produce identical results on this case).Low for the documented run; angle-reference comparison is dominated by the stored fixed-reference inconsistency rather than a known wrong branch.Keep the fixed-reference diagnostic classification visible when updating MATPOWER comparison tolerances or profiles. Keep the explicit TAP = 1 preservation regression, but do not treat lost nominal TAP as the remaining root cause.
case145.m145 buses; medium/small test caseRectangular NR converges: converged=yes, iterations=6, pv2pq_events=1, compare status=OK.large_flatstart_dc_blend + diagnostic_import_scanNo branch-shift entries. Standard degree/radian/sign scans are irrelevant because SHIFT=0. Reciprocal ratio is rejected by diagnostics. Bus shunts are important: disabling them causes very large P/Q residuals.One relevant PV→PQ switch: BUS_I 104, where GEN.VG=1.045 differs from BUS.VM≈1.0059; after switching, comparison against imported setpoint shows dVm≈-0.03909 pu, but the hybrid compare is still within configured tolerances. Several PV buses have Qmin=0.Low in the documented run. No evidence of a wrong Newton branch; angle deviation is very small (`maxdVa
case1354pegase.m1,354 buses; PEGASE caseWith standard MATPOWER-style shift interpretation (sign=1.0, unit=deg) the compare fails. With PEGASE-style interpretation matpower_shift_sign=-1.0, matpower_shift_unit=rad, rectangular NR converges in 3 iterations with pv2pq_events=0; compare status=OK, `maxdVm≈0.00254 pu,maxdVa≈0.47247°`.pegase_shift_rad_opposite + large_flatstart_dc_blend + diagnostic_import_scan
case2869pegase.m2,869 buses; PEGASE caseWith PEGASE-style shift interpretation matpower_shift_sign=-1.0, matpower_shift_unit=rad, rectangular NR converges robustly: converged=yes, iterations=3, pv2pq_events=0, compare status=OK, `maxdVm≈0.00129 pu,maxdVa≈0.25599°`.pegase_shift_rad_opposite + large_flatstart_dc_blend + diagnostic_import_scan
case9241pegase.m9,241 buses; large PEGASE caseLatest run run_case9241pegase.m_20260515_132616.log: with opt_flatstart=true, DC-angle start, profile_blend with profile_source: matpower_reference, start projection enabled, PEGASE-style matpower_shift_sign=-1.0, matpower_shift_unit=rad, matpower_ratio=normal, and ignore_q_limits=true, rectangular NR converges: converged=yes, iterations=4, pv2pq_events=0, pv2pq_buses=0, PF time ≈10.43 s. Strict compare still fails by angle tolerance: `maxdVm≈0.02662 pu,maxdVa≈1.48863°withtol_va=0.99°; the laterstatus=OKline is only the deliberately relaxed1e9` tolerance check.pegase_shift_rad_opposite + large_flatstart_dc_blend + diagnostic_import_scan; for this diagnostic run also ignore_q_limits=true
case13659pegase.m13,659 buses; large PEGASE casev0.8.14: converges cleanly with the validated profile below — plain autodamp (default) reaches final_mismatch≈6.3e-11 in 6 iterations; see the dedicated subsection above. Superseded the earlier "full NR not completed locally" status.See the validated matpower_va/all_bus_vm profile in the subsection above; begin with Q-limits disabledBranch convention residuals strongly prefer shift_unit=rad, shift_sign=-1.0, ratio=normal: `maxΔP≈70.228 MW,maxΔQ
case1951rte.m1,951 buses; large RTE transmission caseLatest documented rectangular run after: converged=yes, iterations=6, pv2pq_events=15, pv2pq_buses=15, PF time ≈2.23 s. Final active PV Q-limit check is OK; REF/slack Q-limit diagnostic is WARN only. Strict MATPOWER compare still reports FAIL with `maxdVm≈0.01025 pu,maxdVa≈1.64992°, but the laterstatus=OKline is only the deliberately relaxed1e9` tolerance check.standard_matpower_import + large_flatstart_dc_blend + diagnostic_import_scan; keep Q-limit diagnostics enabled

YAML profiles

standard_matpower_import

Use for normal MATPOWER reference comparison when imported voltage values are trusted as start values.

opt_flatstart: false
matpower_shift_sign: 1.0
matpower_shift_unit: deg
matpower_ratio: normal
bus_shunt_model: admittance
matpower_pv_voltage_source: gen_vg
compare_voltage_reference: hybrid

large_flatstart_dc_blend

Use for large cases where a true flat start is required, but a classic flat start may converge to an unstable or historically wrong Newton branch. In the current nested YAML schema this profile uses a DC-angle start with a blended voltage start and keeps wrong-branch detection active.

power_flow:
  method: rectangular
  flatstart: true
  tol: 1.0e-5
  max_iter: 80
  autodamp: true
  autodamp_min: 0.05

  wrong_branch_detection: warn   # use fail for strict CI-style rejection
  # Maintainer decision (Issue #196): the wrong-branch rescue retry loop is
  # intentionally out of scope and will not be implemented as part of that
  # work. `wrong_branch_detection: rescue` stays a reserved mode that reports
  # `wrong_branch_rescue_not_implemented` rather than retrying. Detection
  # with full output visibility (report/CSV/console/Web UI/API metadata) plus
  # the APSLF solver as an alternative start/solve path (see
  # docs/src/external_solvers.md) are the supported mitigations for hard
  # flat-start cases.
  wrong_branch_rescue: false
  wrong_branch_min_vm_pu: 0.60
  wrong_branch_max_vm_pu: 1.30
  wrong_branch_max_angle_spread_deg: 180.0
  wrong_branch_max_branch_angle_deg: 90.0
  wrong_branch_min_low_vm_count: 1

  start_mode:
    angle_mode: dc
    voltage_mode: profile_blend
    profile_source: matpower_reference
    start_projection: false
    try_dc_start: true
    try_blend_scan: false
    branch_guard: true
    measure_candidates: true
    accept_unmeasured_dc_start: false
    reuse_import_data: true
    dc_angle_limit_deg: 60.0

matpower_import:
  shift_sign: 1.0
  shift_unit: deg
  ratio: normal
  bus_shunt_model: admittance
  pv_voltage_source: gen_vg
  compare_voltage_reference: hybrid

activsg10k_wrong_branch_historical_scan

Use only for manual diagnostics when trying to reproduce the historical ACTIVSg10k wrong-branch report. This is not a production recommendation. Current v0.8.2 tests did not find a natural wrong-branch reproducer with normal shift/ratio conventions and normal wrong_branch_* thresholds.

power_flow:
  method: rectangular
  flatstart: true
  tol: 1.0e-5
  max_iter: 90
  autodamp: false

  wrong_branch_detection: warn
  wrong_branch_min_vm_pu: 0.60
  wrong_branch_max_vm_pu: 1.30
  wrong_branch_max_angle_spread_deg: 180.0
  wrong_branch_max_branch_angle_deg: 90.0

  start_mode:
    angle_mode: classic
    voltage_mode: profile_blend
    profile_source: matpower_reference
    start_projection: false
    try_dc_start: false
    try_blend_scan: true
    branch_guard: true
    measure_candidates: true
    reuse_import_data: true

matpower_import:
  auto_profile: off
  pv_voltage_source: gen_vg
  compare_voltage_reference: hybrid
  bus_shunt_model: admittance
  shift_unit: deg
  shift_sign: 1.0
  ratio: normal

Observed v0.8.2 result with this default-near reproducer candidate:

status                         = converged
final_converged                = true
wrong_branch_status            = ok
min_vm_pu                      ≈ 0.9235
max_vm_pu                      ≈ 1.1087
wrong_branch_angle_spread_deg  ≈ 107.1
wrong_branch_worst_branch_deg  ≈ 22.94

A more degraded classic/classic voltage-angle start does not currently reproduce a converged wrong branch either; it fails before the post-convergence wrong-branch check with nr_mismatch_not_converged_active_set_unstable.

activsg10k_forced_wrong_branch_detection_test

Use only to validate that wrong-branch configuration forwarding and final-status handling work. This profile intentionally tightens the branch-angle threshold below the observed healthy worst-branch angle; it is not a physical wrong-branch reproducer.

power_flow:
  wrong_branch_detection: warn   # change to fail for final rejection
  wrong_branch_max_branch_angle_deg: 20.0

Expected current result on the healthy ACTIVSg10k solution:

warn mode:
  wrong_branch_status            = warn
  wrong_branch_reason            = branch_angle_exceeded
  wrong_branch_branch_violations = 3

fail mode:
  numerical_converged            = true
  final_converged                = false
  status                         = wrong_branch_detected
  reason                         = wrong_branch_detected

activsg25k_q_limit_guard

Use for the documented successful case_ACTIVSg25k.m run. The key point is a robust DC-angle/blended-voltage flat start with start projection disabled, plus a strong Q-limit guard for zero/narrow-Q PV buses and PV buses whose calculated Q violates limits after the first eligible Q-limit check. Use tol: 1.0e-5 for large benchmark validation unless strict validation is explicitly requested.

opt_flatstart: true
flatstart_angle_mode: dc
flatstart_voltage_mode: profile_blend
profile_source: matpower_reference
start_projection: false
start_projection_try_blend_scan: false
start_projection_try_dc_start: true
start_projection_dc_angle_limit_deg: 70.0
start_projection_blend_lambdas:
  - 0.1
  - 0.25
  - 0.5
  - 0.75

autodamp: true
autodamp_min: 0.05
max_ite: 80
tol: 1.0e-5

ignore_q_limits: false
qlimit_start_iter: 3
qlimit_start_mode: iteration_or_auto
qlimit_auto_q_delta_pu: 0.0001
q_hyst_pu: 0.01
cooldown_iters: 1

qlimit_guard: true
qlimit_guard_min_q_range_pu: 0.02
qlimit_guard_zero_range_mode: lock_pq
qlimit_guard_narrow_range_mode: lock_pq
qlimit_guard_violation_mode: lock_pq
qlimit_guard_violation_threshold_pu: 0.0001
qlimit_guard_max_switches: 3
qlimit_guard_freeze_after_repeated_switching: true
qlimit_guard_accept_bounded_violations: false
qlimit_guard_max_remaining_violations: 0
qlimit_guard_log: true

matpower_shift_sign: 1.0
matpower_shift_unit: deg
matpower_ratio: normal
bus_shunt_model: admittance
matpower_pv_voltage_source: gen_vg
compare_voltage_reference: imported_setpoint

pegase_shift_rad_opposite

Use for PEGASE cases where the branch-shift scan indicates that the stored shift values behave like radians with opposite sign.

matpower_shift_sign: -1.0
matpower_shift_unit: rad
matpower_ratio: normal
bus_shunt_model: admittance
matpower_pv_voltage_source: gen_vg
compare_voltage_reference: hybrid

pegase9241_reference_diagnostic

Use for the documented case9241pegase.m diagnostic runs while isolating import/reference consistency effects before enabling Q-limit behaviour again. The latest log used a DC-angle/blended flat start with start projection.

opt_flatstart: true
flatstart_angle_mode: dc
flatstart_voltage_mode: profile_blend
profile_source: matpower_reference
start_projection: true
start_projection_try_blend_scan: false
start_projection_try_dc_start: true
ignore_q_limits: true
matpower_shift_sign: -1.0
matpower_shift_unit: rad
matpower_ratio: normal
bus_shunt_model: admittance
matpower_pv_voltage_source: gen_vg
compare_voltage_reference: hybrid
diagnose_matpower_reference: true
diagnose_branch_shift_conventions: true
diagnose_pv_voltage_references: true
show_diff: true
log_effective_config: true

diagnostic_import_scan

Use when checking whether deviations originate from import conventions rather than the Newton solver.

diagnose_matpower_reference: true
diagnose_branch_shift_conventions: true
diagnose_pv_voltage_references: true
show_diff: true
log_effective_config: true

Diagnostic classification notes

Use the following short labels in the case matrix where useful:

LabelMeaning
okSolver result and reference comparison are within the configured tolerances.
wrong_branch_riskNewton may converge formally but to an implausible low-voltage or wrong-branch solution.
reference_data_inconsistentThe stored MATPOWER VM/VA reference is not power-balanced against the imported branch data in the fixed-reference self-check.
import_convention_openSHIFT, TAP, ratio, shunt, or voltage-reference conventions still need verification.
pv_limit_sensitiveResult depends materially on PV→PQ switching, Q-limit hysteresis, or zero/near-zero Q limits.
relaxed_compare_onlyA later comparison with artificially huge tolerances, such as 1e9, is only a diagnostic sanity check and must not be counted as a real pass.
pegase_shift_rad_oppositePEGASE-style shift interpretation appears necessary: matpower_shift_sign=-1.0, matpower_shift_unit=rad.
ref_slack_q_warnRemaining Q-limit violation is on the REF/slack bus only and is reported as WARN by default.
final_pq_after_qlimitBus was originally PV but switched to PQ due to Q-limits; its original PV voltage setpoint is no longer enforced.
qlimit_guard_stabilizedQ-limit guard pre-locking and/or violation locking stabilizes many zero/narrow-Q PV buses and allows the active set to converge.
compact_console_neededRun is technically successful, but console output is too verbose; detailed diagnostics should remain in the logfile.
historical_wrong_branch_not_reproducedA previously observed wrong-branch or low-voltage branch remains documented, but current solver/config scans no longer reproduce it naturally.
forced_wrong_branch_detection_testThe threshold is intentionally tightened to validate wrong-branch forwarding/final-status handling; this is not a physical wrong-branch reproducer.

Notes for extending this table

Keep each row short. Prefer numeric evidence over prose:

  • convergence status and iteration count,
  • maximum voltage magnitude deviation,
  • maximum angle deviation,
  • number of PV→PQ switches,
  • number of PV/REF buses without online generators,
  • whether zero Q-limits occur,
  • whether a classic flat start can enter a second Newton solution branch,
  • whether the branch-shift scan indicates a non-standard convention.