pub struct DcSensitivity { /* private fields */ }Expand description
Precomputed DC sensitivity factors for one network.
Holds one factorization per island, computed once. Every accessor below is
a solve against those, never a refactorization — which is the entire reason
sparse::RealFactorization exists
rather than reusing the Newton path’s
solver::LinearSolver.
Implementations§
Source§impl DcSensitivity
impl DcSensitivity
Sourcepub fn new(
buses: &[Bus],
branches: &[DcBranch],
n_branches: usize,
) -> Option<Self>
pub fn new( buses: &[Bus], branches: &[DcBranch], n_branches: usize, ) -> Option<Self>
Factorizes every referenced island’s reduced B.
branches must come from
dc_branches over the same network, and
n_branches must be its flat branch count (lines.len() + transformers.len()) — the same index space
DcSolution::branch_p uses.
Returns None if any referenced island’s B is singular. Islands with
no reference bus are not an error: they simply have no sensitivities,
and every accessor returns None for their buses and branches.
pub fn n_buses(&self) -> usize
pub fn n_branches(&self) -> usize
Sourcepub fn transfer_factors(&self, injections: &[f64]) -> Option<Vec<f64>>
pub fn transfer_factors(&self, injections: &[f64]) -> Option<Vec<f64>>
Branch-flow response to an arbitrary injection pattern — the primitive the other accessors are special cases of.
injections is per-bus and per-unit; within each island whatever does
not sum to zero is absorbed at that island’s reference. Returns per-
branch flow changes, in the flat branch index space.
Costs one solve per island that the pattern actually touches.
Sourcepub fn response(&self, injections: &[f64]) -> Option<(Vec<f64>, Vec<f64>)>
pub fn response(&self, injections: &[f64]) -> Option<(Vec<f64>, Vec<f64>)>
Both halves of the response to an injection pattern: the change in every bus angle and the change in every branch flow.
Returns (d_angle, d_flow), indexed by bus and by flat branch index.
This is what linear::batch builds a whole batch on:
because DC is exactly linear, a scenario’s answer is the base solve
plus this response to the scenario’s injection delta — one solve
against a factorization computed once, rather than a fresh solve per
scenario.
Islands the pattern does not touch are skipped without a solve, and contribute nothing.
Sourcepub fn outage_flows(
&self,
base_flows: &[f64],
branch: usize,
) -> Option<Vec<f64>>
pub fn outage_flows( &self, base_flows: &[f64], branch: usize, ) -> Option<Vec<f64>>
Branch flows after branch trips, given the flows before it did.
This is the N-1 screening primitive: f + LODF[:, l]·f[l], one solve
against the cached factorization and no re-solve of the network. The
outaged branch itself comes back at exactly zero.
None if branch is radial — removing it islands the network, so its
power has nowhere to redistribute to and no post-outage flow exists —
or if it is out of range or in an unreferenced island. Use
is_radial to tell those apart in advance.
base_flows must be indexed by flat branch index, as
DcSolution::branch_p is.
Sourcepub fn multi_outage_flows(
&self,
base_flows: &[f64],
branches: &[usize],
) -> Option<Vec<f64>>
pub fn multi_outage_flows( &self, base_flows: &[f64], branches: &[usize], ) -> Option<Vec<f64>>
Branch flows after every branch in branches trips at once.
The N-2 (and N-k) generalization of outage_flows,
and not obtainable by applying single-branch LODF columns one after
another: simultaneous outages interact, because each one changes how the
others’ power redistributes.
§The generalized formulation
Removing a set L is a rank-k update to B, so Woodbury gives the
whole answer in one k × k solve. With ψ[m][l] the flow appearing on
branch m per unit of power transferred across branch l’s terminals —
one triangular solve against the cached factorization per outaged branch,
exactly what a single-branch outage already needs:
\[ (I - \Psi_{LL}),c = f_L, \qquad f^{new} = f + \sum_{l \in L} c_l, \psi[:, l] \]
For k = 1 this collapses to c = f_l/(1 - d_l) and the familiar
LODF[:, l] = ψ[:, l]/(1 - d_l), which is why
outage_flows simply delegates here rather than
keeping a second implementation.
§When it returns None
I - Ψ_LL is singular exactly when the set is breaking — removing all
of it disconnects the network, so the power has nowhere to redistribute
to and no post-outage flow exists. That is the multi-branch analogue of
a radial branch, and it is a structural fact rather than a numerical
accident, so it is reported rather than papered over. Also None for a
repeated index, an out-of-range index, or a branch that carries no DC
flow.
An empty set returns base_flows unchanged.
Sourcepub fn is_breaking_set(&self, branches: &[usize]) -> bool
pub fn is_breaking_set(&self, branches: &[usize]) -> bool
Whether removing every branch in branches at once would disconnect the
network, leaving no post-outage flows to compute.
The multi-branch analogue of is_radial, and true
for the same malformed inputs multi_outage_flows
rejects.
Sourcepub fn ptdf_column(&self, bus: usize) -> Option<Vec<f64>>
pub fn ptdf_column(&self, bus: usize) -> Option<Vec<f64>>
∂P_branch/∂P_bus over every branch, for injection at one bus.
None if bus is out of range or sits in an island with no reference.
A reference bus’s own column is all zeros — injecting at the slack and
letting the slack absorb it moves nothing.
Sourcepub fn ptdf_row(&self, branch: usize) -> Option<Vec<f64>>
pub fn ptdf_row(&self, branch: usize) -> Option<Vec<f64>>
∂P_branch/∂P_bus over every bus, for one branch.
One solve, not n_buses of them, because B_NN is symmetric.
None if branch is out of range, carries no DC flow, or sits in an
island with no reference.
Sourcepub fn lodf_column(&self, branch: usize) -> Option<Vec<f64>>
pub fn lodf_column(&self, branch: usize) -> Option<Vec<f64>>
The fraction of branch’s pre-outage flow that lands on each other
branch when it trips.
None if branch is radial (see is_radial), out
of range, or in an unreferenced island. The outaged branch’s own entry
is −1: it loses all of its flow, by definition.
Sourcepub fn is_radial(&self, branch: usize) -> bool
pub fn is_radial(&self, branch: usize) -> bool
Whether removing branch would disconnect the network, leaving its
flow nowhere to redistribute to and its LODF column undefined.
true for a branch that is out of range or in an unreferenced island:
there are no redistribution factors for it either way.
Sourcepub fn ptdf_dense(&self) -> Option<DenseMatrix>
pub fn ptdf_dense(&self) -> Option<DenseMatrix>
The full n_branches × n_buses PTDF.
Allocates n_branches · n_buses · 8 bytes — 1.19 GB on
case9241pegase. Prefer ptdf_column or
ptdf_row unless the whole matrix is genuinely
wanted.
Sourcepub fn lodf_dense(&self) -> Option<DenseMatrix>
pub fn lodf_dense(&self) -> Option<DenseMatrix>
The full n_branches × n_branches LODF.
Allocates n_branches² · 8 bytes — 2.06 GB on case9241pegase.
Radial branches’ columns are left at zero, since they have no defined
factors; use is_radial to tell those apart from
branches that genuinely redistribute nothing.
Auto Trait Implementations§
impl Freeze for DcSensitivity
impl RefUnwindSafe for DcSensitivity
impl Send for DcSensitivity
impl Sync for DcSensitivity
impl Unpin for DcSensitivity
impl UnsafeUnpin for DcSensitivity
impl UnwindSafe for DcSensitivity
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T> DistributionExt for Twhere
T: ?Sized,
impl<T, U> Imply<T> for U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more