DC

DC linear active-power approximation

LP

Solver: OSQP

Motivation

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.

Derivation

Three assumptions

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:

  1. Voltage magnitudes are fixed at nominal: |Vi| ≈ 1 p.u. for all i ∈ 𝒩. This eliminates voltage magnitude as a decision variable.
  2. Angle differences are small: sin(θik) ≈ θik and cos(θik) ≈ 1. Valid for tightly synchronized transmission networks where |θi − θj| ≤ 0.3 rad.
  3. Branches are lossless: rij ≪ xij, so the resistance is dropped from line models. The branch admittance simplifies to a pure susceptance: Bij = −1/xij.

From AC polar to DC linear

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:

$$P_{ij} = \frac{\theta_i - \theta_j}{x_{ij}}.$$

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:

$$\sum_{j: (i,j) \in \mathcal{E}} P_{ij} = P_i^g - P_i^d, \quad \forall i \in \mathcal{N}.$$

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.

DC OPF — full problem

The complete DC formulation reads:

$$ \begin{aligned} \min_{P_g, \theta} \quad & \sum_{g \in \mathcal{G}} c_g(P_g) \\[6pt] \text{s.t.} \quad & \sum_{j: (i,j) \in \mathcal{E}} P_{ij} = P_i^g - P_i^d, && \forall i \in \mathcal{N} \\ & P_{ij} = (\theta_i - \theta_j) / x_{ij}, && \forall (i,j) \in \mathcal{E} \\ & \underline{P}_g \le P_g \le \overline{P}_g, && \forall g \in \mathcal{G} \\ & |P_{ij}| \le \overline{P}_{ij}, && \forall (i,j) \in \mathcal{E} \\ & \theta_{\text{slack}} = 0 \end{aligned} $$

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.

Computational considerations

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.

Lirion usage

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.

References

  1. Stott, B., Jardim, J., & Alsaç, O. (2009). DC power flow revisited. IEEE Transactions on Power Systems, 24(3), 1290–1300.
  2. Wood, A. J., Wollenberg, B. F., & Sheblé, G. B. (2013). Power Generation, Operation, and Control (3rd ed.). Wiley.
  3. Stellato, B., Banjac, G., Goulart, P., Bemporad, A., & Boyd, S. (2020). OSQP: an operator splitting solver for quadratic programs. Mathematical Programming Computation, 12, 637–672.
  4. Litvinov, E. (2010). Design and operation of the locational marginal pricing-based electricity markets. IET Generation, Transmission & Distribution, 4(2), 315–323.