pub struct NodeBreakerNetwork {
pub buses: Vec<Bus>,
pub lines: Vec<Line>,
pub transformers: Vec<Transformer>,
pub shunts: Vec<ShuntAdm>,
pub view: BusView,
pub topology: NodeBreakerTopology,
pub switch_labels: Vec<String>,
pub zero_injection: Vec<bool>,
/* private fields */
}Expand description
A network whose retained switches are addressable elements.
The problem this solves is index arithmetic. regularized_branches appends
switch branches to a transformer list, so a switch’s flat branch index is
lines.len() + model_transformers + n — which the caller had to compute,
and which silently desynchronizes the moment anything about the branch order
changes. Owning the mapping removes that whole class of mistake, and it is
what makes the rest of the crate usable on switches without knowing they are
switches.
§What comes free
A retained switch is a branch, so nothing else needed changing to make the existing machinery work on one:
- DC —
linear::dc_power_flowtakes the branch lists, so a switch’s active flow appears inDcSolution::branch_pat its own index. - Sensitivities —
DcSensitivity::lodf_columnat a switch’s branch index is its bus-split distribution factor. - AC contingencies —
batch::BatchSolver::solve_contingenciesoutages a switch by its branch index like any other branch, so a switching campaign is an ordinary contingency sweep.
The one thing that is not free is the flow through a closed switch inside
a loop of closed switches: see degenerate_switches and
zero_impedance_branches.md.
Fields§
§buses: Vec<Bus>§lines: Vec<Line>§transformers: Vec<Transformer>The model’s own transformers, followed by one branch per non-degenerate retained switch.
shunts: Vec<ShuntAdm>§view: BusView§topology: NodeBreakerTopologyThe switch graph the view was derived from, kept so a switch can report
its own kind — a caller deciding whether to operate something needs to
know a breaker from a disconnector, and neither BusView nor
RetainedSwitch carries that.
switch_labels: Vec<String>Per switch, a human-meaningful identifier from the source model (a CGMES
mRID). Empty when the source has none, in which case callers fall back
to SwitchIdx.
zero_injection: Vec<bool>Per bus, whether no injecting equipment terminates on it.
State estimation’s reason for existing on this network: a bay’s internal
nodes carry switches and nothing else, so the finer the topology, the
more of the state is pinned by exact zero-injection constraints rather
than by sensors. See
SeNetwork::from_node_breaker.
Implementations§
Source§impl NodeBreakerNetwork
impl NodeBreakerNetwork
Sourcepub fn new(
buses: Vec<Bus>,
lines: Vec<Line>,
transformers: Vec<Transformer>,
shunts: Vec<ShuntAdm>,
view: BusView,
topology: NodeBreakerTopology,
switch_labels: Vec<String>,
zero_injection: Vec<bool>,
treatment: SwitchTreatment,
) -> Self
pub fn new( buses: Vec<Bus>, lines: Vec<Line>, transformers: Vec<Transformer>, shunts: Vec<ShuntAdm>, view: BusView, topology: NodeBreakerTopology, switch_labels: Vec<String>, zero_injection: Vec<bool>, treatment: SwitchTreatment, ) -> Self
Assembles the network, stamping retained switches under treatment.
Sourcepub fn switch_kind(&self, switch: SwitchIdx) -> Option<SwitchKind>
pub fn switch_kind(&self, switch: SwitchIdx) -> Option<SwitchKind>
A switch’s kind — breaker, disconnector, fuse and so on.
Sourcepub fn switch_label(&self, switch: SwitchIdx) -> String
pub fn switch_label(&self, switch: SwitchIdx) -> String
A switch’s source-model identifier, or its index rendered as text when the source supplied none.
Sourcepub fn n_branches(&self) -> usize
pub fn n_branches(&self) -> usize
Total branch count — the length of every branch-indexed vector the solvers return for this network.
Sourcepub fn branch_of_retained(&self, n: usize) -> Option<usize>
pub fn branch_of_retained(&self, n: usize) -> Option<usize>
The flat branch index of the nth retained switch, or None if it was
degenerate (both ends on one bus) and therefore not stamped.
Sourcepub fn branch_of_switch(&self, switch: SwitchIdx) -> Option<usize>
pub fn branch_of_switch(&self, switch: SwitchIdx) -> Option<usize>
The flat branch index of a switch named by its position in the source
topology, or None if it was not retained or was degenerate.
Sourcepub fn switch_branches(&self) -> Vec<(SwitchIdx, usize)>
pub fn switch_branches(&self) -> Vec<(SwitchIdx, usize)>
Every retained switch’s (SwitchIdx, branch index), skipping degenerate
ones — the list a contingency campaign iterates.
Sourcepub fn set_switch_open(&mut self, switch: SwitchIdx, open: bool) -> bool
pub fn set_switch_open(&mut self, switch: SwitchIdx, open: bool) -> bool
Opens or closes a retained switch in place.
Changes Y-bus values only: the branch keeps its structural entries at zero when open, so the Y-bus sparsity pattern is unchanged.
The Jacobian pattern is a separate question, and the distinction matters for what a caller must invalidate:
- A cached
JacobianPatternis always stale afterwards, since it stores each entry’s admittance. - Its size changes too whenever the flip severs part of the network:
connected_componentssees the opening (it reads values, not just structure),mark_unreferenced_islandspins the stranded buses toSlack, and the unknown count moves with them.
So PersistentSolver::invalidate_admittances
— which keeps the symbolic factorization — is correct only for a switch
the caller knows cannot island anything. Otherwise use
reset. Getting this wrong
used to panic inside faer; RealSparseSystem::solve_values now
refuses the mismatched call instead, so it surfaces as a failed solve.
Returns false if the switch is not retained or was degenerate.
Sourcepub fn is_switch_open(&self, switch: SwitchIdx) -> Option<bool>
pub fn is_switch_open(&self, switch: SwitchIdx) -> Option<bool>
Whether a retained switch is currently open. None if it is not
retained or was degenerate.
Sourcepub fn constrained_switches(&self) -> Vec<ConstrainedSwitch>
pub fn constrained_switches(&self) -> Vec<ConstrainedSwitch>
This network’s retained switches as equality constraints, for
constrained::solve_constrained.
Positionally matches BusView::retained,
including the degenerate switches — a switch whose two ends already share
a bus becomes a self-loop, which the constrained solver reports as
indeterminate rather than skipping. Keeping them here is what lets a
caller index straight from a switch to its flow.
Only meaningful under SwitchTreatment::Constrain. Under
Regularize the switches are already in
the branch list, and passing them here as well would model each of them
twice.
Sourcepub fn switch_flow(
&self,
switch: SwitchIdx,
voltages: &[Complex<f64>],
) -> Option<(f64, f64)>
pub fn switch_flow( &self, switch: SwitchIdx, voltages: &[Complex<f64>], ) -> Option<(f64, f64)>
Complex power entering a switch at its from terminal, given solved bus
voltages. None if the switch has no branch.
This is branch_flow::terminal_flow at the switch’s own index — a
switch reports its flow through exactly the same path any other branch
does.
Trait Implementations§
Source§impl Clone for NodeBreakerNetwork
impl Clone for NodeBreakerNetwork
Auto Trait Implementations§
impl Freeze for NodeBreakerNetwork
impl RefUnwindSafe for NodeBreakerNetwork
impl Send for NodeBreakerNetwork
impl Sync for NodeBreakerNetwork
impl Unpin for NodeBreakerNetwork
impl UnsafeUnpin for NodeBreakerNetwork
impl UnwindSafe for NodeBreakerNetwork
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> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
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