pub struct PersistentSolver { /* private fields */ }Expand description
A Newton-Raphson solver that reuses its symbolic factorization (fill-
reducing ordering, elimination-graph structure — the expensive,
topology-only part of a sparse LU factorization) across repeated
solve calls, not just across the iterations within
one call the way newton_raphson_with_backend already does.
This matters for any workload that solves the same topology repeatedly — a time series, a batch of scenarios, contingency analysis — where re-deriving the ordering from scratch on every call is pure overhead. Measured on a 9,241-bus case, reusing analysis across repeated solves cut per-solve time by ~45% (COLAMD/AMD/BTF ordering was ~1/3 of total solve time when redone from scratch every call).
let mut solver = PersistentSolver::new(JacobianBackend::Scalar);
for _ in 0..10 {
// ... update buses' p_spec/q_spec for the next scenario ...
solver.solve(&mut buses, ybus, 1e-6, 20);
}Call reset (or construct a new PersistentSolver) if
the topology itself changes between solves — a different set of lines,
transformers, or bus types — since the cached ordering would otherwise
silently apply to the wrong sparsity pattern. Changing only bus
values (p_spec, q_spec, voltage_mag/voltage_ang initial guess)
between calls is exactly the case this is designed for and needs no
reset.
Implementations§
Source§impl PersistentSolver
impl PersistentSolver
pub fn new(backend: JacobianBackend) -> Self
Sourcepub fn solve(
&mut self,
buses: &mut [Bus],
ybus: &YBusSparse,
tol: f64,
max_iter: usize,
) -> Vec<IslandReport>
pub fn solve( &mut self, buses: &mut [Bus], ybus: &YBusSparse, tol: f64, max_iter: usize, ) -> Vec<IslandReport>
Runs Newton-Raphson to convergence (or max_iter), reusing cached
symbolic factorization from a previous solve() call on this same
PersistentSolver when available. See the type-level doc comment
for when a cached factorization stays valid.
Like newton_raphson_with_backend, partitions buses into
connected components first (network::connected_components/
classify/mark_unreferenced_islands) so a disconnected, sourceless
region can’t make the whole Jacobian singular, and returns each
component’s own outcome rather than one flat status.
Sourcepub fn solve_with_stats(
&mut self,
buses: &mut [Bus],
ybus: &YBusSparse,
tol: f64,
max_iter: usize,
) -> (Vec<IslandReport>, SolveStats)
pub fn solve_with_stats( &mut self, buses: &mut [Bus], ybus: &YBusSparse, tol: f64, max_iter: usize, ) -> (Vec<IslandReport>, SolveStats)
Exactly solve, additionally returning the
SolveStats the solve produced — iteration count and the
per-iteration convergence trace the loop used to print to stdout.
solve is a wrapper that discards them.
Sourcepub fn invalidate_admittances(&mut self)
pub fn invalidate_admittances(&mut self)
Discards any cached symbolic factorization. Call this before the
next solve() if the topology (not just bus values) has changed
since the last call.
Invalidates the cached Jacobian recipe while keeping every
backend’s symbolic factorization.
The right call when the Y-bus’s values changed but its sparsity
pattern did not — which is exactly a branch contingency built by
network::build_ybus_with_outages,
where the outaged branch keeps its structural entries at zero. The
symbolic factorization depends only on the (row, col) pairs
JacobianPattern::to_triplets emits, and those are unchanged, so it
stays valid; the entries’ cached admittances do not, and must be
re-analyzed.
Re-analysis is O(nonzeros) against the symbolic factorization’s fill-reducing ordering and elimination-tree work, which is the expensive half — measured at ~45% of solve time on a 9,241-bus case. Keeping that is what makes an N-1 sweep cheaper than a sequence of independent solves.
Use reset instead when the pattern itself changed:
a different bus-type assignment, or a topology whose branches were
genuinely dropped rather than zeroed.
pub fn reset(&mut self)
Auto Trait Implementations§
impl Freeze for PersistentSolver
impl RefUnwindSafe for PersistentSolver
impl Send for PersistentSolver
impl Sync for PersistentSolver
impl Unpin for PersistentSolver
impl UnsafeUnpin for PersistentSolver
impl UnwindSafe for PersistentSolver
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