Releases: Grid2op/lightsim2grid
Release list
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.
Release v1.0.0
Lots of changes, the full list is available on the changelog
This release focuses on safety. Lots of safe guards have been put in place to keep the internal states of lightsim2grid memory consistent (no out of memory read or write) and avoiding segfault or other hard failures leading to the instant termination of python interpreter.
This release also completely refactored the Newton Raphson family of algorithms, which can now handle more gracefully a broader type of inputs and different customization.
It also improves usability but improving init from pandapower and pypowsybl, adding initializers from Matpower and powermodels. There is also a dedicated binary format that allow to save and load back lightsim2grid LSGrid really fast (less than a few ms for most grids).
Finally, for this release note at least, the CPP part has been heavily refactored to allow for future integration with other languages (split of the python binding and the core CPP library) but also to allow ghe use external "plugin's" (as .so / python package) to compute the powerflows internally while still using LSgrid as the "python front end".
Lots of breaking changes, all them in the changelog.
Release candidate 1.0.0.rc4
Some additional fixed and API consistency
Release candidate 1.0.0.rc3
Following and improving on the work in v1.0.0.rc2 by fixing bugs arising in batch computation (contingency analysis or time series computation) when some new components (remote voltage control, SVC etc.) are present
Release candidate 1.0.0.rc2
Second release candidate for 1.0.0 — a major version with a pluggable solver architecture, several new grid elements, and expanded network-loader support. See CHANGELOG.rst for the full list of changes.
Highlights
Pluggable solver architecture: built-in and external algorithms now share a common AlgorithmRegistry, loadable by name — including third-party C++ solver plugins (load_algorithm_plugin)
New grid elements: proper HVDC support in AC/DC powerflow, Static Var Compensators (SVC), a dedicated StorageContainer, and remote voltage control for generators/SVCs
Expanded network loading: init_from_pypowsybl gains operating limits, zero-impedance line fusing, and OLF-parity tooling (bake_outer_loops, compare_baked); new native loaders init_from_powermodels and init_from_pf_delta
Performance: multi-threaded ContingencyAnalysis (nb_thread), plus a fast additive binary serialization path (save_binary/load_binary) alongside pickle
Correctness/hardening: whole-grid check_grid() consistency validation (run automatically on load), ASan/UBSan CI, a new Catch2 C++ unit test suite
Breaking changes
Dropped Python 3.8 support (EOL)
lightsim2grid.SolverType moved to lightsim2grid.solver.SolverType
Binary format bumped (grids saved with an older version need re-saving); pickle format changed for storage and HVDC containers
Newton-Raphson Jacobian column ordering changed
Several C++ plugin-facing API renames (set_gridmodel → set_lsgrid, compute_pf signature, etc.) — see CHANGELOG.rst if you maintain a solver plugin
Release: 0.13.1
Yet another release focusing on internal modifications that will allow next developments.
[0.13.1] 2026-04-21
- [BREAKING] when loading a powergrid from pypowsybl with "use_buses_for_sub" tagged
and disconnected element on the grid will now raise a RuntimeError. Before there were
some "automatic" bahaviour to try to find a possible bus which could lead to
error afterwards. - [BREAKING] adding a more precise information about linear solvers. The "refactor" timings
are now also available in solver.get_timers_jacobian() which now returns a tuple of size 10 - [FIXED] an issue where disconnected powerlines could be tagged as "fakely connected"
- [FIXED] some issues when loading a grid from pypowsybl in case of disconnected elements.
- [FIXED] remove the undefined behaviour while maintaining compile time check to prevent
wrong conversion from different bus labelling. - [IMPROVED] the CI to allow automatic push on pypi on new version tag (introduced in version 0.12.0)
- [IMPROVED] reduce code duplication between ContingencyAnalysis and TimeSerie (cpp side)
- [IMPROVED] handling of branches disconnected at only one side: less code duplication and
it should be working with TimeSeries and ContingencyAnalysis - [IMPROVED] speed (DC mode): avoid the systematic call to "refactor" when Ybus is not changed
when using DC approximation. - [IMPROVED] simplify the future integration of other linear solvers and the logic when linear_solvers
are called by decoupling "refactor" steps from "solve" steps (they used to be all under the same
"solve" method).
Release: 0.13.0
This release introduces a more modern building approach (based on scikit-build core) which allow a simpler build mechanism (especially when building from sources) relying on cmake.
It also adresses the remaining "copy on write" issues when initializing a grid from pandapower.
Full changes are:
- [PENDING DEPRECATION] the cpp module (lightsim2grid_cpp) will not be usable directly anymore.
This means that calls like "from lightsim2grid_cpp import XXX" will not work. To replace them
you need to perform "from lightsim2grid.lightsim2grid_cpp import XXX" - [FIXED] some compilation issues on some systems (eg windows when using c++23 standard)
- [FIXED] some issues with "copy on write" and pandas 3 when init from pandapower grid.
- [IMPROVED] cleaner
cktso_lib(from lightsim2grid.compilation_options import cktso_lib) : the file name and extension are omitted - [IMPROVED] easier build by relying on cmake and scikit_build_core to build the cpp part
- [IMPROVED] SuiteSparse to version 7.12.2 (2026-02-05)
Release: 0.12.2
[0.12.2] 2026-02-05
- [FIXED] an issue with shunt buses (was set to 1 even if they were disconnected)
- [FIXED] a warning when applying actions on generator votlage setpoints (due to NaN)
- [FIXED] pandapower grid could be modified when importing a grid from pandapower (extend fixes in #123)
- [FIXED] documentation issue about ContingencyAnalysis (see #124 )
- [IMPROVED] add a test to make sure generator types are available if using
dist_slack_non_renewinformation. - [IMPROVED] test coverage on shunts (a test needed to be skipped due to float comparison in grid2op)
Release: 0.12.1
[0.12.1] 2026-01-09
- [FIXED] phase shift transformers are now properly modeled
for both pandapower (new in this version) and pypowsybl (already
the case in previous version) - [FIXED] a performance issue for all "XXXSingleSlack" (eg KLUSingleSlack) algorithm (filling of the initial
Jacobian matrix was extremly slow due to the massive 'insert' of data in the eigen sparse matrix instead
of relying on the "setFromTriplets" method) - [FIXED] an normal "exception" was not catched in the
close()method of LightSimBackend in case the
backend was closed before any grid was loaded. - [ADDED] possibility to pickle independantly all part of the grid (eg gridmodel.get_lines()
can be pickled independantly from anything else) NB pickling and un-pickling
lightsim2grid objects can only be used for the same lightsim2grid version. - [ADDED] the
init_from_n_powerflowproperty for ContingencyAnalysis (and
ContingencyAnalysisCPP). It allows to chose if the computation of the contingencies
are initialized with the complex voltages resulting of the powerflow in N
(init_from_n_powerflow=True) or if they are initialized from the
given input vector (init_from_n_powerflow=False). Defaults toFalse
Release: 0.12.0
[0.12.0] 2026-01-06
-
[BREAKING] for better consistency, and following pypowsybl convention, trafo and lines "side"
are now called "1" and "2" instead of "hv" / "lv" (for trafo) or "or" / "ex" for powerlines.
For example, what used to be accessible withgridmodel.change_bus_powerline_or(...)is now called
gridmodel.change_bus1_powerline(). This affects powerlines, transformers and dc powerlines but also
"LineInfo", "TrafoInfo" and "DCPowerlineInfo". See below for a (should-be exhaustive) list of changes. -
[BREAKING] the
init_pp_backendpublic attribute is now private (called now_init_pp_backend) and
optional, meaning it'sNonewhen the grid is initialized from pypowsybl (for example). -
[FIXED] some issues with the "load_grid_from_pypowsybl" function (and making sure the graph of the structure
of the lightsim2grid gridmodel matches the one of the pypowsybl grid). -
[FIXED] an issue with the handling of the slack due to a not correct implementation
ofupdate_slack_weights_by_idcpp side (previous slacks were not removed, slacks get_slack_weights
were prop to target_p which caused issues when all slacks had targetp==0.) -
[FIXED] an issue with serialization / de serialization caused by an error in serializing the solver types.
-
[ADDED] in all "xxxInfo" (eg "LoadInfo") information about subtation and position in the topology
vector, with thesub_id/pos_topo_vect(forLoadInfo,SGenInfo,GenInfo,StorageInfo,ShuntInfo)
andsub1_id/sub2_id/pos1_topo_vect/pos2_topo_vect(forLineInfo,TrafoInfoandDCLineInfo) -
[ADDED] possibility to load the pypowsybl grid with extra key-words arguments (by using
pypowsybl_load_kwargsin the
loader_kwargsof LightSimBackend) -
[ADDED] possibility to initialize LightSimBackend with an already loaded grid (by using the
gridkey of the
loader_kwargsof LightSimBackend when loading it with pypowsybl) -
[ADDED] possibility to change the ratio (
rho) of transformers (gridmodel.change_ratio_trafo(trafo_id, new_rho)) -
[ADDED] possibility to change the phase shift (
alpha) of transformers (gridmodel.change_shift_trafo(trafo_id, new_alpha)) -
[ADDED] more consistency checkings to avoid "negative buses" cpp side.
-
[ADDED] information about the coefficients assigned on the Ybus matrix for
LineInfoandTrafoInfo:yac_11,yac_12,
yac_21,yac_22,ydc_11,ydc_12,ydc_21, andydc_22 -
[ADDED] possibility to have a powerline / transformer connected on only one side (for DC and Newton-Raphson algorithm, not implemented
for fast-decoupled yet). This means that powerlines / transformers have 3 statuses: one for each side and one "global". -
[ADDED] possibility to choose the way lightsim2grid will internally treat the powerlines status:
ignore_status_global(gridmodel.set_ignore_status_global(True)orgridmodel.set_ignore_status_global(False)). If set
toFalse(default) the the "global" status is synch with all the others. For example you can deactivate both sides of a line by
deactivatingstatus_globaland conversely if you deactivate both side of a given line, then its "status_global" is set
to "activated". Ifignore_status_globalis set toTruethenglobal_statusis not updated at all and ignored (NB in
this case, callinggridmodel.deactivate_line(...)will deactivate both sides but not the "global status")synch_status_both_side(self.model.set_synch_status_both_side(XXX)). If set toTrue(default) then the status of each
side of any given line will be synched. Meaning that if an action disconnects one side, it will also disconnect the "status_global"
and the other side (NB in this case if the same actions both connects one side and disconnect another, then the outcome is "undefined").
Ifsynch_status_both_sideisFalsethen each side of the powerline is independant from the other (which can lead to powerline /
transformer being connected at only one side).- The complete bahviour is tested in
tests/test_line_disco_one_side.py. Feel free to have a look if you need more information.
-
[IMPROVED] Eigen to version 5.0.1 (2025/11/11)
-
[IMPROVED] rename all ".h" file to ".hpp" for cpp headers (cpp side).
-
[IMPROVED] consistency of "bus labelling" cpp side (implement compile time check to prevent accidental conversion from
LocalBusId,GlobalBusId/GridModelBusIdand / orSolverBusId)
Table to upgrade the names:
============================= ======================= =======================
Class Name Old Attribute Name New Attribute Name
============================= ======================= =======================
TrafoContainer get_bus_from get_bus_id_side_1
TrafoContainer get_bus_to get_bus_id_side_2
TrafoInfo bus_hv_id bus1_id
TrafoInfo bus_lv_id bus2_id
TrafoInfo connected connected_global
TrafoInfo h_pu h1_pu or h2_pu
TrafoInfo is_tap_hv_side is_tap_side_1
TrafoInfo res_p_hv_mw res_p1_mw
TrafoInfo res_q_hv_mvar res_q1_mvar
TrafoInfo res_v_hv_kv res_v1_kv
TrafoInfo res_a_hv_ka res_a1_ka
TrafoInfo res_p_lv_mw res_p2_mw
TrafoInfo res_q_lv_mvar res_q2_mvar
TrafoInfo res_v_lv_kv res_v2_kv
TrafoInfo res_a_lv_ka res_a2_ka
TrafoInfo res_theta_hv_deg res_theta1_deg
TrafoInfo res_theta_lv_deg res_theta2_deg
LineContainer get_bus_from get_bus_id_side_1
LineContainer get_bus_to get_bus_id_side_2
LineInfo connected connected_global
LineInfo bus_or_id bus1_id
LineInfo bus_ex_id bus2_id
LineInfo h_pu removed
LineInfo h_or_pu h1_pu
LineInfo h_ex_pu h2_pu
LineInfo res_p_or_mw res_p1_mw
LineInfo res_q_or_mvar res_q1_mvar
LineInfo res_v_or_kv res_v1_kv
LineInfo res_a_or_ka res_a1_ka
LineInfo res_p_ex_mw res_p2_mw
LineInfo res_q_ex_mvar res_q2_mvar
LineInfo res_v_ex_kv res_v2_kv
LineInfo res_a_ex_ka res_a2_ka
LineInfo res_theta_or_deg res_theta1_deg
LineInfo res_theta_ex_deg res_theta2_deg
DCLineContainer get_bus_from get_bus_id_side_1
DCLineContainer get_bus_to get_bus_id_side_2
DCLineInfo connected connected_global
DCLineInfo bus_or_id bus1_id
DCLineInfo bus_ex_id bus2_id
DCLineInfo target_vm_or_pu target_vm1_pu
DCLineInfo target_vm_ex_pu target_vm2_pu
DCLineInfo gen_or gen1
DCLineInfo gen_ex gen2
DCLineInfo res_p_or_mw res_p1_mw
DCLineInfo res_q_or_mvar res_q1_mvar
DCLineInfo res_v_or_kv res_v1_kv
DCLineInfo res_p_ex_mw res_p2_mw
DCLineInfo res_q_ex_mvar res_q2_mvar
DCLineInfo res_v_ex_kv res_v2_kv
DCLineInfo res_theta_or_deg res_theta1_deg
DCLineInfo res_theta_ex_deg res_theta2_deg
============================= ======================= =======================