Optimal Power Flow (OPF)
GAT provides a four-tier solver hierarchy for optimal power flow, from sub-millisecond economic dispatch to production-grade nonlinear optimization. Each tier offers a different accuracy/speed tradeoff, letting you choose the right tool for each task.
Validated Performance: GAT's IPOPT AC-OPF solver achieves <0.01% gap across all 68 PGLib-OPF benchmark cases, matching reference objectives exactly. See the complete benchmark results for details.
Choosing the Right Solver
Speed vs. Accuracy Tradeoff
Fast βββββββββββββββββββββββββββββββββββββββββββΊ Accurate
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β ED β β DC-OPF β β SOCP β β AC-OPF β
β < 1ms β β ~10ms β β ~100ms β β ~1s β
β No network β β LP approx β β Convex relaxβ β Full NLP β
βββββββββββββββ βββββββββββββββ βββββββββββββββ βββββββββββββββ
β β β β
βΌ βΌ βΌ βΌ
Feasibility N-1 screening Production Final
checks Planning studies dispatch validation
Quick Reference
| Tier | Command | Speed | Accuracy | Best For |
|---|---|---|---|---|
| 1 | gat opf ed | < 1ms | ~20% gap | Feasibility checks, generation scheduling |
| 2 | gat opf dc | ~10ms | ~3-5% gap | N-1 screening, transmission planning |
| 3 | gat opf socp | ~100ms | ~1-3% gap | Production dispatch, voltage-aware |
| 4 | gat opf ac | ~1s | < 0.01% gap | Final validation, full physics |
Decision Tree
Use Economic Dispatch when:
- You need instant results (< 1ms)
- Network constraints don't matter yet
- Quick "can we meet demand?" checks
Use DC-OPF when:
- You're screening thousands of contingencies
- Planning studies where speed matters
- Real power flows are sufficient
Use SOCP when:
- You need voltage information
- Production dispatch decisions
- Tight bounds on generation cost
Use AC-OPF when:
- Final operational validation
- Full physics accuracy required
- Regulatory compliance
Architecture Overview (v0.5.6)
GAT provides a unified OpfSolver supporting multiple solution methods:
| Method | Accuracy | Speed | Status | Use Case |
|---|---|---|---|---|
EconomicDispatch | ~20% gap | Fastest | β Implemented | Quick estimates, screening |
DcOpf | ~3-5% gap | Fast | β Implemented | Planning studies |
SocpRelaxation | ~1-3% gap | Moderate | β Implemented | Research benchmarking |
AcOpf (L-BFGS) | ~2-3% gap | Moderate | β Implemented | Pure Rust deployment |
AcOpf (IPOPT) | <0.01% gap | Fast | β Validated | High-fidelity analysis |
Benchmark Results
The IPOPT backend with analytical Jacobian and Hessian achieves exact agreement with PGLib reference values:
| Case | GAT Objective | Reference | Gap |
|---|---|---|---|
| case14_ieee | $2,178.08/hr | $2,178.10/hr | -0.00% |
| case118_ieee | $97,213.61/hr | $97,214.00/hr | -0.00% |
The SOCP solver has been validated against all 68 PGLib-OPF cases:
| Metric | Value |
|---|---|
| Cases Tested | 68 |
| Convergence Rate | 100% |
| Largest System | 78,484 buses |
| Median Objective Gap | < 1% |
β View complete benchmark results
What's New in 0.5.6
- Constraint scaling / row equilibration for DC-OPF LP conditioning
- Zero-reactance epsilon handling (1e-6) for bus tie transformers
- Unit-aware newtype wrappers (Megawatts, Kilovolts, PerUnit) for compile-time unit safety
- IPOPT timing fix with thread-local intermediate callback for accurate iteration reporting
- Enhanced benchmark appendix with full PGLib DC-OPF and SOCP results
What's New in 0.5.4
- Security hardening for TUI command execution β command allowlisting and metacharacter blocking.
- Content Security Policy enabled in Tauri GUI β XSS protection for desktop app.
- Type-safe event dispatcher β
PathBufand enums replace stringly-typed parameters.
What's New in 0.5.3
- Arena-based allocation for Monte Carlo and N-k contingency evaluation β reduces heap allocations in hot loops.
- gat-ui-common crate β shared UI components between gat-gui and gat-tui.
- Hot path optimizations for AC-OPF and power flow computations.
- Strategy pattern architecture for OPF solver selection with unified dispatcher.
- Improved CI/CD with Native Solvers workflow for IPOPT validation.
What's New in 0.5.2
- Full nonlinear AC-OPF reproduces all 68 PGLib benchmark cases with <0.01% gap using IPOPT backend.
- Multi-period dispatch with generator ramp constraints for day-ahead scheduling.
- IPOPT solver backend with analytical Jacobian and Hessian β matches commercial solver precision.
- Native solver plugin system with automatic fallback to pure-Rust solvers.
- Warm-start options from DC or SOCP solutions for improved convergence.
- Native piecewise-linear cost support for bid curves.
- Generator capability curves (Q limits as function of P).
- Angle difference constraints for stability enforcement.
- Sparse Y-bus with O(nnz) storage for efficient large-network handling.
- Robust Y-bus construction with transformer taps, phase shifters, shunts, and Ο-model line charging.
- Shunt support for exact power flow agreement with external tools.
Solver Backends
GAT provides a native solver plugin system that automatically selects the best available backend:
| Backend | Type | Best For | Availability |
|---|---|---|---|
| L-BFGS (default) | Pure Rust | General AC-OPF, portability | Always available |
| Clarabel | Pure Rust | SOCP, LP problems | Always available |
| IPOPT | Native (C++) | Large NLP, high accuracy | Optional installation |
| HiGHS | Native (C++) | LP/MIP, high performance | Optional installation |
| CBC | Native (C) | MIP problems | Optional installation |
Installing Native Solvers
Native solvers provide better performance for large networks but require system dependencies:
# Build and install IPOPT wrapper (requires libipopt-dev)
# List installed native solvers
# Uninstall a native solver
Architecture Benefits
Native solvers run as isolated subprocesses communicating via Arrow IPC:
- Crash isolation: Native library issues don't crash the main process
- Version flexibility: Different solver versions can coexist
- Portability: Pure-Rust fallbacks always available when native solvers aren't installed
The solver dispatcher automatically selects the best available backend based on problem class (LP, SOCP, NLP, MIP).
Rust API
OpfSolver
use ;
use Network;
// Create solver with method selection
let solver = new
.with_method // or AcOpf
.with_tolerance
.with_max_iterations;
// Solve
let solution: OpfSolution = solver.solve?;
println!;
println!;
println!;
OpfMethod Enum
OpfSolution
Note: Not all fields are populated by all methods. Economic dispatch provides generator outputs, objective, and estimated losses. SOCP and AC-OPF provide full voltage, angle, and LMP data; AC-OPF now backfills LMPs using marginal generator costs after the penalty loop finishes.
SOCP Relaxation (v0.4.0)
The SOCP solver implements the Baran-Wu / Farivar-Low branch-flow model:
Features
| Feature | Status |
|---|---|
| Squared voltage/current variables | β |
| Quadratic costs (cβ + cβΒ·P + cβΒ·PΒ²) | β |
| Phase-shifting transformers | β |
| Off-nominal tap ratios | β |
| Line charging (Ο-model) | β |
| Thermal limits (S_max) | β |
| Voltage bounds | β |
| LMP extraction from duals | β |
Mathematical Formulation
Variables: w_i (squared voltage), β_ij (squared current), P_ij, Q_ij (branch flows)
Objective:
minimize Ξ£ (cβ + cβΒ·P_g + cβΒ·P_gΒ²)
Branch-flow constraints:
w_j = w_i - 2(rΒ·P_ij + xΒ·Q_ij) + (rΒ² + xΒ²)Β·β_ij
P_ijΒ² + Q_ijΒ² β€ w_i Β· β_ij (SOC constraint)
Solver: Clarabel interior-point conic solver (15-30 iterations typical)
References
- Baran & Wu (1989): DOI:10.1109/61.25627
- Farivar & Low (2013): DOI:10.1109/TPWRS.2013.2255317
- Gan, Li, Topcu & Low (2015): DOI:10.1109/TAC.2014.2332712
Full AC-OPF (v0.4.0)
The AC-OPF solver uses polar coordinates with a penalty-method L-BFGS optimizer and now ships with a complete ac_nlp pipeline:
Features
| Feature | Status |
|---|---|
| Polar formulation (V, ΞΈ) | β |
| Y-bus construction (with taps + phase shifts) | β |
| Line charging / Ο-model support | β |
| Quadratic costs | β |
| Voltage bounds | β |
| Generator limits | β |
| Jacobian computation | β |
| L-BFGS penalty optimizer | β |
| Thermal limits (branch flow) | β |
| IPOPT backend | β
(solver-ipopt feature) |
Key components in gat_algo::opf::ac_nlp:
ybus.rs: builds the complex admittance matrix with tap ratios, phase shifters, and shunt line charging.sparse_ybus.rs: O(nnz) sparse Y-bus storage for large networks.power_equations.rs: evaluates P/Q injections and full Jacobians (βP/βΞΈ, βP/βV, βQ/βΞΈ, βQ/βV) in polar form.branch_flow.rs: computes branch apparent power flows for thermal limit enforcement.hessian.rs: second-derivative computation for interior-point methods (IPOPT).solver.rs: wraps argmin's L-BFGS optimizer with a penalty ramp until equality constraints reach feasibility.ipopt_solver.rs: full-featured interior-point solver via IPOPT (requiressolver-ipoptfeature).
Mathematical Formulation
Variables: V_i (voltage magnitude), ΞΈ_i (angle), P_g, Q_g (generator dispatch)
Objective:
minimize Ξ£ (cβ + cβΒ·P_g + cβΒ·P_gΒ²)
Power flow equations:
P_i = Ξ£β±Ό V_iΒ·V_jΒ·(G_ijΒ·cos(ΞΈ_i - ΞΈ_j) + B_ijΒ·sin(ΞΈ_i - ΞΈ_j))
Q_i = Ξ£β±Ό V_iΒ·V_jΒ·(G_ijΒ·sin(ΞΈ_i - ΞΈ_j) - B_ijΒ·cos(ΞΈ_i - ΞΈ_j))
Solver: argmin L-BFGS with iterative penalty method (penalty factor ramps until equality constraints are feasible).
Usage
let solver = new
.with_method
.with_max_iterations
.with_tolerance;
let solution = solver.solve?;
ADMM Distributed OPF (v0.5.6)
GAT implements distributed OPF using the Alternating Direction Method of Multipliers (ADMM), enabling scalable optimization across partitioned networks.
Key Features
| Feature | Status |
|---|---|
| Graph partitioning (METIS) | β |
| Parallel subproblem solving | β |
| Consensus coordination | β |
| Adaptive penalty | β |
| Tie-line flow calculation | β |
| GPU acceleration | β (optional) |
Algorithm
For each iteration k:
1. x-update: Solve local OPF for each partition (parallel)
2. z-update: Average boundary voltages (consensus)
3. Ξ»-update: Update dual variables
4. Check: Compute primal/dual residuals
GPU Acceleration
Branch power flow calculation can use GPU for large networks:
# Build with GPU support
Performance:
- Large networks (100s-1000s of branches): 2-10x speedup
- Small networks: Minimal benefit (kernel overhead)
- Auto-fallback to CPU if GPU unavailable
Usage
use ;
let solver = new;
let result = solver.solve?;
println!;
println!;
References
- Boyd, S., et al. (2011). Distributed Optimization via ADMM.
- Chen, Y., et al. (2025). DPLib: Distributed Power System Benchmark. arXiv:2506.20819.
Generator Cost Models
Generators support polynomial and piecewise-linear cost functions via the CostModel enum:
use ;
// Quadratic cost: $100 + $20/MWh + $0.01/MWΒ²h
let gen = new
.with_p_limits // Pmin=10 MW, Pmax=100 MW
.with_q_limits // Qmin=-50 MVAr, Qmax=50 MVAr
.with_cost;
// Linear cost: $50 + $25/MWh
let gen2 = new
.with_p_limits
.with_cost;
// Piecewise linear: [(MW, $/hr), ...]
let gen3 = new
.with_p_limits
.with_cost;
CostModel Methods
CLI Commands
GAT provides four OPF commands matching the solver hierarchy:
# Tier 1: Economic Dispatch (< 1ms)
# Tier 2: DC-OPF (~10ms for 118-bus)
# Tier 3: SOCP Relaxation (~100ms for 118-bus)
# Tier 4: AC-OPF (~1s for 118-bus)
Economic Dispatch (gat opf ed)
Merit-order dispatch ignoring network constraints. Fastest option for "can we meet demand?" checks.
Output: Generator dispatch (P) ordered by marginal cost.
DC-OPF (gat opf dc)
Linear approximation with B-matrix flow constraints. Standard for transmission planning.
Features:
- Real power flow on branches
- Generator cost minimization
- Optional branch flow limits
- LMP extraction from duals
Output: Branch flows, generator dispatch, bus LMPs.
SOCP Relaxation (gat opf socp)
Second-order cone relaxation with voltage magnitude modeling. Production-ready for most applications.
Features:
- Squared voltage/current variables
- Quadratic generator costs
- Transformer tap ratios and phase shifters
- Thermal limits (apparent power)
- LMP extraction from duals
Backend: Clarabel (pure Rust, no external dependencies)
Output: Branch flows, voltages, generator dispatch, LMPs.
AC-OPF (gat opf ac)
Full nonlinear AC-OPF with polar formulation. Maximum accuracy for final validation.
Options:
--tol: convergence tolerance (default1e-4)--max-iter: maximum iterations (default200)--warm-start: initialization βflat,dc, orsocp(recommended)
Backend: IPOPT with analytical Jacobian and Hessian (if installed), otherwise L-BFGS
Output: Full voltage profile (V, ΞΈ), generator P/Q, branch flows, losses, LMPs.
Test Fixtures
test_data/opf provides reusable CSVs for local experiments:
costs.csv: sample marginal costs for buses0and1.limits.csv: matchingpmin,pmax, anddemandentries.branch_limits.csv: tight limits for violation testing.piecewise.csv: two-piece segments for piecewise cost testing.
Troubleshooting
OPF Returns Infeasible
Symptoms: "Problem infeasible" or "No solution found"
Common Causes & Solutions:
-
Insufficient generation capacity
# Total Pmax must exceed total load + losses -
Transmission limits too tight
# Relax limits temporarily to diagnose -
Missing or incorrect cost data
# Verify all generators have costs | \ -
Network islands
# Each island needs its own slack/generation
AC-OPF Does Not Converge
Symptoms: IPOPT reports "Maximum iterations exceeded" or "Restoration failed"
Solutions:
-
Use SOCP warm-start (recommended)
-
Increase iterations and relax tolerance
-
Check voltage bounds
# Widen voltage bounds if too restrictive | \ -
Fall back to L-BFGS if IPOPT unavailable
Large Objective Gap vs Reference
Symptoms: Cost differs significantly from MATPOWER/PowerModels results
Causes & Solutions:
-
Different cost function interpretation
# Verify cost units ($/MWh vs $/MW) | -
Generator limits not binding correctly
# Check dispatch is within limits | \ -
Loss modeling differences
- DC-OPF ignores losses (expected ~3-5% gap)
- Use SOCP or AC-OPF for loss-inclusive comparison
SOCP Relaxation Gap Too Large
Symptoms: SOCP objective significantly lower than AC-OPF
Solutions:
-
Tighten voltage bounds
# Narrow voltage range reduces relaxation gap -
Check for binding constraints
# Large gaps often indicate loose problem | \
Negative LMPs
Symptoms: Some buses show negative locational marginal prices
Interpretation: This is often correct! Negative LMPs occur when:
- Curtailment is cheaper than transmission
- Congestion creates "trapped" low-cost generation
- Renewable must-run constraints
Verification:
# Check which constraints are binding
| \
Memory/Performance Issues
Large systems (>10k buses):
# Use DC-OPF for screening
# For AC-OPF, use sparse linear algebra
Batch scenarios:
# Process in parallel batches
Related Documentation
- Benchmarks: Complete PGLib-OPF validation results β 68 cases, 100% convergence
- Power Flow: Power Flow Guide
- State Estimation: State Estimation Guide
- Reliability: Reliability Guide
- Solver Architecture: Native Solver Plugin System