Every bus’s voltage magnitude and the sine and cosine of its angle, taken
once per Newton iteration and read by both the power injections and the
Jacobian fill — which used to evaluate the same sines and cosines each.
A mutable Y-bus under construction: a COO (triplet) accumulator. Entries
at the same (row, col) are summed once finalized via finish() — this
gives the same accumulation semantics as the old dense ybus[(i,j)] += val, including for parallel branches between the same two buses (e.g.
symmetric/distribution-case’s two parallel transformers).
A finalized, frozen Y-bus: consolidated per-row admittance neighbors (for
sparse-aware assembly of the linear initial guess and the Jacobian) plus
a ready-to-use sparse matrix (for power_injections’s mat-vec, needed
every Newton-Raphson iteration). Built once via YBus::finish.
Computes the four branch admittance entries [yff, yft, ytf, ytt] for a
two-winding transformer branch. Implements PGM’s π-equivalent model:
y_shunt is split equally between both terminals. The complex tap ratio
tap = k·exp(jθ) carries both the off-nominal magnitude k and the
vector-group phase shift θ.
Builds a Y-bus with the branches flagged in outaged taken out of service,
keeping their structural entries so the sparsity pattern is identical to
the intact network’s.
Groups buses into connected components via the Y-bus’s actual admittance
graph — two buses are in the same component iff there’s a path of
nonzero off-diagonal Y-bus entries between them (row(i)’s own diagonal
self-entry, j == i, is skipped, since it’s a shunt term, not a branch
to another bus). Each returned Vec<usize> is one component’s member
bus indices, sorted ascending; components are returned in ascending
order of their first (lowest-index) member.
Computes the effective (P, Q) injection at a bus at its current voltage
magnitude: p_spec/q_spec (constant-power) plus any ZIP terms evaluated
at bus.voltage_mag. For a bus with no ZIP terms this is exactly
(bus.p_spec, bus.q_spec).
The effective shunt admittance seen at a half-open transformer’s
connected end: y_shunt/2 + 1/(1/y_series + 2/y_shunt). Mathematically,
this expression’s limit as y_shunt → 0 is exactly 0 (with no
magnetizing branch at all, opening one end truly isolates the connected
side — there’s no other path for current to flow), but literal complex
division by y_shunt = 0+0j hits a 0/0 pattern and evaluates to NaN
instead of that limit. y_shunt == 0 exactly is common in practice
(magnetizing admittance is often left unspecified/zero, e.g. in real
CGMES transformer data far more often than gridoxide’s own PGM test
fixtures happen to combine with a half-open status), so this needs an
explicit guard, not just trusting the formula.
Computes a smarter-than-flat-start initial voltage guess for Newton-Raphson
by solving one linearized constant-admittance system, mirroring PGM’s
NewtonRaphsonPFSolver::initialize_derived_solver. Each energized (PQ)
bus’s injection is approximated as a constant admittance y = -conj(S)
evaluated at the flat-start |V|=1 assumption and added to the Y-bus
diagonal; Slack buses (both real sources and de-energized nodes, which
gridoxide models as fixed Slack buses at V=0) keep their already-set
voltage. The resulting linear system Y'_nn·U_n = -Y'_ns·U_s is solved for
the unknown PQ bus voltages via LU decomposition, and voltage_mag/
voltage_ang are overwritten with the result. If the reduced system is
singular, buses are left at their prior (flat-start) values. PGM applies no
step damping or voltage clamping beyond this — a better initial guess is
its only robustness mechanism, needed on networks combining weak sources
with large transformer phase shifts where plain flat-start NR diverges.
Computes per-unit source impedance (r, x) from short-circuit power and R/X
ratio. Matches PGM’s Source::math_param (z_abs = base_power_3p / sk,
with no dependence on u_ref — the source’s reference voltage only sets
the fixed voltage at the virtual slack bus, not the branch impedance).
Computes the complex off-nominal tap ratio k · exp(j·clock·π/6) from a
numerator/denominator voltage pair. u_num/u_denom are the (possibly
tap-adjusted) nameplate voltages on the two sides; the magnitude ratio
u_num/u_denom gives k. Used both by transformer_tap (2-winding) and
the three-winding/asymmetric-transformer paths.
Computes the three-winding transformer’s delta→wye (star-equivalent)
short-circuit voltage and loss parameters (uk_T1, uk_T2, uk_T3) and
(pk_T1, pk_T2, pk_T3), referenced to side 1’s power base. Mirrors PGM’s
ThreeWindingTransformer::calculate_uk/calculate_pk (tap-dependent
uk_min/uk_max adjustment is not implemented — this three-winding
support only covers fixtures with no such tap-dependent impedance range).
Computes per-unit series and shunt admittances from transformer nameplate data.
Both are referenced to the to-side (u2) voltage base.
Like transformer_admittances, but with separately specified nameplate
(“to”-field, used for absolute impedance/shunt magnitude scaling) and rated
(“to”-base, used for the per-unit base) to-side voltages — needed when the
two differ, as for a three-winding transformer’s internal star leg, whose
nameplate voltage tracks the tapped side while its per-unit base stays
pinned to the physical node’s rated voltage. uk/pk may be negative (as
PGM’s three-winding delta→wye conversion can produce); the sign of uk is
carried onto the series reactance, matching PGM’s transformer_params().
Computes sequence-domain (y0, y1, y2) branch admittance parameters
(each [yff, yft, ytf, ytt]) for a two-winding transformer, needed for
asymmetric (3-phase) power flow and for short-circuit calculation.