Power Flow Overview for Developers
PowerFlows.jl solves steady-state power flow on a PowerSystems.System. The public API is built around PowerFlowEvaluationModel values (what problem to solve) and, for AC cases, an ACPowerFlowSolverType (how to solve it). See Evaluation Models vs. Solver Algorithms for that split and for the three AC formulations (ACPolarPowerFlow, ACRectangularPowerFlow, ACMixedPowerFlow).
AC solves use sparse Jacobians factorized with KLU.jl. The initial guess comes from the current bus setpoints in sys, optionally adjusted by enhanced flat start and related options on the evaluation model.
Two standalone usage modes
Most callers use one of the following patterns.
1. Solve and return results (solve_power_flow)
solve_power_flow reads injections and setpoints from sys, runs the selected evaluation model, and returns a Dict of DataFrames ("bus_results", "flow_results", and "lcc_results" when LCC HVDC is present). The System is not modified.
using PowerFlows
using PowerSystems
using PowerSystemCaseBuilder
sys = build_system(PSITestSystems, "c_sys14"; runchecks = false)
pf = ACPowerFlow()ACPolarPowerFlow{NewtonRaphsonACPowerFlow}(false, nothing, false, false, false, nothing, true, false, false, false, PowerNetworkMatrices.NetworkReduction[], 1, String[], false, false, Dict{Symbol, Any}())results = solve_power_flow(pf, sys)
results["bus_results"]| bus_number | Vm | θ | P_gen | P_load | P_net | Q_gen | Q_load | Q_net |
|---|---|---|---|---|---|---|---|---|
| Int64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 | Float64 |
| 1 | 1.06 | 0.0 | 232.55090506782906 | 0.0 | 232.55090506782906 | -15.529078407207178 | 0.0 | -15.529078407207178 |
| 2 | 1.045 | -0.08704576237894333 | 40.0 | 21.7 | 18.3 | 46.92158629034729 | 12.7 | 34.22158629034729 |
| 3 | 1.01 | -0.2223975863687207 | 0.0 | 94.19999999999999 | -94.19999999999999 | 27.136399074342837 | 19.0 | 8.136399074342837 |
| 4 | 1.0142324081898735 | -0.17900881200359442 | 0.0 | 47.8 | -47.8 | 0.0 | -3.9 | 3.9 |
| 5 | 1.017238179848024 | -0.15297200104735895 | 0.0 | 7.6 | -7.6 | 0.0 | 1.6 | -1.6 |
| 6 | 1.07 | -0.25163674129841473 | 0.0 | 11.200000000000001 | -11.200000000000001 | 21.60389347429052 | 7.5 | 14.103893474290519 |
| 7 | 1.0503437795744979 | -0.23128949300382112 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
| 8 | 1.09 | -0.2312894930038211 | 0.0 | 0.0 | 0.0 | 24.53890523566427 | 0.0 | 24.53890523566427 |
| 9 | 1.0337108965111232 | -0.2588720513851722 | 0.0 | 29.5 | -29.5 | 0.0 | 16.6 | -16.6 |
| 10 | 1.0325605999979304 | -0.262518640571551 | 0.0 | 9.0 | -9.0 | 0.0 | 5.800000000000001 | -5.800000000000001 |
| ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ | ⋮ |
For DC formulations, pass a FlowReporting mode so branch flows use the same arc basis as the rest of the package:
keys(solve_power_flow(DCPowerFlow(), sys, FlowReporting.ARC_FLOWS))KeySet for a Dict{String, Dict{String, DataFrame}} with 1 entry. Keys:
"1"2. Solve and write back into the system (solve_and_store_power_flow!)
solve_and_store_power_flow! solves the same problem and, on success, updates bus voltages, branch flows, and generator setpoints in sys. It returns true or false for convergence — useful in scripts and validation loops.
converged = solve_and_store_power_flow!(pf, sys)trueSolver tolerances and iteration limits can be passed as keyword arguments (for example tol, maxIterations); configuration such as time_steps, network_reductions, and correct_bustypes belongs on the evaluation model constructor.
Typical uses: initializing a case before export, checking AC feasibility after a scheduling step, or batch validation when you already have a System in memory.
Capabilities relevant to developers
- AC formulations — polar power balance (default), Da Costa rectangular current injection, and mixed current–power balance (
ACMixedPowerFlow). - AC solvers — Newton–Raphson, trust region, Levenberg–Marquardt; robust homotopy and gradient descent on polar only.
- DC — bus-angle DC, PTDF, and virtual PTDF; multi-period DC is supported.
- HVDC — LCC line-commutated converters on all three AC formulations; VSC/HVDC models per package tests and docs.
- Post-processing — optional reactive-power limit enforcement, PSS/e export via
PSSEExportPowerFlow, loss and voltage-stability factors (polar only).
For formulation and solver selection at scale, see How to choose an AC formulation and solver.
Power flow in the loop (PowerSimulations.jl)
There is a third integration pattern that does not call solve_power_flow from user code directly, but still exercises the same solvers inside PowerFlows.jl.
In production-cost, unit commitment, and economic-dispatch workflows, PowerSimulations.jl (PSI) can run an AC (or DC) power flow after each optimization interval while a simulation is executing. This is often called power flow in the loop (or in-the-loop PF).
How PSI wires it
- You pass a
PowerFlowEvaluationModel(for exampleACPowerFlowwith an optionalPSSEExportPowerFlowexporter) into a PSINetworkModelvia thepower_flow_evaluationkeyword. - During
build!/execute!, PSI constructs aPowerFlowDatacontainer (seemake_power_flow_containerin the source) and maps UC/ED decision variables (dispatch, load, storage, etc.) into PF injection data for each time step. - At the appropriate point in the simulation, PSI calls
solve_power_flow!on that container — the same in-place solve used internally by standalone AC solves — then copies voltages, angles, and branch flows into auxiliary variables on the optimization results (for examplePowerFlowVoltageMagnitude__ACBus,PowerFlowBranchActivePowerFromTo__Line).
So from a PowerFlows.jl maintainer's perspective, in-the-loop usage is still PowerFlowEvaluationModel + solve_power_flow! on PowerFlowData; PSI owns the scheduling, input mapping, and exposure of results to the simulation interface.
Why it matters for PF development
- Changes to residual/Jacobian setup, multi-period behavior, LCC handling, or convergence reporting can surface in PSI simulations even when standalone
solve_power_flowtests still pass. - PSI currently rejects some PF options in this path (for example network reductions on in-the-loop containers); see
check_network_reductionin PowerSimulations. - The UC stage still optimizes over its own network model (commonly PTDF); the in-loop AC solve is a post-optimization evaluation on the committed dispatch, not a feedback loop into the MILP/LP. PSI
use_slackson the network model refers to slack variables in the optimization formulation, not to AC/PTDF reconciliation.
Learn more in PowerSimulations
PSI documents the end-to-end workflow (template setup, auxiliary variables, comparing PTDF UC flows to AC in-loop flows) in its tutorial Running Power Flow In The Loop with Unit Commitment.
Standalone PF examples and formulation trade-offs remain in the Solving a Power Flow tutorial and the Explanation pages (for example Evaluation Models vs. Solver Algorithms).
Related reading
- Evaluation Models vs. Solver Algorithms
- Mixed Current-Power Balance Formulation
- Line-Commutated Converter (LCC) Implementations
- Public API — evaluation models and
solve_*entry points