Skip to content

Releases: Grid2op/lightsim2grid

Release 1.1.0

Choose a tag to compare

@BDonnot BDonnot released this 22 Sep 15:07
dec6adc

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_cpf traces the PV curve from the
    current operating point to a target state and stops at the voltage-collapse nose. Its options
    follow MATPOWER's cpf.*. load_steering / gen_steering choose which elements move, and
    ContinuationSweepCPP computes the whole curve for a single symbolic factorization.
  • Differentiable powerflows: lightsim2grid.differentiable.BatchCPUPowerFlow turns 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,
    with solve_transpose on the linear solvers). Install it with
    pip install lightsim2grid[torch]; torch remains optional.
  • Physical violations: compute_physical_violations on 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
    LimitViolation now carries a ViolationCategory: 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_pypowsybl reads 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_VERSION goes 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_bus are 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 of LSGrid, so code that uses an LSGrid across 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_pf now 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=0 used 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() and update_topo() now report every bus leaving t
    This fixes grid2op's automatically_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

  • ContingencyAnalysisCPP gains, in python, everything the other batch classes gained since
    1.0.0.
  • In handle_disconnected_grid mode, a contingency that strands a lone remote voltage
    regulator is no longer reported as diverged.
  • Batch modify_gen_v now 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_loops no 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 between compute() 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=native builds now also compile KLU and SuiteSparse with it.

Other additions

  • Three cache levels on the batch algorithms: clear_grid_results(), clear_batch_in and clear_batch_outputs()`.
  • get_linear_solver_stats() on the batch classes, to check that a sweep really reuses its
    factorization. set_refactor_fallback on every linear solver.
  • Every loader now records which substation each element belongs to. A MATPOWER case
    BASE_KV is 0 everywhere is now accepted.
  • (C++) VoltageControlPlan, BaseAlgo::get_bus_mismatch(), new AlgoControl flags
    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

Choose a tag to compare

@BDonnot BDonnot released this 29 Aug 15:45
b950131

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

Pre-release

Choose a tag to compare

@BDonnot BDonnot released this 22 Aug 15:25
dd18921

Some additional fixed and API consistency

Release candidate 1.0.0.rc3

Pre-release

Choose a tag to compare

@BDonnot BDonnot released this 10 Aug 06:16
a1207f7

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

Pre-release

Choose a tag to compare

@BDonnot BDonnot released this 04 Aug 20:32
362e594

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

Choose a tag to compare

@BDonnot BDonnot released this 21 Apr 12:24
5bfc7f8

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

Choose a tag to compare

@BDonnot BDonnot released this 14 Apr 09:18
4c07ffd

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

Choose a tag to compare

@BDonnot BDonnot released this 06 Feb 08:14
c983af9

[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_renew information.
  • [IMPROVED] test coverage on shunts (a test needed to be skipped due to float comparison in grid2op)

Release: 0.12.1

Choose a tag to compare

@BDonnot BDonnot released this 09 Jan 16:39
da45850

[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_powerflow property 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 to False

Release: 0.12.0

Choose a tag to compare

@BDonnot BDonnot released this 06 Jan 11:06
2b7ae34

[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 with gridmodel.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_backend public attribute is now private (called now _init_pp_backend) and
    optional, meaning it's None when 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
    of update_slack_weights_by_id cpp 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 the sub_id / pos_topo_vect (for LoadInfo, SGenInfo, GenInfo, StorageInfo, ShuntInfo)
    and sub1_id / sub2_id / pos1_topo_vect / pos2_topo_vect (for LineInfo, TrafoInfo and DCLineInfo)

  • [ADDED] possibility to load the pypowsybl grid with extra key-words arguments (by using pypowsybl_load_kwargs in the
    loader_kwargs of LightSimBackend)

  • [ADDED] possibility to initialize LightSimBackend with an already loaded grid (by using the grid key of the
    loader_kwargs of 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 LineInfo and TrafoInfo: yac_11, yac_12,
    yac_21, yac_22, ydc_11, ydc_12, ydc_21, and ydc_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) or gridmodel.set_ignore_status_global(False)). If set
      to False (default) the the "global" status is synch with all the others. For example you can deactivate both sides of a line by
      deactivating status_global and conversely if you deactivate both side of a given line, then its "status_global" is set
      to "activated". If ignore_status_global is set to True then global_status is not updated at all and ignored (NB in
      this case, calling gridmodel.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 to True (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").
      If synch_status_both_side is False then 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 / GridModelBusId and / or SolverBusId)

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      
=============================    =======================  =======================