Skip to content

Commit

Permalink
fixing an issue with 'legacy' grid2op and storage unit
Browse files Browse the repository at this point in the history
Signed-off-by: DONNOT Benjamin <benjamin.donnot@rte-france.com>
  • Loading branch information
BDonnot committed Dec 17, 2024
1 parent 1990c36 commit 29adda4
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 6 deletions.
13 changes: 11 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,22 @@ TODO: in `main.cpp` check the returned policy of pybind11 and also the `py::call
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.10.0] 2024-12-16
[0.10.0] 2024-12-17
-------------------
- [BREAKING] disconnected storage now raises errors if some power is produced / absorbed
- [BREAKING] disconnected storage now raises errors if some power is produced / absorbed, when using legacy grid2op version,
you can retrieve the previous behaviour by initializing the `LightSimBackend` with
`backend = LightSimBackend(..., stop_if_storage_disco=False)`
- [BREAKING] with the new `detachment_is_allowed` feature in grid2op, the kwargs `stop_if_load_disco`,
`stop_if_gen_disco` (and `stop_if_storage_disco`) are now optional. They are set up from the
call to `grid2op.make(...)` and are erased by the `allow_detachment` kwargs. In other words,
you don't need to set `stop_if_load_disco`, `stop_if_gen_disco` or `stop_if_storage_disco`. It is
automatically set by `grid2op.make(..., allow_detachment=XXX)` to have the correct bahaviour.
- [FIXED] an issue with the storage units (when asking it to produce / consume
but deactivating them with the same action the grid did not diverge)
- [IMPROVED] add the grid2op "detachement" support (loads and generators are allowed
to be disconnected from the grid)
- [ADDED] a kwargs `stop_if_storage_disco` to control (in legacy grid2op version) the behaviour
of the backend when a storage unit is disconnected.

[0.9.2.post2] 2024-11-29
--------------------------
Expand Down
53 changes: 49 additions & 4 deletions lightsim2grid/lightSimBackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
try:
from grid2op.Space import DEFAULT_ALLOW_DETACHMENT
except ImportError:
# for backward compatibility with grid2op <= 1.11.0
# for backward compatibility with grid2op < 1.11.0
DEFAULT_ALLOW_DETACHMENT = False

try:
Expand Down Expand Up @@ -84,6 +84,7 @@ def __init__(self,
loader_kwargs : Optional[dict] = None,
stop_if_load_disco : Optional[bool] = None,
stop_if_gen_disco : Optional[bool] = None,
stop_if_storage_disco : Optional[bool] = None,
):
#: ``int`` maximum number of iteration allowed for the solver
#: if the solver has not converge after this, it will
Expand Down Expand Up @@ -147,6 +148,13 @@ def __init__(self,
#: if set to ``True`` (default) then the backend will raise a
#: BackendError in case of disconnected generator
self._stop_if_gen_disco = stop_if_gen_disco

#: .. versionadded:: 0.10.0
#:
#: if set to ``True`` (default) then the backend will raise a
#: BackendError in case of disconnected storage that are
#: asked to produce / absorb something
self._stop_if_storage_disco = stop_if_storage_disco

self._aux_init_super(detailed_infos_for_cascading_failures,
can_be_copied,
Expand All @@ -159,7 +167,8 @@ def __init__(self,
loader_method,
loader_kwargs,
stop_if_load_disco,
stop_if_gen_disco)
stop_if_gen_disco,
stop_if_storage_disco)

# backward compat: need to define it if not done by grid2op
if not hasattr(self, "_can_be_copied"):
Expand Down Expand Up @@ -339,7 +348,8 @@ def _aux_init_super(self,
loader_method,
loader_kwargs,
stop_if_load_disco,
stop_if_gen_disco):
stop_if_gen_disco,
stop_if_storage_disco):
try:
# for grid2Op >= 1.7.1
Backend.__init__(self,
Expand All @@ -355,6 +365,7 @@ def _aux_init_super(self,
loader_kwargs=loader_kwargs,
stop_if_load_disco=stop_if_load_disco,
stop_if_gen_disco=stop_if_gen_disco,
stop_if_storage_disco=stop_if_storage_disco
)
except TypeError as exc_:
warnings.warn("Please use grid2op >= 1.7.1: with older grid2op versions, "
Expand Down Expand Up @@ -578,6 +589,17 @@ def _aux_set_correct_detach_flags(self):
warnings.warn("Call to `grid2op.make(..., allow_detachement=True)` will erase the lightsim2grid kwargs `stop_if_load_disco=True`")
self._stop_if_load_disco = False

if self._stop_if_storage_disco is None:
# user did not specify anything
self._stop_if_storage_disco = False
elif not self._stop_if_storage_disco:
# force conversion to the proper type
self._stop_if_storage_disco = False
elif self._stop_if_storage_disco:
# erase default values and continue like the grid2op call specifies
warnings.warn("Call to `grid2op.make(..., allow_detachement=True)` will erase the lightsim2grid kwargs `stop_if_storage_disco=True`")
self._stop_if_storage_disco = False

else:
# user did not allow detachment (or it's a legacy grid2op version), I check the correct flags
if self._stop_if_gen_disco is None:
Expand All @@ -601,6 +623,17 @@ def _aux_set_correct_detach_flags(self):
# erase default values and continue like the grid2op call specifies
warnings.warn("Call to `grid2op.make(..., allow_detachement=False)` will erase the lightsim2grid kwargs `stop_if_load_disco=False`")
self._stop_if_load_disco = True

if self._stop_if_storage_disco is None:
# user did not specify anything
self._stop_if_storage_disco = True
elif self._stop_if_storage_disco:
# force conversion to proper type
self._stop_if_storage_disco = True
elif not self._stop_if_storage_disco:
# erase default values and continue like the grid2op call specifies
warnings.warn("Call to `grid2op.make(..., allow_detachement=False)` will erase the lightsim2grid kwargs `stop_if_storage_disco=False`")
self._stop_if_storage_disco = True

def load_grid(self,
path : Union[os.PathLike, str],
Expand Down Expand Up @@ -1426,6 +1459,17 @@ def runpf(self, is_dc : bool=False) -> Tuple[bool, Union[Exception, None]]:
gen_disco = np.where(disco)[0]
self._timer_postproc += time.perf_counter() - beg_postroc
raise BackendError(f"At least one generator is disconnected (check gen {gen_disco})")

if self.__has_storage:
sto_active = (self.storage_p != 0.)
sto_act_disco = (((~np.isfinite(self.storage_v)) & sto_active).any() or
((self.storage_v <= 0.) & sto_active).any()
)
if self._stop_if_storage_disco and sto_act_disco:
disco = ((~np.isfinite(self.storage_v)) | (self.storage_v <= 0.)) & sto_active
sto_disco = np.where(disco)[0]
self._timer_postproc += time.perf_counter() - beg_postroc
raise BackendError(f"At least one storage unit is disconnected (check gen {sto_disco})")
# TODO storage case of divergence !

if type(self).shunts_data_available:
Expand Down Expand Up @@ -1537,7 +1581,8 @@ def copy(self) -> Self:
self._loader_method,
self._loader_kwargs,
self._stop_if_load_disco,
self._stop_if_gen_disco)
self._stop_if_gen_disco,
self._stop_if_storage_disco)

# for backward compat (attribute was not necessarily present in early grid2op)
if not hasattr(res, "_can_be_copied"):
Expand Down

0 comments on commit 29adda4

Please sign in to comment.