Expand description
Batched power flow: one topology, many scenarios, solved across all cores.
This is the workload where parallelism actually pays. A single solve is ~60% sparse LU, which neither threads nor a GPU help with; but N-1 screening, time series/QSTS and Monte Carlo run thousands of independent solves over one unchanging topology, and those scale essentially linearly.
Two properties make that cheap here:
- Every scenario shares one
YBusSparse, so the Jacobian’s sparsity pattern is identical across the whole batch. Each worker keeps onePersistentSolverand amortizes a single symbolic factorization across its entire share of the batch — measured at ~45% of solve time on a 9,241-bus case when redone per solve. - Scenarios are fully independent, so the only coordination is handing out indices.
BatchSolver::solve_contingencies extends this to branch outages,
which change the network rather than its bus values. The first property
above appears to rule that out — and it was long assumed to — but only the
sparsity pattern has to hold still, not the Y-bus itself:
network::build_ybus_with_outages
takes a branch out while keeping its structural entries, so the symbolic
factorization still carries across the sweep. What cannot carry is the
Jacobian’s cached per-nonzero recipe, which stores the admittance it was
analyzed against; that is re-derived per scenario via
PersistentSolver::invalidate_admittances, at O(nonzeros) rather than a
fresh symbolic analysis. Measured at 2.0–2.7x against independent solves,
single-threaded, before any parallelism.
This is also the CPU baseline any future GPU work has to beat: beating a single-threaded CPU solver is not a result.
Re-exports§
pub use crate::scenario::BatchError;pub use crate::scenario::BusOverride;pub use crate::scenario::Scenario;pub use crate::scenario::uniform_load_scaling;
Structs§
- Batch
Solver - Solves many scenarios over one shared topology, in parallel.