Skip to content

Commit

Permalink
Merge pull request #442 from laure-crochepierre/assistant_params
Browse files Browse the repository at this point in the history
Assistant feature (code cleaning + new parameter)
  • Loading branch information
BDonnot committed Apr 21, 2023
2 parents e888cf6 + 221a958 commit b9e1ac3
Show file tree
Hide file tree
Showing 63 changed files with 1,922 additions and 23 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ test_issue196.py
test_increasingreward.py
PlayWithRedispCurtail.ipynb
test_jorge/
grid2op/data_test/l2rpn_neurips_2020_track1_with_alarm.zip
# For backward compatibility
grid2op/data_test/l2rpn_neurips_2020_track1_with_alert.zip
issue_208_res/
test_issue_208.py
Expand All @@ -320,6 +322,8 @@ res_alert/
env_debug_time_last_alarm_inconsistency.zip
env_debug_time_last_alarm_inconsistency/
OpponentCalibration.ipynb
grid2op/data_test/l2rpn_neurips_2020_track1_with_alarm/_statistics_do_nothing/
# For backward compatibility
grid2op/data_test/l2rpn_neurips_2020_track1_with_alert/_statistics_do_nothing/
save/
shorten_env.py
Expand Down
5 changes: 5 additions & 0 deletions grid2op/Action/BaseAction.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,8 @@ def alarm_raised(self) -> np.ndarray:
"""
INTERNAL
.. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\
This function is used to know if the given action aimed at raising an alarm or not.
Returns
Expand Down Expand Up @@ -1882,6 +1884,7 @@ def _digest_curtailment(self, dict_):
self.curtail = dict_["curtail"]

def _digest_alarm(self, dict_):
""".. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\"""
if "raise_alarm" in dict_:
self.raise_alarm = dict_["raise_alarm"]

Expand Down Expand Up @@ -4721,6 +4724,7 @@ def line_change_status(self, values):
@property
def raise_alarm(self) -> np.ndarray:
"""
.. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\
Property to raise alarm.
If you set it to ``True`` an alarm is raised for the given area, otherwise None are raised.
Expand Down Expand Up @@ -4752,6 +4756,7 @@ def raise_alarm(self) -> np.ndarray:

@raise_alarm.setter
def raise_alarm(self, values):
""".. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\"""
if "raise_alarm" not in self.authorized_keys:
raise IllegalAction("Impossible to send alarms with this action type.")
orig_ = copy.deepcopy(self._raise_alarm)
Expand Down
4 changes: 4 additions & 0 deletions grid2op/Action/SerializableActionSpace.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ def _sample_storage_power(self, rnd_update=None):
return rnd_update

def _sample_raise_alarm(self, rnd_update=None):
""".. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\"""
if rnd_update is None:
rnd_update = {}
rnd_area = self.space_prng.randint(self.dim_alarms)
Expand Down Expand Up @@ -881,6 +882,9 @@ def get_all_unitary_line_set_simple(action_space):

@staticmethod
def get_all_unitary_alarm(action_space):
"""
.. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\
"""
res = []
for i in range(action_space.dim_alarms):
status = np.full(action_space.dim_alarms, fill_value=False, dtype=dt_bool)
Expand Down
10 changes: 6 additions & 4 deletions grid2op/Environment/BaseEnv.py
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,8 @@ def load_alarm_data(self):
"""
Internal
.. warning:: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\
Notes
------
This is called when the environment class is not created, so i need to read the data of the grid from the
Expand All @@ -777,9 +779,9 @@ def load_alarm_data(self):
-------
"""
file_alerts = os.path.join(self.get_path_env(), BaseEnv.ALARM_FILE_NAME)
if os.path.exists(file_alerts) and os.path.isfile(file_alerts):
with open(file_alerts, mode="r", encoding="utf-8") as f:
file_alarms = os.path.join(self.get_path_env(), BaseEnv.ALARM_FILE_NAME)
if os.path.exists(file_alarms) and os.path.isfile(file_alarms):
with open(file_alarms, mode="r", encoding="utf-8") as f:
dict_alarm = json.load(f)
key = "fixed"
if key not in dict_alarm:
Expand All @@ -800,7 +802,7 @@ def load_alarm_data(self):
raise EnvError(
f"You provided a description of the area of the grid for the alarms, but a "
f'line named "{line}" is present in your file but not in the grid. Please '
f"check the file {file_alerts} and make sure it contains only the line named "
f"check the file {file_alarms} and make sure it contains only the line named "
f"{sorted(self.backend.name_line)}."
)
# update the list and dictionary that remembers everything
Expand Down
10 changes: 5 additions & 5 deletions grid2op/Observation/baseObservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,21 +263,21 @@ class BaseObservation(GridObjects):
is_alarm_illegal: ``bool``
whether the last alarm has been illegal (due to budget constraint). It can only be ``True`` if an alarm
was raised by the agent on the previous step. Otherwise it is always ``False``
was raised by the agent on the previous step. Otherwise it is always ``False`` (warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\)
time_since_last_alarm: ``int``
Number of steps since the last successful alarm has been raised. It is `-1` if no alarm has been raised yet.
Number of steps since the last successful alarm has been raised. It is `-1` if no alarm has been raised yet. (warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\)
last_alarm: :class:`numpy.ndarray`, dtype:int
For each zones, gives how many steps since the last alarm was raised successfully for this zone
For each zones, gives how many steps since the last alarm was raised successfully for this zone (warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\)
attention_budget: ``int``
The current attention budget
was_alarm_used_after_game_over: ``bool``
Was the last alarm used to compute anything related
to the attention budget when there was a game over (can only be set to ``True`` if the observation
corresponds to a game over, but not necessarily)
to the attention budget when there was a game over. It can only be set to ``True`` if the observation
corresponds to a game over, but not necessarily. (warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\)
gen_margin_up: :class:`numpy.ndarray`, dtype:float
From how much can you increase each generators production between this
Expand Down
8 changes: 4 additions & 4 deletions grid2op/Observation/completeObservation.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,19 +86,19 @@ class CompleteObservation(BaseObservation):
35. :attr:`BaseObservation.curtailment` : the current curtailment applied
[:attr:`grid2op.Space.GridObjects.n_gen` elements]
36. :attr:`BaseObservation.is_alarm_illegal` whether the last alarm has been illegal (due to budget
constraint) [``bool``]
constraint), warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\ [``bool``]
37. :attr:`BaseObservation.curtailment_limit` : the current curtailment limit (if any)
[:attr:`grid2op.Space.GridObjects.n_gen` elements]
38. :attr:`BaseObservation.time_since_last_alarm` number of step since the last alarm has been raised
successfully [``int``]
successfully (warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\ ) [``int``]
39. :attr:`BaseObservation.last_alarm` : for each alarm zone, gives the last step at which an alarm has
been successfully raised at this zone
been successfully raised at this zone (warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\)
[:attr:`grid2op.Space.GridObjects.dim_alarms` elements]
40. :attr:`BaseObservation.attention_budget` : the current attention budget
[``int``]
41. :attr:`BaseObservation.was_alarm_used_after_game_over` : was the last alarm used to compute anything related
to the attention budget when there was a game over (can only be set to ``True`` if the observation
corresponds to a game over)
corresponds to a game over), warning: /!\\\\ Only valid with "l2rpn_icaps_2021" environment /!\\\\
[``bool``]
"""
Expand Down
20 changes: 20 additions & 0 deletions grid2op/Parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ class Parameters:
Number of steps for which it's worth it to give an alarm (if an alarm is send outside of the window
`[ALARM_BEST_TIME - ALARM_WINDOW_SIZE, ALARM_BEST_TIME + ALARM_WINDOW_SIZE]` then it does not grant anything
ALERT_TIME_WINDOW : ``int``
Number of steps for which it's worth it to give an alert after an attack. If the alert is sent before, the assistant
score doesn't take into account that an alert is raised.
MAX_SIMULATE_PER_STEP: ``int``
Maximum number of calls to `obs.simuate(...)` allowed per step (reset each "env.step(...)"). Defaults to -1 meaning "as much as you want".
Expand Down Expand Up @@ -201,6 +205,9 @@ def __init__(self, parameters_path=None):
self.ALARM_BEST_TIME = 12
self.ALARM_WINDOW_SIZE = 12

# alert
self.ALERT_TIME_WINDOW = 12

# number of simulate
self.MAX_SIMULATE_PER_STEP = dt_int(-1)
self.MAX_SIMULATE_PER_EPISODE = dt_int(-1)
Expand Down Expand Up @@ -339,6 +346,10 @@ def init_from_dict(self, dict_):
if "ALARM_WINDOW_SIZE" in dict_:
self.ALARM_WINDOW_SIZE = dt_int(dict_["ALARM_WINDOW_SIZE"])

# alert parameters
if "ALERT_TIME_WINDOW" in dict_:
self.ALERT_TIME_WINDOW = dt_int(dict_["ALERT_TIME_WINDOW"])

if "MAX_SIMULATE_PER_STEP" in dict_:
self.MAX_SIMULATE_PER_STEP = dt_int(dict_["MAX_SIMULATE_PER_STEP"])

Expand Down Expand Up @@ -389,6 +400,7 @@ def to_dict(self):
res["ACTIVATE_STORAGE_LOSS"] = bool(self.ACTIVATE_STORAGE_LOSS)
res["ALARM_BEST_TIME"] = int(self.ALARM_BEST_TIME)
res["ALARM_WINDOW_SIZE"] = int(self.ALARM_WINDOW_SIZE)
res["ALERT_TIME_WINDOW"] = int(self.ALERT_TIME_WINDOW)
res["MAX_SIMULATE_PER_STEP"] = int(self.MAX_SIMULATE_PER_STEP)
res["MAX_SIMULATE_PER_EPISODE"] = int(self.MAX_SIMULATE_PER_EPISODE)
return res
Expand Down Expand Up @@ -624,11 +636,19 @@ def check_valid(self):
raise RuntimeError(
f'Impossible to convert ALARM_BEST_TIME to int with error \n:"{exc_}"'
)
try:
self.ALERT_TIME_WINDOW = dt_int(self.ALERT_TIME_WINDOW)
except Exception as exc_:
raise RuntimeError(
f'Impossible to convert ALERT_TIME_WINDOW to int with error \n:"{exc_}"'
)

if self.ALARM_WINDOW_SIZE <= 0:
raise RuntimeError("self.ALARM_WINDOW_SIZE should be a positive integer !")
if self.ALARM_BEST_TIME <= 0:
raise RuntimeError("self.ALARM_BEST_TIME should be a positive integer !")
if self.ALERT_TIME_WINDOW <= 0:
raise RuntimeError("self.ALERT_TIME_WINDOW should be a positive integer !")

try:
self.MAX_SIMULATE_PER_STEP = int(
Expand Down
16 changes: 16 additions & 0 deletions grid2op/data_test/l2rpn_idf_2023_with_alert/alerts_info.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"fixed": {"west": ["34_35_110", "34_36_111", "33_35_113", "33_36_114", "32_36_112", "36_38_115", "36_39_116",
"38_39_119", "39_40_120", "39_41_121", "40_41_122", "41_48_131", "41_48_132",
"33_42_124", "37_36_179", "37_64_161", "42_43_123", "43_44_125", "44_48_133",
"45_47_128", "44_45_126", "47_48_134", "45_46_127", "46_48_130",
"48_68_170", "46_68_169"],
"east": ["50_51_137", "48_65_164", "48_65_165", "51_52_138", "52_53_139", "48_53_141", "48_53_142",
"48_49_135", "48_50_136", "50_57_149", "49_56_147", "55_57_148", "55_56_146", "54_55_145",
"53_55_144", "53_54_143", "53_58_150", "54_58_154", "55_58_152", "55_58_153",
"62_58_180", "58_59_155", "58_60_156", "62_63_160", "59_60_157", "63_60_181", "60_61_159",
"59_61_158", "63_64_163", "61_66_167", "61_65_166", "65_66_168", "64_65_182"],
"middle": ["41_48_131", "41_48_132", "44_48_133", "47_48_134", "46_48_130", "48_68_170",
"48_65_164", "48_65_165", "48_49_135", "48_50_136", "48_53_141", "48_53_142"]
},
"is_alert": "True"
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"maintenance_starting_hour": 9 ,
"maintenance_ending_hour": 17,
"line_to_maintenance": ["62_58_180",
"62_63_160",
"48_50_136",
"48_53_141",
"41_48_131",
"39_41_121",
"43_44_125",
"44_45_126",
"34_35_110",
"54_58_154"],
"daily_proba_per_month_maintenance": [0.0, 0.0, 0.0, 0.02, 0.02, 0.03, 0.05, 0.06, 0.03, 0.02, 0.0, 0.0],
"max_daily_number_per_month_maintenance": [0, 0, 0, 1, 1, 2, 2, 2, 1, 1, 0, 0]
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2012-04-01 00:00
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
00:05
121 changes: 121 additions & 0 deletions grid2op/data_test/l2rpn_idf_2023_with_alert/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from grid2op.Action import PlayableAction, PowerlineSetAction
from grid2op.Reward import AlarmReward
from grid2op.Rules import DefaultRules
from grid2op.Chronics import Multifolder
from grid2op.Chronics import GridStateFromFileWithForecastsWithMaintenance
from grid2op.Backend import PandaPowerBackend
from grid2op.Opponent import GeometricOpponent, BaseActionBudget
from grid2op.operator_attention import LinearAttentionBudget

lines_attacked = [
"62_58_180",
"62_63_160",
"48_50_136",
"48_53_141",
"41_48_131",
"39_41_121",
"43_44_125",
"44_45_126",
"34_35_110",
"54_58_154",
]

opponent_attack_cooldown = 12 # 1 hour, 1 hour being 12 time steps
opponent_attack_duration = 96 # 8 hours at maximum
opponent_budget_per_ts = (
0.17 # opponent_attack_duration / opponent_attack_cooldown + epsilon
)
opponent_init_budget = 144.0 # no need to attack straightfully, it can attack starting at midday the first day
config = {
"backend": PandaPowerBackend,
"action_class": PlayableAction,
"observation_class": None,
"reward_class": AlarmReward,
"gamerules_class": DefaultRules,
"chronics_class": Multifolder,
"grid_value_class": GridStateFromFileWithForecastsWithMaintenance,
"volagecontroler_class": None,
"names_chronics_to_grid": None,
"thermal_limits": [
60.9,
231.9,
272.6,
212.8,
749.2,
332.4,
348.0,
414.4,
310.1,
371.4,
401.2,
124.3,
298.5,
86.4,
213.9,
160.8,
112.2,
291.4,
489.0,
489.0,
124.6,
196.7,
191.9,
238.4,
174.2,
105.6,
143.7,
293.4,
288.9,
107.7,
415.5,
148.2,
124.2,
154.4,
85.9,
106.5,
142.0,
124.0,
130.2,
86.2,
278.1,
182.0,
592.1,
173.1,
249.8,
441.0,
344.2,
722.8,
494.6,
494.6,
196.7,
151.8,
263.4,
364.1,
327.0,
370.5,
441.0,
300.3,
656.2,
],
"opponent_attack_cooldown": opponent_attack_cooldown,
"opponent_attack_duration": opponent_attack_duration,
"opponent_budget_per_ts": opponent_budget_per_ts,
"opponent_init_budget": opponent_init_budget,
"opponent_action_class": PowerlineSetAction,
"opponent_class": GeometricOpponent,
"opponent_budget_class": BaseActionBudget,
"kwargs_opponent": {
"lines_attacked": lines_attacked,
"attack_every_xxx_hour": 24,
"average_attack_duration_hour": 4,
"minimum_attack_duration_hour": 1,
},
"has_attention_budget": True,
"attention_budget_class": LinearAttentionBudget,
"kwargs_attention_budget": {
"max_budget": 3.0,
"budget_per_ts": 1.0 / (12.0 * 16),
"alarm_cost": 1.0,
"init_budget": 2.0,
},
}

0 comments on commit b9e1ac3

Please sign in to comment.