import os
import numpy as np
import scipy.sparse as sp
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import pandapower as pp
import pandapower.networks as pn
HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.normpath(os.path.join(HERE, "..", "paper", "sparsity_isomorphism.png"))
def dSbus_dV(Ybus, V):
Ibus = Ybus @ V
Vnorm = V / np.abs(V)
diagV = sp.diags(V)
diagIbus = sp.diags(Ibus)
diagVnorm = sp.diags(Vnorm)
dS_dVm = diagV @ (Ybus @ diagVnorm).conj() + diagIbus.conj() @ diagVnorm
dS_dVa = 1j * diagV @ (diagIbus - Ybus @ diagV).conj()
return dS_dVm.tocsc(), dS_dVa.tocsc()
def main():
net = pn.case39()
pp.runpp(net)
ppc = net._ppc
Ybus = ppc["internal"]["Ybus"].tocsc()
Vm = ppc["bus"][:, 7]
Va = np.deg2rad(ppc["bus"][:, 8])
V = Vm * np.exp(1j * Va)
btype = ppc["bus"][:, 1].astype(int)
pv = np.where(btype == 2)[0]
pq = np.where(btype == 1)[0]
slack = np.where(btype == 3)[0]
n = Ybus.shape[0]
npv = len(pv)
npq = len(pq)
npvpq = npv + npq
m = npvpq + npq
T_perm = np.concatenate([pq, pv, slack])
T_mat = sp.eye(n, format='csc')[T_perm, :]
TYT = (T_mat @ Ybus @ T_mat.T).tocsc() V_p = T_mat @ V
dS_dVm_p, dS_dVa_p = dSbus_dV(TYT, V_p)
Jfull = sp.bmat([[dS_dVa_p.real, dS_dVm_p.real],
[dS_dVa_p.imag, dS_dVm_p.imag]], format='csc')
col_P = np.concatenate([np.arange(npvpq), n + np.arange(npq)])
P = sp.csc_matrix((np.ones(m), (np.arange(m), col_P)), shape=(m, 2 * n))
Jred = (P @ Jfull @ P.T).tocsc()
col_PY = np.concatenate([np.arange(npvpq), np.arange(npq)])
P_Y = sp.csc_matrix((np.ones(m), (np.arange(m), col_PY)), shape=(m, n))
Yred = (P_Y @ TYT @ P_Y.T).tocsc()
fig, axes = plt.subplots(2, 2, figsize=(7.5, 7.5))
panels = [
(TYT, r"$\mathbf{T}\mathbf{Y}_{\mathrm{bus}}\mathbf{T}^{\!\top}$"),
(dS_dVa_p, r"$\partial \mathbf{S}_{\mathrm{bus}} / \partial \boldsymbol{\theta}$"),
(Yred, r"$\mathbf{P}\,(\mathbf{T}\mathbf{Y}_{\mathrm{bus}}\mathbf{T}^{\!\top})\,\mathbf{P}^{\!\top}$"),
(Jred, r"$\mathbf{J}_{\mathrm{red}}$"),
]
for ax, (M, t) in zip(axes.flat, panels):
ax.spy(M, markersize=4, color="black")
ax.set_title(t, fontsize=13)
ax.set_xticks([])
ax.set_yticks([])
plt.tight_layout()
plt.savefig(OUT, dpi=200, bbox_inches="tight")
print(f"Saved {OUT}")
print(f" n={n} npq={npq} npv={npv} m={m} (Jred: {m}×{m})")
print(f" TYT nnz={TYT.nnz} Jred nnz={Jred.nnz} Yred nnz={Yred.nnz}")
if __name__ == "__main__":
main()