pub struct BatchSolver { /* private fields */ }Expand description
Solves many scenarios over one shared topology, in parallel.
let scenarios: Vec<Scenario> = (0..256)
.map(|k| Scenario::new(vec![BusOverride::new(3).p(-0.1 * k as f64)]))
.collect();
let batch = BatchSolver::new(JacobianBackend::KluNative);
let reports = batch.solve(&buses, ybus, &scenarios, 1e-6, 20).unwrap();
assert_eq!(reports.len(), 256);Implementations§
Source§impl BatchSolver
impl BatchSolver
Sourcepub fn new(backend: JacobianBackend) -> Self
pub fn new(backend: JacobianBackend) -> Self
Uses rayon’s global thread pool (honors RAYON_NUM_THREADS).
Sourcepub fn with_threads(
backend: JacobianBackend,
threads: usize,
) -> Result<Self, BatchError>
pub fn with_threads( backend: JacobianBackend, threads: usize, ) -> Result<Self, BatchError>
Uses a dedicated pool of exactly threads workers. Built once here
and reused by every solve call, so repeated batches never pay
thread-creation cost.
Sourcepub fn solve(
&self,
buses_template: &[Bus],
ybus: &YBusSparse,
scenarios: &[Scenario],
tol: f64,
max_iter: usize,
) -> Result<Vec<PowerFlowReport>, BatchError>
pub fn solve( &self, buses_template: &[Bus], ybus: &YBusSparse, scenarios: &[Scenario], tol: f64, max_iter: usize, ) -> Result<Vec<PowerFlowReport>, BatchError>
Solves every scenario and returns one PowerFlowReport each, in
scenario order regardless of thread count.
Each scenario starts from buses_template with its overrides applied
and a fresh linear_initial_guess, so scenarios never influence
each other’s starting point — results are identical to a sequential
loop over PersistentSolver::solve, which tests/batch_solver_test.rs
asserts directly.
A scenario that fails to converge is not an error: its report
carries SolveStatus::MaxIterationsReached/Singular and the rest of
the batch is unaffected. Divergent contingency scenarios are normal
and must not poison the batch.
Sourcepub fn solve_contingencies(
&self,
buses_template: &[Bus],
lines: &[Line],
transformers: &[Transformer],
shunts: &[ShuntAdm],
scenarios: &[Scenario],
tol: f64,
max_iter: usize,
) -> Result<Vec<PowerFlowReport>, BatchError>
pub fn solve_contingencies( &self, buses_template: &[Bus], lines: &[Line], transformers: &[Transformer], shunts: &[ShuntAdm], scenarios: &[Scenario], tol: f64, max_iter: usize, ) -> Result<Vec<PowerFlowReport>, BatchError>
Solves every scenario honoring Scenario::branch_outages,
returning one PowerFlowReport each in scenario order.
Takes branch lists rather than a finished Y-bus, because an outage changes the network rather than its bus values, and a Y-bus has already summed the branches away.
§Two paths, and why
Most contingencies leave the network connected. Those take the fast
path: network::build_ybus_with_outages
rebuilds the Y-bus with the outaged branches contributing nothing but
keeping their structural entries, so the sparsity pattern — and
therefore jacobian::JacobianPattern and the symbolic factorization
behind it — is bit-for-bit the intact network’s. A worker reuses one
PersistentSolver across every such scenario it handles, exactly as
solve does for injection-only batches. That is what
this method exists to make possible, and it is why the old
“an outage forces its own sparsity pattern” objection turns out to be
avoidable in the common case.
A contingency that splits the network cannot use that trick:
connected_components reads the
same structural entries and cannot tell a zero-valued one from a live
one, so it would report the severed buses as still connected and their
now-referenceless rows would come back as a singular solve instead of an
honest NoReferenceBus. Those scenarios are detected up front with
structural_component_count
— removing branches can only increase the component count, so a count
above the intact network’s is exactly the “something split” condition —
and take a slow path: the outaged branches are dropped outright and the
worker’s solver is reset around that scenario, since its pattern
genuinely differs.
A scenario that fails to converge is not an error: its report carries
the failure and the rest of the batch is unaffected. Islanding into a
sourceless region is not a failure at all — that island comes back
IslandStatus::NoReferenceBus, which for N-1 screening is a result.
Auto Trait Implementations§
impl !RefUnwindSafe for BatchSolver
impl !UnwindSafe for BatchSolver
impl Freeze for BatchSolver
impl Send for BatchSolver
impl Sync for BatchSolver
impl Unpin for BatchSolver
impl UnsafeUnpin for BatchSolver
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