Skip to content

Commit 3b0b687

Browse files
authored
Merge pull request #605 from BDonnot/bd_dev
Add 90% of the "init state" feature
2 parents 9a4ac6b + cc9fd62 commit 3b0b687

File tree

116 files changed

+6547
-147
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

116 files changed

+6547
-147
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ jobs:
164164
grid2op.testinstall
165165
166166
legacy_lightsim:
167-
executor: python38
167+
executor: python38 # needs to be 38: whl of lightsim were not released for 3.10 at the time
168168
resource_class: small
169169
steps:
170170
- checkout

.github/workflows/main.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,15 @@ jobs:
6464
6565
- name: Install wheel
6666
run: |
67-
pip3 install dist/*.whl --user
67+
pip3 install dist/*.whl
6868
pip freeze
6969
7070
- name: Check package can be imported
7171
run: |
7272
python3 -c "import grid2op"
7373
python3 -c "from grid2op import *"
7474
python3 -c "from grid2op.Action._backendAction import _BackendAction"
75-
75+
7676
- name: Upload wheel
7777
uses: actions/upload-artifact@v2
7878
with:

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,11 @@ grid2op/tests/requirements.txt
403403
grid2op/tests/venv_test_311/
404404
issue_577/
405405
junk.py
406+
grid2op/tests/20240429_failed_tests.txt
407+
grid2op/tests/20240429_failed_tests_small.txt
408+
grid2op/tests/20240429_teq_test.txt
409+
grid2op/tests/req_38_np121
410+
test_make_2_envs.py
406411

407412
# profiling files
408413
**.prof

CHANGELOG.rst

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,28 @@ Change Log
3333

3434
[1.10.2] - 2024-xx-yy
3535
-------------------------
36+
- [BREAKING] the `runner.run_one_episode` now returns an extra first argument:
37+
`chron_id, chron_name, cum_reward, timestep, max_ts = runner.run_one_episode()` which
38+
is consistant with `runner.run(...)` (previously it returned only
39+
`chron_name, cum_reward, timestep, max_ts = runner.run_one_episode()`)
40+
- [BREAKING] the runner now has no `chronics_handler` attribute (`runner.chronics_handler`
41+
is not defined)
3642
- [ADDED] it is now possible to call `change_reward` directly from
3743
an observation (no need to do it from the Observation Space)
3844
- [ADDED] method to change the reward from the observation (observation_space
3945
is not needed anymore): you can use `obs.change_reward`
4046
- [ADDED] a way to automatically set the `experimental_read_from_local_dir` flags
4147
(with automatic class creation). For now it is disable by default, but you can
4248
activate it transparently (see doc)
43-
- [ADDED] TODO the possibility to set the grid in an initial state (using an action) TODO
49+
- [ADDED] possibility to set the grid to an initial state (using an action) when using the
50+
"time series" classes. The supported classes are `GridStateFromFile` - and all its derivative,
51+
`FromOneEpisodeData`, `FromMultiEpisodeData`, `FromNPY` and `FromHandlers`. The classes `ChangeNothing`
52+
and `FromChronix2grid` are not supported at the moment.
53+
- [ADDED] an "Handler" (`JSONInitStateHandler`) that can set the grid to an initial state (so as to make
54+
compatible the `FromHandlers` time series class with this new feature)
4455
- [FIXED] a small issue that could lead to having
4556
"redispatching_unit_commitment_availble" flag set even if the redispatching
46-
data was not loded correctly
57+
data was not loaded correctly
4758
- [FIXED] EducPandaPowerBackend now properly sends numpy array in the class attributes
4859
(instead of pandas series)
4960
- [FIXED] an issue when loading back data (with `EpisodeData`): when there were no storage units
@@ -52,6 +63,11 @@ Change Log
5263
grid layout was set
5364
- [FIXED] notebook 5 on loading back data with `EpisodeData`.
5465
- [FIXED] converter between backends (could not handle more than 2 busbars)
66+
- [FIXED] a bug in `BaseMultiProcessEnvironment`: set_filter had no impact
67+
- [FIXED] an issue in the `Runner` (`self.chronics_handler` was sometimes used, sometimes not
68+
and most of the time incorrectly)
69+
- [FIXED] on `RemoteEnv` class (impact all multi process environment): the kwargs used to build then backend
70+
where not used which could lead to"wrong" backends being used in the sub processes.
5571
- [IMPROVED] documentation about `obs.simulate` to make it clearer the
5672
difference between env.step and obs.simulate on some cases
5773
- [IMPROVED] type hints on some methods of `GridObjects`

docs/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
author = 'Benjamin Donnot'
2323

2424
# The full version, including alpha/beta/rc tags
25-
release = '1.10.2.dev1'
25+
release = '1.10.2.dev2'
2626
version = '1.10'
2727

2828

grid2op/Action/actionSpace.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
import copy
1111
from typing import Dict, List, Any, Literal
1212

13+
import grid2op
14+
from grid2op.typing_variables import DICT_ACT_TYPING
1315
from grid2op.Action.baseAction import BaseAction
1416
from grid2op.Action.serializableActionSpace import SerializableActionSpace
1517

@@ -74,22 +76,9 @@ def __init__(
7476

7577
def __call__(
7678
self,
77-
dict_: Dict[Literal["injection",
78-
"hazards",
79-
"maintenance",
80-
"set_line_status",
81-
"change_line_status",
82-
"set_bus",
83-
"change_bus",
84-
"redispatch",
85-
"set_storage",
86-
"curtail",
87-
"raise_alarm",
88-
"raise_alert"], Any] = None,
79+
dict_: DICT_ACT_TYPING = None,
8980
check_legal: bool = False,
90-
env: "grid2op.Environment.BaseEnv" = None,
91-
*,
92-
injection=None,
81+
env: "grid2op.Environment.BaseEnv" = None
9382
) -> BaseAction:
9483
"""
9584
This utility allows you to build a valid action, with the proper sizes if you provide it with a valid
@@ -132,9 +121,15 @@ def __call__(
132121
An action that is valid and corresponds to what the agent want to do with the formalism defined in
133122
see :func:`Action.udpate`.
134123
124+
Notes
125+
-----
126+
127+
This function is not in the "SerializableActionSpace" because the
128+
"legal_action" is not serialized. TODO ?
129+
135130
"""
136131
# build the action
137-
res = self.actionClass()
132+
res : BaseAction = self.actionClass()
138133

139134
# update the action
140135
res.update(dict_)

grid2op/Action/baseAction.py

Lines changed: 85 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@
1010
import numpy as np
1111
import warnings
1212
from typing import Tuple, Dict, Literal, Any, List
13+
14+
1315
try:
1416
from typing import Self
1517
except ImportError:
1618
from typing_extensions import Self
1719

1820
from packaging import version
1921

22+
import grid2op
23+
from grid2op.typing_variables import DICT_ACT_TYPING
2024
from grid2op.dtypes import dt_int, dt_bool, dt_float
2125
from grid2op.Exceptions import *
2226
from grid2op.Space import GridObjects
@@ -624,6 +628,7 @@ def as_serializable_dict(self) -> dict:
624628
625629
"""
626630
res = {}
631+
cls = type(self)
627632
# bool elements
628633
if self._modif_alert:
629634
res["raise_alert"] = [
@@ -645,7 +650,7 @@ def as_serializable_dict(self) -> dict:
645650
self._aux_serialize_add_key_change("gen_change_bus", "generators_id", res["change_bus"])
646651
self._aux_serialize_add_key_change("line_or_change_bus", "lines_or_id", res["change_bus"])
647652
self._aux_serialize_add_key_change("line_ex_change_bus", "lines_ex_id", res["change_bus"])
648-
if hasattr(type(self), "n_storage") and type(self).n_storage:
653+
if hasattr(cls, "n_storage") and cls.n_storage:
649654
self._aux_serialize_add_key_change("storage_change_bus", "storages_id", res["change_bus"])
650655
if not res["change_bus"]:
651656
del res["change_bus"]
@@ -664,7 +669,7 @@ def as_serializable_dict(self) -> dict:
664669
self._aux_serialize_add_key_set("gen_set_bus", "generators_id", res["set_bus"])
665670
self._aux_serialize_add_key_set("line_or_set_bus", "lines_or_id", res["set_bus"])
666671
self._aux_serialize_add_key_set("line_ex_set_bus", "lines_ex_id", res["set_bus"])
667-
if hasattr(type(self), "n_storage") and type(self).n_storage:
672+
if hasattr(cls, "n_storage") and cls.n_storage:
668673
self._aux_serialize_add_key_set("storage_set_bus", "storages_id", res["set_bus"])
669674
if not res["set_bus"]:
670675
del res["set_bus"]
@@ -715,7 +720,7 @@ def as_serializable_dict(self) -> dict:
715720
if not res["injection"]:
716721
del res["injection"]
717722

718-
if type(self).shunts_data_available:
723+
if cls.shunts_data_available:
719724
res["shunt"] = {}
720725
if np.isfinite(self.shunt_p).any():
721726
res["shunt"]["shunt_p"] = [
@@ -2094,11 +2099,31 @@ def _digest_redispatching(self, dict_):
20942099

20952100
def _digest_storage(self, dict_):
20962101
if "set_storage" in dict_:
2097-
self.storage_p = dict_["set_storage"]
2098-
2102+
try:
2103+
self.storage_p = dict_["set_storage"]
2104+
except IllegalAction as exc_:
2105+
cls = type(self)
2106+
# only raise the error if I am not in compat mode
2107+
if cls.glop_version == grid2op.__version__:
2108+
raise exc_
2109+
else:
2110+
# TODO be more specific on the version
2111+
warnings.warn(f"Ignored error on storage units, because "
2112+
f"you are in a backward compatibility mode.")
2113+
20992114
def _digest_curtailment(self, dict_):
21002115
if "curtail" in dict_:
2101-
self.curtail = dict_["curtail"]
2116+
try:
2117+
self.curtail = dict_["curtail"]
2118+
except IllegalAction as exc_:
2119+
cls = type(self)
2120+
# only raise the error if I am not in compat mode
2121+
if cls.glop_version == grid2op.__version__:
2122+
raise exc_
2123+
else:
2124+
# TODO be more specific on the version
2125+
warnings.warn(f"Ignored error on curtailment, because "
2126+
f"you are in a backward compatibility mode.")
21022127

21032128
def _digest_alarm(self, dict_):
21042129
"""
@@ -2125,7 +2150,7 @@ def _reset_vect(self):
21252150
self._subs_impacted = None
21262151
self._lines_impacted = None
21272152

2128-
def update(self, dict_):
2153+
def update(self, dict_: DICT_ACT_TYPING):
21292154
"""
21302155
Update the action with a comprehensible format specified by a dictionary.
21312156
@@ -6410,7 +6435,6 @@ def decompose_as_unary_actions(self,
64106435
tmp += a
64116436
assert tmp == act
64126437
6413-
64146438
Parameters
64156439
----------
64166440
group_topo : bool, optional
@@ -6473,3 +6497,56 @@ def decompose_as_unary_actions(self,
64736497
if self._modif_curtailment:
64746498
self._aux_decompose_as_unary_actions_curtail(cls, group_curtail, res)
64756499
return res
6500+
6501+
def _add_act_and_remove_line_status_only_set(self, other: "BaseAction") -> "BaseAction":
6502+
"""INTERNAL
6503+
6504+
This is used by the environment when combining action in the "set state" in env.reset.
6505+
6506+
It supposes both self and other are only "set" actions
6507+
6508+
.. versionadded:: 1.10.2
6509+
6510+
"""
6511+
self += other
6512+
cls = type(self)
6513+
# switch off in self the element disconnected in other
6514+
switched_off = other._set_line_status == -1
6515+
switched_off |= other._set_topo_vect[cls.line_or_pos_topo_vect] == -1
6516+
switched_off |= other._set_topo_vect[cls.line_ex_pos_topo_vect] == -1
6517+
self._set_topo_vect[cls.line_or_pos_topo_vect[switched_off]] = -1
6518+
self._set_topo_vect[cls.line_ex_pos_topo_vect[switched_off]] = -1
6519+
self._set_line_status[switched_off] = -1
6520+
6521+
# switch on in self the element reconnected in other
6522+
switched_on = other._set_line_status == 1
6523+
switched_on |= other._set_topo_vect[cls.line_or_pos_topo_vect] > 0
6524+
switched_on |= other._set_topo_vect[cls.line_ex_pos_topo_vect] > 0
6525+
self._set_line_status[switched_on] = 1
6526+
# "reconnect" object through topo vect
6527+
topo_vect = other._set_topo_vect > 0
6528+
self._set_topo_vect[topo_vect] = other._set_topo_vect[topo_vect]
6529+
6530+
if (self._set_line_status != 0).any():
6531+
self._modif_set_status = True
6532+
if (self._set_topo_vect != 0).any():
6533+
self._modif_set_bus = True
6534+
return self
6535+
6536+
def remove_change(self) -> "BaseAction":
6537+
"""This function will modify 'self' and remove all "change" action type.
6538+
6539+
It is mainly used in the environment, when removing the "change" type for setting the original
6540+
state of the grid.
6541+
6542+
.. versionadded:: 1.10.2
6543+
6544+
"""
6545+
if self._change_bus_vect.any():
6546+
warnings.warn("This action modified the buses with `change_bus` ")
6547+
self._change_bus_vect[:] = False
6548+
self._modif_change_bus = False
6549+
if self._switch_line_status.any():
6550+
self._switch_line_status[:] = False
6551+
self._modif_change_status = False
6552+
return self

grid2op/Agent/oneChangeThenNothing.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
# SPDX-License-Identifier: MPL-2.0
77
# This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems.
88

9+
import warnings
910
from grid2op.Agent.baseAgent import BaseAgent
1011

1112

@@ -29,6 +30,11 @@ class OneChangeThenNothing(BaseAgent):
2930
3031
.. code-block:: python
3132
33+
# This class has been deprecated, please use the env.reset()
34+
# with proper options instead
35+
36+
37+
DEPRECATED !
3238
import grid2op
3339
from grid2op.Agent import OneChangeThenNothing
3440
acts_dict_ = [{}, {"set_line_status": [(0,-1)]}] # list of dictionaries. Each dictionary
@@ -44,12 +50,35 @@ class OneChangeThenNothing(BaseAgent):
4450
# run 2 episode with it
4551
res_2 = runner.run(nb_episode=2)
4652
53+
Notes:
54+
------
55+
56+
After grid2op 1.10.2, this class has been deprecated. A cleaner alternative
57+
to use it is to set the initial state of grid when calling `env.reset` like this:
58+
59+
.. code-block:: python
60+
61+
import grid2op
62+
63+
env = grid2op.make("l2rpn_case14_sandbox") # create an environment
64+
dict_act_json = ... # dict representing an action
65+
obs = env.reset(options={"init state": dict_act_json})
66+
67+
This way of doing offers:
68+
69+
- more flexibility: rules are not checked
70+
- more flexibility: any type of actions acting on anything can be performed
71+
(even if the action would be illegal for the agent)
72+
- less trouble: cooldown are not affected
73+
4774
"""
4875

4976
my_dict = {}
5077

5178
def __init__(self, action_space):
5279
BaseAgent.__init__(self, action_space)
80+
cls = type(self)
81+
warnings.warn(f"Deprecated class, please use `env.reset(options={{'init state': {self.action_space(cls.my_dict).to_json()}, 'method': 'ignore' }})` instead")
5382
self.has_changed = False
5483
self.do_nothing_action = self.action_space({})
5584

0 commit comments

Comments
 (0)