ACR

Full nonlinear AC in rectangular coordinates

NLP

Solver: Ipopt

Motivation

ACR is the AC OPF rewritten in rectangular voltage coordinates: instead of magnitude and angle (|Vi|, θi), each bus voltage is decomposed into real and imaginary parts (vir, vii). The two formulations describe the same feasible set — identical physics, identical optimal solutions in principle — but the algebraic structure they expose to a nonlinear solver is markedly different.

Use ACR when the trigonometric functions in polar AC cause numerical trouble: ill-conditioned Jacobians near singular operating points, convergence stagnation on heavily loaded networks, or when warm-starting from a load flow whose phase angles are unreliable. The rectangular formulation replaces sin/cos with polynomials, producing a Jacobian sparsity pattern that Ipopt sometimes prefers — particularly on networks with HVDC links or phase-shifting transformers where polar angles wrap problematically.

Derivation

Rectangular voltage variables

Each bus voltage phasor is written as a sum of real and imaginary parts:

$$V_i = v_i^r + j v_i^i, \quad |V_i|^2 = (v_i^r)^2 + (v_i^i)^2, \quad \theta_i = \arctan(v_i^i / v_i^r).$$

Voltage magnitude bounds become quadratic, and the angle reference is enforced by fixing the imaginary part of the slack bus to zero (vslacki = 0). The Y-bus relation I = YV is unchanged — Yik = Gik + jBik still holds, only the voltage representation differs.

Power flow in rectangular form

Substituting the rectangular decomposition into the complex-power equation Si = Vi · (Σk Yik Vk)* and separating real and imaginary parts yields polynomial expressions for active and reactive power injections:

$$P_i = \sum_{k} \left[ G_{ik}(v_i^r v_k^r + v_i^i v_k^i) + B_{ik}(v_i^i v_k^r - v_i^r v_k^i) \right]$$
$$Q_i = \sum_{k} \left[ G_{ik}(v_i^i v_k^r - v_i^r v_k^i) - B_{ik}(v_i^r v_k^r + v_i^i v_k^i) \right]$$

No trigonometric functions appear — only bilinear products of voltage components. Branch flows Sij follow the same pattern, producing degree-4 polynomials in (vr, vi) when squared for thermal limits. The problem remains non-convex (bilinear terms are non-convex), but the structure is purely polynomial.

ACR OPF — full problem

The complete formulation reads:

$$ \begin{aligned} \min_{P^g, Q^g, v^r, v^i} \quad & \sum_{g \in \mathcal{G}} c_g(P_g^g) \\[6pt] \text{s.t.} \quad & P_i^g - P_i^d = P_i(v^r, v^i), && \forall i \in \mathcal{N} \\ & Q_i^g - Q_i^d = Q_i(v^r, v^i), && \forall i \in \mathcal{N} \\ & \underline{V}_i^2 \le (v_i^r)^2 + (v_i^i)^2 \le \overline{V}_i^2, && \forall i \in \mathcal{N} \\ & \underline{P}_g^g \le P_g^g \le \overline{P}_g^g, \; \underline{Q}_g^g \le Q_g^g \le \overline{Q}_g^g, && \forall g \in \mathcal{G} \\ & P_{ij}^2(v^r, v^i) + Q_{ij}^2(v^r, v^i) \le \overline{S}_{ij}^2, && \forall (i,j) \in \mathcal{E} \\ & v_{\text{slack}}^i = 0 \end{aligned} $$

The optimization variables double in count compared to polar AC (2 voltage components per bus instead of magnitude + angle), but constraints remain at the same algebraic complexity. The slack-bus anchor vslacki = 0 removes the rotational invariance of the problem.

Computational considerations

ACR and polar AC describe the same physical problem and reach the same global optimum when a unique solution exists. In practice, however, interior-point solvers can converge to different local optima depending on the formulation — neither is universally better. Ipopt typically performs comparably on both, with ACR slightly preferred on networks where angle wrapping or near-singular Jacobians cause issues in polar form.

The bilinear/polynomial structure of ACR is also the entry point for global optimization methods: SDP and moment-based relaxations build naturally on rectangular variables. Within Lirion, the practical advice is: try AC first, switch to ACR when polar fails to converge or when downstream tooling expects rectangular output (e.g., piecewise convex envelopes for spatial branch-and-bound).

Lirion usage

Solving ACR OPF on a MATPOWER case file requires a single call to solve:

using Lirion

# Solve ACR — same problem as AC, different coordinates
out = solve("case118.m"; model = acr(), algorithm = centralized())

# Rectangular voltage components
vr = out.solution["bus"]["vr"]   # real parts
vi = out.solution["bus"]["vi"]   # imaginary parts

# Reconstruct magnitudes and angles
V_mag = sqrt.(vr.^2 .+ vi.^2)
V_ang = atan.(vi, vr)

println("Objective:    \$", round(out.objective, digits=2))
println("Solve time:    ", round(out.solve_time, digits=3), " s")

The out object follows the PowerModels.jl result schema. Branch flows are available under out.solution["branch"]["pf"].

References

  1. Cain, M. B., O'Neill, R. P., & Castillo, A. (2012). History of optimal power flow and formulations. FERC Staff Technical Paper, 1–36.
  2. Bukhsh, W. A., Grothey, A., McKinnon, K. I. M., & Trodden, P. A. (2013). Local solutions of the optimal power flow problem. IEEE Transactions on Power Systems, 28(4), 4780–4788.
  3. Lavaei, J., & Low, S. H. (2012). Zero duality gap in optimal power flow problem. IEEE Transactions on Power Systems, 27(1), 92–107.
  4. Coffrin, C., Hijazi, H. L., & Van Hentenryck, P. (2016). The QC relaxation: A theoretical and computational study on optimal power flow. IEEE TPS, 31(4), 3008–3018.