Repository navigation
Release 1.1.0
lightsim2grid 1.1.0
This release adds a continuation powerflow and differentiable batch powerflows (pytorch), and
models storage units and active power limits more fully. It also detects results that are
physically unreachable and makes the solvers faster across the board. Many correctness fixes
come with it, mostly around voltage control, the distributed slack and the solver cache.
Highlights
- Continuation powerflow:
ContinuationPowerFlow/run_cpftraces the PV curve from the
current operating point to a target state and stops at the voltage-collapse nose. Its options
follow MATPOWER'scpf.*.load_steering/gen_steeringchoose which elements move, and
ContinuationSweepCPPcomputes the whole curve for a single symbolic factorization. - Differentiable powerflows:
lightsim2grid.differentiable.BatchCPUPowerFlowturns a batch
of powerflows into a pytorch operation. It is differentiable with respect to injections and
generator voltage setpoints, through the adjoint of the batch (keep_jacobian/solve_JT,
withsolve_transposeon the linear solvers). Install it with
pip install lightsim2grid[torch]; torch remains optional. - Physical violations:
compute_physical_violationson every batch algorithm and on its
python wrapper reports solutions that no real grid can reach. These are a bus needing more
reactive power than its machines can provide, an hvdc line past its maximum power, or a
generator or battery pushed past its P limits by the distributed slack. Every
LimitViolationnow carries aViolationCategory: OPERATIONAL, PHYSICAL or SOLVER. - Storage units: batteries can take part in the distributed slack and regulate their bus
voltage, and they have optional active power limits.init_from_pypowsyblreads all three
the way OpenLoadFlow does. - Generators: optional active power limits (
set_gen_p_limits), read by every loader that
provides them, and a reactive sharing key (set_gen_reactive_key) for generators that
regulate the same bus. - MATPOWER in grid2op: with
LightSimBackend(loader_method="matpower"), a grid2op
environment can ship a MATPOWER case as its powergrid. - Generator contingencies:
ScenarioSweep.set_contingency_gens(mask)drops a generator for
a given step. It re-shares the distributed slack and switches the bus PV -> PQ when needed,
without any extra symbolic factorization.
Breaking changes
BINARY_FORMAT_VERSIONgoes from 4 to 10. Bus connectivity is no longer stored (it is
recounted from the elements), and generators and storage units carry new state. Files saved
with an earlier version no longer load.- A grid where several elements regulate the same bus with different voltage setpoints is
now refused. Before, the last setpoint written silently won. LSGrid.deactivate_bus/reactivate_busare now deprecated no-ops. A bus is in the
powerflow if and only if an active element sits on it, so to remove a bus, disconne
elements.LSGrid.get_bus_status()returns a new list (a copy) instead of a reference to an
vector.- (C++) Everything a solver family caches now lives in one
SolverSideCache. This ch
memory layout ofLSGrid, so code that uses anLSGridacross a module boundary (
example gpusim2grid) must be rebuilt.
Fixes
Correctness of the powerflow
- The fast-decoupled algorithms kept the distributed slack at its initial guess. It i
re-solved at every iteration, and FDPF lands on the Newton-Raphson answer. - Fast-decoupled and Gauss-Seidel solved grids with remote or shared voltage control,
voltage-mode SVCs, to a wrong answer.ac_pfnow refuses such grids for these algorithms. - The active power of generators sharing the distributed slack with batteries was ove
- The reactive power published for elements sharing a bus could be NaN or counted twice.
- The Jacobian of hvdc angle droop now includes the derivative of the dc-line losses.
solution was already right; the batch gradients were not. - A converged Newton-Raphson now always reports angles in [-pi, pi].
- A slack bus held by a voltage-regulating storage unit is no longer given a free voltage
magnitude.
Solver cache and grid state
- A non-converged powerflow keeps its last iterate readable (
max_iter=0used to ret
nothing). - A powerflow that throws part-way no longer leaves a cache that claims to be up to d
unset_changes()called with a modification that was never solved no longer makes the next
powerflow solve the old grid.consider_only_main_component()andupdate_topo()now report every bus leaving t
This fixes grid2op'sautomatically_disconnect=True.- Bus connectivity no longer drifts from the elements: after a refused
change_bus,
holding only an SVC, and when read before the first powerflow. - Opening one end of a phase-shifting transformer now invalidates the DC injections.
Batch algorithms
ContingencyAnalysisCPPgains, in python, everything the other batch classes gained since
1.0.0.- In
handle_disconnected_gridmode, a contingency that strands a lone remote voltage
regulator is no longer reported as diverged. - Batch
modify_gen_vnow applies to generators that regulate a remote bus. - Stale results after registering a new contingency no longer make
get_flows()rais - The batch algorithms no longer write into the grid's own cache or reset its solver.
OpenLoadFlow comparison (bake_outer_loops / remove_outer_loops)
- Closer agreement with OpenLoadFlow on voltage control, reactive limits (clamping an
capability curve extrapolation), shared controls, and the default distributed slack. remove_outer_loopsno longer depends on the process's hash seed.
Misc
- Selecting a fast-decoupled algorithm by name no longer fails on the first powerflow
- The KLU / NICSLU / CKTSO headers can be included twice in a translation unit.
Performance
Answers are identical to 1.0.0 (bit for bit in most cases), and a large share of the
powerflow has been removed:
- Batch algorithms: the base case (grid reading, connectivity, the "n" powerflow and the
Jacobian analysis) is kept betweencompute()calls, per-thread algorithms are kep
a single graph search settles every N-1 contingency. The row loop is also leaner. - Newton-Raphson: cheaper Jacobian assembly and sparsity build, fewer allocations
iteration, and a better initial distributed slack. - Other algorithms: fast-decoupled is noticeably faster, Gauss-Seidel is much fas
building the DC matrix is faster. - Results: branch flows, currents and shunts are computed faster.
- Grid side: the voltage-control plan is built once per powerflow, bus connectivi
tracked incrementally, and the checks on ids the library produced itself are debug-only.
Every check on user input is kept. -march=nativebuilds now also compile KLU and SuiteSparse with it.
Other additions
- Three cache levels on the batch algorithms:
clear_grid_results(),clear_batch_in andclear_batch_outputs()`. get_linear_solver_stats()on the batch classes, to check that a sweep really reuses its
factorization.set_refactor_fallbackon every linear solver.- Every loader now records which substation each element belongs to. A MATPOWER case
BASE_KVis 0 everywhere is now accepted. - (C++)
VoltageControlPlan,BaseAlgo::get_bus_mismatch(), newAlgoControlflags
shared interface for the element containers (BranchContainer, `VoltageSourceConta
...). - New benchmarks (
benchmarks/cache_profiling/,make_exotic_grid.cpp) and new C++
The full list is in CHANGELOG.rst.