Skip to content

hybrid cpb formulation#372

Merged
jd-lara merged 21 commits into
mainfrom
jd/hybrid-cpb-formulation
May 19, 2026
Merged

hybrid cpb formulation#372
jd-lara merged 21 commits into
mainfrom
jd/hybrid-cpb-formulation

Conversation

@jd-lara
Copy link
Copy Markdown
Member

@jd-lara jd-lara commented May 17, 2026

@luke-kiernan after looking at the LM performance with the rectangular model I realized that there were structural weaknesses to LM with rectangular.

Long story short, I added a mixed formulation that uses Rectangular in PQ buses and Polar on PV buses which performs really well with LM and the other solvers too.

This PR also adds proper scaling optionality to LM to make it not as bad for rectangular and protections.

I also asked Claude to document the formulation as well as make a script to benchmark and add notes on model and solver selector.

overall is a long PR but a step forward on the search for improved algorithmic and moiling efficiencies in PF.

This PR also fixes a broken test in main from #370

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Introduces a third AC power flow formulation — ACMixedPowerFlow (Mixed Current-Power Balance, MCPB) — that uses divided current balance at PQ buses and power balance + |V|² constraint at PV buses in rectangular (e, f) coordinates. Adds optional Marquardt diagonal column scaling to the Levenberg–Marquardt solver (defaulting on for rectangular, off for polar), hardens the rectangular CI residual/Jacobian with a V_FLOOR2 = 1e-16 floor on |V|², extends voltage-magnitude validation to rectangular/mixed via squared-magnitude checks, ships extensive parity/jacobian/flat-start/LCC tests against polar and rectangular references, and adds tutorial/explanation docs plus a benchmark script.

Changes:

  • New MCPB formulation (ACMixedPowerFlow, residual, Jacobian, setup, finalize) wired through improve_x0, initialize_power_flow_variables, NR/TR/LM/Iwamoto step paths, and finalize.
  • LM workspace gains D/marquardt_scaling, with formulation-dispatched default; LM driver accepts marquardt_scaling and re-scales each iteration.
  • Rectangular CI residual/Jacobian floored by V_FLOOR2; new _validate_squared_voltage_magnitudes dispatched for rect and mixed.

Reviewed changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/PowerFlows.jl Export ACMixedPowerFlow; include the three new MCPB source files.
src/power_flow_types.jl New ACMixedPowerFlow{ACSolver} struct + constructor with solver-type validation; LM docstring documents marquardt_scaling.
src/power_flow_setup.jl improve_x0 overload and initialize_power_flow_variables for MCPB; union-widened helpers; shared _enhanced_flat_start covers both rect and mixed layouts.
src/power_flow_method.jl Union-widens step/finalize/validation helpers to accept MCPB residual/Jacobian; new _finalize_formulation! for mixed; rect/mixed _validate_state_magnitudes.
src/mixed_cpb_setup.jl Offsets, fill/initial-state, update-data round-trip, and post-convergence mixed_finalize_bus_injections! (raw-Y matvec + LCC self-admittance).
src/mixed_cpb_power_flow_residual.jl ACMixedCPBResidual with shared state caches, imag-first PQ rows, eq.7/eq.8 PV rows, REF rect-verbatim, LCC tail.
src/mixed_cpb_power_flow_jacobian.jl ACMixedCPBJacobian with structure builder, constant-Yb PQ block fill, per-iteration diagonal + PV off-diagonal + slack + LCC updates via nzval caches.
src/levenberg-marquardt.jl Adds D and marquardt_scaling to LMWorkspace; update_column_scale!, per-iteration √λ·D damping, formulation-dispatched default.
src/rectangular_ci_power_flow_residual.jl V_FLOOR2 floor on `
src/rectangular_ci_power_flow_jacobian.jl Matching V_FLOOR2 floors in PQ/PV/REF diagonal blocks and slack cross-terms.
src/common.jl New _validate_squared_voltage_magnitudes for rect/mixed layouts.
src/definitions.jl Defines V_FLOOR2 = 1e-16.
test/test_mixed_cpb_*.jl (5 files) Type validation, setup round-trip, residual zero-at-polar, Jacobian structure + FD + alloc + driver wiring, LCC residual zero, polar/rect parity matrix incl. NR/TR/LM, flat-start coverage.
test/test_rectangular_ci_power_flow.jl LM scaling option tests, squared-magnitude validation, V_FLOOR2 degeneracy guard.
test/test_solve_power_flow.jl Comment/testset rename "Hybrid"→"Mixed".
test/performance/performance_test.jl Adds MCPB solver variants and grouped per-formulation reporting.
scripts/benchmarks/formulation_solver_comparison.jl New 3×3 formulation×solver benchmark script.
docs/make.jl, docs/src/explanation/mixed_cpb_formulation.md, lm_vs_gauss_seidel.md, tutorials/solving_a_power_flow.jl Doc additions describing MCPB and LM-vs-GS positioning + selection table.

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

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 17, 2026

Performance Results

Precompile Time

Main This Branch Delta
2.444 s 2.455 s +0.5%

Solve Time

Polar AC

Test Main This Branch Delta
NewtonRaphsonACPowerFlow First Solve 11.403 s 11.47 s +0.6%
NewtonRaphsonACPowerFlow Second Solve 81.2 ms 242.2 ms +198.1%
RobustHomotopyPowerFlow First Solve 16.82 s 16.182 s -3.8%
RobustHomotopyPowerFlow Second Solve 8.596 s 8.624 s +0.3%
NewtonRaphsonACPowerFlow(iwamoto) First Solve 198.3 ms 194.9 ms -1.7%
NewtonRaphsonACPowerFlow(iwamoto) Second Solve 509.1 ms 217.2 ms -57.3%
TrustRegionACPowerFlow(iwamoto) First Solve 1.652 s 1.806 s +9.3%
TrustRegionACPowerFlow(iwamoto) Second Solve 529.8 ms 79.1 ms -85.1%

Rectangular CI

Test Main This Branch Delta
ACRectangularPowerFlow{NR} First Solve 4.957 s 5.008 s +1.0%
ACRectangularPowerFlow{NR} Second Solve 497.6 ms 47.4 ms -90.5%
ACRectangularPowerFlow{NR}(iwamoto) First Solve 154.7 ms 163.4 ms +5.6%
ACRectangularPowerFlow{NR}(iwamoto) Second Solve 38.1 ms 39.9 ms +4.8%
ACRectangularPowerFlow{TR} First Solve 5.368 s 5.576 s +3.9%
ACRectangularPowerFlow{TR} Second Solve 39.7 ms 40.2 ms +1.4%
ACRectangularPowerFlow{TR}(iwamoto_fallback) First Solve 178.0 ms 158.2 ms -11.1%
ACRectangularPowerFlow{TR}(iwamoto_fallback) Second Solve 39.7 ms 40.0 ms +0.7%

Mixed CPB

Test Main This Branch Delta
ACMixedPowerFlow{NR} Solve FAILED N/A N/A
ACMixedPowerFlow{NR}(iwamoto) Solve FAILED N/A N/A
ACMixedPowerFlow{TR} Solve FAILED N/A N/A
ACMixedPowerFlow{TR}(iwamoto_fallback) Solve FAILED N/A N/A
ACMixedPowerFlow{LM} Solve FAILED N/A N/A
ACMixedPowerFlow{NR} First Solve N/A 5.236 s N/A
ACMixedPowerFlow{NR} Second Solve N/A 41.6 ms N/A
ACMixedPowerFlow{NR}(iwamoto) First Solve N/A 160.9 ms N/A
ACMixedPowerFlow{NR}(iwamoto) Second Solve N/A 41.3 ms N/A
ACMixedPowerFlow{TR} First Solve N/A 5.043 s N/A
ACMixedPowerFlow{TR} Second Solve N/A 42.6 ms N/A
ACMixedPowerFlow{TR}(iwamoto_fallback) First Solve N/A 161.7 ms N/A
ACMixedPowerFlow{TR}(iwamoto_fallback) Second Solve N/A 59.0 ms N/A
ACMixedPowerFlow{LM} First Solve N/A 6.986 s N/A
ACMixedPowerFlow{LM} Second Solve N/A 535.4 ms N/A

DC

Test Main This Branch Delta
DCPowerFlow First Solve 5.171 s 4.78 s -7.6%
DCPowerFlow Second Solve 15.3 ms 14.7 ms -3.9%
PTDFDCPowerFlow First Solve 1.711 s 1.75 s +2.3%
PTDFDCPowerFlow Second Solve 68.5 ms 76.4 ms +11.6%
vPTDFDCPowerFlow First Solve 5.265 s 5.256 s -0.2%
vPTDFDCPowerFlow Second Solve 3.37 s 3.411 s +1.2%

Copy link
Copy Markdown
Collaborator

@luke-kiernan luke-kiernan left a comment

Choose a reason for hiding this comment

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

First pass. Big 2 comments:

  1. Redundant offset/block size logic for the CBP method.
  2. Test correctness of the CBP Jacobian by looking at asymptotic agreement with finite differences to the expected order.

Fix those and I'll take another look.

Comment thread src/ac_power_flow_residual.jl
Comment thread src/common.jl
Comment thread src/levenberg-marquardt.jl Outdated
Comment thread src/mixed_cpb_power_flow_jacobian.jl Outdated
Comment thread src/mixed_cpb_power_flow_residual.jl
Comment thread test/test_mixed_cpb_jacobian.jl Outdated
Comment thread test/test_mixed_cpb_jacobian.jl Outdated
Comment thread src/mixed_cpb_power_flow_jacobian.jl
@luke-kiernan
Copy link
Copy Markdown
Collaborator

luke-kiernan commented May 18, 2026

    # uniformly 2; vector kept for signature parity with the rectangular formulation
    fill!(block_sizes, Int8(2))
    pos = REC_INDEX_TYPE(1)
    for i in 1:n_buses
        offsets[i] = pos
        pos += REC_INDEX_TYPE(2)
    end

Oh, so maybe leaving the offsets/block sizes was purposeful? I question the wisdom of this: as-is, I'd be pleasantly surprised if these constants were propagated by the compiler to their fullest extent.

If the goal is inter-operability (being able to write code that works for both CBP and CI), then just make getters and multiple-dispatch: get_block_size returns block_size[i] for rectangular CI, 2 for CBP.

@jd-lara jd-lara requested a review from luke-kiernan May 18, 2026 22:33
Copy link
Copy Markdown
Collaborator

@luke-kiernan luke-kiernan left a comment

Choose a reason for hiding this comment

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

The one thing I'd like fixed here is the x0 = keyword argument, for overriding the "improve initial guess" stuff.

Comment thread src/ac_power_flow_residual.jl
Comment thread src/mixed_cpb_power_flow_jacobian.jl Outdated
Comment thread src/power_flow_setup.jl
Comment thread test/test_mixed_cpb_jacobian.jl
Comment thread test/test_mixed_cpb_jacobian.jl Outdated
@jd-lara jd-lara requested a review from luke-kiernan May 19, 2026 05:08
Copy link
Copy Markdown
Collaborator

@luke-kiernan luke-kiernan left a comment

Choose a reason for hiding this comment

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

One misleading comment, but that's it.

# PERF: have not investigated other factorization methods. SPQR does not allow
# for in-place updates or re-use of symbolic factorization, but with non
# square matrices--J^T J form is more unstable--we don't have a lot of options.
# SPQR: enables a cached symbolic factorization with in-place numeric
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wait, you figured out a way to reuse the symbolic factorization?! When I asked Claude about that a while back, it told me that SPQR simply didn't allow for separate symbolic vs numeric factorization.

Edit: Oh. We're recomputing the whole thing--ws.F = LinearAlgebra.qr(ws.A)--and this comment is just wrong.

@jd-lara jd-lara merged commit 66222f9 into main May 19, 2026
7 checks passed
@jd-lara jd-lara deleted the jd/hybrid-cpb-formulation branch May 19, 2026 17:18
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.

3 participants