Skip to main content

DcSensitivity

Struct DcSensitivity 

Source
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

Source

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.

Source

pub fn n_buses(&self) -> usize

Source

pub fn n_branches(&self) -> usize

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> ByRef<T> for T

Source§

fn by_ref(&self) -> &T

Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> DistributionExt for T
where T: ?Sized,

Source§

fn rand<T>(&self, rng: &mut (impl Rng + ?Sized)) -> T
where Self: Distribution<T>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Imply<T> for U
where T: ?Sized, U: ?Sized,

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V