AC branch pi-model power flow equations (P/Q and |S|) with transformer tap ratio and phase shift, matching `acopf-math-model.md` and MATPOWER branch fields. Use when computing branch flows in either direction, aggregating bus injections for nodal balance, checking MVA (rateA) limits, computing branch loading %, or debugging sign/units issues in AC power flow.
Implement the exact branch power flow equations in acopf-math-model.md using MATPOWER branch data:
[F_BUS, T_BUS, BR_R, BR_X, BR_B, RATE_A, RATE_B, RATE_C, TAP, SHIFT, BR_STATUS, ANGMIN, ANGMAX]
scripts/branch_flows.py to compute per-unit branch flows.Example:
import json
import numpy as np
from scripts.branch_flows import compute_branch_flows_pu, build_bus_id_to_idx
data = json.load(open("/root/network.json"))
baseMVA = float(data["baseMVA"])
buses = np.array(data["bus"], dtype=float)
branches = np.array(data["branch"], dtype=float)
bus_id_to_idx = build_bus_id_to_idx(buses)
Vm = buses[:, 7] # initial guess VM
Va = np.deg2rad(buses[:, 8]) # initial guess VA
br = branches[0]
P_ij, Q_ij, P_ji, Q_ji = compute_branch_flows_pu(Vm, Va, br, bus_id_to_idx)
S_ij_MVA = (P_ij**2 + Q_ij**2) ** 0.5 * baseMVA
S_ji_MVA = (P_ji**2 + Q_ji**2) ** 0.5 * baseMVA
print(S_ij_MVA, S_ji_MVA)
baseMVA:
abs(TAP) < 1e-12, treat tap = 1.0 (no transformer).SHIFT from degrees to radians.Given BR_R = r, BR_X = x:
r == 0 and x == 0, set g = 0, b = 0 (avoid divide-by-zero).BR_B is the total line charging susceptance (b_c) (per unit).Let:
tap is real, shift is radiansinv_t = 1/tap, inv_t2 = inv_t^2Then the real/reactive power flow from i→j is:
And from j→i is:
Compute apparent power:
RATE_A is an MVA limit (may be 0 meaning “no limit”).For reporting “most loaded branches”:
loading_pct = 100 * max(|S_ij|, |S_ji|) / RATE_A if RATE_A > 0, else 0.To build the branch flow sum for each bus (i):
This yields arrays P_out[i], Q_out[i] such that the nodal balance can be written as:
SHIFT=0 and TAP=1, if (V_i = V_j) and (\theta_i=\theta_j), then (P_{ij}\approx 0) and (P_{ji}\approx 0) (lossless only if r=0).r=x=0) you should not get meaningful flows; treat as g=b=0 (no series element).