Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade to version 0.9.1 #90

Merged
merged 8 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,30 @@ TODO HVDC in Jacobian (see pandapower)
TODO: in ContingencyAnalysisCpp: add back the `if(!ac_solver_used)` inside the `remove_from_Ybus`
in order to perform the "invertibility" check
TODO: in `main.cpp` check the returned policy of pybind11 and also the `py::call_guard<py::gil_scoped_release>()` stuff
TODO: a cpp class that is able to compute (DC powerflow) ContingencyAnalysis and TimeSeries using PTDF and LODF
TODO: integration test with pandapower (see `pandapower/contingency/contingency.py` and import `lightsim2grid_installed` and check it's True)

[0.9.1] 2024-xx-yy
--------------------------
- [FIXED] a bug due to wrong type (in a numpy array) for the element name which lead in turn
to a fail assertion (equality between two numpy arrays returning a bool and not an array)
- [FIXED] a bug when init a grid from pypowsybl: the wrong value was used for trafos `h` (double)
- [FIXED] a bug when init a grid from pypowsybl: wrong values for `_ls_to_orig` and `_orig_to_ls`
was set (and later used)
- [FIXED] yet another bug when init a grid from pypowsybl: the voltage in kV (not in pu)
could be set due to "wrong" labelling of the bus ids
- [FIXED] yet another bug when init a grid from pypowsybl: the ratio of the transformers
sent in lightsim2grid did not take into account the "`rated_u1` `rated_u2`" on both side
(only used on one side)
- [FIXED] yet another bug when init a grid from pypowsybl: the ratio of the transformers
sent in lightsim2grid did not take into account the ratio in the `pypow_net.get_ratio_tap_changers()`
- [ADDED] a method for the `ContingencyAnalysisCPP` class that returns, for all contingencies
in the contingency list, which will be simulated and which causes the grid to be disconnected.
- [ADDED] it is now possible to use "one substation" (voltage level) pypowsybl side is
one substation in lightsim2grid.
- [IMPROVED] removing a weird `1j * h_` when initializing powerlines and transformers. This was
part of a pandapower "hack" which is not present anymore (see
https://github.com/BDonnot/lightsim2grid/issues/88#issue-2443299039)

[0.9.0] 2024-07-29
--------------------------
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'Benjamin DONNOT'

# The full version, including alpha/beta/rc tags
release = "0.9.0"
release = "0.9.1"
version = '0.9'

# -- General configuration ---------------------------------------------------
Expand Down
49 changes: 48 additions & 1 deletion docs/lightsimbackend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ For standard grid2op environment, you can use it like:
# the `LightSimBackend` will be used to carry out the powerflow computation instead
# of the default grid2op `PandaPowerBackend`

Customization of the backend
Customization of the solver
-------------------------------
.. warning::
Use grid2op > 1.7.1 for this feature to work properly. Otherwise some bugs (hard to detect) will occur.
Expand All @@ -63,6 +63,9 @@ You can customize the way the backend behaves in different ways:
- `dist_slack_non_renew`: by default in most grid2op environment, the slack bus is "centralize" / "single slack". This parameters
allows to bypass this restriction and use all non renewable generators (and turned on and with > 0.) in a distributed
slack bus setting. It might change the default `solver_type` used.
- \* `use_static_gen`: bool=False, DO NOT USE AT THE MOMENT. When it will be available, you will be able to loader_kwargs
both "static" generators (pq generators) and "regular" (pv generators) as generators in lightsim2grid. It does
not work at the moment and has no effect.
- \* `detailed_infos_for_cascading_failures`: for exhaustivity, do not modify.
- \* `can_be_copied`: for exhaustivity, do not modify.

Expand All @@ -84,12 +87,56 @@ The easiest way to customize your backend is when you create the grid2op environ
)
)

Customization of the input format
----------------------------------

For a few versions now, we try to extend the capability of lightsim2grid and make it work
with other data "reader". We started this process by allowing to initialize a
lightsim2grid `GridModel` from a pypowsybl network.

For example, if you environment contains a grid in the iidm format (native format of pypowsybl networks),
you can load it with:

.. code-block:: python

import grid2op
from lightsim2grid.LightSimBackend import LightSimBackend
from grid2op.Agent import RandomAgent

# create an environment
env_with_iidm_as_the_grid_description = ...
env = grid2op.make(env_name,
backend=LightSimBackend(loader_method="pypowsybl")
)

You can also customize the way lightsim2grid works with some extra options:


- `loader_method`: Literal["pandapower", "pypowsybl"]: from which grid "file description"
the grid will be loaded. If you use `pandapower` then pandapower needs to be installed.
If you specified `pypowsybl` then pypowsybl needs to be installed on your machine.
- `loader_kwargs` : ``dict``: some customization to use when loading the grid. It is not
not used when loading the grid from `pandapower`. Please refer to the documentation of
:attr:`LightSimBackend._loader_kwargs` for more information.

Other Customization
--------------------

Here are some other extra features you can use in lightsim2grid (but that are not yet supported by grid2op
so not really usable...) :

- stop_if_load_disco : Optional[bool] = True: whether to stop the computation (returning a `DivergingPowerflow` exception)
if a load is disconnected.
- stop_if_gen_disco : Optional[bool] = True: whether to stop the computation (returning a `DivergingPowerflow` exception)
if a generator is disconnected.

Detailed documentation
--------------------------

.. automodule:: lightsim2grid.lightSimBackend
:members:
:autosummary:
:private-members:


* :ref:`genindex`
Expand Down
2 changes: 1 addition & 1 deletion lightsim2grid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# SPDX-License-Identifier: MPL-2.0
# This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.

__version__ = "0.9.0"
__version__ = "0.9.1"

__all__ = ["newtonpf", "SolverType", "ErrorType", "solver", "compilation_options"]

Expand Down
28 changes: 16 additions & 12 deletions lightsim2grid/elements/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,33 @@
# SPDX-License-Identifier: MPL-2.0
# This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.

__all__ = ["DataGen",
__all__ = ["GeneratorContainer",
"GenInfo",
"DataSGen",
"SGenContainer",
"SGenInfo",
"DataLoad",
"LoadContainer",
"LoadInfo",
"DataShunt",
"ShuntContainer",
"ShuntInfo",
"DataTrafo",
"TrafoContainer",
"TrafoInfo",
"DataLine",
"LineContainer",
"LineInfo",
"DCLineContainer",
"DCLineInfo",
]

from lightsim2grid_cpp import DataGen
from lightsim2grid_cpp import GeneratorContainer
from lightsim2grid_cpp import GenInfo
from lightsim2grid_cpp import DataSGen
from lightsim2grid_cpp import SGenContainer
from lightsim2grid_cpp import SGenInfo
from lightsim2grid_cpp import DataLoad
from lightsim2grid_cpp import LoadContainer
from lightsim2grid_cpp import LoadInfo
from lightsim2grid_cpp import DataShunt
from lightsim2grid_cpp import ShuntContainer
from lightsim2grid_cpp import ShuntInfo
from lightsim2grid_cpp import DataTrafo
from lightsim2grid_cpp import TrafoContainer
from lightsim2grid_cpp import TrafoInfo
from lightsim2grid_cpp import DataLine
from lightsim2grid_cpp import LineContainer
from lightsim2grid_cpp import LineInfo
from lightsim2grid_cpp import DCLineContainer
from lightsim2grid_cpp import DCLineInfo
53 changes: 38 additions & 15 deletions lightsim2grid/gridmodel/from_pandapower/_aux_add_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@
# This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.

import numpy as np
from packaging import version
import pandapower as pp

from ._pp_bus_to_ls_bus import pp_bus_to_ls
from ._my_const import _MIN_PP_VERSION_ADV_GRID_MODEL

def _aux_add_line(converter, model, pp_net, pp_to_ls=None):
"""
Expand All @@ -29,21 +32,41 @@ def _aux_add_line(converter, model, pp_net, pp_to_ls=None):
"Some pp_net.line[\"parallel\"] != 1 it is not handled by lightsim yet.")

#### find the right powerline parameters
line_r, line_x, line_h = \
converter.get_line_param(
pp_net.line["r_ohm_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["x_ohm_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["c_nf_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["g_us_per_km"].values * pp_net.line["length_km"].values,
pp_net.bus.loc[pp_net.line["from_bus"]]["vn_kv"],
pp_net.bus.loc[pp_net.line["to_bus"]]["vn_kv"],
)

### add them to the grid
model.init_powerlines(line_r, line_x, line_h,
pp_bus_to_ls(pp_net.line["from_bus"].values, pp_to_ls),
pp_bus_to_ls(pp_net.line["to_bus"].values, pp_to_ls)
)
if version.parse(pp.__version__) >= _MIN_PP_VERSION_ADV_GRID_MODEL:
# new pandapower with support for different h at both side
line_r, line_x, line_h_or, line_h_ex = \
converter.get_line_param(
pp_net.line["r_ohm_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["x_ohm_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["g_us_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["c_nf_per_km"].values * pp_net.line["length_km"].values,
pp_net.bus.loc[pp_net.line["from_bus"]]["vn_kv"],
pp_net.bus.loc[pp_net.line["to_bus"]]["vn_kv"],
)

### add them to the grid
model.init_powerlines_full(line_r, line_x, line_h_or, line_h_ex,
pp_bus_to_ls(pp_net.line["from_bus"].values, pp_to_ls),
pp_bus_to_ls(pp_net.line["to_bus"].values, pp_to_ls)
)

else:
# legacy pandapower, when they did not support lines with different h both side
line_r, line_x, line_h = \
converter.get_line_param_legacy(
pp_net.line["r_ohm_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["x_ohm_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["g_us_per_km"].values * pp_net.line["length_km"].values,
pp_net.line["c_nf_per_km"].values * pp_net.line["length_km"].values,
pp_net.bus.loc[pp_net.line["from_bus"]]["vn_kv"],
pp_net.bus.loc[pp_net.line["to_bus"]]["vn_kv"],
)

### add them to the grid
model.init_powerlines(line_r, line_x, line_h,
pp_bus_to_ls(pp_net.line["from_bus"].values, pp_to_ls),
pp_bus_to_ls(pp_net.line["to_bus"].values, pp_to_ls)
)
for line_id, is_connected in enumerate(pp_net.line["in_service"].values):
if not is_connected:
# powerline is deactivated
Expand Down
80 changes: 55 additions & 25 deletions lightsim2grid/gridmodel/from_pandapower/_aux_add_trafo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@

import warnings
import numpy as np
from ._pp_bus_to_ls_bus import pp_bus_to_ls
import pandapower as pp
from packaging import version

from ._pp_bus_to_ls_bus import pp_bus_to_ls
from ._my_const import _MIN_PP_VERSION_ADV_GRID_MODEL

def _aux_add_trafo(converter, model, pp_net, pp_to_ls):
"""
Expand Down Expand Up @@ -69,30 +72,57 @@ def _aux_add_trafo(converter, model, pp_net, pp_to_ls):
tap_angles_ = np.deg2rad(tap_angles_)

# compute physical parameters
trafo_r, trafo_x, trafo_b = \
converter.get_trafo_param(tap_step_pct,
tap_pos,
tap_angles_, # in radian !
is_tap_hv_side,
pp_net.bus.loc[pp_net.trafo["hv_bus"]]["vn_kv"],
pp_net.bus.loc[pp_net.trafo["lv_bus"]]["vn_kv"],
pp_net.trafo["vk_percent"].values,
pp_net.trafo["vkr_percent"].values,
pp_net.trafo["sn_mva"].values,
pp_net.trafo["pfe_kw"].values,
pp_net.trafo["i0_percent"].values,
)

# initialize the grid
model.init_trafo(trafo_r,
trafo_x,
trafo_b,
tap_step_pct,
tap_pos,
shift_,
is_tap_hv_side,
pp_bus_to_ls(pp_net.trafo["hv_bus"].values, pp_to_ls),
pp_bus_to_ls(pp_net.trafo["lv_bus"].values, pp_to_ls))
if version.parse(pp.__version__) >= _MIN_PP_VERSION_ADV_GRID_MODEL:
# TODO
trafo_r, trafo_x, trafo_b = \
converter.get_trafo_param(tap_step_pct,
tap_pos,
tap_angles_, # in radian !
is_tap_hv_side,
pp_net.bus.loc[pp_net.trafo["hv_bus"]]["vn_kv"],
pp_net.bus.loc[pp_net.trafo["lv_bus"]]["vn_kv"],
pp_net.trafo["vk_percent"].values,
pp_net.trafo["vkr_percent"].values,
pp_net.trafo["sn_mva"].values,
pp_net.trafo["pfe_kw"].values,
pp_net.trafo["i0_percent"].values,
)

# initialize the grid
model.init_trafo(trafo_r,
trafo_x,
trafo_b,
tap_step_pct,
tap_pos,
shift_,
is_tap_hv_side,
pp_bus_to_ls(pp_net.trafo["hv_bus"].values, pp_to_ls),
pp_bus_to_ls(pp_net.trafo["lv_bus"].values, pp_to_ls))
else:
trafo_r, trafo_x, trafo_b = \
converter.get_trafo_param_legacy(tap_step_pct,
tap_pos,
tap_angles_, # in radian !
is_tap_hv_side,
pp_net.bus.loc[pp_net.trafo["hv_bus"]]["vn_kv"],
pp_net.bus.loc[pp_net.trafo["lv_bus"]]["vn_kv"],
pp_net.trafo["vk_percent"].values,
pp_net.trafo["vkr_percent"].values,
pp_net.trafo["sn_mva"].values,
pp_net.trafo["pfe_kw"].values,
pp_net.trafo["i0_percent"].values,
)

# initialize the grid
model.init_trafo(trafo_r,
trafo_x,
trafo_b,
tap_step_pct,
tap_pos,
shift_,
is_tap_hv_side,
pp_bus_to_ls(pp_net.trafo["hv_bus"].values, pp_to_ls),
pp_bus_to_ls(pp_net.trafo["lv_bus"].values, pp_to_ls))

for tr_id, is_connected in enumerate(pp_net.trafo["in_service"].values):
if not is_connected:
Expand Down
11 changes: 11 additions & 0 deletions lightsim2grid/gridmodel/from_pandapower/_my_const.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright (c) 2024, RTE (https://www.rte-france.com)
# See AUTHORS.txt
# This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0.
# If a copy of the Mozilla Public License, version 2.0 was not distributed with this file,
# you can obtain one at http://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
# This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.

from packaging import version
# pandapower version with more advanced grid modelling
_MIN_PP_VERSION_ADV_GRID_MODEL = version.parse("2.15")
Loading