Solver: OSQP
The DC OPF is the workhorse of power-system operations research and the model used by virtually every ISO for day-ahead and real-time markets. It linearizes the AC power-flow equations around the flat-start operating point, ignoring reactive power, voltage magnitudes, and losses — a brutal simplification, but one that yields a convex linear program solvable in milliseconds for transmission networks with thousands of buses.
Use DC OPF whenever speed and scale matter more than physical fidelity: market clearing, security-constrained unit commitment, expansion planning, and as a fast warm-start for the full AC formulation. Be aware that DC ignores reactive power entirely and may produce dispatches that violate voltage limits when realized in AC simulation — a common source of “DC-AC mismatch” in production grids.
The DC approximation rests on three simplifications applied to the AC power-flow equations derived for the AC model. Each one trades physical accuracy for computational tractability:
Applying the three assumptions to the AC active-power equation collapses the trigonometric, bilinear coupling into a purely linear expression. Active power flow on branch (i,j) becomes:
The reactive-power equation vanishes entirely under these assumptions — Q is simply not modeled in DC OPF. The bus-balance constraint reduces to the algebraic statement that the sum of branch flows out of bus i equals net injection:
The resulting problem has the AC OPF’s combinatorial structure (one constraint per bus, one variable per generator and angle) but with linear constraints throughout, yielding a tractable linear program.
The complete DC formulation reads:
Throughout, $P_g$ denotes the active power output of generator $g \in \mathcal{G}$, while $P_i^g$ and $P_i^d$ denote the aggregated generation and demand at bus $i \in \mathcal{N}$. These relate via $P_i^g = \sum_{g \in \mathcal{G}_i} P_g$, where $\mathcal{G}_i \subseteq \mathcal{G}$ is the set of generators at bus $i$. This convention is used throughout all model pages.
The slack-bus constraint θslack = 0 fixes the otherwise free reference angle (the problem is invariant under θ → θ + c). All other variables are unbounded in sign for θ and box-bounded for Pg.
DC OPF is a linear program with structure that modern LP solvers — OSQP, HiGHS, Gurobi, CPLEX — handle extremely efficiently. Solve times on a 30,000-bus continental network are typically under one second on commodity hardware. Lirion defaults to OSQP, an open-source operator-splitting solver well-suited for the large, sparse LPs that DC OPF produces.
The dual variables of the bus-balance constraints are the locational marginal prices (LMPs) — the central market signal in deregulated electricity markets. Their interpretation is exact within the DC model and approximate (but standard practice) when used as ex-post price signals from AC dispatches.
Solving the DC OPF problem on a MATPOWER case file requires a single call to solve() with model = dc() and algorithm = centralized(). Lirion handles parsing, network reduction, OSQP invocation, and LMP extraction — returning a structured output compatible with the PowerModels.jl schema.
using Lirion
# Load and solve a DC OPF
out = solve("case30.m"; model = dc(), algorithm = centralized())
# Active dispatch and LMPs
Pg = out.solution["gen"]["pg"]
LMPs = out.solution["bus"]["lam_kcl"] # marginal prices [$/MWh]
println("Total cost: \$", round(out.objective, digits=2))
println("Solve time: ", round(out.solve_time, digits=4), " s") The out object includes the dual variables of the bus-balance constraints as LMPs — directly available as lam_kcl in the solution dictionary. For multi-formulation comparisons, pair this with the benchmark() utility.