From c617e06b717347e6a203510f300ba65eb0f822b9 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 14 Jun 2023 15:56:14 +0200 Subject: [PATCH 001/103] first version of alert agent baseline for assistant --- grid2op/Agent/alertAgent.py | 73 +++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 grid2op/Agent/alertAgent.py diff --git a/grid2op/Agent/alertAgent.py b/grid2op/Agent/alertAgent.py new file mode 100644 index 000000000..ed4564cb5 --- /dev/null +++ b/grid2op/Agent/alertAgent.py @@ -0,0 +1,73 @@ +# Copyright (c) 2019-2020, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. +import numpy as np +from grid2op.Agent.recoPowerlineAgent import RecoPowerlineAgent +import pandas as pd + +#try: +# from lightsim2grid import LightSimBackend +# +# bkclass = LightSimBackend +# # raise ImportError() +#except ImportError as excq_: +# from grid2op.Backend import PandaPowerBackend + + + +class AlertAgent(RecoPowerlineAgent): + """ + This is a :class:`AlertAgent` example, which will attempt to reconnect powerlines and send alerts on the worst possible attacks: for each disconnected powerline + that can be reconnected, it will simulate the effect of reconnecting it. And reconnect the one that lead to the + highest simulated reward. It will also simulate the effect of having a line disconnection on attackable lines and raise alerts for the worst ones + + """ + + def __init__(self, action_space,percentage_alert=30,simu_step=0,alertable_line_ids=None):#[0, 9, 13, 14, 18, 23, 27, 39, 45, 56]): + RecoPowerlineAgent.__init__(self, action_space) + self.percentage_alert = percentage_alert + self.alertable_line_ids=alertable_line_ids + self.simu_step=simu_step + + def act(self, observation, reward, done=False): + action=super().act(observation, reward, done=False) + + if (self.alertable_line_ids is None): + self.alertable_line_ids = [i for i in range(observation.n_line) if observation.name_line[i] in observation.alertable_line_names] + + #simu d'analyse de sécurité à chaque pas de temps sur les lignes attaquées + n_alertable_lines=len(self.alertable_line_ids) + nb_overloads=np.zeros(n_alertable_lines) + rho_max_N_1=np.zeros(n_alertable_lines) + + # test which backend to know which method to call + + N_1_actions=[self.action_space({"set_line_status": [(id_, -1)]}) for id_ in self.alertable_line_ids] + for i, action in enumerate(N_1_actions): + + #check that line is not already disconnected + if (observation.line_status[self.alertable_line_ids[i]]): + ( + simul_obs, + simul_reward, + simul_has_error, + simul_info, + ) = observation.simulate(action,time_step=self.simu_step) + + rho_simu=simul_obs.rho + if(not simul_has_error): + nb_overloads[i]=np.sum(rho_simu >= 1) + rho_max_N_1[i]=np.max(rho_simu) + + df_to_sort=pd.DataFrame({"nb_overloads":nb_overloads,"rho_max_N_1":rho_max_N_1}) + indices=df_to_sort.sort_values(['nb_overloads','rho_max_N_1'], ascending=False).index + + #alerts to send + indices_to_keep=list(indices[0:int(self.percentage_alert/100*n_alertable_lines)]) + action.raise_alert = [i for i in indices_to_keep]#[self.alertable_line_ids[i] for i in indices_to_keep]#[attackable_line_id] + + return action From bbdeb53eaf9c5cc6eadc0cd6bd5e1d2612b706e6 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 4 Jul 2023 10:50:06 +0200 Subject: [PATCH 002/103] updating alert agent and add test --- grid2op/Agent/alertAgent.py | 16 ++++---- .../l2rpn_idf_2023_with_alert/config.py | 2 + grid2op/tests/test_baseline_alert.py | 41 +++++++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 grid2op/tests/test_baseline_alert.py diff --git a/grid2op/Agent/alertAgent.py b/grid2op/Agent/alertAgent.py index ed4564cb5..388ede7ca 100644 --- a/grid2op/Agent/alertAgent.py +++ b/grid2op/Agent/alertAgent.py @@ -27,30 +27,30 @@ class AlertAgent(RecoPowerlineAgent): """ - def __init__(self, action_space,percentage_alert=30,simu_step=0,alertable_line_ids=None):#[0, 9, 13, 14, 18, 23, 27, 39, 45, 56]): + def __init__(self, action_space,percentage_alert=30,simu_step=0):#[0, 9, 13, 14, 18, 23, 27, 39, 45, 56]): RecoPowerlineAgent.__init__(self, action_space) self.percentage_alert = percentage_alert - self.alertable_line_ids=alertable_line_ids + #self.alertable_line_ids=alertable_line_ids self.simu_step=simu_step def act(self, observation, reward, done=False): action=super().act(observation, reward, done=False) - - if (self.alertable_line_ids is None): - self.alertable_line_ids = [i for i in range(observation.n_line) if observation.name_line[i] in observation.alertable_line_names] + alertable_line_ids=observation.alertable_line_ids + #if (self.alertable_line_ids is None): + # self.alertable_line_ids = [i for i in range(observation.n_line) if observation.name_line[i] in observation.alertable_line_names] #simu d'analyse de sécurité à chaque pas de temps sur les lignes attaquées - n_alertable_lines=len(self.alertable_line_ids) + n_alertable_lines=len(alertable_line_ids) nb_overloads=np.zeros(n_alertable_lines) rho_max_N_1=np.zeros(n_alertable_lines) # test which backend to know which method to call - N_1_actions=[self.action_space({"set_line_status": [(id_, -1)]}) for id_ in self.alertable_line_ids] + N_1_actions=[self.action_space({"set_line_status": [(id_, -1)]}) for id_ in alertable_line_ids] for i, action in enumerate(N_1_actions): #check that line is not already disconnected - if (observation.line_status[self.alertable_line_ids[i]]): + if (observation.line_status[alertable_line_ids[i]]): ( simul_obs, simul_reward, diff --git a/grid2op/data_test/l2rpn_idf_2023_with_alert/config.py b/grid2op/data_test/l2rpn_idf_2023_with_alert/config.py index 630dd98c2..96dfe9c41 100644 --- a/grid2op/data_test/l2rpn_idf_2023_with_alert/config.py +++ b/grid2op/data_test/l2rpn_idf_2023_with_alert/config.py @@ -9,6 +9,8 @@ try: from grid2op.l2rpn_utils import ActionIDF2023, ObservationIDF2023 except ImportError: + from grid2op.Observation import CompleteObservation + import warnings warnings.warn("The grid2op version you are trying to use is too old for this environment. Please upgrade it.") ActionIDF2023 = PlayableAction ObservationIDF2023 = CompleteObservation diff --git a/grid2op/tests/test_baseline_alert.py b/grid2op/tests/test_baseline_alert.py new file mode 100644 index 000000000..b3959b193 --- /dev/null +++ b/grid2op/tests/test_baseline_alert.py @@ -0,0 +1,41 @@ +from grid2op.tests.helper_path_test import * + +from grid2op import make +from grid2op.Reward import AlertReward +from grid2op.Runner import Runner +from grid2op.Agent.alertAgent import AlertAgent + +# test alert agent no blackout +class TestAlertNoBlackout(unittest.TestCase): + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + + def test_alert_Agent(self) -> None: + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=AlertReward(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + percentage_alert =30 # 30% of lines with alert per step + my_agent = AlertAgent(env.action_space, percentage_alert=percentage_alert) + runner = Runner(**env.get_params_for_runner(), agentClass=None ,agentInstance=my_agent) + # runner = Runner(**env.get_params_for_runner(), agentClass=AlertAgent) + res = runner.run(nb_episode=1, nb_process=1, path_save=None, + add_detailed_output=True) + + # test if the number of alerts sent er lines are recovered + alerts_count =np.sum([res[0][5].observations[i].active_alert for i in range(1, len(res[0][5].observations))] + ,axis=0) + assert(np.all(alerts_count==[9, 9, 4, 0, 5, 0, 0, 0, 0, 0])) + + # test that we observe the expected alert rate + nb_steps =res[0][4] + nb_alertable_lines =len(env.alertable_line_names) + ratio_alerts_step =np.sum(alerts_count ) /(nb_steps*nb_alertable_lines) + assert(np.round(ratio_alerts_step ,decimals=1 )==np.round(percentage_alert/100 ,decimals=1)) \ No newline at end of file From 8f633e71c15de0bd00c542bcc32675b07aa6d499 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 5 Jul 2023 13:07:22 +0200 Subject: [PATCH 003/103] correcting bug in Alert Agent doing line disconnections + add assert in test --- grid2op/Agent/alertAgent.py | 12 ++++-------- grid2op/tests/test_baseline_alert.py | 22 ++++++++++++++-------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/grid2op/Agent/alertAgent.py b/grid2op/Agent/alertAgent.py index 388ede7ca..875678b58 100644 --- a/grid2op/Agent/alertAgent.py +++ b/grid2op/Agent/alertAgent.py @@ -27,17 +27,14 @@ class AlertAgent(RecoPowerlineAgent): """ - def __init__(self, action_space,percentage_alert=30,simu_step=0):#[0, 9, 13, 14, 18, 23, 27, 39, 45, 56]): + def __init__(self, action_space,percentage_alert=30,simu_step=0): RecoPowerlineAgent.__init__(self, action_space) self.percentage_alert = percentage_alert - #self.alertable_line_ids=alertable_line_ids self.simu_step=simu_step def act(self, observation, reward, done=False): action=super().act(observation, reward, done=False) alertable_line_ids=observation.alertable_line_ids - #if (self.alertable_line_ids is None): - # self.alertable_line_ids = [i for i in range(observation.n_line) if observation.name_line[i] in observation.alertable_line_names] #simu d'analyse de sécurité à chaque pas de temps sur les lignes attaquées n_alertable_lines=len(alertable_line_ids) @@ -45,9 +42,8 @@ def act(self, observation, reward, done=False): rho_max_N_1=np.zeros(n_alertable_lines) # test which backend to know which method to call - N_1_actions=[self.action_space({"set_line_status": [(id_, -1)]}) for id_ in alertable_line_ids] - for i, action in enumerate(N_1_actions): + for i, action_to_simulate in enumerate(N_1_actions): #check that line is not already disconnected if (observation.line_status[alertable_line_ids[i]]): @@ -56,7 +52,7 @@ def act(self, observation, reward, done=False): simul_reward, simul_has_error, simul_info, - ) = observation.simulate(action,time_step=self.simu_step) + ) = observation.simulate(action_to_simulate,time_step=self.simu_step) rho_simu=simul_obs.rho if(not simul_has_error): @@ -68,6 +64,6 @@ def act(self, observation, reward, done=False): #alerts to send indices_to_keep=list(indices[0:int(self.percentage_alert/100*n_alertable_lines)]) - action.raise_alert = [i for i in indices_to_keep]#[self.alertable_line_ids[i] for i in indices_to_keep]#[attackable_line_id] + action.raise_alert = [i for i in indices_to_keep] return action diff --git a/grid2op/tests/test_baseline_alert.py b/grid2op/tests/test_baseline_alert.py index b3959b193..7f3691aa3 100644 --- a/grid2op/tests/test_baseline_alert.py +++ b/grid2op/tests/test_baseline_alert.py @@ -25,17 +25,23 @@ def test_alert_Agent(self) -> None: percentage_alert =30 # 30% of lines with alert per step my_agent = AlertAgent(env.action_space, percentage_alert=percentage_alert) runner = Runner(**env.get_params_for_runner(), agentClass=None ,agentInstance=my_agent) - # runner = Runner(**env.get_params_for_runner(), agentClass=AlertAgent) - res = runner.run(nb_episode=1, nb_process=1, path_save=None, + + res = runner.run(nb_episode=1, nb_process=1, path_save=None,agent_seeds=[0],env_seeds=[0],max_iter=3, add_detailed_output=True) + id_chron, name_chron, cum_reward, nb_time_step, max_ts, episode_data = res[0] - # test if the number of alerts sent er lines are recovered - alerts_count =np.sum([res[0][5].observations[i].active_alert for i in range(1, len(res[0][5].observations))] + # test if the number of alerts sent on lines are recovered + alerts_count =np.sum([obs.active_alert for obs in episode_data.observations[1:]] ,axis=0) - assert(np.all(alerts_count==[9, 9, 4, 0, 5, 0, 0, 0, 0, 0])) + print(alerts_count) + assert(np.all(alerts_count==[3, 3, 2, 0, 1, 0, 0, 0, 0, 0])) # test that we observe the expected alert rate - nb_steps =res[0][4] nb_alertable_lines =len(env.alertable_line_names) - ratio_alerts_step =np.sum(alerts_count ) /(nb_steps*nb_alertable_lines) - assert(np.round(ratio_alerts_step ,decimals=1 )==np.round(percentage_alert/100 ,decimals=1)) \ No newline at end of file + ratio_alerts_step =np.sum(alerts_count ) /(nb_time_step*nb_alertable_lines) + assert(np.round(ratio_alerts_step ,decimals=1 )==np.round(percentage_alert/100 ,decimals=1)) + + #check that alert agent is not doing any intervention on the grid in this short time frame + #as the reco power line, it should only do actions to reconnect lines when allowed, but cannot happen in this short time frame + has_action_impact=[act.impact_on_objects()['has_impact'] for act in episode_data.actions] + assert(~np.any(has_action_impact)) \ No newline at end of file From 4acd3d8fd82610a492698a9b3a79338b6f663c5f Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Thu, 6 Jul 2023 15:57:19 +0200 Subject: [PATCH 004/103] nrescore: use basereward cls simulation check --- grid2op/Reward/_newRenewableSourcesUsageScore.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index d55d7ef71..5db2846b1 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -38,7 +38,7 @@ def initialize(self, env): self.reset(env) def reset(self, env): - self._is_simul_env = is_simulated_env(env) + self._is_simul_env = self.is_simulated_env(env) if self._is_simul_env: return @@ -76,15 +76,4 @@ def _surlinear_func_curtailment(x, center=80, eps=1e-6): f_standardizer= lambda x : np.ones_like(x) * f_centralized(100) * (x >= center) - np.ones_like(x) * f_centralized(50) * (x < center) return f_centralized(x) / f_standardizer(x) - - -#to wait before PR Laure -def is_simulated_env(env): - - # to prevent cyclical import - from grid2op.Environment._ObsEnv import _ObsEnv - from grid2op.Environment._forecast_env import _ForecastEnv - - # This reward is not compatible with simulations - return isinstance(env, (_ObsEnv, _ForecastEnv)) From 9134f793306d399576d9fa92c0ae4f320be5ba4c Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Thu, 6 Jul 2023 17:57:11 +0200 Subject: [PATCH 005/103] score2023: add alertcostscore --- grid2op/Reward/__init__.py | 5 +- grid2op/Reward/_alertCostScore.py | 70 +++++++++++++++++++ grid2op/Reward/_assistantScore.py | 65 ----------------- .../Reward/_newRenewableSourcesUsageScore.py | 5 +- grid2op/utils/l2rpn_idf_2023_scores.py | 30 ++++---- 5 files changed, 90 insertions(+), 85 deletions(-) create mode 100644 grid2op/Reward/_alertCostScore.py delete mode 100644 grid2op/Reward/_assistantScore.py diff --git a/grid2op/Reward/__init__.py b/grid2op/Reward/__init__.py index 1c3567c79..04d31b97e 100644 --- a/grid2op/Reward/__init__.py +++ b/grid2op/Reward/__init__.py @@ -24,8 +24,7 @@ "AlertReward", "_AlarmScore", "_NewRenewableSourcesUsageScore", - "_AssistantConfidenceScore", - "_AssistantCostScore" + "_AlertCostScore" ] from grid2op.Reward.constantReward import ConstantReward @@ -52,7 +51,7 @@ from grid2op.Reward.l2rpn_wcci2022_scorefun import L2RPNWCCI2022ScoreFun from grid2op.Reward.alertReward import AlertReward from grid2op.Reward._newRenewableSourcesUsageScore import _NewRenewableSourcesUsageScore -from grid2op.Reward._assistantScore import _AssistantConfidenceScore, _AssistantCostScore +from grid2op.Reward._alertCostScore import _AlertCostScore import warnings diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py new file mode 100644 index 000000000..0fad367ce --- /dev/null +++ b/grid2op/Reward/_alertCostScore.py @@ -0,0 +1,70 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import numpy as np +from grid2op.Reward.baseReward import BaseReward +from grid2op.Reward._newRenewableSourcesUsageScore import _NewRenewableSourcesUsageScore +from grid2op.dtypes import dt_float +from grid2op.Exceptions import Grid2OpException + +class _AlertCostScore(BaseReward): + """ + + INTERNAL + + .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ + It **must not** serve as a reward. This scored needs to be **MAXIMIZED**, + as it is a negative! Also, this "reward" is not scaled or anything. Use it as your + own risk. + + Implemented as a reward to make it easier to use in the context of the L2RPN competitions, this reward is based on the "alert feature" + where the agent is asked to send information about potential line overload issue on the grid after unpredictable powerline + disconnection (attack of the opponent). + The alerts are assessed once per attack. In this scheme, this "reward" computed the assistant"cost score", which penalized the number of alerts + the assistant have produced during an episode. It should not be used to train an agent. + + """ + def __init__(self, logger=None): + BaseReward.__init__(self, logger=logger) + self.reward_min = dt_float(-1.0) + self.reward_max = dt_float(1.0) + self._is_simul_env = False + + def __initialize__(self, env): + if not env._has_attention_budget: + raise Grid2OpException( + 'Impossible to use the "_AlertCostScore" with an environment for which the Assistant feature ' + 'is disabled. Please make sure "env._has_attention_budget" is set to ``True`` or ' + "change the reward class with `grid2op.make(..., reward_class=AnyOtherReward)`" + ) + self.reset(env) + + def reset(self, env): + self._is_simul_env = self.is_simulated_env(env) + if self._is_simul_env: + return + self.total_nb_alertes_possible = (env.chronics_handler.max_timestep() + 1) * (env.dim_alerts) + self.total_nb_alerts = 0 + + def __call__(self, env, obs, is_done): + if self._is_simul_env: + return dt_float(0.) + + if is_done: + ratio_nb_alerts = 100 * ( 1 - self.total_nb_alerts / self.total_nb_alertes_possible) + return self._penalization_fun(ratio_nb_alerts) + else: + self.total_nb_alerts = obs.total_number_of_alerts + return dt_float(0.) + + @staticmethod + def _penalization_fun(x, center=80): + return _NewRenewableSourcesUsageScore._surlinear_func_curtailment(x=x, center=center) + + + diff --git a/grid2op/Reward/_assistantScore.py b/grid2op/Reward/_assistantScore.py deleted file mode 100644 index 707c46299..000000000 --- a/grid2op/Reward/_assistantScore.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. - -import numpy as np -from grid2op.Reward.baseReward import BaseReward - -class _AssistantConfidenceScore(BaseReward): - """ - - INTERNAL - - .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ - It **must not** serve as a reward. This scored needs to be **MINIMIZED**, - and a reward needs to be maximized! Also, this "reward" is not scaled or anything. Use it as your - own risk. - - Implemented as a reward to make it easier to use in the context of the L2RPN competitions, this "reward" - computed the assistant "confidence score", which evaluates how confident an agent was in its actions for handling - unforeseen line l disconnection events prior to occurring. - It should not be used to train an agent. - - """ - def __init__(self, logger=None): - BaseReward.__init__(self, logger=logger) - - def __initialize__(self, env): - self.reset(env) - - def reset(self): - pass - - def __call__(self, env, obs, is_done): - pass - -class _AssistantCostScore(BaseReward): - """ - - INTERNAL - - .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ - It **must not** serve as a reward. This scored needs to be **MINIMIZED**, - and a reward needs to be maximized! Also, this "reward" is not scaled or anything. Use it as your - own risk. - - Implemented as a reward to make it easier to use in the context of the L2RPN competitions, this "reward" - computed the assistant"cost score", which penalized the number of alarm the assistant have produced. - It should not be used to train an agent. - - """ - def __init__(self, logger=None): - BaseReward.__init__(self, logger=logger) - - def __initialize__(self, env): - self.reset(env) - - def reset(self): - pass - - def __call__(self, env, obs, is_done): - pass \ No newline at end of file diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index 5db2846b1..c0a8eda44 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -42,8 +42,9 @@ def reset(self, env): if self._is_simul_env: return - self.gen_res_p_curtailed_list = np.zeros(env.chronics_handler.max_timestep() + 1) - self.gen_res_p_before_curtail_list = np.zeros(env.chronics_handler.max_timestep() + 1) + max_timesteps = env.chronics_handler.max_timestep() + 1 + self.gen_res_p_curtailed_list = np.zeros(max_timesteps) + self.gen_res_p_before_curtail_list = np.zeros(max_timesteps) def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 8a4502634..ba26c96d5 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -7,7 +7,7 @@ # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. from grid2op.utils.l2rpn_2020_scores import ScoreL2RPN2020 -from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AssistantConfidenceScore, _AssistantCostScore +from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, AlertReward, _AlertCostScore from grid2op.utils.underlying_statistics import EpisodeStatistics @@ -102,13 +102,13 @@ def __init__( nb_process_stats=nb_process_stats, scores_func={ "grid_operational_cost": L2RPNSandBoxScore, - #"assistance_confidence": _AssistantConfidenceScore, - #"assistant_cost": _AssistantCostScore, + "assistance_confidence": AlertReward, + "assistant_cost": _AlertCostScore, "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, }, score_names=["grid_operational_cost_scores", - #"assistant_confidence_scores", - #"assistant_cost_scores", + "assistant_confidence_scores", + "assistant_cost_scores", "new_renewable_sources_usage_scores"], ) @@ -164,18 +164,18 @@ def _compute_episode_score( nres_score = self.scale_nres_score * nres_score #assistant_confidence_score - # new_renewable_sources_usage_score_nm = "assistant_confidence_scores" - # real_nm = EpisodeStatistics._nm_score_from_attr_name(new_renewable_sources_usage_score_nm) - # key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" - # assistant_confidence_score = float(other_rewards[-1][key_score_file]) - assistant_confidence_score = 0 #self.scale_assistant_score * assistant_confidence_score + assistant_confidence_score_nm = "assistant_confidence_scores" + real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_confidence_score_nm) + key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" + assistant_confidence_score = float(other_rewards[-1][key_score_file]) + assistant_confidence_score = self.scale_assistant_score * assistant_confidence_score #assistant_cost_score - # new_renewable_sources_usage_score_nm = "assistant_cost_scores" - # real_nm = EpisodeStatistics._nm_score_from_attr_name(new_renewable_sources_usage_score_nm) - # key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" - # assistant_cost_score = float(other_rewards[-1][key_score_file]) - assistant_cost_score = 0 #self.scale_assistant_score * assistant_cost_score + assistant_cost_score_nm = "assistant_cost_scores" + real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_cost_score_nm) + key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" + assistant_cost_score = float(other_rewards[-1][key_score_file]) + assistant_cost_score = self.scale_assistant_score * assistant_cost_score assistant_score = self.weight_confidence_assistant_score * assistant_confidence_score +\ (1. - self.weight_confidence_assistant_score) * assistant_cost_score From 268e60e84e4504282f10e952e1b80dd5c5425879 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Thu, 6 Jul 2023 19:07:48 +0200 Subject: [PATCH 006/103] score2023: add tests and capping cost assistant --- grid2op/Reward/_alertCostScore.py | 9 +- grid2op/tests/test_RewardAlertCostScore.py | 167 ++++++++++++++++++ ...est_RewardNewRenewableSourcesUsageScore.py | 8 + grid2op/utils/l2rpn_idf_2023_scores.py | 3 + 4 files changed, 184 insertions(+), 3 deletions(-) create mode 100644 grid2op/tests/test_RewardAlertCostScore.py diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index 0fad367ce..b7c54e12e 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -34,6 +34,8 @@ def __init__(self, logger=None): self.reward_min = dt_float(-1.0) self.reward_max = dt_float(1.0) self._is_simul_env = False + self.total_nb_alertes_possible = None + self.total_nb_alerts = None def __initialize__(self, env): if not env._has_attention_budget: @@ -48,18 +50,19 @@ def reset(self, env): self._is_simul_env = self.is_simulated_env(env) if self._is_simul_env: return + self.total_nb_alertes_possible = (env.chronics_handler.max_timestep() + 1) * (env.dim_alerts) self.total_nb_alerts = 0 - def __call__(self, env, obs, is_done): - if self._is_simul_env: + def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): + if self.is_simulated_env(env): return dt_float(0.) if is_done: ratio_nb_alerts = 100 * ( 1 - self.total_nb_alerts / self.total_nb_alertes_possible) return self._penalization_fun(ratio_nb_alerts) else: - self.total_nb_alerts = obs.total_number_of_alerts + self.total_nb_alerts = env._total_number_of_alert return dt_float(0.) @staticmethod diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py new file mode 100644 index 000000000..d5ce083ae --- /dev/null +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -0,0 +1,167 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import warnings +import numpy as np +import unittest +import tempfile +import grid2op +from grid2op.Reward import _AlertCostScore +from grid2op.Agent import DoNothingAgent, BaseAgent +from grid2op.tests.helper_path_test import * +from grid2op.Exceptions import Grid2OpException +from grid2op.Runner import Runner +from grid2op.Observation import BaseObservation +from grid2op.Action import BaseAction +from grid2op.Episode import EpisodeData + +class AlertAgent(BaseAgent): + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + if observation.current_step == 2: + return self.action_space({"raise_alert": [0]}) + return super().act(observation, reward, done) + + +class TestAlertCostScore(unittest.TestCase): + + def test_specs(self): + # test function without actual data + assert _AlertCostScore._penalization_fun(50) == -1. + assert _AlertCostScore._penalization_fun(80) == 0. + assert _AlertCostScore._penalization_fun(100) == 1. + + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + + def tearDown(self) -> None: + return super().tearDown() + + def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : + """ When no blackout and no attack occur, and no alert is raised we expect a reward of 0 + until the end of the episode where we get the max reward 1. + + Raises: + Grid2OpException: raise an exception if an attack occur + """ + with grid2op.make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertCostScore + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + obs, reward, done, info = env.step(env.action_space()) + if done: + assert reward == 1. + else: + assert reward == 0. + + +class TestSimulate(unittest.TestCase): + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + self.env = grid2op.make(self.env_nm, test=True, difficulty="1", + reward_class=_AlertCostScore) + self.env.seed(0) + return super().setUp() + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_simulate(self): + obs = self.env.reset() + simO, simr, simd, simi = obs.simulate(self.env.action_space()) + assert simr == 0. + assert not simd + + go_act = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}}) + simO, simr, simd, simi = obs.simulate(go_act) + assert simr == 1., f"{simr} vs 1." + assert simd + + def test_simulated_env(self): + obs = self.env.reset() + f_env = obs.get_forecast_env() + forD = False + while not forD: + forO, forR, forD, forI = f_env.step(self.env.action_space()) + assert forR == 0. + + f_env = obs.get_forecast_env() + forD = False + go_act = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}}) + while not forD: + forO, forR, forD, forI = f_env.step(go_act) + assert forR == 1. + + +class TestRunner(unittest.TestCase): + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + self.env = grid2op.make(self.env_nm, test=True, difficulty="1", + reward_class=_AlertCostScore) + self.env.seed(0) + return super().setUp() + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_dn_agent(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) + assert res[0][2] == 1. + + def test_simagent(self): + obs = self.env.reset() + + class SimAgent(BaseAgent): + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + go_act = self.action_space({"set_bus": {"generators_id": [(0, -1)]}}) + simO, simr, simd, simi = obs.simulate(go_act) + simO, simr, simd, simi = obs.simulate(self.action_space()) + return super().act(observation, reward, done) + + runner = Runner(**self.env.get_params_for_runner(), + agentClass=SimAgent) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) + assert res[0][2] == 1. + + def test_episodeData(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], add_detailed_output=True) + assert res[0][2] == 1. + assert res[0][5].rewards[8] == 1. + + def test_with_save(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + with tempfile.TemporaryDirectory() as f: + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], + path_save=f) + assert res[0][2] == 1. + ep0, *_ = EpisodeData.list_episode(f) + ep = EpisodeData.from_disk(*ep0) + assert ep.rewards[8] == 1. + + +if __name__ == "__main__": + unittest.main() diff --git a/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py b/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py index bb4fe6b64..dd0f6140d 100644 --- a/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py +++ b/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py @@ -148,6 +148,14 @@ def test_simulate_ignored(self): break return reward == 1. + + def test_simulated_env(self): + obs = self.env.reset() + f_env = obs.get_forecast_env() + forD = False + while not forD: + forO, forR, forD, forI = f_env.step(self.env.action_space()) + assert forR == 0. if __name__ == "__main__": diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index ba26c96d5..b2e5fd5a3 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -88,6 +88,7 @@ def __init__( weight_nres_score=0.15, weight_confidence_assistant_score=0.7, min_nres_score=-100, + min_assistant_cost_score=-100, ): ScoreL2RPN2020.__init__( @@ -122,6 +123,7 @@ def __init__( self.weight_nres_score = weight_nres_score self.weight_confidence_assistant_score = weight_confidence_assistant_score self.min_nres_score = min_nres_score + self.min_assistant_cost_score = min_assistant_cost_score def _compute_episode_score( self, @@ -175,6 +177,7 @@ def _compute_episode_score( real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_cost_score_nm) key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" assistant_cost_score = float(other_rewards[-1][key_score_file]) + assistant_cost_score = max(assistant_cost_score, self.min_assistant_cost_score / self.scale_assistant_score) assistant_cost_score = self.scale_assistant_score * assistant_cost_score assistant_score = self.weight_confidence_assistant_score * assistant_confidence_score +\ From 84407054b45ec9e54e6f8a0a83d5afce13e07d86 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 7 Jul 2023 09:32:20 +0200 Subject: [PATCH 007/103] fix some bugs in the pkg archive and improve MultiFolder --- CHANGELOG.rst | 5 +++++ MANIFEST.in | 6 +++++- docs/conf.py | 2 +- grid2op/Chronics/multiFolder.py | 2 +- grid2op/__init__.py | 2 +- grid2op/tests/test_Runner.py | 2 ++ 6 files changed, 15 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f3da7a544..48b26f5b8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -31,6 +31,11 @@ Change Log - [???] "asynch" multienv - [???] properly model interconnecting powerlines +[1.9.2] - 2023-07-xx +--------------------- +- [FIXED] broken environ "l2rpn_idf_2023" (with test=True) due to the presence of a `__pycache__` folder +- [FIXED] time series `MultiFolder` will now ignore folder `__pycache__` + [1.9.1] - 2023-07-06 -------------------- - [BREAKING] (slightly): default `gym_compat` module now inherit from `gymnasium` (if diff --git a/MANIFEST.in b/MANIFEST.in index 6da49fdbe..25337d7a1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,5 @@ -recursive-include grid2op/data *.bz2 *.json *.zip prods_charac.csv *.py .multimix storage_units_charac.csv start_datetime.info time_interval.info \ No newline at end of file +recursive-include grid2op/data *.bz2 *.json *.zip prods_charac.csv *.py .multimix storage_units_charac.csv start_datetime.info time_interval.info +global-exclude */__pycache__/* +global-exclude *.pyc +global-exclude grid2op/data_test/* +global-exclude grid2op/tests/* diff --git a/docs/conf.py b/docs/conf.py index 9b2060d90..bf71370d0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -22,7 +22,7 @@ author = 'Benjamin Donnot' # The full version, including alpha/beta/rc tags -release = '1.9.1' +release = '1.9.2.dev0' version = '1.9' diff --git a/grid2op/Chronics/multiFolder.py b/grid2op/Chronics/multiFolder.py index a3ebc4f68..a308744b1 100644 --- a/grid2op/Chronics/multiFolder.py +++ b/grid2op/Chronics/multiFolder.py @@ -211,7 +211,7 @@ def init_subpath(self): self.subpaths = [ os.path.join(self.path, el) for el in os.listdir(self.path) - if os.path.isdir(os.path.join(self.path, el)) + if os.path.isdir(os.path.join(self.path, el)) and (el != "__pycache__") and (not el.startwith(".")) ] self.subpaths.sort() self.subpaths = np.array(self.subpaths) diff --git a/grid2op/__init__.py b/grid2op/__init__.py index 48ff21c31..867a9964c 100644 --- a/grid2op/__init__.py +++ b/grid2op/__init__.py @@ -11,7 +11,7 @@ Grid2Op """ -__version__ = '1.9.1' +__version__ = '1.9.2.dev0' __all__ = [ "Action", diff --git a/grid2op/tests/test_Runner.py b/grid2op/tests/test_Runner.py index 6dee798ae..7a05dda13 100644 --- a/grid2op/tests/test_Runner.py +++ b/grid2op/tests/test_Runner.py @@ -497,6 +497,8 @@ def test_backward_compatibility(self): "1.7.1", "1.7.2", "1.8.1", + "1.9.0", + "1.9.1", ] curr_version = "test_version" assert ( From 60815138af51f8e7f75f882a85c88eca2b411e19 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 7 Jul 2023 10:31:27 +0200 Subject: [PATCH 008/103] fix a bug --- grid2op/Chronics/multiFolder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/Chronics/multiFolder.py b/grid2op/Chronics/multiFolder.py index a308744b1..f4612ea50 100644 --- a/grid2op/Chronics/multiFolder.py +++ b/grid2op/Chronics/multiFolder.py @@ -211,7 +211,7 @@ def init_subpath(self): self.subpaths = [ os.path.join(self.path, el) for el in os.listdir(self.path) - if os.path.isdir(os.path.join(self.path, el)) and (el != "__pycache__") and (not el.startwith(".")) + if os.path.isdir(os.path.join(self.path, el)) and (el != "__pycache__") and (not el.startswith(".")) ] self.subpaths.sort() self.subpaths = np.array(self.subpaths) From 4dfd7a2a433f029b14ea7c0e76f55a6706c41843 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 7 Jul 2023 11:56:32 +0200 Subject: [PATCH 009/103] fix a bug in the backward compat, but still a bug for 1.9.0 --- CHANGELOG.rst | 1 + grid2op/Space/GridObjects.py | 20 ++++++++++++++------ grid2op/tests/test_Runner.py | 23 ++++++++++++++--------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 48b26f5b8..9870c95e8 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -35,6 +35,7 @@ Change Log --------------------- - [FIXED] broken environ "l2rpn_idf_2023" (with test=True) due to the presence of a `__pycache__` folder - [FIXED] time series `MultiFolder` will now ignore folder `__pycache__` +- [FIXED] an issue with compatibility with previous versions (due to alert) [1.9.1] - 2023-07-06 -------------------- diff --git a/grid2op/Space/GridObjects.py b/grid2op/Space/GridObjects.py index c4189b987..e4e1338a2 100644 --- a/grid2op/Space/GridObjects.py +++ b/grid2op/Space/GridObjects.py @@ -2706,9 +2706,12 @@ def process_grid2op_compat(cls): # this feature did not exist before. cls.dim_alarms = 0 cls.assistant_warning_type = None + if cls.glop_version < "1.9.1": # this feature did not exists before cls.dim_alerts = 0 + cls.alertable_line_names = [] + cls.alertable_line_ids = [] @classmethod def get_obj_connect_to(cls, _sentinel=None, substation_id=None): @@ -3705,12 +3708,17 @@ class res(GridObjects): if "dim_alerts" in dict_: # NB by default the constructor do as if there were no alert so that's great ! cls.dim_alerts = dict_["dim_alerts"] - cls.alertable_line_names = extract_from_dict( - dict_, "alertable_line_names", lambda x: np.array(x).astype(str) - ) - cls.alertable_line_ids = extract_from_dict( - dict_, "alertable_line_ids", lambda x: np.array(x).astype(dt_int) - ) + if cls.dim_alerts > 0: + cls.alertable_line_names = extract_from_dict( + dict_, "alertable_line_names", lambda x: np.array(x).astype(str) + ) + cls.alertable_line_ids = extract_from_dict( + dict_, "alertable_line_ids", lambda x: np.array(x).astype(dt_int) + ) + else: + cls.alertable_line_names = [] + cls.alertable_line_ids = [] + # retrieve the redundant information that are not stored (for efficiency) obj_ = cls() obj_._compute_pos_big_topo_cls() diff --git a/grid2op/tests/test_Runner.py b/grid2op/tests/test_Runner.py index 7a05dda13..6f5152ba6 100644 --- a/grid2op/tests/test_Runner.py +++ b/grid2op/tests/test_Runner.py @@ -497,7 +497,7 @@ def test_backward_compatibility(self): "1.7.1", "1.7.2", "1.8.1", - "1.9.0", + # "1.9.0", # this one is bugy I don"t know why "1.9.1", ] curr_version = "test_version" @@ -519,8 +519,10 @@ def test_backward_compatibility(self): agent_seeds=[42, 69], ) # check that i can read this data generate for this runner - self._aux_backward(path, curr_version, curr_version) - + try: + self._aux_backward(path, curr_version, curr_version) + except Exception as exc_: + raise RuntimeError(f"error for {curr_version}") from exc_ assert ( "curtailment" in CompleteObservation.attr_list_vect ), "error after the first runner" @@ -531,17 +533,20 @@ def test_backward_compatibility(self): self._aux_backward( PATH_PREVIOUS_RUNNER, f"res_agent_{grid2op_version}", grid2op_version ) - + for grid2op_version in backward_comp_version: # check that i can read previous data stored from previous grid2Op version # can be loaded properly with warnings.catch_warnings(): warnings.filterwarnings("ignore") - self._aux_backward( - PATH_PREVIOUS_RUNNER, - f"res_agent_{grid2op_version}", - grid2op_version, - ) + try: + self._aux_backward( + PATH_PREVIOUS_RUNNER, + f"res_agent_{grid2op_version}", + grid2op_version, + ) + except Exception as exc_: + raise RuntimeError(f"error for {grid2op_version}") from exc_ assert "curtailment" in CompleteObservation.attr_list_vect, ( f"error after the legacy version " f"{grid2op_version}" ) From 9488af9ff4b10b48dd4722a905f0ecb769c764ce Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 12:16:25 +0200 Subject: [PATCH 010/103] score2023: add whole score test --- grid2op/tests/test_RewardAlertCostScore.py | 4 +-- grid2op/tests/test_score_idf_2023.py | 29 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index d5ce083ae..318b1997f 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -90,7 +90,7 @@ def test_simulate(self): go_act = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}}) simO, simr, simd, simi = obs.simulate(go_act) - assert simr == 1., f"{simr} vs 1." + assert simr == 0., f"{simr} vs 0." assert simd def test_simulated_env(self): @@ -106,7 +106,7 @@ def test_simulated_env(self): go_act = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}}) while not forD: forO, forR, forD, forI = f_env.step(go_act) - assert forR == 1. + assert forR == 0. class TestRunner(unittest.TestCase): diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index a298c5545..93fe04844 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -146,6 +146,35 @@ def test_score_helper(self): assert res_agent1[0][1][2] - res_agent2[0][1][2] >= res_agent2[0][1][2] - res_agent2[0][1][2] finally: my_score.clear_all() + + def test_score_helper2(self): + """basic tests for ScoreL2RPN2023 class""" + self.env.reset() + try: + my_score = ScoreL2RPN2023( + self.env, + nb_scenario=self.nb_scenario, + env_seeds=[0 for _ in range(self.nb_scenario)], + agent_seeds=[0 for _ in range(self.nb_scenario)], + max_step=self.max_iter, + weight_op_score=0.65, + weight_assistant_score=25, + weight_nres_score=0.15, + scale_nres_score=100, + scale_assistant_score=100, + min_nres_score=-100., + min_assistant_cost_score=-100) + + # test do nothing indeed gets 100. + res_dn = my_score.get(DoNothingAgent(self.env.action_space)) + for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + assert nres_score == 100. + assert ep_score == 0.65 * op_score + 0.15 * nres_score + 0.25 * (0.7 * assistant_confidence_score + 0.3 * assistant_cost_score) + assert assistant_cost_score == 100. + assert assistant_confidence_score == 100. #no blackout with no disconnections + + finally: + my_score.clear_all() def test_min_score(self): """test the score does not go bellow the minimum in input""" From 0a63998f20df59ece39d6d2d3f93247c329e69f6 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 14:55:41 +0200 Subject: [PATCH 011/103] score2023: create alertscore cumulating reward --- grid2op/Reward/__init__.py | 4 +- grid2op/Reward/_alertTrustScore.py | 76 ++++++++++++++++++++++++++ grid2op/utils/l2rpn_idf_2023_scores.py | 4 +- 3 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 grid2op/Reward/_alertTrustScore.py diff --git a/grid2op/Reward/__init__.py b/grid2op/Reward/__init__.py index 04d31b97e..54bacfb73 100644 --- a/grid2op/Reward/__init__.py +++ b/grid2op/Reward/__init__.py @@ -24,7 +24,8 @@ "AlertReward", "_AlarmScore", "_NewRenewableSourcesUsageScore", - "_AlertCostScore" + "_AlertCostScore", + "_AlertTrustScore" ] from grid2op.Reward.constantReward import ConstantReward @@ -52,6 +53,7 @@ from grid2op.Reward.alertReward import AlertReward from grid2op.Reward._newRenewableSourcesUsageScore import _NewRenewableSourcesUsageScore from grid2op.Reward._alertCostScore import _AlertCostScore +from grid2op.Reward._alertTrustScore import _AlertTrustScore import warnings diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py new file mode 100644 index 000000000..30ce9d038 --- /dev/null +++ b/grid2op/Reward/_alertTrustScore.py @@ -0,0 +1,76 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import numpy as np +from grid2op.Reward import AlertReward +from grid2op.dtypes import dt_float + +class _AlertTrustScore(AlertReward): + """ + + INTERNAL + + .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ + It **must not** serve as a reward. This scored needs to be **MAXIMIZED**, + as it is a negative! Also, this "reward" is not scaled or anything. Use it as your + own risk. + + Implemented as a reward to make it easier to use in the context of the L2RPN competitions, this reward is based on the "alert feature" + where the agent is asked to send information about potential line overload issue on the grid after unpredictable powerline + disconnection (attack of the opponent). + The alerts are assessed once per attack. In this scheme, this "reward" computed the assistant"cost score", which penalized the number of alerts + the assistant have produced during an episode. It should not be used to train an agent. + + """ + + def __init__(self, + logger=None, + reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=1.0): + + super().init(logger, + reward_min_no_blackout, + reward_min_blackout, + reward_max_no_blackout, + reward_max_blackout, + reward_end_episode_bonus) + + self.reward_min = dt_float(-1.0) + self.reward_max = dt_float(1.0) + self.score_min_ep = lambda k: -1.*(k-1) + (-10 *1.) + self.score_max_ep = lambda k: 1. * k + 1 + + def __initialize__(self, env): + super().__initialize__(env) + + def reset(self, env): + super().reset(env) + self.total_nb_attacks = 0 + self.cumulated_reward = 0 + + def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): + res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) + + if self.is_simulated_env(env): + return 0. + + self.cumulated_reward += res + self.total_nb_attacks += 1.* (env._time_since_last_attack == 0) + + if not is_done: + return 0. + else: + score_min_ep = self.score_min_ep(self.total_nb_attacks) + score_max_ep = self.score_max_ep(self.total_nb_attacks) + standardized_score = (self.cumulated_reward - score_min_ep) / (score_max_ep - score_min_ep + 1e-6) + score_ep = standardized_score * 2. - 1. + + return score_ep diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index b2e5fd5a3..0e9e45d82 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -7,7 +7,7 @@ # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. from grid2op.utils.l2rpn_2020_scores import ScoreL2RPN2020 -from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, AlertReward, _AlertCostScore +from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AlertTrustScore, _AlertCostScore from grid2op.utils.underlying_statistics import EpisodeStatistics @@ -103,7 +103,7 @@ def __init__( nb_process_stats=nb_process_stats, scores_func={ "grid_operational_cost": L2RPNSandBoxScore, - "assistance_confidence": AlertReward, + "assistance_confidence": _AlertTrustScore, "assistant_cost": _AlertCostScore, "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, }, From aed1bd9de45f758e257d8cd3a2aead272544584f Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 15:03:20 +0200 Subject: [PATCH 012/103] score2023: trust fix & one test --- grid2op/Reward/_alertTrustScore.py | 2 +- grid2op/tests/test_RewardAlertCostScore.py | 37 ++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 30ce9d038..8d945839d 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -36,7 +36,7 @@ def __init__(self, reward_max_blackout=2.0, reward_end_episode_bonus=1.0): - super().init(logger, + super().__init__(logger, reward_min_no_blackout, reward_min_blackout, reward_max_no_blackout, diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 318b1997f..06c8e5d14 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -11,7 +11,7 @@ import unittest import tempfile import grid2op -from grid2op.Reward import _AlertCostScore +from grid2op.Reward import _AlertCostScore, _AlertTrustScore from grid2op.Agent import DoNothingAgent, BaseAgent from grid2op.tests.helper_path_test import * from grid2op.Exceptions import Grid2OpException @@ -161,7 +161,40 @@ def test_with_save(self): ep0, *_ = EpisodeData.list_episode(f) ep = EpisodeData.from_disk(*ep0) assert ep.rewards[8] == 1. - + + +class TestAlertTrustScore(unittest.TestCase): + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + + def tearDown(self) -> None: + return super().tearDown() + + def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : + """ When no blackout and no attack occur, and no alert is raised we expect a reward of 0 + until the end of the episode where we get the max reward 1. + + Raises: + Grid2OpException: raise an exception if an attack occur + """ + with grid2op.make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + obs, reward, done, info = env.step(env.action_space()) + if done: + assert reward == 1. + else: + assert reward == 0. if __name__ == "__main__": unittest.main() From 2ba8ad0fdfb1d7da62cf95bb9aa25b86ea90e30e Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 15:20:35 +0200 Subject: [PATCH 013/103] score2023: min max fun with reward args --- grid2op/Reward/_alertTrustScore.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 8d945839d..34da3c58c 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -45,8 +45,8 @@ def __init__(self, self.reward_min = dt_float(-1.0) self.reward_max = dt_float(1.0) - self.score_min_ep = lambda k: -1.*(k-1) + (-10 *1.) - self.score_max_ep = lambda k: 1. * k + 1 + self.score_min_ep = lambda k: reward_min_no_blackout * (k - 1) + reward_min_blackout + self.score_max_ep = lambda k: reward_max_no_blackout * k + reward_end_episode_bonus def __initialize__(self, env): super().__initialize__(env) From 30751b3e89a65d3658725b4fec0220219939436e Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 15:25:01 +0200 Subject: [PATCH 014/103] score2023: simulation order fix --- grid2op/Reward/_alertTrustScore.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 34da3c58c..51b9769fd 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -57,16 +57,16 @@ def reset(self, env): self.cumulated_reward = 0 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) - + score_ep = 0. if self.is_simulated_env(env): - return 0. + return score_ep + res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res self.total_nb_attacks += 1.* (env._time_since_last_attack == 0) if not is_done: - return 0. + return score_ep else: score_min_ep = self.score_min_ep(self.total_nb_attacks) score_max_ep = self.score_max_ep(self.total_nb_attacks) From c2e0347d022a1b02a2c40cc405ed9bb6aa7e895a Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 15:42:03 +0200 Subject: [PATCH 015/103] score2023: fix attack counting --- grid2op/Reward/_alertTrustScore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 51b9769fd..124e1d739 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -63,7 +63,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res - self.total_nb_attacks += 1.* (env._time_since_last_attack == 0) + self.total_nb_attacks += 1.* (any(env._time_since_last_attack == 0)) if not is_done: return score_ep From a9e429a5774174c69072408ad8f16a103451a56c Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 15:43:21 +0200 Subject: [PATCH 016/103] score2023: simulation return trust --- grid2op/Reward/_alertCostScore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index b7c54e12e..20cbc1262 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -55,7 +55,7 @@ def reset(self, env): self.total_nb_alerts = 0 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - if self.is_simulated_env(env): + if any([self.is_simulated_env(env), not env._has_attention_budget]): return dt_float(0.) if is_done: From a7cb5786b4eb439b20a962a6cebf9542471ba830 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Fri, 7 Jul 2023 17:41:46 +0200 Subject: [PATCH 017/103] score2023: more fix --- grid2op/Reward/_alertCostScore.py | 8 +++++++- grid2op/Reward/_alertTrustScore.py | 2 +- grid2op/tests/test_RewardAlertCostScore.py | 3 ++- grid2op/tests/test_score_idf_2023.py | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index 20cbc1262..0181797d8 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -44,6 +44,12 @@ def __initialize__(self, env): 'is disabled. Please make sure "env._has_attention_budget" is set to ``True`` or ' "change the reward class with `grid2op.make(..., reward_class=AnyOtherReward)`" ) + if not env.dim_alerts > 0: + raise Grid2OpException( + 'Impossible to use the "_AlertCostScore" with an environment for which the Assistant feature ' + 'is disabled. Please make sure "env.dim_alerts" is > 0 or ' + "change the reward class with `grid2op.make(..., reward_class=AnyOtherReward)`" + ) self.reset(env) def reset(self, env): @@ -55,7 +61,7 @@ def reset(self, env): self.total_nb_alerts = 0 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - if any([self.is_simulated_env(env), not env._has_attention_budget]): + if self.is_simulated_env(env): return dt_float(0.) if is_done: diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 124e1d739..616ab5c71 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -63,7 +63,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res - self.total_nb_attacks += 1.* (any(env._time_since_last_attack == 0)) + self.total_nb_attacks += np.sum(env._time_since_last_attack == 0) if not is_done: return score_ep diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 06c8e5d14..0179af45e 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -127,9 +127,10 @@ def test_dn_agent(self): obs = self.env.reset() runner = Runner(**self.env.get_params_for_runner()) res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) - assert res[0][2] == 1. + assert res[0][2] == 1. #it got to the end def test_simagent(self): + #simulate blackout but act donothing obs = self.env.reset() class SimAgent(BaseAgent): diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index 93fe04844..4fab7789f 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -49,7 +49,7 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - class TestScoreL2RPN2023(unittest.TestCase): def setUp(self) -> None: - env_name = "l2rpn_case14_sandbox" + env_name = "l2rpn_idf_2023_with_alert" with warnings.catch_warnings(): warnings.filterwarnings("ignore") self.env = grid2op.make(env_name, From 77ee3db797adff1b56c58d6e33ee1827d0a3950f Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Mon, 10 Jul 2023 14:09:02 +0200 Subject: [PATCH 018/103] adding doc for l2rpn_idf_2023 --- docs/available_envs.rst | 84 ++++++++++++++++++++++++++- docs/img/l2rpn_idf_2023_areas.png | Bin 0 -> 336403 bytes docs/img/l2rpn_idf_2023_att.png | Bin 0 -> 363693 bytes docs/img/l2rpn_idf_2023_layout.png | Bin 0 -> 266144 bytes docs/img/l2rpn_idf_2023_maint.png | Bin 0 -> 363945 bytes grid2op/tests/test_l2rpn_idf_2023.py | 2 +- 6 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 docs/img/l2rpn_idf_2023_areas.png create mode 100644 docs/img/l2rpn_idf_2023_att.png create mode 100644 docs/img/l2rpn_idf_2023_layout.png create mode 100644 docs/img/l2rpn_idf_2023_maint.png diff --git a/docs/available_envs.rst b/docs/available_envs.rst index 29ecf8ef6..f2c8da22c 100644 --- a/docs/available_envs.rst +++ b/docs/available_envs.rst @@ -4,6 +4,10 @@ .. |l2rpn_neurips_2020_track1_layout| image:: ./img/l2rpn_neurips_2020_track1_layout.png .. |l2rpn_neurips_2020_track2_layout| image:: ./img/l2rpn_neurips_2020_track2_layout.png .. |l2rpn_wcci_2022_layout| image:: ./img/l2rpn_wcci_2022_layout.png +.. |l2rpn_idf_2023_layout| image:: ./img/l2rpn_idf_2023_layout.png +.. |l2rpn_idf_2023_areas| image:: ./img/l2rpn_idf_2023_areas.png +.. |l2rpn_idf_2023_maint| image:: ./img/l2rpn_idf_2023_maint.png +.. |l2rpn_idf_2023_att| image:: ./img/l2rpn_idf_2023_att.png Available environments @@ -55,6 +59,7 @@ env name grid size maintenance opponent redis :ref:`l2rpn_neurips_2020_track2` 118 sub. ✔️ ️ ❌ ️ ✔️ ️ ❌ :ref:`l2rpn_icaps_2021` 36 sub. ✔️ ️ ✔️ ️ ✔️ ️ ❌ :ref:`l2rpn_wcci_2022` 118 sub. ✔️ ️ ✔️ ️ ✔️ ️ ✔️ ️ +:ref:`l2rpn_idf_2023` 118 sub. ✔️ ️ ✔️ ️ ✔️ ️ ✔️ ️ \* educ_case14_redisp \* 14 sub. ❌️ ❌ ️ ️ ✔️ ️ ❌ \* educ_case14_storage \* 14 sub. ❌️ ❌ ️ ✔️ ️ ✔️ \* rte_case5_example \* 5 sub. ❌️ ❌ ️ ️ ❌ ️ ️ ❌ @@ -139,6 +144,83 @@ This grid looks like: |l2rpn_case14_sandbox_layout| +.. _l2rpn_idf_2023: + + +l2rpn_idf_2023 +++++++++++++++++ + +This environment is also based on the 118 grid. The original grid has been modified (mainly for generator and loads location) to +accomodate for the "possible energy mix" of France in 2035. + +It comes with 16 years worth of data, 1 year being divided in 52 weeks so 16 x 52 = 832 different scenarios and takes up around +~ 5.4 GB of space. + +To create it you can : + +.. code-block:: python + + import grid2op + env_name = "lrpn_idf_2023" + env = grid2op.make(env_name) + +It counts 118 substations, 186 powerlines, 99 loads and 62 generators. It will be used for the L2RPN competitions funded by Region Ile De France: +"Paris Region AI Challenge Energy Transition" and is free to use for everyone. + +You have the possibility, provided that you installed `chronix2grid` (with `pip install grid2op[chronix2grid]`), to generate as +much data as you want with the :func:`grid2op.Environment.Environment.generate_data` function. See its documentation for more information. + +The environment can be seen: + +|l2rpn_idf_2023_layout| + +Compared to previous available environments there are some new features including: + +- 12 steps ahead forecast: with any observation, you can now have access to forecast 12 steps ahead with, for example `obs.simulate(..., time_step=12)` + or `obs.get_forecast_env()` which has a maximum duration of 12 steps (previously it was only 1 step ahead forecast). This could be used in + `model based` strategy for example (see page :ref:`model_based_rl` for more examples) +- a more complex opponent: the opponent can attack 3 lines in 3 different areas of the grid at the same time (instead of + being limited to just 1 attack) +- more complex rules: in this environment to balance for the fact that the opponent can makes 3 attacks, the agent can also act on 3 different + powerlines and 3 different substation per step (one per area). + +The grid is split in 3 disctinct areas: + +|l2rpn_idf_2023_areas| + +Like most grid2op environment, it also has maintenance. Lines that can be in maintenance are: + +.. line_color_maint = np.zeros(env.n_line) +.. line_in_maintenance = {'21_22_93', '39_41_121', '54_58_154', '17_18_88', '29_37_117', +.. '91_92_37', '41_48_131', '80_79_175', '88_91_33', '48_50_136', +.. '43_44_125', '12_14_68', '62_58_180', '44_45_126', '74_117_81', +.. '26_31_106', '4_10_162', '93_95_43', '62_63_160', '48_53_141', +.. '34_35_110'} +.. line_in_maintenance = list(line_in_maintenance) + +.. line_color_maint[np.isin(env.name_line, line_in_maintenance) & np.isin(np.arange(env.n_line), lines_by_area[0])] = 1.0 +.. line_color_maint[np.isin(env.name_line, line_in_maintenance) & np.isin(np.arange(env.n_line), lines_by_area[1])] = 2.0 +.. line_color_maint[np.isin(env.name_line, line_in_maintenance) & np.isin(np.arange(env.n_line), lines_by_area[2])] = 3.0 +.. plot_helper._line_color_scheme = ["gray", "blue", "orange", "red"] +.. _ = plot_helper.plot_info(line_values=line_color_maint, coloring="line") +.. plot_helper.restore_line_palette() + +|l2rpn_idf_2023_maint| + +And the lines that can be attacked by the opponent are: + +.. attacked_lines = [106, 93, 88, 162, 68, 117, 180, 160, 136, 141, 131, 121, 125, 126, 110, 154, 81, 43, 33, 37, 62, 61] +.. line_color_att = np.zeros(env.n_line) +.. line_color_att[np.isin(np.arange(env.n_line), attacked_lines) & np.isin(np.arange(env.n_line), lines_by_area[0])] = 1.0 +.. line_color_att[np.isin(np.arange(env.n_line), attacked_lines) & np.isin(np.arange(env.n_line), lines_by_area[1])] = 2.0 +.. line_color_att[np.isin(np.arange(env.n_line), attacked_lines) & np.isin(np.arange(env.n_line), lines_by_area[2])] = 3.0 +.. plot_helper._line_color_scheme = ["gray", "blue", "orange", "red"] +.. _ = plot_helper.plot_info(line_values=line_color_att, coloring="line") +.. plot_helper.restore_line_palette() + +|l2rpn_idf_2023_att| + + .. _l2rpn_wcci_2022: l2rpn_wcci_2022 @@ -159,7 +241,7 @@ much data as you want with the :func:`grid2op.Environment.Environment.generate_d env_name = "l2rpn_wcci_2022" env = grid2op.make(env_name) -It counts 118 substations, 186 powerlines, 91 loads and 62 loads. It will be used for the L2RPN competitions at WCCI in 2022. +It counts 118 substations, 186 powerlines, 91 loads and 62 generators. It will be used for the L2RPN competitions at WCCI in 2022. |l2rpn_wcci_2022_layout| diff --git a/docs/img/l2rpn_idf_2023_areas.png b/docs/img/l2rpn_idf_2023_areas.png new file mode 100644 index 0000000000000000000000000000000000000000..9b576c2540a89fa6a5ff31a4e9e1e2016b029a52 GIT binary patch literal 336403 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

SLg0WN^$SI;37gEtnG&H_1*%5 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áD8zSgjfnoKo9Cf^EJcg-fP^hn zsTkB?VZ`Ze1o-5Nj*NcLa#`HO!p{n-s9-`x69H;&btlc}O29Q*k!Ji#?)rP)?~5+V z`k&9)LlsXV3@PN4L+?`<*xC%o!# zH6{j(PaWb;)$J1Adu~@!aSS&HJ8VWA9UX_kOj&AFg$ZI$`RxM2d2q`Cv=EDxm1g8) z3~6@+y@S*0PuqMTo1q$S{5)1dsYCtc^M#FZOTkJ$l_>lPXTQ_H{=(e#@E4D#)y_Yu zkS9GLJj)>qFZ#9!K2Qv%HrGNu-YKo@#WRWOIg7sRe59Vu@vS3b+2;-bKH>QUE_fFh z*M(*Qf0QOp?&^m6;;1yJ!5x*)FXR(;>e!eZNc@lwC3124A;1%-r=9+JManZ$*R1tz)UqrPfa#M(4Rt8T|EF9GH1kB1l<5vH<>k@U6Wbh+ z{|-tUD+o`nw`oX;l|$9mrlYIOxVSGU_{4}LG3iZRZ}Qk6m+h0}OPY1#>VnpOB6e{~ z*9>%dQ*zCwE)#i8kriS_s-apm%N*k+tv;+c>3GI^cS$_oiJi2O1H2*)lUUG(7B-xv z3)mtvG@)2%|M`;!Ca*B;Iela`PV#qGGsP6eL_wXv?trd&5up)4iqBcu{V==q@jrGJ;hN0TEF?$Q3Cd z{UHn)&INc*L?Cp1@1SNyc74dS%NsXtsAq}Zz{TME9nj41idbx!QT0tzqC>VTzSJ+kl|DQ9GP`)9b*|xL_v9IAvQqn4 z6`f)<1ddGZi*;R?jj{tO|KYvq@nvcIK0_vq=z&^|h$f5O9j zyA%G4h6XJ!gH5a02w#Msq(hSAO{4WVZv5@xwukcHpI`zdZEk%0FBy^5uj3f|wmZwU z6zszkc79|4BEn9?L-#?fkw;2|HqgWruSKaSBb0@fR~FjF+{+Z_^1&hleQO&WR^S|q z6MQ|u`q=5F#LN+etK$vRFX-txw47fgNZO4A;)U~^Hfs(2?D;ru6^H*;_!!{#WW`E4 zy~65D%U#ca96Fno@7rLze$3}EZr#!Kx_xAX2$|DcYzAU9SeRLXY>tB060y9zEaO2Y zs*-B?uX!`j(KpQLno)0Gc27C;u8{j`(fD?3Z;?iUd;-H0Z!QZWWH1-ZUxD2D%?iKM z?vIVSI?Cb8v3F&OT-)2*NQMvWsjcfZ4>LtByha#N>G#5~uIxWUdeD8;MG&LtaQU7l zByDjtP+uws{$9I#B5}f1INFAuK}hf9)C2T>`?2o(zTLJ%mFp+7)%GM$$BSiPXp)REQn^Ht?+#3W|wf#bcf+D?PyqmRo`qbsZEj z6)cL0Q&!PtrR+za*uUG6l0E%bg;K$!Am7`zbAI{k5fO?4#x3iYLjnY@8}s6}DbwlV zyZ4W&lT{Vq!4r1bfiZg+!rnpkg>PcExQk6X|0g|;7$gK3_E9VbM|L#@xpW|2+I?X| zOzhM5n(o$xM|ws^FD#UiStAGvI=UhF+CeabdbZkWHU*p#me$tHAa)LG>_FX1*PdQdggox-K! z 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%0AMtd*(c^;JVr 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�$_H_>nU@n%80XE~w45jDi9JJp3 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

GeM4|hSCS28LxKl?shlUz}1LC9pZ05SWx$2 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
iuw-ne6f{+xrC~nT}a^Hr5zbprWd8Y~=4e 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 z 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

    xh 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

    P;MkQrim0$_-t^t;xv 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 O2s~Z=T-G@yGyworzODHH literal 0 HcmV?d00001 diff --git a/docs/img/l2rpn_idf_2023_maint.png b/docs/img/l2rpn_idf_2023_maint.png new file mode 100644 index 0000000000000000000000000000000000000000..2c7962c9d806e75fd5477e55b8853b8e07fc4b30 GIT binary patch literal 363945 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 literal 0 HcmV?d00001 diff --git a/grid2op/tests/test_l2rpn_idf_2023.py b/grid2op/tests/test_l2rpn_idf_2023.py index b8627b3ee..b8aad0cfe 100644 --- a/grid2op/tests/test_l2rpn_idf_2023.py +++ b/grid2op/tests/test_l2rpn_idf_2023.py @@ -18,7 +18,7 @@ import pdb -class L2RPNIDF2023Tester(unittest.TestCase): +class TestL2RPNIDF2023Tester(unittest.TestCase): def setUp(self) -> None: with warnings.catch_warnings(): warnings.filterwarnings("ignore") From d1b5d7098880f5003a02b9a87fed7640bb73ad38 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Mon, 10 Jul 2023 15:03:11 +0200 Subject: [PATCH 019/103] improving doc [skip ci] --- docs/observation.rst | 2 +- grid2op/Backend/Backend.py | 4 +-- grid2op/Environment/BaseEnv.py | 4 +-- grid2op/Observation/baseObservation.py | 41 +++++++++++++++++---- grid2op/Observation/completeObservation.py | 42 ++++++++++++++-------- grid2op/Observation/observationSpace.py | 10 +++--- grid2op/Space/GridObjects.py | 23 +++++++++++- 7 files changed, 94 insertions(+), 32 deletions(-) diff --git a/docs/observation.rst b/docs/observation.rst index d4b308999..86bc3baba 100644 --- a/docs/observation.rst +++ b/docs/observation.rst @@ -86,7 +86,7 @@ how well the past action performed. The second main input received from the environment is the :class:`BaseObservation`. This is gives the BaseAgent partial, noisy, or complete information about the current state of the environment. This module implement a generic :class:`BaseObservation` class and an example of a complete observation in the case of the Learning -To Run a Power Network (`l2RPN `_ ) competition. +To Run a Power Network (`L2RPN `_ ) competition. Compared to other Reinforcement Learning problems the L2PRN competition allows another flexibility. Today, when operating a powergrid, operators have "forecasts" at their disposal. We wanted to make them available in the diff --git a/grid2op/Backend/Backend.py b/grid2op/Backend/Backend.py index c9e91ea5c..d71e97af5 100644 --- a/grid2op/Backend/Backend.py +++ b/grid2op/Backend/Backend.py @@ -57,7 +57,7 @@ class Backend(GridObjects, ABC): It is NOT recommended to use this class outside the Environment. - An example of a valid backend is provided in the :class:`PandapowerBackend`. + An example of a valid backend is provided in the :class:`PandaPowerBackend`. All the abstract methods (that need to be implemented for a backend to work properly) are (more information given in the :ref:`create-backend-module` page): @@ -622,7 +622,7 @@ def set_thermal_limit(self, limits): def update_thermal_limit_from_vect(self, thermal_limit_a): """You can use it if your backend stores the thermal limits - of the grid in a vector (see PandaPowerBackend for example) + of the grid in a vector (see :class:`PandaPowerBackend` for example) .. warning:: This is not called by the environment and cannot be used to diff --git a/grid2op/Environment/BaseEnv.py b/grid2op/Environment/BaseEnv.py index f86f90cd4..d24d159a9 100644 --- a/grid2op/Environment/BaseEnv.py +++ b/grid2op/Environment/BaseEnv.py @@ -108,7 +108,7 @@ class BaseEnv(GridObjects, RandomObject, ABC): The current observation (or None if it's not intialized) backend: :class:`grid2op.Backend.Backend` - The backend used to compute the powerflows and cascading failures. + The backend used to compute the powerflows. done: ``bool`` Whether the environment is "done". If ``True`` you need to call :func:`Environment.reset` in order @@ -3738,7 +3738,7 @@ def parameters(self): .. code-block:: python - env.params.WHATEVER = NEW_VALUE + env.params.WHATEVER = NEW_VALUE # no effet ! This will have absolutely no impact. diff --git a/grid2op/Observation/baseObservation.py b/grid2op/Observation/baseObservation.py index 7f95ff27c..4dff51ecf 100644 --- a/grid2op/Observation/baseObservation.py +++ b/grid2op/Observation/baseObservation.py @@ -297,13 +297,20 @@ class BaseObservation(GridObjects): active_alert: :class:`numpy.ndarray`, dtype:bool .. warning:: Only available if the environment supports the "alert" feature (*eg* "l2rpn_idf_2023"). - This function gives the lines "under alert" at the given observation. + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + + This attribute gives the lines "under alert" at the given observation. It is only relevant for the "real" environment and not for `obs.simulate` nor `obs.get_forecast_env` - active_alert time_since_last_alert alert_duration total_number_of_alert time_since_last_attack was_alert_used_after_attack time_since_last_alert: :class:`numpy.ndarray`, dtype:int .. warning:: Only available if the environment supports the "alert" feature (*eg* "l2rpn_idf_2023"). + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + Give the time since an alert has been raised for each powerline. If you just raise an alert for attackable line `i` then obs.time_since_last_alert[i] = 0 (and counter increase by 1 each step). @@ -313,21 +320,33 @@ class BaseObservation(GridObjects): alert_duration: :class:`numpy.ndarray`, dtype:int .. warning:: Only available if the environment supports the "alert" feature (*eg* "l2rpn_idf_2023"). + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + Give the time since an alert has started for all attackable line. If you just raise an alert for attackable line `i` then obs.time_since_last_alert[i] = 1 and this counter increase by 1 each step as long as the agent continues to "raise an alert on attackable line i" When the attackable line `i` is not under an alert then obs.time_since_last_alert[i] = 0 - total_number_of_alerts: :class:`numpy.ndarray`, dtype:int + total_number_of_alert: :class:`numpy.ndarray`, dtype:int .. warning:: Only available if the environment supports the "alert" feature (*eg* "l2rpn_idf_2023"). - This function counts, since the beginning of the current episode, the total number + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + + This attribute stores, since the beginning of the current episode, the total number of alerts (here 1 alert = one alert for 1 powerline for 1 step) sent by the agent. time_since_last_attack: :class:`numpy.ndarray`, dtype:int .. warning:: Only available if the environment supports the "alert" feature (*eg* "l2rpn_idf_2023"). + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + Similar to `time_since_last_alert` but for the attack. For each attackable line `i` it counts the number of steps since the powerline has @@ -355,7 +374,11 @@ class BaseObservation(GridObjects): This attribute is only filled if you use a compatible reward (*eg* :class:`grid2op.Reward.AlertReward`) as the main reward (or a "combined" reward with this reward being part of it) - + + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + For each attackable line `i` it says: - obs.was_alert_used_after_attack[i] = 0 => attackable line i has not been attacked @@ -371,6 +394,10 @@ class BaseObservation(GridObjects): attack_under_alert: :class:`numpy.ndarray`, dtype:int .. warning:: Only available if the environment supports the "alert" feature (*eg* "l2rpn_idf_2023"). + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + For each attackable line `i` it says: - obs.attack_under_alert[i] = 0 => attackable line i has not been attacked OR it @@ -3522,7 +3549,7 @@ def add_act(self, act, issue_warn=True): Returns ------- - res: :class:`grid2op.Observation.Observation` + res: :class:`grid2op.Observation.BaseObservation` The resulting observation. Note that this observation is not initialized with everything. It is only relevant when you want to study the resulting topology after you applied an action. Lots of `res` attributes are empty. @@ -4438,7 +4465,7 @@ def update_after_reward(self, env): You probably don't have to use except if you develop a specific observation class ! - .. info:: + .. note:: If you want to develop a new type of observation with a new type of reward, you can use the `env._reward_to_obs` attribute (dictionary) in the reward to pass information to the observation (in this function). diff --git a/grid2op/Observation/completeObservation.py b/grid2op/Observation/completeObservation.py index e74273199..201e94f00 100644 --- a/grid2op/Observation/completeObservation.py +++ b/grid2op/Observation/completeObservation.py @@ -67,9 +67,9 @@ class CompleteObservation(BaseObservation): 26. :attr:`BaseObservation.time_before_cooldown_sub` representation of the cooldown time on the substations [:attr:`grid2op.Space.GridObjects.n_sub` elements] 27. :attr:`BaseObservation.time_next_maintenance` number of timestep before the next maintenance (-1 means - no maintenance are planned, 0 a maintenance is in operation) [:attr:`BaseObservation.n_line` elements] + no maintenance are planned, 0 a maintenance is in operation) [:attr:`grid2op.Space.GridObjects.n_line` elements] 28. :attr:`BaseObservation.duration_next_maintenance` duration of the next maintenance. If a maintenance - is taking place, this is the number of timestep before it ends. [:attr:`BaseObservation.n_line` elements] + is taking place, this is the number of timestep before it ends. [:attr:`grid2op.Space.GridObjects.n_line` elements] 29. :attr:`BaseObservation.target_dispatch` the target dispatch for each generator [:attr:`grid2op.Space.GridObjects.n_gen` elements] 30. :attr:`BaseObservation.actual_dispatch` the actual dispatch for each generator @@ -107,18 +107,32 @@ class CompleteObservation(BaseObservation): constraint) [``bool``] 43. :attr:`BaseObservation.curtailment_limit` : the current curtailment limit (if any) [:attr:`grid2op.Space.GridObjects.n_gen` elements] - 44. :attr:`BaseObservation.curtailment_limit_effective` TODO - 45. :attr:`BaseObservation.current_step` TODO - 46. :attr:`BaseObservation.max_step` TODO - 47. :attr:`BaseObservation.delta_time` TODO - 48. :attr:`BaseObservation.gen_margin_up` TODO - 49. :attr:`BaseObservation.gen_margin_down` TODO - 50. :attr:`BaseObservation.last_alert` TODO - 51. :attr:`BaseObservation.time_since_last_alert` TODO - 52. :attr:`BaseObservation.alert_duration` TODO - 53. :attr:`BaseObservation.total_number_of_alert` TODO - 54. :attr:`BaseObservation.time_since_last_attack` TODO - 55. :attr:`BaseObservation.was_alert_used_after_attack` TODO + 44. :attr:`BaseObservation.curtailment_limit_effective` Limit (in ratio of gen_pmax) imposed on + each renewable generator effectively imposed by the environment. + 45. :attr:`BaseObservation.current_step` the number of steps since the beginning of the episode (it's + 0 for the observation after a call to `env.reset()`) + 46. :attr:`BaseObservation.max_step` maximum number of steps that can be done by the environment. + When :attr:`BaseObservation.current_step` is :attr:`BaseObservation.max_step` the the environment + is done. + 47. :attr:`BaseObservation.delta_time` Amount of time (in minutes) represented by a step. In general, there + are the equivalent of 5 minutes between two steps. + 48. :attr:`BaseObservation.gen_margin_up` From how much can you increase each generators production between this + step and the next. + 49. :attr:`BaseObservation.gen_margin_down` From how much can you decrease each generators production between this + step and the next. + 50. :attr:`BaseObservation.active_alert` This attribute gives the lines "under alert" at the given observation. + 51. :attr:`BaseObservation.time_since_last_alert` Give the time since an alert has been raised for each powerline. + 52. :attr:`BaseObservation.alert_duration` Give the time since an alert has started for all attackable line. + 53. :attr:`BaseObservation.total_number_of_alert` Total number of alerts since the beginning of the episode sent by + the agent + 54. :attr:`BaseObservation.time_since_last_attack` For each attackable line `i` it counts the number of steps since the powerline has + been attacked + 55. :attr:`BaseObservation.was_alert_used_after_attack` For each attackable line `i` it says if an alert has been used or not + for the computation of the reward: +1 means "used and the alert was correct", -1 means "used and the alert was not correct" + and 0 means "not used" + 56. :attr:`BaseObservation.attack_under_alert` For each attackable line `i` it says if an alert has been sent (+1) or not (-1) + for each attackable line currently under attack. + """ attr_list_vect = [ diff --git a/grid2op/Observation/observationSpace.py b/grid2op/Observation/observationSpace.py index 0cb64871f..2094273b5 100644 --- a/grid2op/Observation/observationSpace.py +++ b/grid2op/Observation/observationSpace.py @@ -40,18 +40,18 @@ class ObservationSpace(SerializableObservationSpace): _simulate_parameters: :class:`grid2op.Parameters.Parameters` Type of Parameters used to compute powerflow for the forecast. - rewardClass: ``type`` + rewardClass: Union[type, BaseReward] Class used by the :class:`grid2op.Environment.Environment` to send information about its state to the - :class:`grid2op.BaseAgent.BaseAgent`. You can change this class to differentiate between the reward of output of + :class:`grid2op.Agent.BaseAgent`. You can change this class to differentiate between the reward of output of :func:`BaseObservation.simulate` and the reward used to train the BaseAgent. action_helper_env: :class:`grid2op.Action.ActionSpace` BaseAction space used to create action during the :func:`BaseObservation.simulate` - reward_helper: :class:`grid2op.Reward.HelperReward` + reward_helper: :class:`grid2op.Reward.RewardHelper` BaseReward function used by the the :func:`BaseObservation.simulate` function. - obs_env: :class:`_ObsEnv` + obs_env: :class:`grid2op.Environment._Obsenv._ObsEnv` Instance of the environment used by the BaseObservation Helper to provide forcecast of the grid state. _empty_obs: :class:`BaseObservation` @@ -78,7 +78,7 @@ def __init__( .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ - Env: requires :attr:`grid2op.Environment.parameters` and :attr:`grid2op.Environment.backend` to be valid + Env: requires :attr:`grid2op.Environment.BaseEnv.parameters` and :attr:`grid2op.Environment.BaseEnv.backend` to be valid """ # lazy import to prevent circular references (Env -> Observation -> Obs Space -> _ObsEnv -> Env) diff --git a/grid2op/Space/GridObjects.py b/grid2op/Space/GridObjects.py index e4e1338a2..887583a1a 100644 --- a/grid2op/Space/GridObjects.py +++ b/grid2op/Space/GridObjects.py @@ -439,7 +439,28 @@ class GridObjects: alarms_lines_area = {} # for each lines of the grid, gives on which area(s) it is # TODO alarms_area_lines = [] # for each area in the grid, gives which powerlines it contains # TODO - # TODO specify the unit of redispatching data MWh, $/MW etc. + dim_alerts: `int` + The dimension of the "alert space" (number of powerline on which the agent can sent an alert) + + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + + alertable_line_names: `np.ndarray` + Name (in order) of each powerline on which the agent can send an alarm. It has the size corresponding to :attr:`GridObjects.dim_alerts` + and contain names of powerlines (string). + + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 + + alertable_line_ids: `np.ndarray` + Id (in order) of each powerline on which the agent can send an alarm. It has the size corresponding to :attr:`GridObjects.dim_alerts` + and contain ids of powerlines (integer). + + .. seealso:: :ref:`grid2op-alert-module` section of the doc for more information + + .. versionadded:: 1.9.1 """ BEFORE_COMPAT_VERSION = "neurips_2020_compat" From 45bf53590ddca5dbc9319a26136485618ddec4a5 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Mon, 10 Jul 2023 15:05:17 +0200 Subject: [PATCH 020/103] improving error message when neither gym nor gymnasium are installed --- grid2op/gym_compat/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grid2op/gym_compat/__init__.py b/grid2op/gym_compat/__init__.py index d6952ae6a..0672745d7 100644 --- a/grid2op/gym_compat/__init__.py +++ b/grid2op/gym_compat/__init__.py @@ -22,6 +22,9 @@ from grid2op.gym_compat.utils import _MAX_GYM_VERSION_RANDINT, GYM_VERSION, GYMNASIUM_AVAILABLE, GYM_AVAILABLE +if GYM_AVAILABLE is False and GYMNASIUM_AVAILABLE is False: + raise ImportError("Neither gymnasium nor gym are installed. The `grid2op.gym_compat` module cannot be used.") + # base for all gym converter from grid2op.gym_compat.base_gym_attr_converter import BaseGymAttrConverter if GYMNASIUM_AVAILABLE: From e06f58547bc6603b29468834cde06da35fe6a9dc Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Mon, 10 Jul 2023 16:00:40 +0200 Subject: [PATCH 021/103] adding the possibility to check number of calls to highres simulators in scores --- .../test_highres_sim_counter_in_scores.py | 120 ++++++++++++++++++ grid2op/utils/icaps_2021_scores.py | 6 +- grid2op/utils/l2rpn_2020_scores.py | 11 +- grid2op/utils/l2rpn_idf_2023_scores.py | 2 + grid2op/utils/l2rpn_wcci_2022_scores.py | 15 ++- grid2op/utils/underlying_statistics.py | 9 +- 6 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 grid2op/tests/test_highres_sim_counter_in_scores.py diff --git a/grid2op/tests/test_highres_sim_counter_in_scores.py b/grid2op/tests/test_highres_sim_counter_in_scores.py new file mode 100644 index 000000000..e2ab9215c --- /dev/null +++ b/grid2op/tests/test_highres_sim_counter_in_scores.py @@ -0,0 +1,120 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import warnings +import numpy as np +import unittest + +import grid2op +from grid2op.Action import ActionSpace, BaseAction +from grid2op.utils import ScoreL2RPN2023, ScoreL2RPN2022, ScoreICAPS2021, ScoreL2RPN2020 +from grid2op.Observation import BaseObservation +from grid2op.Agent.doNothing import DoNothingAgent, BaseAgent +from grid2op.Chronics import FromHandlers +from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler, DoNothingHandler + + +class _TesterSimulateAgent(BaseAgent): + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + observation.simulate(self.action_space()) + observation.simulate(self.action_space()) + return super().act(observation, reward, done) + + +class TestHighResSimCountInScore: + def _score_fun(self): + raise RuntimeError() + + def _env_name(self): + return "l2rpn_case14_sandbox" + + def setUp(self) -> None: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + self.env = grid2op.make(self._env_name(), + test=True, + data_feeding_kwargs={"gridvalueClass": FromHandlers, + "gen_p_handler": CSVHandler("prod_p"), + "load_p_handler": CSVHandler("load_p"), + "gen_v_handler": DoNothingHandler("gen_v"), + "load_q_handler": CSVHandler("load_q"), + "h_forecast": (5,), + "gen_p_for_handler": PerfectForecastHandler("prod_p_forecasted", quiet_warnings=True), + # "gen_v_for_handler": PerfectForecastHandler("prod_v_forecasted", quiet_warnings=True), + "load_p_for_handler": PerfectForecastHandler("load_p_forecasted", quiet_warnings=True), + "load_q_for_handler": PerfectForecastHandler("load_q_forecasted", quiet_warnings=True), + },) + self.env.set_max_iter(20) + params = self.env.parameters + params.NO_OVERFLOW_DISCONNECTION = True + params.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION = True + self.seed = 0 + self.scen_id = 0 + self.nb_scenario = 2 + self.max_iter = 10 + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_score_helper(self): + """basic tests for ScoreL2RPN2023 class""" + self.env.reset() + my_score = self._score_fun()( + self.env, + nb_scenario=self.nb_scenario, + env_seeds=[0 for _ in range(self.nb_scenario)], + agent_seeds=[0 for _ in range(self.nb_scenario)], + max_step=self.max_iter, + add_nb_highres_sim=True) + try: + # test do nothing indeed gets 0 + res_dn = my_score.get(DoNothingAgent(self.env.action_space)) + assert len(res_dn) == 4 + all_scores, ts_survived, total_ts, nb_highres_sim = res_dn + assert nb_highres_sim == [0] * self.nb_scenario, f"do nothing does not have 0 but {nb_highres_sim}" + + # test do nothing indeed gets 2 x . + res_tester = my_score.get(_TesterSimulateAgent(self.env.action_space)) + assert len(res_tester) == 4 + all_scores, ts_survived, total_ts, nb_highres_sim = res_tester + assert nb_highres_sim == [2 * self.max_iter] * self.nb_scenario, f"_TesterSimulateAgent does not have 2x but {nb_highres_sim}" + + finally: + my_score.clear_all() + +class TestHighResSimCountInScore2023(TestHighResSimCountInScore, unittest.TestCase): + def _score_fun(self): + return ScoreL2RPN2023 + + def _env_name(self): + return "l2rpn_idf_2023" + +class TestHighResSimCountInScore2022(TestHighResSimCountInScore, unittest.TestCase): + def _score_fun(self): + return ScoreL2RPN2022 + + def _env_name(self): + return "l2rpn_case14_sandbox" + +class TestHighResSimCountInScore2021(TestHighResSimCountInScore, unittest.TestCase): + def _score_fun(self): + return ScoreICAPS2021 + + def _env_name(self): + return "l2rpn_icaps_2021" + +class TestHighResSimCountInScore2020(TestHighResSimCountInScore, unittest.TestCase): + def _score_fun(self): + return ScoreL2RPN2020 + + def _env_name(self): + return "l2rpn_case14_sandbox" + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/grid2op/utils/icaps_2021_scores.py b/grid2op/utils/icaps_2021_scores.py index d9b69e1f7..fbe3dd455 100644 --- a/grid2op/utils/icaps_2021_scores.py +++ b/grid2op/utils/icaps_2021_scores.py @@ -95,6 +95,7 @@ def __init__( scale_alarm_score=100.0, weight_op_score=0.7, weight_alarm_score=0.3, + add_nb_highres_sim=False, ): ScoreL2RPN2020.__init__( @@ -112,6 +113,7 @@ def __init__( "alarm_cost": _AlarmScore, }, score_names=["grid_operational_cost_scores", "alarm_cost_scores"], + add_nb_highres_sim=add_nb_highres_sim, ) self.scale_alarm_score = scale_alarm_score self.weight_op_score = weight_op_score @@ -124,7 +126,7 @@ def _compute_episode_score( other_rewards, dn_metadata, no_ov_metadata, - score_file_to_use=None, + score_file_to_use="grid_operational_cost_scores", ): """ Performs the rescaling of the score given the information stored in the "statistics" of this @@ -144,7 +146,7 @@ def _compute_episode_score( # score_file_to_use should match the # L2RPNSandBoxScore key in # self.scores_func - score_file_to_use="grid_operational_cost_scores", + score_file_to_use=score_file_to_use ) # should match underlying_statistics.run_env `dict_kwg["other_rewards"][XXX] = ...` # XXX is right now f"{EpisodeStatistics.KEY_SCORE}_{nm}" [this should match the XXX] diff --git a/grid2op/utils/l2rpn_2020_scores.py b/grid2op/utils/l2rpn_2020_scores.py index 2707af710..b234c3f08 100644 --- a/grid2op/utils/l2rpn_2020_scores.py +++ b/grid2op/utils/l2rpn_2020_scores.py @@ -91,6 +91,7 @@ def __init__( nb_process_stats=1, scores_func=L2RPNSandBoxScore, score_names=None, + add_nb_highres_sim=False, ): self.env = env self.nb_scenario = nb_scenario @@ -129,6 +130,7 @@ def __init__( agent=agent_reco, score_names=score_names, ) + self.add_nb_highres_sim = add_nb_highres_sim self.__cleared = False def _init_stat( @@ -357,7 +359,7 @@ def get(self, agent, path_save=None, nb_process=1): if self.verbose >= 1: print("Starts the evaluation of the agent") # TODO logger - EpisodeStatistics.run_env( + nb_highres_sim = EpisodeStatistics.run_env( self.env, env_seeds=self.env_seeds, agent_seeds=self.agent_seeds, @@ -369,7 +371,9 @@ def get(self, agent, path_save=None, nb_process=1): nb_scenario=self.nb_scenario, pbar=self.verbose >= 2, nb_process=nb_process, + add_nb_highres_sim=self.add_nb_highres_sim, ) + # NB nb_highres_sim is None if self.add_nb_highres_sim is False ! if self.verbose >= 1: print("Start the evaluation of the scores") # TODO logger @@ -406,7 +410,10 @@ def get(self, agent, path_save=None, nb_process=1): if need_delete: dir_tmp.cleanup() - return all_scores, ts_survived, total_ts + res = all_scores, ts_survived, total_ts + if self.add_nb_highres_sim: + res = all_scores, ts_survived, total_ts, nb_highres_sim + return res if __name__ == "__main__": diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 8a4502634..158749b06 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -88,6 +88,7 @@ def __init__( weight_nres_score=0.15, weight_confidence_assistant_score=0.7, min_nres_score=-100, + add_nb_highres_sim=False, ): ScoreL2RPN2020.__init__( @@ -110,6 +111,7 @@ def __init__( #"assistant_confidence_scores", #"assistant_cost_scores", "new_renewable_sources_usage_scores"], + add_nb_highres_sim=add_nb_highres_sim, ) assert(weight_op_score + weight_assistant_score + weight_nres_score==1.) diff --git a/grid2op/utils/l2rpn_wcci_2022_scores.py b/grid2op/utils/l2rpn_wcci_2022_scores.py index dac710d92..7b0611e65 100644 --- a/grid2op/utils/l2rpn_wcci_2022_scores.py +++ b/grid2op/utils/l2rpn_wcci_2022_scores.py @@ -23,5 +23,16 @@ def __init__(self, verbose=0, max_step=-1, nb_process_stats=1, scores_func=L2RPNWCCI2022ScoreFun, - score_names=None): - super().__init__(env, env_seeds, agent_seeds, nb_scenario, min_losses_ratio, verbose, max_step, nb_process_stats, scores_func, score_names) + score_names=None, + add_nb_highres_sim=False): + super().__init__(env, + env_seeds, + agent_seeds, + nb_scenario, + min_losses_ratio, + verbose, + max_step, + nb_process_stats, + scores_func, + score_names, + add_nb_highres_sim=add_nb_highres_sim) diff --git a/grid2op/utils/underlying_statistics.py b/grid2op/utils/underlying_statistics.py index 5916b45d7..287db0262 100644 --- a/grid2op/utils/underlying_statistics.py +++ b/grid2op/utils/underlying_statistics.py @@ -538,6 +538,7 @@ def run_env( agent_seeds, pbar, nb_process, + add_nb_highres_sim=False, ): if scores_func is not None: @@ -567,7 +568,7 @@ def run_env( "be a dictionary" ) runner = Runner(**dict_kwg, agentClass=None, agentInstance=agent) - runner.run( + res_runner = runner.run( path_save=path_save, nb_episode=nb_scenario, max_iter=max_step, @@ -575,7 +576,13 @@ def run_env( agent_seeds=agent_seeds, pbar=pbar, nb_process=nb_process, + add_detailed_output=False, # check the return value if you change this + add_nb_highres_sim=add_nb_highres_sim ) + if add_nb_highres_sim: + res = [el[-1] for el in res_runner] + return res + return None def get_metadata(self): """return the metadata as a dictionary""" From 3c060039ce8314d39f35129b257f6d14b121296b Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Mon, 10 Jul 2023 17:04:27 +0200 Subject: [PATCH 022/103] score2023: indentation and initialize fix --- grid2op/Reward/_alertCostScore.py | 11 ++-- grid2op/Reward/_alertTrustScore.py | 46 ++++++++-------- grid2op/tests/test_RewardAlertCostScore.py | 61 ++++++++++++++++++++-- 3 files changed, 86 insertions(+), 32 deletions(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index 0181797d8..ad5594e32 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -37,13 +37,8 @@ def __init__(self, logger=None): self.total_nb_alertes_possible = None self.total_nb_alerts = None - def __initialize__(self, env): - if not env._has_attention_budget: - raise Grid2OpException( - 'Impossible to use the "_AlertCostScore" with an environment for which the Assistant feature ' - 'is disabled. Please make sure "env._has_attention_budget" is set to ``True`` or ' - "change the reward class with `grid2op.make(..., reward_class=AnyOtherReward)`" - ) + def initialize(self, env): + if not env.dim_alerts > 0: raise Grid2OpException( 'Impossible to use the "_AlertCostScore" with an environment for which the Assistant feature ' @@ -61,7 +56,7 @@ def reset(self, env): self.total_nb_alerts = 0 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - if self.is_simulated_env(env): + if self._is_simul_env: return dt_float(0.) if is_done: diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 616ab5c71..e46237708 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -48,29 +48,33 @@ def __init__(self, self.score_min_ep = lambda k: reward_min_no_blackout * (k - 1) + reward_min_blackout self.score_max_ep = lambda k: reward_max_no_blackout * k + reward_end_episode_bonus - def __initialize__(self, env): - super().__initialize__(env) + def initialize(self, env): + self._is_simul_env = self.is_simulated_env(env) + if self._is_simul_env: + return + self.reset(env) + return super().initialize(env) - def reset(self, env): - super().reset(env) - self.total_nb_attacks = 0 - self.cumulated_reward = 0 + def reset(self, env): + super().reset(env) + self.total_nb_attacks = 0 + self.cumulated_reward = 0 - def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - score_ep = 0. - if self.is_simulated_env(env): - return score_ep + def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): + score_ep = 0. + if self._is_simul_env: + return score_ep - res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) - self.cumulated_reward += res - self.total_nb_attacks += np.sum(env._time_since_last_attack == 0) + res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) + self.cumulated_reward += res + self.total_nb_attacks += np.sum(env._time_since_last_attack == 0) - if not is_done: - return score_ep - else: - score_min_ep = self.score_min_ep(self.total_nb_attacks) - score_max_ep = self.score_max_ep(self.total_nb_attacks) - standardized_score = (self.cumulated_reward - score_min_ep) / (score_max_ep - score_min_ep + 1e-6) - score_ep = standardized_score * 2. - 1. + if not is_done: + return score_ep + else: + score_min_ep = self.score_min_ep(self.total_nb_attacks) + score_max_ep = self.score_max_ep(self.total_nb_attacks) + standardized_score = (self.cumulated_reward - score_min_ep) / (score_max_ep - score_min_ep + 1e-6) + score_ep = standardized_score * 2. - 1. - return score_ep + return score_ep diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 0179af45e..50706c17f 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -109,7 +109,7 @@ def test_simulated_env(self): assert forR == 0. -class TestRunner(unittest.TestCase): +class TestRunnerAlertCost(unittest.TestCase): def setUp(self) -> None: self.env_nm = os.path.join( PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" @@ -193,9 +193,64 @@ def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : for i in range(env.max_episode_duration()): obs, reward, done, info = env.step(env.action_space()) if done: - assert reward == 1. + assert reward == 1., f"{reward} vs 1." else: - assert reward == 0. + assert reward == 0., f"{reward} vs 0." + + +class TestRunnerAlertTrust(unittest.TestCase): + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + self.env = grid2op.make(self.env_nm, test=True, difficulty="1", + reward_class=_AlertTrustScore) + self.env.seed(0) + return super().setUp() + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_dn_agent(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) + assert res[0][2] == 1. #it got to the end + + def test_simagent(self): + #simulate blackout but act donothing + obs = self.env.reset() + + class SimAgent(BaseAgent): + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + go_act = self.action_space({"set_bus": {"generators_id": [(0, -1)]}}) + simO, simr, simd, simi = obs.simulate(go_act) + simO, simr, simd, simi = obs.simulate(self.action_space()) + return super().act(observation, reward, done) + + runner = Runner(**self.env.get_params_for_runner(), + agentClass=SimAgent) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) + assert res[0][2] == 1. + + def test_episodeData(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], add_detailed_output=True) + assert res[0][2] == 1. + assert res[0][5].rewards[8] == 1. + + def test_with_save(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + with tempfile.TemporaryDirectory() as f: + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], + path_save=f) + assert res[0][2] == 1. + ep0, *_ = EpisodeData.list_episode(f) + ep = EpisodeData.from_disk(*ep0) + assert ep.rewards[8] == 1. if __name__ == "__main__": unittest.main() From 8a9b813013d6c7cba3124b6021185faf3c84117b Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Mon, 10 Jul 2023 18:17:42 +0200 Subject: [PATCH 023/103] score2023: revert normalization of trustscore --- grid2op/Reward/_alertTrustScore.py | 9 +- grid2op/tests/test_RewardAlertCostScore.py | 167 ++++++++++++++++++++- 2 files changed, 169 insertions(+), 7 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index e46237708..88a8143ed 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -72,9 +72,10 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): if not is_done: return score_ep else: - score_min_ep = self.score_min_ep(self.total_nb_attacks) - score_max_ep = self.score_max_ep(self.total_nb_attacks) - standardized_score = (self.cumulated_reward - score_min_ep) / (score_max_ep - score_min_ep + 1e-6) - score_ep = standardized_score * 2. - 1. + # score_min_ep = self.score_min_ep(self.total_nb_attacks) + # score_max_ep = self.score_max_ep(self.total_nb_attacks) + # standardized_score = (self.cumulated_reward - score_min_ep) / (score_max_ep - score_min_ep + 1e-6) + # score_ep = standardized_score * 2. - 1. + score_ep = self.cumulated_reward return score_ep diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 50706c17f..9aa86a8ee 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -17,14 +17,68 @@ from grid2op.Exceptions import Grid2OpException from grid2op.Runner import Runner from grid2op.Observation import BaseObservation -from grid2op.Action import BaseAction from grid2op.Episode import EpisodeData +from grid2op.Parameters import Parameters +from grid2op.Opponent import BaseOpponent, GeometricOpponent +from grid2op.Action import BaseAction, PlayableAction + + +ALL_ATTACKABLE_LINES= [ + "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", + ] + +ATTACKED_LINE = "48_50_136" + +def _get_steps_attack(kwargs_opponent, multi=False): + """computes the steps for which there will be attacks""" + ts_attack = np.array(kwargs_opponent["steps_attack"]) + res = [] + for i, ts in enumerate(ts_attack): + if not multi: + res.append(ts + np.arange(kwargs_opponent["duration"])) + else: + res.append(ts + np.arange(kwargs_opponent["duration"][i])) + return np.unique(np.concatenate(res).flatten()) class AlertAgent(BaseAgent): def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: if observation.current_step == 2: return self.action_space({"raise_alert": [0]}) return super().act(observation, reward, done) + +class TestOpponent(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=10, steps_attack=[0,1]): + attacked_line = lines_attacked[0] + self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + return self.custom_attack, self.duration class TestAlertCostScore(unittest.TestCase): @@ -171,11 +225,16 @@ def setUp(self) -> None: ) def tearDown(self) -> None: - return super().tearDown() + return super().tearDown() + + def get_blackout(self, env): + blackout_action = env.action_space({}) + blackout_action.gen_set_bus = [(0, -1)] + return blackout_action def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : """ When no blackout and no attack occur, and no alert is raised we expect a reward of 0 - until the end of the episode where we get the max reward 1. + until the end of the episode where we get the max reward 1 as score. Raises: Grid2OpException: raise an exception if an attack occur @@ -197,6 +256,108 @@ def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : else: assert reward == 0., f"{reward} vs 0." + def test_assistant_reward_value_blackout_attack_no_alert(self) -> None : + """ + When 1 line is attacked at step 3 and we don't raise any alert + and a blackout occur at step 4 + we expect a score of -10 at step 4 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with grid2op.make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore, + _add_to_name="_tarvbana" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if step == 3 : + act = self.get_blackout(env) + obs, reward, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if step == 4: + # When the blackout occurs, reward is -10 because we didn't raise an attack + assert reward == -10, f"error for step {step}: {reward} vs -10" + assert done + break + else : + assert reward == 0, f"error for step {step}: {reward} vs 0" + + def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : + """ + When 1 line is attacked at step 3 and we do raise an alert + and a blackout occur at step 4 + we expect a score of 2. at step 4 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with grid2op.make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore, + _add_to_name="_tarvbarga" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 2: + # I raise the alert (on the right line) just before the opponent attack + # opp attack at step = 3, so i = 2 + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, reward, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if step == 4: + assert reward == 2, f"error for step {step}: {reward} vs 2" + assert done + break + else : + assert reward == 0, f"error for step {step}: {reward} vs 0" + class TestRunnerAlertTrust(unittest.TestCase): def setUp(self) -> None: From 41769abcb60069a30725551a5476f2f1e8554807 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Mon, 10 Jul 2023 18:31:29 +0200 Subject: [PATCH 024/103] score2023: copy methods from alert tests --- grid2op/tests/test_RewardAlertCostScore.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 9aa86a8ee..453cb02df 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -227,6 +227,9 @@ def setUp(self) -> None: def tearDown(self) -> None: return super().tearDown() + def get_dn(self, env): + return env.action_space({}) + def get_blackout(self, env): blackout_action = env.action_space({}) blackout_action.gen_set_bus = [(0, -1)] From 771c0a30208568184ade8716402fc4d3ff78dcbe Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Mon, 10 Jul 2023 18:52:48 +0200 Subject: [PATCH 025/103] score2023: trustalert add static method for norm --- grid2op/Reward/_alertTrustScore.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 88a8143ed..f28056321 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -74,8 +74,13 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): else: # score_min_ep = self.score_min_ep(self.total_nb_attacks) # score_max_ep = self.score_max_ep(self.total_nb_attacks) - # standardized_score = (self.cumulated_reward - score_min_ep) / (score_max_ep - score_min_ep + 1e-6) - # score_ep = standardized_score * 2. - 1. - score_ep = self.cumulated_reward + score_ep = self.cumulated_reward # self._normalisation_fun(self.cumulated_reward, score_min_ep, score_max_ep) return score_ep + + @staticmethod + def _normalisation_fun(score, score_min_ep, score_max_ep): + standardized_score = (score - score_min_ep) / (score_max_ep - score_min_ep) + score_ep = standardized_score * 2. - 1. + return score_ep + From 762a8bcbdd9ded09d1ef04e787ad829dedb7bdea Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 09:30:44 +0200 Subject: [PATCH 026/103] score2023: add path data folder tests --- grid2op/tests/test_score_idf_2023.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index 4fab7789f..10a503595 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -6,6 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. +import os import warnings import numpy as np import unittest @@ -18,6 +19,7 @@ from grid2op.Chronics import FromHandlers from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler from grid2op.Reward import _NewRenewableSourcesUsageScore +from grid2op.tests.helper_path_test import * class CurtailTrackerAgent(BaseAgent): @@ -49,7 +51,9 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - class TestScoreL2RPN2023(unittest.TestCase): def setUp(self) -> None: - env_name = "l2rpn_idf_2023_with_alert" + env_name = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) with warnings.catch_warnings(): warnings.filterwarnings("ignore") self.env = grid2op.make(env_name, From 1ca333fe512735b96ac01e752938e906ebe3f571 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 11:05:19 +0200 Subject: [PATCH 027/103] score2023: add test blackout simul NRES score --- grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py b/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py index dd0f6140d..d4527b132 100644 --- a/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py +++ b/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py @@ -149,6 +149,14 @@ def test_simulate_ignored(self): return reward == 1. + def test_simulate_blackout_ignored(self): + obs = self.env.reset() + obs, reward, done, _ = self.env.step(self.env.action_space()) + go_act = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}}) + simO, simr, simd, simi = obs.simulate(go_act) + assert simr == 0., f"{simr} vs 0." + assert simd + def test_simulated_env(self): obs = self.env.reset() f_env = obs.get_forecast_env() From d3bf2d0a577b478e9eaa566e75bd11fdb97a7fe6 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Tue, 11 Jul 2023 12:24:47 +0200 Subject: [PATCH 028/103] add tests for _AlertTrustScore --- grid2op/tests/test_alert_trust_score.py | 1260 +++++++++++++++++++++++ 1 file changed, 1260 insertions(+) create mode 100644 grid2op/tests/test_alert_trust_score.py diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py new file mode 100644 index 000000000..73665aacb --- /dev/null +++ b/grid2op/tests/test_alert_trust_score.py @@ -0,0 +1,1260 @@ +# Copyright (c) 2019-2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import warnings +import numpy as np +import unittest +import os +import tempfile +from grid2op.Observation import BaseObservation +from grid2op.tests.helper_path_test import * + +from grid2op import make +from grid2op.Reward import _AlertTrustScore +from grid2op.Parameters import Parameters +from grid2op.Exceptions import Grid2OpException +from grid2op.Runner import Runner # TODO +from grid2op.Opponent import BaseOpponent, GeometricOpponent, GeometricOpponentMultiArea +from grid2op.Action import BaseAction, PlayableAction +from grid2op.Agent import BaseAgent +from grid2op.Episode import EpisodeData + + +ALL_ATTACKABLE_LINES= [ + "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", + ] + +ATTACKED_LINE = "48_50_136" + + +def _get_steps_attack(kwargs_opponent, multi=False): + """computes the steps for which there will be attacks""" + ts_attack = np.array(kwargs_opponent["steps_attack"]) + res = [] + for i, ts in enumerate(ts_attack): + if not multi: + res.append(ts + np.arange(kwargs_opponent["duration"])) + else: + res.append(ts + np.arange(kwargs_opponent["duration"][i])) + return np.unique(np.concatenate(res).flatten()) + + +class TestOpponent(GeometricOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=10, steps_attack=[0,1]): + super().init(partial_env, lines_attacked, ) + attacked_line = lines_attacked[0] + self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + return self.custom_attack, self.duration + + +class TestOpponentMultiLines(GeometricOpponentMultiArea): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=[10,10], steps_attack=[0,1]): + super().init(partial_env, [[l] for l in lines_attacked]) + attacked_line = lines_attacked[0] + self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in lines_attacked] + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + index = self.steps_attack.index(current_step) + + return self.custom_attack[index], self.duration[index] + + +# Test alert blackout / tets alert no blackout +class TestAlertTrustScoreNoBlackout(unittest.TestCase): + """test the basic bahavior of the assistant alert feature when no attack occur """ + + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + + def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : + """ When no blackout and no attack occur, and no alert is raised we expect a reward of 0 + until the end of the episode where we have a bonus (here artificially 42) + + Raises: + Grid2OpException: raise an exception if an attack occur + """ + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + obs, score, done, info = env.step(env.action_space()) + if info["opponent_attack_line"] is None : + if i == env.max_episode_duration()-1: + assert score == 42 + else : + assert score == 0 + else : + raise Grid2OpException('No attack expected') + + assert done + + def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : + """ When an alert is raised while no attack / nor blackout occur, we expect a score of 0 + until the end of the episode where we have a 42s + + Raises: + Grid2OpException: raise an exception if an attack occur + """ + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + done = False + attackable_line_id=0 + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + if step == 1 : + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + + if info["opponent_attack_line"] is None : + if step == env.max_episode_duration(): + assert score == 42 + else : + assert score == 0 + else : + raise Grid2OpException('No attack expected') + + assert done +# If attack + def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : + """ When we don't raise an alert for an attack (at step 1) + but no blackout occur, we expect a final score of 43 + otherwise 0 at other time steps + + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[1]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnbana" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 43 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : + """When an alert occur at step 2, we raise an alert at step 1 + We expect a score of 41 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnba" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = env.action_space() + if i == 1 : + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 41 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : + """ When we raise an alert too late for an attack (at step 2) but no blackout occur, + we expect a score of 43 + + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsnbaatl" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = env.action_space() + if step == 2 : + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 43 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : + """ When we raise an alert too early for an attack (at step 2) + but no blackout occur, we expect a score of 43 + + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsnbaate" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = env.action_space() + if step == 0 : + # An alert is raised at step 0 + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 43 + else : + assert score == 0 + + # 2 ligne attaquées + def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> None : + """ When we don't raise an alert for 2 attacks at the same time (step 1) + but no blackout occur, we expect a score of 43 + """ + + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=3, + steps_attack=[1]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnb2astna" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 43 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> None : + """ When we raise only 1 alert for 2 attacks at the same time (step 2) + but no blackout occur, we expect a score of 42 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsnb2ast1a" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = env.action_space() + if step == 1 : + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 42 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> None : + """ When we raise 2 alerts for 2 attacks at the same time (step 2) + but no blackout occur, we expect a score of 41 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsnb2ast2a" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_ids = [0, 1] + act = env.action_space() + if step == 1 : + act = env.action_space({"raise_alert": attackable_line_ids}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 41 + else : + assert score == 0 + + + def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> None : + """ When we don't raise an alert for 2 attacks at two times resp. (steps 1 and 2) + but no blackout occur, we expect a score of 44 + """ + + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1, 1], + steps_attack=[1, 2]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnb2dtna" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent, multi=True) : + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 44 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> None : + """ When we raise 2 alert for 2 attacks at two times (step 2 and 3) + but no blackout occur, we expect a reward of 40 + """ + + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1,1], + steps_attack=[2, 3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnb2dt2a" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + if step == 1 : + act = env.action_space({"raise_alert": [0]}) + elif step == 2 : + act = env.action_space({"raise_alert": [1]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 40 + else : + assert score == 0 + + def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack(self) -> None : + """ When we raise 1 alert on the first attack while we have 2 attacks at two times (steps 2 and 3) + but no blackout occur, we expect a score of 42 + """ + + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1,1], + steps_attack=[2, 3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnb2dtafa" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + if step == 1 : + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + score == 42 + else : + assert score == 0 + + + def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attack(self) -> None : + """ When we raise 1 alert on the second attack while we have 2 attacks at two times (steps 2 and 3) + but no blackout occur, we expect a score of 42 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1,1], + steps_attack=[2, 3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsnb2dtasa" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = env.action_space() + if i == 2 : + act = env.action_space({"raise_alert": [1]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 42 + else : + assert score == 0, f"error for step {step}: {score} vs 0" + + + +class TestAlertTrustScoreBlackout(unittest.TestCase): + """test the basic bahavior of the assistant alert feature when a blackout occur""" + + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + + def get_dn(self, env): + return env.action_space({}) + + def get_blackout(self, env): + blackout_action = env.action_space({}) + blackout_action.gen_set_bus = [(0, -1)] + return blackout_action + +# Cas avec blackout 1 ligne attaquée +# return -10 + def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : + """ + When 1 line is attacked at step 3 and we don't raise any alert + and a blackout occur at step 4 + we expect a score of -10 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsbana" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if step == 3 : + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == -10 + break + else : + assert score == 0 +# return 2 + def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : + """When 1 line is attacked at step 3 and we raise a good alert + and a blackout occur at step 4 + we expect a score of 2 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsbarga" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 2: + # I raise the alert (on the right line) just before the opponent attack + # opp attack at step = 3, so i = 2 + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 2 + break + else : + assert score == 0 + +# return -10 + def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout(self) -> None : + """ + When 1 line is attacked at step 3 and we raise 1 alert too late + we expect a score of -10 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsbarajbb" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 1: + # opponent attack at step 3, so when i = 2 + # i raise the alert BEFORE that (so when i = 1) + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == -10 + break + else : + assert score == 0 + + def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> None : + """ + When 1 line is attacked at step 3 and we raise 1 alert too early + we expect a score of -10 + """ + # return -10 + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsbarate" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 1: + # opp attacks at step = 3, so i = 2, I raise an alert just before + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == -10 + break + else : + assert score == 0 + +# return 2 + def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts(self) -> None : + """ + When 2 lines are attacked simustaneously at step 2 and we raise 2 alert + we expect a score of 2 after the blackout + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=3, + steps_attack=[3, 3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsb2lssiwga" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 2: + # attack at step 3, so when i = 2 (which is the right time to send an alert) + act = env.action_space({"raise_alert": [0,1]}) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == 2 + break + else : + assert score == 0 + +# return -4 + def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_alert(self) -> None: + """ + When 2 lines are attacked simustaneously at step 2 and we raise only 1 alert + we expect a score of -4 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=3, + steps_attack=[3, 3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsb2laso1a" + ) as env : + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 2: + # attack at step 3, so i = 2, which is the + # right time to send an alert + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == -4 + break + else : + assert score == 0 + +# return 2 + def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_alerts(self) -> None : + """ + When 2 lines are attacked at different steps 3 and 4 and we raise 2 alert + we expect a score of 2 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1,1], + steps_attack=[3, 4]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsb2ldsiwga" + ) as env : + env.seed(0) + obs = env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 2 : + # opp attack "line 0" at step 3 so i = 2 => good alert + act = env.action_space({"raise_alert": [0]}) + elif i == 3 : + # opp attack "line 1" at step 4 so i = 3 => good alert + act = env.action_space({"raise_alert": [1]}) + elif i == 4 : + # trigger blackout + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done : + assert score == 2 + break + else : + assert score == 0, f"error for step {step}: {score} vs 0" + + def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_window_only_1_alert_on_first_attacked_line(self) -> None: + """ + When 2 lines are attacked at different steps 3 and 4 and we raise 1 alert on the first attack + we expect a score of -4 on blackout at step 4 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1,1], + steps_attack=[3, 4]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsb2ladsiwo1aofal" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 2 : + # opp attack "line 0" at step 3 so i = 2 => good alert + act = env.action_space({"raise_alert": [0]}) + elif i == 3 : + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 # i = step - 1 at this stage + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done : + assert score == -4 + break + else : + assert score == 0, f"error for step {step}: {score} vs 0" + +# return -4 + def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_window_only_1_alert_on_second_attacked_line(self) -> None: + """ + When 2 lines are attacked at different steps 2 and 3 and we raise 1 alert on the second attack + we expect a score of -4 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1,1], + steps_attack=[3, 4]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsb2ladsiwo1aosal" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3 : + # opp attack "line 1" at step 4 so i = 3 => good alert + act = env.action_space({"raise_alert": [1]}) + elif i == 4 : + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done : + assert score == -4., f"error for step {step}: {score} vs -4" + break + else : + assert score == 0, f"error for step {step}: {score} vs 0" + +# return 2 + def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1_good_alert(self) -> None: + """ + When 2 lines are attacked at different steps 3 and 6 and we raise 1 alert on the second attack + we expect score of 3 + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], + duration=[1, 1], + steps_attack=[3, 6]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponentMultiLines, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + _add_to_name="_tatsb2lad1iw1ga" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 5 : + # opp attack "line 1" at step 6 so i = 5 => good alert + act = env.action_space({"raise_alert": [1]}) + elif i == 6 : + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent, multi=True): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done : + assert score == 3, f"error for step {step}: {score} vs 2" + assert done + break + else : + assert score == 0, f"error for step {step}: {score} vs 0" + +# return 0 + def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : + + """Even if there is a blackout, an we raise an alert + we expect a score of 0 because there is no attack""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 1: + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + if info["opponent_attack_line"] is None : + assert score == 0. + else : + raise Grid2OpException('No attack expected') + + if done : + break + + assert done + +# return 0 + def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : + """Even if there is a blackout, an we don't raise an alert + we expect a score of 0 because there is no attack""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + if info["opponent_attack_line"] is None : + assert score == 0. + else : + raise Grid2OpException('No attack expected') + + if done : + break + + assert done + +# return 0 + def test_assistant_trust_score_blackout_attack_before_window_alert(self) -> None : + """Even if there is a blackout, an we raise an alert too early + we expect a score of 0 because there is no attack""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i in [0, 1, 2]: + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + if info["opponent_attack_line"] is None : + assert score == 0. + else : + raise Grid2OpException('No attack expected') + + if done : + break + + assert done + +# return 0 + def test_assistant_trust_score_blackout_attack_before_window_no_alert(self) -> None : + """Even if there is a blackout, an we raise an alert too late + we expect a score of 0 because there is no attack""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3 : + act = self.get_blackout(env) + elif i == 4: + # we never go here ... + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + + if info["opponent_attack_line"] is None : + assert score == 0. + else : + raise Grid2OpException('No attack expected') + + if done : + break + + assert done + + +if __name__ == "__main__": + unittest.main() From e5dbd23b2b1cad2d3bc362d59ead3b8cb942d57c Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 11 Jul 2023 14:04:51 +0200 Subject: [PATCH 029/103] fix an issue with the detection of simulated environments in reward --- CHANGELOG.rst | 2 + grid2op/Environment/_ObsEnv.py | 1 + grid2op/Observation/observationSpace.py | 6 ++- grid2op/tests/test_simenv_blackout.py | 65 +++++++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 grid2op/tests/test_simenv_blackout.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 9870c95e8..49d5ad755 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -36,6 +36,8 @@ Change Log - [FIXED] broken environ "l2rpn_idf_2023" (with test=True) due to the presence of a `__pycache__` folder - [FIXED] time series `MultiFolder` will now ignore folder `__pycache__` - [FIXED] an issue with compatibility with previous versions (due to alert) +- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (self.is_simulated_env() + was not working as expected due to a wrong init of the reward in `_ObsEnv`) [1.9.1] - 2023-07-06 -------------------- diff --git a/grid2op/Environment/_ObsEnv.py b/grid2op/Environment/_ObsEnv.py index 0fef691a4..fd57345bf 100644 --- a/grid2op/Environment/_ObsEnv.py +++ b/grid2op/Environment/_ObsEnv.py @@ -94,6 +94,7 @@ def __init__( self._reward_helper = reward_helper self._helper_action_class = helper_action_class + # TODO init reward and other reward # initialize the observation space self._obsClass = None diff --git a/grid2op/Observation/observationSpace.py b/grid2op/Observation/observationSpace.py index 2094273b5..93c178508 100644 --- a/grid2op/Observation/observationSpace.py +++ b/grid2op/Observation/observationSpace.py @@ -123,6 +123,8 @@ def __init__( if _with_obs_env: self._create_obs_env(env) self.reward_helper.initialize(self.obs_env) + for k, v in self.obs_env.other_rewards.items(): + v.reset(self.obs_env) else: self.with_forecast = False self.obs_env = None @@ -445,9 +447,9 @@ def reset(self, real_env): self.__nb_simulate_called_this_step = 0 self.__nb_simulate_called_this_episode = 0 if self.with_forecast: - self.obs_env._reward_helper.reset(real_env) + self.obs_env._reward_helper.reset(self.obs_env) for k, v in self.obs_env.other_rewards.items(): - v.reset(real_env) + v.reset(self.obs_env) self.obs_env.reset() self._env_param = copy.deepcopy(real_env.parameters) diff --git a/grid2op/tests/test_simenv_blackout.py b/grid2op/tests/test_simenv_blackout.py new file mode 100644 index 000000000..7ec3c1bef --- /dev/null +++ b/grid2op/tests/test_simenv_blackout.py @@ -0,0 +1,65 @@ +# Copyright (c) 2019-2022, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import unittest +import warnings + +import grid2op +from grid2op.Reward import BaseReward + + +class SimEnvRewardTester(BaseReward): + def reset(self, env): + self._sim_env = self.is_simulated_env(env) + return super().reset(env) + + def initialize(self, env): + self._sim_env = self.is_simulated_env(env) + return super().initialize(env) + + def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): + if self._sim_env: + return -1. + return 1. + + +class TestIsSimulatedEnv(unittest.TestCase): + def setUp(self) -> None: + env_name = "l2rpn_case14_sandbox" + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + self.env = grid2op.make(env_name, test=True, reward_class=SimEnvRewardTester) + return super().setUp() + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_simulate(self): + obs = self.env.reset() + obs, reward, done, info = self.env.step(self.env.action_space()) + assert reward == 1., f"{reward} vs 1." + sim_o, sim_r, *_ = obs.simulate(self.env.action_space()) + assert sim_r == -1., f"{reward} vs -1." + sim_o, sim_r, sim_d, sim_i = obs.simulate(self.env.action_space({"set_bus": {"loads_id": [(0, -1)]}})) + assert sim_d + assert sim_r == -1., f"{reward} vs -1." + + def test_forecast_env(self): + obs = self.env.reset() + for_env = obs.get_forecast_env() + for_d = False + i = 0 + while not for_d: + i += 1 + for_o, for_r, for_d, for_i = for_env.step(self.env.action_space()) + assert for_r == -1.0, f"{for_r} vs -1. for iter {i}" + + +if __name__ == "__main__": + unittest.main() From 850e3f85be1298900c37a346447cdb1880e8aab4 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Tue, 11 Jul 2023 14:11:25 +0200 Subject: [PATCH 030/103] add assertion for total_nb_attacks --- grid2op/tests/test_alert_trust_score.py | 66 ++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 73665aacb..6f617b7ed 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -141,6 +141,9 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : if info["opponent_attack_line"] is None : if i == env.max_episode_duration()-1: assert score == 42 + assert env._reward_helper.template_reward.total_nb_attacks==0 + assert env._reward_helper.template_reward.cumulated_reward==42 + else : assert score == 0 else : @@ -177,6 +180,8 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : if info["opponent_attack_line"] is None : if step == env.max_episode_duration(): assert score == 42 + assert env._reward_helper.template_reward.total_nb_attacks==0 + assert env._reward_helper.template_reward.cumulated_reward==42 else : assert score == 0 else : @@ -220,6 +225,8 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : if done: assert score == 43 + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==43 else : assert score == 0 @@ -260,6 +267,9 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : if done: assert score == 41 + + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==41 else : assert score == 0 @@ -301,6 +311,8 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : if done: assert score == 43 + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==43 else : assert score == 0 @@ -343,6 +355,9 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : if done: assert score == 43 + + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==43 else : assert score == 0 @@ -382,6 +397,9 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> if done: assert score == 43 + + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==43 else : assert score == 0 @@ -422,6 +440,8 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N if done: assert score == 42 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==42 else : assert score == 0 @@ -462,6 +482,8 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N if done: assert score == 41 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==41 else : assert score == 0 @@ -502,6 +524,8 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> if done: assert score == 44 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==44 else : assert score == 0 @@ -544,6 +568,8 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N if done: assert score == 40 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==40 else : assert score == 0 @@ -584,6 +610,8 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack if done: score == 42 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==42 else : assert score == 0 @@ -624,6 +652,8 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac if done: assert score == 42 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==42 else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -691,6 +721,8 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : if done: assert score == -10 + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==-10 break else : assert score == 0 @@ -713,6 +745,7 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), _add_to_name="_tatsbarga" ) as env : new_param = Parameters() @@ -740,6 +773,8 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : if done: assert score == 2 + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==2 break else : assert score == 0 @@ -763,6 +798,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), _add_to_name="_tatsbarajbb" ) as env : new_param = Parameters() @@ -790,6 +826,8 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( if done: assert score == -10 + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==-10 break else : assert score == 0 @@ -813,6 +851,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), _add_to_name="_tatsbarate" ) as env : new_param = Parameters() @@ -839,6 +878,8 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No if done: assert score == -10 + assert env._reward_helper.template_reward.total_nb_attacks==1 + assert env._reward_helper.template_reward.cumulated_reward==-10 break else : assert score == 0 @@ -862,6 +903,7 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), _add_to_name="_tatsb2lssiwga" ) as env : new_param = Parameters() @@ -889,6 +931,8 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts if done: assert score == 2 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==2 break else : assert score == 0 @@ -905,6 +949,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler with make(self.env_nm, test=True, difficulty="1", + reward_class=_AlertTrustScore(reward_end_episode_bonus=42), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, @@ -940,6 +985,8 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler if done: assert score == -4 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==-4 break else : assert score == 0 @@ -990,6 +1037,8 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a if done : assert score == 2 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==2 break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1034,6 +1083,8 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo if done : assert score == -4 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==-4 break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1079,6 +1130,9 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo if done : assert score == -4., f"error for step {step}: {score} vs -4" + + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==-4 break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1124,7 +1178,9 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - assert score == 3, f"error for step {step}: {score} vs 2" + assert score == 3 + assert env._reward_helper.template_reward.total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==3 assert done break else : @@ -1154,6 +1210,8 @@ def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : assert score == 0. + assert env._reward_helper.template_reward.total_nb_attacks==0. + assert env._reward_helper.template_reward.cumulated_reward==0. else : raise Grid2OpException('No attack expected') @@ -1183,6 +1241,8 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : assert score == 0. + assert env._reward_helper.template_reward.total_nb_attacks==0. + assert env._reward_helper.template_reward.cumulated_reward==0. else : raise Grid2OpException('No attack expected') @@ -1214,6 +1274,8 @@ def test_assistant_trust_score_blackout_attack_before_window_alert(self) -> None obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : assert score == 0. + assert env._reward_helper.template_reward.total_nb_attacks==0. + assert env._reward_helper.template_reward.cumulated_reward==0. else : raise Grid2OpException('No attack expected') @@ -1247,6 +1309,8 @@ def test_assistant_trust_score_blackout_attack_before_window_no_alert(self) -> N if info["opponent_attack_line"] is None : assert score == 0. + assert env._reward_helper.template_reward.total_nb_attacks==0. + assert env._reward_helper.template_reward.cumulated_reward==0. else : raise Grid2OpException('No attack expected') From 847bbd9bb0f5fb782f2eff233306afcf4dc205f6 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 15:53:42 +0200 Subject: [PATCH 031/103] score2023: normalization on survived timesteps --- grid2op/Reward/_alertCostScore.py | 3 ++- grid2op/Reward/_alertTrustScore.py | 9 +++++---- grid2op/utils/underlying_statistics.py | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index ad5594e32..dafa978f3 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -52,7 +52,7 @@ def reset(self, env): if self._is_simul_env: return - self.total_nb_alertes_possible = (env.chronics_handler.max_timestep() + 1) * (env.dim_alerts) + #self.total_nb_alertes_possible = (env.chronics_handler.max_timestep() + 1) * (env.dim_alerts) self.total_nb_alerts = 0 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): @@ -60,6 +60,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return dt_float(0.) if is_done: + self.total_nb_alertes_possible = env.nb_time_step * env.dim_alerts ratio_nb_alerts = 100 * ( 1 - self.total_nb_alerts / self.total_nb_alertes_possible) return self._penalization_fun(ratio_nb_alerts) else: diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index f28056321..1d595c9eb 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -46,7 +46,8 @@ def __init__(self, self.reward_min = dt_float(-1.0) self.reward_max = dt_float(1.0) self.score_min_ep = lambda k: reward_min_no_blackout * (k - 1) + reward_min_blackout - self.score_max_ep = lambda k: reward_max_no_blackout * k + reward_end_episode_bonus + self.score_max_ep = lambda k: np.max(reward_max_no_blackout * (k - 1) + reward_max_blackout, + reward_max_no_blackout * k + reward_end_episode_bonus) def initialize(self, env): self._is_simul_env = self.is_simulated_env(env) @@ -72,9 +73,9 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): if not is_done: return score_ep else: - # score_min_ep = self.score_min_ep(self.total_nb_attacks) - # score_max_ep = self.score_max_ep(self.total_nb_attacks) - score_ep = self.cumulated_reward # self._normalisation_fun(self.cumulated_reward, score_min_ep, score_max_ep) + score_min_ep = self.score_min_ep(self.total_nb_attacks) + score_max_ep = self.score_max_ep(self.total_nb_attacks) + score_ep = self._normalisation_fun(self.cumulated_reward, score_min_ep, score_max_ep) return score_ep diff --git a/grid2op/utils/underlying_statistics.py b/grid2op/utils/underlying_statistics.py index 287db0262..a083facec 100644 --- a/grid2op/utils/underlying_statistics.py +++ b/grid2op/utils/underlying_statistics.py @@ -104,7 +104,7 @@ class EpisodeStatistics(object): SCENARIO_IDS = "scenario_ids.npz" SCORES = "scores.npz" SCORES_CLEAN = re.sub("\\.npz", "", SCORES) - KEY_SCORE = "__scores" + KEY_SCORE = "_scores" SCORE_FOOTPRINT = ".has_score" STATISTICS_FOLDER = "_statistics" STATISTICS_FOOTPRINT = ".statistics" From 07fae3f4cd4193e99a7a76d0117b38f0928310c0 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 16:10:42 +0200 Subject: [PATCH 032/103] score2023: test normalized and fix dtype --- grid2op/Reward/_alertTrustScore.py | 2 +- grid2op/tests/test_RewardAlertCostScore.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 1d595c9eb..5111c1157 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -46,7 +46,7 @@ def __init__(self, self.reward_min = dt_float(-1.0) self.reward_max = dt_float(1.0) self.score_min_ep = lambda k: reward_min_no_blackout * (k - 1) + reward_min_blackout - self.score_max_ep = lambda k: np.max(reward_max_no_blackout * (k - 1) + reward_max_blackout, + self.score_max_ep = lambda k: max(reward_max_no_blackout * (k - 1) + reward_max_blackout, reward_max_no_blackout * k + reward_end_episode_bonus) def initialize(self, env): diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 453cb02df..a225e9a6d 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -302,8 +302,8 @@ def test_assistant_reward_value_blackout_attack_no_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if step == 4: - # When the blackout occurs, reward is -10 because we didn't raise an attack - assert reward == -10, f"error for step {step}: {reward} vs -10" + # When the blackout occurs, reward is -1 because we didn't raise an attack so min + assert reward == -1, f"error for step {step}: {reward} vs -1" assert done break else : @@ -313,7 +313,7 @@ def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : """ When 1 line is attacked at step 3 and we do raise an alert and a blackout occur at step 4 - we expect a score of 2. at step 4 + we expect a score max at step 4 """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], duration=3, @@ -355,7 +355,7 @@ def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if step == 4: - assert reward == 2, f"error for step {step}: {reward} vs 2" + assert reward == 1, f"error for step {step}: {reward} vs 1" #we did rise alert at first attack on going blackout assert done break else : From 3a2f0a05dc3cb1786bb9ed06bd126561aa1a5c37 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 16:49:37 +0200 Subject: [PATCH 033/103] score2023: nm key episodestat fix --- grid2op/utils/l2rpn_idf_2023_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 0bd393e60..bd999ea25 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -104,7 +104,7 @@ def __init__( nb_process_stats=nb_process_stats, scores_func={ "grid_operational_cost": L2RPNSandBoxScore, - "assistance_confidence": _AlertTrustScore, + "assistant_confidence": _AlertTrustScore, "assistant_cost": _AlertCostScore, "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, }, From 475f6fad0c970122fa176e416d88cdd5fab3e7a4 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 18:15:54 +0200 Subject: [PATCH 034/103] score2023: rm alertcost & add confusion kpi alert --- grid2op/Reward/_alertTrustScore.py | 11 +++++++- grid2op/utils/l2rpn_idf_2023_scores.py | 36 +++++++++++++------------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 5111c1157..e95946934 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -60,6 +60,10 @@ def reset(self, env): super().reset(env) self.total_nb_attacks = 0 self.cumulated_reward = 0 + self.true_alert_true_attack = 0 + self.true_alert_false_attack = 0 + self.false_alert_true_attack = 0 + self.false_alert_false_attack = 0 def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): score_ep = 0. @@ -68,7 +72,12 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res - self.total_nb_attacks += np.sum(env._time_since_last_attack == 0) + lines_attacked = env._time_since_last_attack == 0 + self.total_nb_attacks += np.sum(lines_attacked) + self.true_alert_true_attack = np.sum(env._time_since_last_alert[lines_attacked]==0) + self.true_alert_false_attack = np.sum(env._time_since_last_alert[~lines_attacked]==0) + self.false_alert_true_attack = np.sum(env._time_since_last_alert[lines_attacked]!=0) + self.false_alert_false_attack = np.sum(env._time_since_last_alert[~lines_attacked]!=0) if not is_done: return score_ep diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index bd999ea25..bcd6344fd 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -7,7 +7,7 @@ # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. from grid2op.utils.l2rpn_2020_scores import ScoreL2RPN2020 -from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AlertTrustScore, _AlertCostScore +from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AlertTrustScore #, _AlertCostScore from grid2op.utils.underlying_statistics import EpisodeStatistics @@ -86,9 +86,9 @@ def __init__( weight_op_score=0.6, weight_assistant_score=0.25, weight_nres_score=0.15, - weight_confidence_assistant_score=0.7, + #weight_confidence_assistant_score=0.7, min_nres_score=-100, - min_assistant_cost_score=-100, + #min_assistant_cost_score=-100, add_nb_highres_sim=False, ): @@ -105,27 +105,27 @@ def __init__( scores_func={ "grid_operational_cost": L2RPNSandBoxScore, "assistant_confidence": _AlertTrustScore, - "assistant_cost": _AlertCostScore, + #"assistant_cost": _AlertCostScore, "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, }, score_names=["grid_operational_cost_scores", "assistant_confidence_scores", - "assistant_cost_scores", + #"assistant_cost_scores", "new_renewable_sources_usage_scores"], add_nb_highres_sim=add_nb_highres_sim, ) assert(weight_op_score + weight_assistant_score + weight_nres_score==1.) - assert(all([weight_confidence_assistant_score>=0., weight_confidence_assistant_score<=1.])) + #assert(all([weight_confidence_assistant_score>=0., weight_confidence_assistant_score<=1.])) self.scale_assistant_score = scale_assistant_score self.scale_nres_score = scale_nres_score self.weight_op_score = weight_op_score self.weight_assistant_score = weight_assistant_score self.weight_nres_score = weight_nres_score - self.weight_confidence_assistant_score = weight_confidence_assistant_score + #self.weight_confidence_assistant_score = weight_confidence_assistant_score self.min_nres_score = min_nres_score - self.min_assistant_cost_score = min_assistant_cost_score + #self.min_assistant_cost_score = min_assistant_cost_score def _compute_episode_score( self, @@ -172,20 +172,20 @@ def _compute_episode_score( real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_confidence_score_nm) key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" assistant_confidence_score = float(other_rewards[-1][key_score_file]) - assistant_confidence_score = self.scale_assistant_score * assistant_confidence_score + assistant_score = self.scale_assistant_score * assistant_confidence_score #assistant_cost_score - assistant_cost_score_nm = "assistant_cost_scores" - real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_cost_score_nm) - key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" - assistant_cost_score = float(other_rewards[-1][key_score_file]) - assistant_cost_score = max(assistant_cost_score, self.min_assistant_cost_score / self.scale_assistant_score) - assistant_cost_score = self.scale_assistant_score * assistant_cost_score + # assistant_cost_score_nm = "assistant_cost_scores" + # real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_cost_score_nm) + # key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" + # assistant_cost_score = float(other_rewards[-1][key_score_file]) + # assistant_cost_score = max(assistant_cost_score, self.min_assistant_cost_score / self.scale_assistant_score) + # assistant_cost_score = self.scale_assistant_score * assistant_cost_score - assistant_score = self.weight_confidence_assistant_score * assistant_confidence_score +\ - (1. - self.weight_confidence_assistant_score) * assistant_cost_score + # assistant_score = self.weight_confidence_assistant_score * assistant_confidence_score +\ + # (1. - self.weight_confidence_assistant_score) * assistant_cost_score ep_score = ( self.weight_op_score * op_score + self.weight_nres_score * nres_score + self.weight_assistant_score * assistant_score ) - return (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score), n_played, total_ts + return (ep_score, op_score, nres_score, assistant_score), n_played, total_ts From 32286799eb9a1d743924f83c09052b34e34ec33c Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Tue, 11 Jul 2023 20:15:26 +0200 Subject: [PATCH 035/103] score2023: fix cumulation of kpi --- grid2op/Reward/_alertTrustScore.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index e95946934..f74c5e070 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -74,10 +74,10 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): self.cumulated_reward += res lines_attacked = env._time_since_last_attack == 0 self.total_nb_attacks += np.sum(lines_attacked) - self.true_alert_true_attack = np.sum(env._time_since_last_alert[lines_attacked]==0) - self.true_alert_false_attack = np.sum(env._time_since_last_alert[~lines_attacked]==0) - self.false_alert_true_attack = np.sum(env._time_since_last_alert[lines_attacked]!=0) - self.false_alert_false_attack = np.sum(env._time_since_last_alert[~lines_attacked]!=0) + self.true_alert_true_attack += np.sum(env._time_since_last_alert[lines_attacked]==0) + self.true_alert_false_attack += np.sum(env._time_since_last_alert[~lines_attacked]==0) + self.false_alert_true_attack += np.sum(env._time_since_last_alert[lines_attacked]!=0) + self.false_alert_false_attack += np.sum(env._time_since_last_alert[~lines_attacked]!=0) if not is_done: return score_ep From 0668439cf322b55af2bdeabfb2db74075565126c Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Wed, 12 Jul 2023 10:11:52 +0200 Subject: [PATCH 036/103] score2023: test_alert_trust neutralized score val --- grid2op/tests/test_alert_trust_score.py | 54 ++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 6f617b7ed..a50074d21 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -140,7 +140,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : obs, score, done, info = env.step(env.action_space()) if info["opponent_attack_line"] is None : if i == env.max_episode_duration()-1: - assert score == 42 + #assert score == 42 assert env._reward_helper.template_reward.total_nb_attacks==0 assert env._reward_helper.template_reward.cumulated_reward==42 @@ -179,7 +179,7 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : if info["opponent_attack_line"] is None : if step == env.max_episode_duration(): - assert score == 42 + #assert score == 42 assert env._reward_helper.template_reward.total_nb_attacks==0 assert env._reward_helper.template_reward.cumulated_reward==42 else : @@ -224,7 +224,7 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 43 + #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==43 else : @@ -266,7 +266,7 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 41 + #assert score == 41 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==41 @@ -310,7 +310,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 43 + #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==43 else : @@ -354,7 +354,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 43 + #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==43 @@ -396,7 +396,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 43 + #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==43 @@ -439,7 +439,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 42 + #assert score == 42 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==42 else : @@ -481,7 +481,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 41 + #assert score == 41 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==41 else : @@ -523,7 +523,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 44 + #assert score == 44 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==44 else : @@ -567,7 +567,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 40 + #assert score == 40 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==40 else : @@ -609,7 +609,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - score == 42 + #score == 42 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==42 else : @@ -651,7 +651,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 42 + #assert score == 42 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==42 else : @@ -720,7 +720,7 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == -10 + #assert score == -10 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==-10 break @@ -772,7 +772,7 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 2 + #assert score == 2 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==2 break @@ -825,7 +825,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == -10 + #assert score == -10 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==-10 break @@ -877,7 +877,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == -10 + #assert score == -10 assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==-10 break @@ -930,7 +930,7 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == 2 + #assert score == 2 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==2 break @@ -984,7 +984,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == -4 + #assert score == -4 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==-4 break @@ -1036,7 +1036,7 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - assert score == 2 + #assert score == 2 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==2 break @@ -1082,7 +1082,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - assert score == -4 + #assert score == -4 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==-4 break @@ -1129,7 +1129,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - assert score == -4., f"error for step {step}: {score} vs -4" + #assert score == -4., f"error for step {step}: {score} vs -4" assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==-4 @@ -1178,7 +1178,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - assert score == 3 + #assert score == 3 assert env._reward_helper.template_reward.total_nb_attacks==2 assert env._reward_helper.template_reward.cumulated_reward==3 assert done @@ -1209,7 +1209,7 @@ def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : act = env.action_space({"raise_alert": [0]}) obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : - assert score == 0. + #assert score == 0. assert env._reward_helper.template_reward.total_nb_attacks==0. assert env._reward_helper.template_reward.cumulated_reward==0. else : @@ -1240,7 +1240,7 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : act = self.get_blackout(env) obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : - assert score == 0. + #assert score == 0. assert env._reward_helper.template_reward.total_nb_attacks==0. assert env._reward_helper.template_reward.cumulated_reward==0. else : @@ -1273,7 +1273,7 @@ def test_assistant_trust_score_blackout_attack_before_window_alert(self) -> None act = env.action_space({"raise_alert": [0]}) obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : - assert score == 0. + #assert score == 0. assert env._reward_helper.template_reward.total_nb_attacks==0. assert env._reward_helper.template_reward.cumulated_reward==0. else : @@ -1308,7 +1308,7 @@ def test_assistant_trust_score_blackout_attack_before_window_no_alert(self) -> N obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : - assert score == 0. + #assert score == 0. assert env._reward_helper.template_reward.total_nb_attacks==0. assert env._reward_helper.template_reward.cumulated_reward==0. else : From d8d7a04124bba13272676d64e3e9ff7ace9822b5 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 12 Jul 2023 16:33:48 +0200 Subject: [PATCH 037/103] add min_assistant_score to L2RPN idf score and debug scoring idf tests --- grid2op/tests/test_score_idf_2023.py | 79 ++++++++++++---------------- 1 file changed, 33 insertions(+), 46 deletions(-) diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index 4fab7789f..330aa3c5b 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -71,7 +71,7 @@ def setUp(self) -> None: params.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION = True self.seed = 0 self.scen_id = 0 - self.nb_scenario = 2 + self.nb_scenario = 1 self.max_iter = 10 def tearDown(self) -> None: @@ -81,8 +81,7 @@ def tearDown(self) -> None: def test_score_helper(self): """basic tests for ScoreL2RPN2023 class""" self.env.reset() - try: - my_score = ScoreL2RPN2023( + my_score = ScoreL2RPN2023( self.env, nb_scenario=self.nb_scenario, env_seeds=[0 for _ in range(self.nb_scenario)], @@ -94,10 +93,11 @@ def test_score_helper(self): scale_nres_score=100, scale_assistant_score=100, min_nres_score=-300.) - + + try: # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): assert nres_score == 100. assert ep_score == 0.8 * op_score + 0.2 * nres_score @@ -107,72 +107,62 @@ def test_score_helper(self): gen_renewable = self.env.gen_renewable, gen_pmax=self.env.gen_pmax, curtail_level = 0.95)) - # assert np.allclose(res_agent0[0][0][2], 81.83611011377577) - # assert np.allclose(res_agent0[0][1][2], 68.10026022372575) + assert np.allclose(res_agent0[0][0][0], 0.8 * res_agent0[0][0][1] + 0.2 * res_agent0[0][0][2]) - assert np.allclose(res_agent0[0][0][2], 16.73128726588182) - assert np.allclose(res_agent0[0][1][2], -26.02070223995034) + assert np.allclose(res_agent0[0][0][2], 16.29061336683084) res_agent1 = my_score.get(CurtailTrackerAgent(self.env.action_space, gen_renewable = self.env.gen_renewable, gen_pmax=self.env.gen_pmax, curtail_level = 0.9)) - # assert np.allclose(res_agent1[0][0][2], 56.256863965501466) - # assert np.allclose(res_agent1[0][1][2], 43.370607328810415) - assert np.allclose(res_agent1[0][0][2], -49.61104170080321) - assert np.allclose(res_agent1[0][1][2], -78.00216266500183) + + assert np.allclose(res_agent1[0][0][2], -45.167919756806064) # decrease assert 100. - res_agent0[0][0][2] >= res_agent0[0][0][2] - res_agent1[0][0][2] - assert 100. - res_agent0[0][1][2] >= res_agent0[0][1][2] - res_agent1[0][1][2] res_agent2 = my_score.get(CurtailTrackerAgent(self.env.action_space, gen_renewable = self.env.gen_renewable, gen_pmax=self.env.gen_pmax, curtail_level = 0.8)) - assert np.allclose(res_agent2[0][0][2], -127.62213025108333) - assert np.allclose(res_agent2[0][1][2], -143.83405253996978) + assert np.allclose(res_agent2[0][0][2], -120.71966085513259) # decrease assert 100. - res_agent1[0][0][2] >= res_agent1[0][0][2] - res_agent2[0][0][2] - assert 100. - res_agent1[0][1][2] >= res_agent1[0][1][2] - res_agent2[0][1][2] res_agent3 = my_score.get(CurtailTrackerAgent(self.env.action_space, gen_renewable = self.env.gen_renewable, gen_pmax=self.env.gen_pmax, curtail_level = 0.7)) - assert np.allclose(res_agent3[0][0][2], -169.9519401162611) - assert np.allclose(res_agent3[0][1][2], -179.45065441917586) + assert np.allclose(res_agent3[0][0][2], -164.20345819832642) assert res_agent1[0][0][2] - res_agent2[0][0][2] >= res_agent2[0][0][2] - res_agent2[0][0][2] - assert res_agent1[0][1][2] - res_agent2[0][1][2] >= res_agent2[0][1][2] - res_agent2[0][1][2] finally: my_score.clear_all() def test_score_helper2(self): """basic tests for ScoreL2RPN2023 class""" self.env.reset() + my_score = ScoreL2RPN2023( + self.env, + nb_scenario=self.nb_scenario, + env_seeds=[0 for _ in range(self.nb_scenario)], + agent_seeds=[0 for _ in range(self.nb_scenario)], + max_step=self.max_iter, + weight_op_score=0.6, + weight_assistant_score=0.25, + weight_nres_score=0.15, + scale_nres_score=100, + scale_assistant_score=100, + min_nres_score=-100., + min_assistant_cost_score=-100) try: - my_score = ScoreL2RPN2023( - self.env, - nb_scenario=self.nb_scenario, - env_seeds=[0 for _ in range(self.nb_scenario)], - agent_seeds=[0 for _ in range(self.nb_scenario)], - max_step=self.max_iter, - weight_op_score=0.65, - weight_assistant_score=25, - weight_nres_score=0.15, - scale_nres_score=100, - scale_assistant_score=100, - min_nres_score=-100., - min_assistant_cost_score=-100) - # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): assert nres_score == 100. - assert ep_score == 0.65 * op_score + 0.15 * nres_score + 0.25 * (0.7 * assistant_confidence_score + 0.3 * assistant_cost_score) - assert assistant_cost_score == 100. - assert assistant_confidence_score == 100. #no blackout with no disconnections - + assert ep_score == 0.6 * op_score + 0.15 * nres_score + 0.25 * assistant_score + assert assistant_score == 100. + assert op_score == 0 + finally: my_score.clear_all() @@ -197,10 +187,7 @@ def test_min_score(self): gen_renewable = self.env.gen_renewable, gen_pmax=self.env.gen_pmax, curtail_level = 0.7)) - # assert np.allclose(res_agent3[0][0][2], -169.9519401162611) - # assert np.allclose(res_agent3[0][1][2], -179.45065441917586) assert np.allclose(res_agent3[0][0][2], -100.) - assert np.allclose(res_agent3[0][1][2], -100.) finally: my_score.clear_all() @@ -227,22 +214,22 @@ def test_spec(self): tol = 3e-5 # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): assert abs(nres_score - 100.) <= tol # test 80% gets indeed close to 0 res_80 = my_score.get(CurtailAgent(self.env.action_space, 0.8)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_80[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_80[0]): assert abs(nres_score) <= tol # test 50% gets indeed close to -100 res_50 = my_score.get(CurtailAgent(self.env.action_space, 0.5)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_50[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_50[0]): assert abs(nres_score + 100.) <= tol # test bellow 50% still gets close to -100 res_30 = my_score.get(CurtailAgent(self.env.action_space, 0.3)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_30[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_30[0]): assert abs(nres_score + 100.) <= tol finally: my_score.clear_all() From 0a1d0330406002a6e09e2880137df52b87213631 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Wed, 12 Jul 2023 16:36:23 +0200 Subject: [PATCH 038/103] score2023: exception error weights scores --- grid2op/tests/test_score_idf_2023.py | 11 +++++------ grid2op/utils/l2rpn_idf_2023_scores.py | 8 ++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index 10a503595..5b89b9b22 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -161,8 +161,8 @@ def test_score_helper2(self): env_seeds=[0 for _ in range(self.nb_scenario)], agent_seeds=[0 for _ in range(self.nb_scenario)], max_step=self.max_iter, - weight_op_score=0.65, - weight_assistant_score=25, + weight_op_score=0.6, + weight_assistant_score=0.25, weight_nres_score=0.15, scale_nres_score=100, scale_assistant_score=100, @@ -171,11 +171,10 @@ def test_score_helper2(self): # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): assert nres_score == 100. - assert ep_score == 0.65 * op_score + 0.15 * nres_score + 0.25 * (0.7 * assistant_confidence_score + 0.3 * assistant_cost_score) - assert assistant_cost_score == 100. - assert assistant_confidence_score == 100. #no blackout with no disconnections + assert ep_score == 0.6 * op_score + 0.15 * nres_score + 0.25 * assistant_score + #assert assistant_score == 100. #no blackout with no disconnections finally: my_score.clear_all() diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index bcd6344fd..5c886f595 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -9,7 +9,7 @@ from grid2op.utils.l2rpn_2020_scores import ScoreL2RPN2020 from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AlertTrustScore #, _AlertCostScore from grid2op.utils.underlying_statistics import EpisodeStatistics - +from grid2op.Exceptions import Grid2OpException class ScoreL2RPN2023(ScoreL2RPN2020): """ @@ -115,7 +115,11 @@ def __init__( add_nb_highres_sim=add_nb_highres_sim, ) - assert(weight_op_score + weight_assistant_score + weight_nres_score==1.) + test_weights = weight_op_score + weight_assistant_score + weight_nres_score + if not test_weights != 1: + raise Grid2OpException( + 'The weights of each component of the score shall sum to 1' + ) #assert(all([weight_confidence_assistant_score>=0., weight_confidence_assistant_score<=1.])) self.scale_assistant_score = scale_assistant_score From ee83f7c4be7dd3d13dfd20196fb855f140e5f1d7 Mon Sep 17 00:00:00 2001 From: GoubetClem Date: Wed, 12 Jul 2023 16:43:36 +0200 Subject: [PATCH 039/103] score2023 : erreur exception rise... tired --- grid2op/utils/l2rpn_idf_2023_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 5c886f595..c3936e9bf 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -116,7 +116,7 @@ def __init__( ) test_weights = weight_op_score + weight_assistant_score + weight_nres_score - if not test_weights != 1: + if not test_weights == 1: raise Grid2OpException( 'The weights of each component of the score shall sum to 1' ) From 682991e8cc0b1a245d88c0de88e9c126ca259a8e Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 12 Jul 2023 16:55:12 +0200 Subject: [PATCH 040/103] add min_assistant_cost_score --- grid2op/utils/l2rpn_idf_2023_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index c3936e9bf..6e46939f4 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -88,7 +88,7 @@ def __init__( weight_nres_score=0.15, #weight_confidence_assistant_score=0.7, min_nres_score=-100, - #min_assistant_cost_score=-100, + min_assistant_cost_score=-100, add_nb_highres_sim=False, ): From 146538b421c2e2fd8466d476280c4ec81bb67859 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 12 Jul 2023 16:56:47 +0200 Subject: [PATCH 041/103] update comparison for cost weights to add up to 1 --- grid2op/utils/l2rpn_idf_2023_scores.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 6e46939f4..37fa923a2 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -116,7 +116,7 @@ def __init__( ) test_weights = weight_op_score + weight_assistant_score + weight_nres_score - if not test_weights == 1: + if test_weights != 1.0: raise Grid2OpException( 'The weights of each component of the score shall sum to 1' ) From 72837e3058b2fa595ed09d5be8d51dc915d20102 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 18 Jul 2023 15:33:36 +0200 Subject: [PATCH 042/103] improving computation time --- CHANGELOG.rst | 6 +- _profiling/profiler_simulate.py | 52 ++-- grid2op/Action/BaseAction.py | 226 +++++++++--------- grid2op/Action/SerializableActionSpace.py | 20 +- grid2op/Action/_BackendAction.py | 98 ++++---- grid2op/Agent/recoPowerLinePerArea.py | 4 +- grid2op/Agent/recoPowerlineAgent.py | 2 +- grid2op/Backend/Backend.py | 18 +- grid2op/Backend/PandaPowerBackend.py | 26 +- grid2op/Chronics/GSFFWFWM.py | 4 +- grid2op/Chronics/multiFolder.py | 2 +- grid2op/Converter/AnalogStateConverter.py | 4 +- grid2op/Converter/BackendConverter.py | 2 +- grid2op/Converter/ConnectivityConverter.py | 4 +- grid2op/Environment/BaseEnv.py | 92 +++---- grid2op/Environment/BaseMultiProcessEnv.py | 2 +- grid2op/Environment/Environment.py | 4 +- grid2op/Environment/MultiEnvMultiProcess.py | 4 +- grid2op/Environment/_ObsEnv.py | 13 +- grid2op/Observation/baseObservation.py | 34 +-- grid2op/Opponent/BaseActionBudget.py | 2 +- grid2op/Opponent/WeightedRandomOpponent.py | 2 +- grid2op/Plot/BasePlot.py | 2 +- grid2op/PlotGrid/BasePlot.py | 2 +- grid2op/Reward/_alarmScore.py | 4 +- .../Reward/_newRenewableSourcesUsageScore.py | 6 +- grid2op/Reward/alarmReward.py | 4 +- grid2op/Reward/alertReward.py | 4 +- grid2op/Reward/distanceReward.py | 2 +- grid2op/Reward/economicReward.py | 4 +- grid2op/Reward/l2RPNReward.py | 2 +- grid2op/Reward/l2RPNSandBoxScore.py | 6 +- grid2op/Reward/l2rpn_wcci2022_scorefun.py | 2 +- grid2op/Reward/linesCapacityReward.py | 6 +- grid2op/Reward/linesReconnectedReward.py | 2 +- grid2op/Reward/redispReward.py | 12 +- grid2op/Rules/LookParam.py | 4 +- grid2op/Rules/PreventDiscoStorageModif.py | 2 +- grid2op/Rules/PreventReconnection.py | 4 +- grid2op/Rules/rulesByArea.py | 4 +- grid2op/Space/GridObjects.py | 78 +++--- grid2op/gym_compat/box_gym_actspace.py | 6 +- grid2op/gym_compat/box_gym_obsspace.py | 4 +- grid2op/gym_compat/continuous_to_discrete.py | 2 +- .../gym_compat/multidiscrete_gym_actspace.py | 4 +- grid2op/gym_compat/utils.py | 2 +- grid2op/simulator/simulator.py | 20 +- grid2op/tests/test_simulate_disco_load.py | 48 ++++ grid2op/utils/l2rpn_2020_scores.py | 18 +- 49 files changed, 487 insertions(+), 388 deletions(-) create mode 100644 grid2op/tests/test_simulate_disco_load.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 49d5ad755..65e943ed3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -38,7 +38,11 @@ Change Log - [FIXED] an issue with compatibility with previous versions (due to alert) - [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (self.is_simulated_env() was not working as expected due to a wrong init of the reward in `_ObsEnv`) - +- [FIXED] an issue when disconnecting loads / generators / storage units and changing their values in the same + action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" has the priority and +- [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or + `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance +- [IMPROVED] overall performance of the `simulate` function by improving speed of copy of `_BackendAction` [1.9.1] - 2023-07-06 -------------------- - [BREAKING] (slightly): default `gym_compat` module now inherit from `gymnasium` (if diff --git a/_profiling/profiler_simulate.py b/_profiling/profiler_simulate.py index cae2c3292..1becddd89 100644 --- a/_profiling/profiler_simulate.py +++ b/_profiling/profiler_simulate.py @@ -29,37 +29,61 @@ import pdb -def make_env(): - env_name = "l2rpn_icaps_2021" +NB_SIMULATE = 10 +ENV_NAME = "l2rpn_icaps_2021_small" +ENV_NAME = "l2rpn_idf_2023" + + +def make_env(env_name=ENV_NAME): with warnings.catch_warnings(): warnings.filterwarnings("ignore") fake_env = grid2op.make(env_name, test=True) param = fake_env.parameters param.NO_OVERFLOW_DISCONNECTION = True - env = grid2op.make(env_name+"_small", backend=LightSimBackend(), param=param) + env = grid2op.make(env_name, backend=bk_cls(), param=param) + env.seed(0) + env.reset() return env -def run_env(env): +def run_env(env, cp_env, cp_simu): done = False while not done: act = env.action_space() + cp_env.enable() obs, reward, done, info = env.step(act) + cp_env.disable() if not done: - simulate(obs, env.action_space()) + simulate(obs, env.action_space, NB_SIMULATE, cp_simu) -def simulate(obs, act): - simobs, rim_r, sim_d, sim_info = obs.simulate(act) +def simulate(obs, action_space, nb_simu=NB_SIMULATE, cp=None): + acts = [action_space.sample() for _ in range(nb_simu)] + # acts = [action_space() for _ in range(nb_simu)] + tmp = sum(acts, start = action_space()) + try: + if cp is not None: + cp.enable() + for i in range(nb_simu): + simobs, rim_r, sim_d, sim_info = obs.simulate(acts[i]) + prev_act = acts[i] + if cp is not None: + cp.disable() + except RuntimeError as exc_: + raise exc_ if __name__ == "__main__": env = make_env() - cp = cProfile.Profile() - cp.enable() - run_env(env) - cp.disable() + cp_simu = cProfile.Profile() + cp_env = cProfile.Profile() + run_env(env, cp_env, cp_simu) nm_f, ext = os.path.splitext(__file__) - nm_out = f"{nm_f}_{nm_bk_used}.prof" - cp.dump_stats(nm_out) - print("You can view profiling results with:\n\tsnakeviz {}".format(nm_out)) + nm_out_simu = f"{nm_f}_{nm_bk_used}_{ENV_NAME}_{NB_SIMULATE}_simu_1.prof" + nm_out_env = f"{nm_f}_{nm_bk_used}_{ENV_NAME}_{NB_SIMULATE}_env_1.prof" + cp_simu.dump_stats(nm_out_simu) + cp_env.dump_stats(nm_out_env) + print("You can view profiling results with:\n\tsnakeviz {}".format(nm_out_env)) + print("You can view profiling results with:\n\tsnakeviz {}".format(nm_out_simu)) +# base: 66.7 s +# sans copy dans simulate: 65.2 diff --git a/grid2op/Action/BaseAction.py b/grid2op/Action/BaseAction.py index 0c1c4ed9b..38ac3c128 100644 --- a/grid2op/Action/BaseAction.py +++ b/grid2op/Action/BaseAction.py @@ -676,15 +676,15 @@ def as_serializable_dict(self) -> dict: if type(self).shunts_data_available: res["shunt"] = {} - if np.any(np.isfinite(self.shunt_p)): + if np.isfinite(self.shunt_p).any(): res["shunt"]["shunt_p"] = [ (int(sh_id), float(val)) for sh_id, val in enumerate(self.shunt_p) if np.isfinite(val) ] - if np.any(np.isfinite(self.shunt_q)): + if np.isfinite(self.shunt_q).any(): res["shunt"]["shunt_q"] = [ (int(sh_id), float(val)) for sh_id, val in enumerate(self.shunt_q) if np.isfinite(val) ] - if np.any(self.shunt_bus != 0): + if (self.shunt_bus != 0).any(): res["shunt"]["shunt_bus"] = [ (int(sh_id), int(val)) for sh_id, val in enumerate(self.shunt_bus) @@ -825,17 +825,17 @@ def _get_array_from_attr_name(self, attr_name): def _post_process_from_vect(self): self._modif_inj = self._dict_inj != {} - self._modif_set_bus = np.any(self._set_topo_vect != 0) - self._modif_change_bus = np.any(self._change_bus_vect) - self._modif_set_status = np.any(self._set_line_status != 0) - self._modif_change_status = np.any(self._switch_line_status) - self._modif_redispatch = np.any( + self._modif_set_bus = (self._set_topo_vect != 0).any() + self._modif_change_bus = (self._change_bus_vect).any() + self._modif_set_status = (self._set_line_status != 0).any() + self._modif_change_status = (self._switch_line_status).any() + self._modif_redispatch = ( np.isfinite(self._redispatch) & (self._redispatch != 0.0) - ) - self._modif_storage = np.any(self._storage_power != 0.0) - self._modif_curtailment = np.any(self._curtail != -1.0) - self._modif_alarm = np.any(self._raise_alarm) - self._modif_alert = np.any(self._raise_alert) + ).any() + self._modif_storage = (self._storage_power != 0.0).any() + self._modif_curtailment = (self._curtail != -1.0).any() + self._modif_alarm = self._raise_alarm.any() + self._modif_alert = self._raise_alert.any() def _assign_attr_from_name(self, attr_nm, vect): if hasattr(self, attr_nm): @@ -846,8 +846,8 @@ def _assign_attr_from_name(self, attr_nm, vect): super()._assign_attr_from_name(attr_nm, vect) self._post_process_from_vect() else: - if np.any(np.isfinite(vect)): - if np.any(vect != 0.0): + if np.isfinite(vect).any(): + if (vect != 0.0).any(): self._dict_inj[attr_nm] = vect def check_space_legit(self): @@ -1029,17 +1029,17 @@ def __eq__(self, other) -> bool: return False is_ok_me = np.isfinite(self.shunt_p) is_ok_ot = np.isfinite(other.shunt_p) - if np.any(is_ok_me != is_ok_ot): + if (is_ok_me != is_ok_ot).any(): return False - if not np.all(self.shunt_p[is_ok_me] == other.shunt_p[is_ok_ot]): + if not (self.shunt_p[is_ok_me] == other.shunt_p[is_ok_ot]).all(): return False is_ok_me = np.isfinite(self.shunt_q) is_ok_ot = np.isfinite(other.shunt_q) - if np.any(is_ok_me != is_ok_ot): + if (is_ok_me != is_ok_ot).any(): return False - if not np.all(self.shunt_q[is_ok_me] == other.shunt_q[is_ok_ot]): + if not (self.shunt_q[is_ok_me] == other.shunt_q[is_ok_ot]).all(): return False - if not np.all(self.shunt_bus == other.shunt_bus): + if not (self.shunt_bus == other.shunt_bus).all(): return False return True @@ -1414,7 +1414,7 @@ def _assign_iadd_or_warn(self, attr_name, new_value): old_is_finite = np.isfinite(old_value) new_finite = new_value[new_is_finite | old_is_finite] old_finite = old_value[new_is_finite | old_is_finite] - if np.any(new_finite != old_finite): + if (new_finite != old_finite).any(): warnings.warn( type(self).ERR_ACTION_CUT.format(attr_name) ) @@ -1473,7 +1473,7 @@ def __iadd__(self, other): ) # redispatching redispatching = other._redispatch - if np.any(redispatching != 0.0): + if (redispatching != 0.0).any(): if "_redispatch" not in self.attr_list_set: warnings.warn( type(self).ERR_ACTION_CUT.format("_redispatch") @@ -1484,8 +1484,8 @@ def __iadd__(self, other): # storage set_storage = other._storage_power - ok_ind = np.isfinite(set_storage) & np.any(set_storage != 0.0) - if np.any(ok_ind): + ok_ind = np.isfinite(set_storage) & (set_storage != 0.0).any() + if ok_ind.any(): if "_storage_power" not in self.attr_list_set: warnings.warn( type(self).ERR_ACTION_CUT.format("_storage_power") @@ -1496,7 +1496,7 @@ def __iadd__(self, other): # curtailment curtailment = other._curtail ok_ind = np.isfinite(curtailment) & (curtailment != -1.0) - if np.any(ok_ind): + if ok_ind.any(): if "_curtail" not in self.attr_list_set: warnings.warn( type(self).ERR_ACTION_CUT.format("_curtail") @@ -2222,7 +2222,7 @@ def _check_for_correct_modif_flags(self): ) if "injection" not in self.authorized_keys: raise IllegalAction("You illegally act on the injection") - if np.any(self._change_bus_vect): + if self._change_bus_vect.any(): if not self._modif_change_bus: raise AmbiguousAction( "A action of type change_bus is performed while the appropriate flag is not " @@ -2231,7 +2231,7 @@ def _check_for_correct_modif_flags(self): ) if "change_bus" not in self.authorized_keys: raise IllegalAction("You illegally act on the bus (using change)") - if np.any(self._set_topo_vect != 0): + if (self._set_topo_vect != 0).any(): if not self._modif_set_bus: raise AmbiguousAction( "A action of type set_bus is performed while the appropriate flag is not " @@ -2241,7 +2241,7 @@ def _check_for_correct_modif_flags(self): if "set_bus" not in self.authorized_keys: raise IllegalAction("You illegally act on the bus (using set)") - if np.any(self._set_line_status != 0): + if (self._set_line_status != 0).any(): if not self._modif_set_status: raise AmbiguousAction( "A action of type line_set_status is performed while the appropriate flag is not " @@ -2254,7 +2254,7 @@ def _check_for_correct_modif_flags(self): "You illegally act on the powerline status (using set)" ) - if np.any(self._switch_line_status): + if (self._switch_line_status).any(): if not self._modif_change_status: raise AmbiguousAction( "A action of type line_change_status is performed while the appropriate flag " @@ -2267,7 +2267,7 @@ def _check_for_correct_modif_flags(self): "You illegally act on the powerline status (using change)" ) - if np.any(self._redispatch != 0.0): + if (self._redispatch != 0.0).any(): if not self._modif_redispatch: raise AmbiguousAction( "A action of type redispatch is performed while the appropriate flag " @@ -2278,7 +2278,7 @@ def _check_for_correct_modif_flags(self): if "redispatch" not in self.authorized_keys: raise IllegalAction("You illegally act on the redispatching") - if np.any(self._storage_power != 0.0): + if (self._storage_power != 0.0).any(): if not self._modif_storage: raise AmbiguousAction( "A action on the storage unit is performed while the appropriate flag " @@ -2289,7 +2289,7 @@ def _check_for_correct_modif_flags(self): if "set_storage" not in self.authorized_keys: raise IllegalAction("You illegally act on the storage unit") - if np.any(self._curtail != -1.0): + if (self._curtail != -1.0).any(): if not self._modif_curtailment: raise AmbiguousAction( "A curtailment is performed while the action is not supposed to have done so. " @@ -2298,7 +2298,7 @@ def _check_for_correct_modif_flags(self): if "curtail" not in self.authorized_keys: raise IllegalAction("You illegally act on the curtailment") - if np.any(self._raise_alarm): + if (self._raise_alarm).any(): if not self._modif_alarm: raise AmbiguousAction( "Incorrect way to raise some alarm, the appropriate flag is not " @@ -2307,7 +2307,7 @@ def _check_for_correct_modif_flags(self): if "raise_alarm" not in self.authorized_keys: raise IllegalAction("You illegally send an alarm.") - if np.any(self._raise_alert): + if (self._raise_alert).any(): if not self._modif_alert: raise AmbiguousActionRaiseAlert( "Incorrect way to raise some alert, the appropriate flag is not " @@ -2374,7 +2374,7 @@ def _check_for_ambiguity(self): if ( self._modif_change_status and self._modif_set_status - and np.any(self._set_line_status[self._switch_line_status] != 0) + and (self._set_line_status[self._switch_line_status] != 0).any() ): raise InvalidLineStatus( "You asked to change the status (connected / disconnected) of a powerline by" @@ -2446,17 +2446,17 @@ def _check_for_ambiguity(self): "environment. Please set up the proper costs for generator" ) - if np.any(self._redispatch[~self.gen_redispatchable] != 0.0): + if (self._redispatch[~self.gen_redispatchable] != 0.0).any(): raise InvalidRedispatching( "Trying to apply a redispatching action on a non redispatchable generator" ) if self._single_act: - if np.any(self._redispatch > self.gen_max_ramp_up): + if (self._redispatch > self.gen_max_ramp_up).any(): raise InvalidRedispatching( "Some redispatching amount are above the maximum ramp up" ) - if np.any(-self._redispatch > self.gen_max_ramp_down): + if (-self._redispatch > self.gen_max_ramp_down).any(): raise InvalidRedispatching( "Some redispatching amount are bellow the maximum ramp down" ) @@ -2465,12 +2465,12 @@ def _check_for_ambiguity(self): new_p = self._dict_inj["prod_p"] tmp_p = new_p + self._redispatch indx_ok = np.isfinite(new_p) - if np.any(tmp_p[indx_ok] > self.gen_pmax[indx_ok]): + if (tmp_p[indx_ok] > self.gen_pmax[indx_ok]).any(): raise InvalidRedispatching( "Some redispatching amount, cumulated with the production setpoint, " "are above pmax for some generator." ) - if np.any(tmp_p[indx_ok] < self.gen_pmin[indx_ok]): + if (tmp_p[indx_ok] < self.gen_pmin[indx_ok]).any(): raise InvalidRedispatching( "Some redispatching amount, cumulated with the production setpoint, " "are below pmin for some generator." @@ -2486,20 +2486,20 @@ def _check_for_ambiguity(self): if ( self._modif_set_bus and self._modif_change_bus - and np.any(self._set_topo_vect[self._change_bus_vect] != 0) + and (self._set_topo_vect[self._change_bus_vect] != 0).any() ): raise InvalidBusStatus( "You asked to change the bus of an object with" ' using the keyword "change_bus" and set this same object state in "set_bus"' ". This ambiguous behaviour is not supported" ) - if self._modif_set_bus and np.any(self._set_topo_vect < -1): + if self._modif_set_bus and (self._set_topo_vect < -1).any(): raise InvalidBusStatus( "Invalid set_bus. Buses should be either -1 (disconnect), 0 (change nothing)," "1 (assign this object to bus one) or 2 (assign this object to bus" "2). A negative number has been found." ) - if self._modif_set_bus and np.any(self._set_topo_vect > 2): + if self._modif_set_bus and (self._set_topo_vect > 2).any(): raise InvalidBusStatus( "Invalid set_bus. Buses should be either -1 (disconnect), 0 (change nothing)," "1 (assign this object to bus one) or 2 (assign this object to bus" @@ -2526,13 +2526,13 @@ def _check_for_ambiguity(self): if self._modif_set_bus: disco_or = self._set_topo_vect[self.line_or_pos_topo_vect] == -1 - if np.any(self._set_topo_vect[self.line_ex_pos_topo_vect][disco_or] > 0): + if (self._set_topo_vect[self.line_ex_pos_topo_vect][disco_or] > 0).any(): raise InvalidLineStatus( "A powerline is connected (set to a bus at extremity end) and " "disconnected (set to bus -1 at origin end)" ) disco_ex = self._set_topo_vect[self.line_ex_pos_topo_vect] == -1 - if np.any(self._set_topo_vect[self.line_or_pos_topo_vect][disco_ex] > 0): + if (self._set_topo_vect[self.line_or_pos_topo_vect][disco_ex] > 0).any(): raise InvalidLineStatus( "A powerline is connected (set to a bus at origin end) and " "disconnected (set to bus -1 at extremity end)" @@ -2551,17 +2551,17 @@ def _check_for_ambiguity(self): raise AmbiguousAction( 'Action of type "set_bus" are not supported by this action type' ) - if np.any( + if ( self._set_topo_vect[self.line_or_pos_topo_vect[id_disc]] > 0 - ) or np.any(self._set_topo_vect[self.line_ex_pos_topo_vect[id_disc]] > 0): + ).any() or (self._set_topo_vect[self.line_ex_pos_topo_vect[id_disc]] > 0).any(): raise InvalidLineStatus( "You ask to disconnect a powerline but also to connect it " "to a certain bus." ) - if np.any( + if ( self._set_topo_vect[self.line_or_pos_topo_vect[id_reco]] == -1 - ) or np.any(self._set_topo_vect[self.line_ex_pos_topo_vect[id_reco]] == -1): + ).any() or (self._set_topo_vect[self.line_ex_pos_topo_vect[id_reco]] == -1).any(): raise InvalidLineStatus( "You ask to reconnect a powerline but also to disconnect it " "from a certain bus." @@ -2571,27 +2571,27 @@ def _check_for_ambiguity(self): raise AmbiguousAction( 'Action of type "change_bus" are not supported by this action type' ) - if np.any( + if ( self._change_bus_vect[self.line_or_pos_topo_vect[id_disc]] > 0 - ) or np.any(self._change_bus_vect[self.line_ex_pos_topo_vect[id_disc]] > 0): + ).any() or (self._change_bus_vect[self.line_ex_pos_topo_vect[id_disc]] > 0).any(): raise InvalidLineStatus( "You ask to disconnect a powerline but also to change its bus." ) - if np.any( + if ( self._change_bus_vect[ self.line_or_pos_topo_vect[self._set_line_status == 1] ] - ): + ).any(): raise InvalidLineStatus( "You ask to connect an origin powerline but also to *change* the bus to which " "it is connected. This is ambiguous. You must *set* this bus instead." ) - if np.any( + if ( self._change_bus_vect[ self.line_ex_pos_topo_vect[self._set_line_status == 1] ] - ): + ).any(): raise InvalidLineStatus( "You ask to connect an extremity powerline but also to *change* the bus to " "which it is connected. This is ambiguous. You must *set* this bus instead." @@ -2642,7 +2642,7 @@ def _check_for_ambiguity(self): f"{self.dim_alarms}" ) else: - if np.any(self._raise_alarm): + if self._raise_alarm.any(): raise AmbiguousAction( f"Unrecognize alarm action: an action acts on the alarm, yet it's not tagged " f"as doing so. Expect wrong behaviour." @@ -2655,7 +2655,7 @@ def _check_for_ambiguity(self): f"{self.dim_alerts}" ) else: - if np.any(self._raise_alert): + if self._raise_alert.any(): raise AmbiguousActionRaiseAlert( f"Unrecognize alert action: an action acts on the alert, yet it's not tagged " f"as doing so. Expect wrong behaviour." @@ -2677,13 +2677,13 @@ def _is_storage_ambiguous(self): "self._storage_power.shape[0] != self.n_storage: wrong number of storage " "units affected" ) - if np.any(self._storage_power < -self.storage_max_p_prod): + if (self._storage_power < -self.storage_max_p_prod).any(): where_bug = np.where(self._storage_power < -self.storage_max_p_prod)[0] raise InvalidStorage( f"you asked a storage unit to absorb more than what it can: " f"self._storage_power[{where_bug}] < -self.storage_max_p_prod[{where_bug}]." ) - if np.any(self._storage_power > self.storage_max_p_absorb): + if (self._storage_power > self.storage_max_p_absorb).any(): where_bug = np.where(self._storage_power > self.storage_max_p_absorb)[0] raise InvalidStorage( f"you asked a storage unit to produce more than what it can: " @@ -2691,9 +2691,9 @@ def _is_storage_ambiguous(self): ) if "_storage_power" not in self.attr_list_set: - if np.any(self._set_topo_vect[self.storage_pos_topo_vect] > 0): + if (self._set_topo_vect[self.storage_pos_topo_vect] > 0).any(): raise InvalidStorage("Attempt to modify bus (set) of a storage unit") - if np.any(self._change_bus_vect[self.storage_pos_topo_vect]): + if (self._change_bus_vect[self.storage_pos_topo_vect]).any(): raise InvalidStorage("Attempt to modify bus (change) of a storage unit") def _is_curtailment_ambiguous(self): @@ -2717,21 +2717,21 @@ def _is_curtailment_ambiguous(self): "units affected" ) - if np.any((self._curtail < 0.0) & (self._curtail != -1.0)): + if ((self._curtail < 0.0) & (self._curtail != -1.0)).any(): where_bug = np.where((self._curtail < 0.0) & (self._curtail != -1.0))[0] raise InvalidCurtailment( f"you asked to perform a negative curtailment: " f"self._curtail[{where_bug}] < 0. " f"Curtailment should be a real number between 0.0 and 1.0" ) - if np.any(self._curtail > 1.0): + if (self._curtail > 1.0).any(): where_bug = np.where(self._curtail > 1.0)[0] raise InvalidCurtailment( f"you asked a storage unit to produce more than what it can: " f"self._curtail[{where_bug}] > 1. " f"Curtailment should be a real number between 0.0 and 1.0" ) - if np.any(self._curtail[~self.gen_renewable] != -1.0): + if (self._curtail[~self.gen_renewable] != -1.0).any(): raise InvalidCurtailment( "Trying to apply a curtailment on a non renewable generator" ) @@ -2988,32 +2988,32 @@ def impact_on_objects(self) -> dict: "reconnections": {"count": 0, "powerlines": []}, "disconnections": {"count": 0, "powerlines": []}, } - if np.any(self._set_line_status == 1): + if (self._set_line_status == 1).any(): force_line_status["changed"] = True has_impact = True - force_line_status["reconnections"]["count"] = np.sum( + force_line_status["reconnections"]["count"] = ( self._set_line_status == 1 - ) + ).sum() force_line_status["reconnections"]["powerlines"] = np.where( self._set_line_status == 1 )[0] - if np.any(self._set_line_status == -1): + if (self._set_line_status == -1).any(): force_line_status["changed"] = True has_impact = True - force_line_status["disconnections"]["count"] = np.sum( + force_line_status["disconnections"]["count"] = ( self._set_line_status == -1 - ) + ).sum() force_line_status["disconnections"]["powerlines"] = np.where( self._set_line_status == -1 )[0] # handles action on swtich line status switch_line_status = {"changed": False, "count": 0, "powerlines": []} - if np.sum(self._switch_line_status): + if self._switch_line_status.sum(): switch_line_status["changed"] = True has_impact = True - switch_line_status["count"] = np.sum(self._switch_line_status) + switch_line_status["count"] = self._switch_line_status.sum() switch_line_status["powerlines"] = np.where(self._switch_line_status)[0] topology = { @@ -3023,7 +3023,7 @@ def impact_on_objects(self) -> dict: "disconnect_bus": [], } # handles topology - if np.any(self._change_bus_vect): + if self._change_bus_vect.any(): for id_, k in enumerate(self._change_bus_vect): if k: obj_id, objt_type, substation_id = self._obj_caract_from_topo_id( @@ -3040,7 +3040,7 @@ def impact_on_objects(self) -> dict: topology["changed"] = True has_impact = True - if np.any(self._set_topo_vect != 0): + if (self._set_topo_vect != 0).any(): for id_, k in enumerate(self._set_topo_vect): if k > 0: obj_id, objt_type, substation_id = self._obj_caract_from_topo_id( @@ -3072,7 +3072,7 @@ def impact_on_objects(self) -> dict: # handle redispatching redispatch = {"changed": False, "generators": []} - if np.any(self._redispatch != 0.0): + if (self._redispatch != 0.0).any(): for gen_idx in range(self.n_gen): if self._redispatch[gen_idx] != 0.0: gen_name = self.name_gen[gen_idx] @@ -3198,12 +3198,12 @@ def as_dict(self) -> dict: res[k] = 1.0 * self._dict_inj[k] # handles actions on force line status - if np.any(self._set_line_status != 0): + if (self._set_line_status != 0).any(): res["set_line_status"] = {} - res["set_line_status"]["nb_connected"] = np.sum(self._set_line_status == 1) - res["set_line_status"]["nb_disconnected"] = np.sum( + res["set_line_status"]["nb_connected"] = (self._set_line_status == 1).sum() + res["set_line_status"]["nb_disconnected"] = ( self._set_line_status == -1 - ) + ).sum() res["set_line_status"]["connected_id"] = np.where( self._set_line_status == 1 )[0] @@ -3212,17 +3212,17 @@ def as_dict(self) -> dict: )[0] # handles action on swtich line status - if np.sum(self._switch_line_status): + if self._switch_line_status.sum(): res["change_line_status"] = {} - res["change_line_status"]["nb_changed"] = np.sum(self._switch_line_status) + res["change_line_status"]["nb_changed"] = self._switch_line_status.sum() res["change_line_status"]["changed_id"] = np.where( self._switch_line_status )[0] # handles topology change - if np.any(self._change_bus_vect): + if (self._change_bus_vect).any(): res["change_bus_vect"] = {} - res["change_bus_vect"]["nb_modif_objects"] = np.sum(self._change_bus_vect) + res["change_bus_vect"]["nb_modif_objects"] = self._change_bus_vect.sum() all_subs = set() for id_, k in enumerate(self._change_bus_vect): if k: @@ -3241,9 +3241,9 @@ def as_dict(self) -> dict: res["change_bus_vect"]["modif_subs_id"] = sorted(all_subs) # handles topology set - if np.any(self._set_topo_vect): + if (self._set_topo_vect!= 0).any(): res["set_bus_vect"] = {} - res["set_bus_vect"]["nb_modif_objects"] = np.sum(self._set_topo_vect) + res["set_bus_vect"]["nb_modif_objects"] = (self._set_topo_vect != 0).sum() all_subs = set() for id_, k in enumerate(self._set_topo_vect): if k != 0: @@ -3262,15 +3262,15 @@ def as_dict(self) -> dict: res["set_bus_vect"]["nb_modif_subs"] = len(all_subs) res["set_bus_vect"]["modif_subs_id"] = sorted(all_subs) - if np.any(self._hazards): + if self._hazards.any(): res["hazards"] = np.where(self._hazards)[0] - res["nb_hazards"] = np.sum(self._hazards) + res["nb_hazards"] = self._hazards.sum() - if np.any(self._maintenance): + if self._maintenance.any(): res["maintenance"] = np.where(self._maintenance)[0] - res["nb_maintenance"] = np.sum(self._maintenance) + res["nb_maintenance"] = self._maintenance.sum() - if np.any(self._redispatch != 0.0): + if (self._redispatch != 0.0).any(): res["redispatch"] = 1.0 * self._redispatch if self._modif_storage: @@ -3328,14 +3328,14 @@ def get_types(self) -> Tuple[bool, bool, bool, bool, bool, bool, bool]: injection = "load_p" in self._dict_inj or "prod_p" in self._dict_inj voltage = "prod_v" in self._dict_inj if self.shunts_data_available: - voltage = voltage or np.any(np.isfinite(self.shunt_p)) - voltage = voltage or np.any(np.isfinite(self.shunt_q)) - voltage = voltage or np.any(self.shunt_bus != 0) + voltage = voltage or np.isfinite(self.shunt_p).any() + voltage = voltage or np.isfinite(self.shunt_q).any() + voltage = voltage or (self.shunt_bus != 0).any() lines_impacted, subs_impacted = self.get_topological_impact() - topology = np.any(subs_impacted) - line = np.any(lines_impacted) - redispatching = np.any(self._redispatch != 0.0) + topology = subs_impacted.any() + line = lines_impacted.any() + redispatching = (self._redispatch != 0.0).any() storage = self._modif_storage curtailment = self._modif_curtailment return injection, voltage, topology, line, redispatching, storage, curtailment @@ -3427,7 +3427,7 @@ def _aux_effect_on_substation(self, substation_id): raise Grid2OpException(f"`substation_id` should be positive.") res = {} - beg_ = int(np.sum(self.sub_info[:substation_id])) + beg_ = int(self.sub_info[:substation_id].sum()) end_ = int(beg_ + self.sub_info[substation_id]) res["change_bus"] = self._change_bus_vect[beg_:end_] res["set_bus"] = self._set_topo_vect[beg_:end_] @@ -3762,11 +3762,11 @@ def _aux_affect_object_int( raise IllegalAction( f'{name_el}_id should be convertible to integer. Error was : "{exc_}"' ) - if np.any(values < min_val): + if (values < min_val).any(): raise IllegalAction( f"new_bus should be between {min_val} and {max_val}, found a value < {min_val}" ) - if np.any(values > max_val): + if (values > max_val).any(): raise IllegalAction( f"new_bus should be between {min_val} and {max_val}, found a value > {max_val}" ) @@ -4391,11 +4391,11 @@ def _aux_affect_object_bool( raise IllegalAction( f'{name_el}_id should be convertible to integer. Error was : "{exc_}"' ) - if np.any(values < 0): + if (values < 0).any(): raise IllegalAction( f"Impossible to change a negative {name_el} with negative id" ) - if np.any(values > nb_els): + if (values > nb_els).any(): raise IllegalAction( f"Impossible to change a {name_el} id because there are only " f"{nb_els} on the grid and you wanted to change an element with an " @@ -5391,12 +5391,12 @@ def _aux_aux_convert_and_check_np_array(self, array_): "of float." ) array_ = array_.astype(dt_int) - if np.any(array_ < -1): + if (array_ < -1).any(): raise IllegalAction( f"Impossible to set element to bus {np.min(array_)}. Buses must be " f"-1, 0, 1 or 2." ) - if np.any(array_ > 2): + if (array_ > 2).any(): raise IllegalAction( f"Impossible to set element to bus {np.max(array_)}. Buses must be " f"-1, 0, 1 or 2." @@ -5434,7 +5434,7 @@ def _aux_set_bus_sub(self, values): # should be a tuple (sub_id, new_topo) sub_id, topo_repr, nb_el = self._check_for_right_vectors_sub(values) topo_repr = self._aux_aux_convert_and_check_np_array(topo_repr) - start_ = np.sum(self.sub_info[:sub_id]) + start_ = self.sub_info[:sub_id].sum() end_ = start_ + nb_el self._set_topo_vect[start_:end_] = topo_repr elif isinstance(values, list): @@ -5582,7 +5582,7 @@ def _aux_change_bus_sub(self, values): sub_id, topo_repr, nb_el = self._check_for_right_vectors_sub(values) topo_repr = self._aux_aux_convert_and_check_np_array_change(topo_repr) - start_ = np.sum(self.sub_info[:sub_id]) + start_ = self.sub_info[:sub_id].sum() end_ = start_ + nb_el self._change_bus_vect[start_:end_] = topo_repr elif isinstance(values, list): @@ -5813,12 +5813,12 @@ def limit_curtail_storage(self, res_add_storage = np.zeros(cls.n_storage, dtype=dt_float) res_add_curtailed = np.zeros(cls.n_gen, dtype=dt_float) - max_down = np.sum(obs.gen_margin_down) - max_up = np.sum(obs.gen_margin_up) + max_down = obs.gen_margin_down.sum() + max_up = obs.gen_margin_up.sum() # storage - total_mw_storage = np.sum(res._storage_power) - total_storage_consumed = np.sum(res._storage_power) + total_mw_storage = res._storage_power.sum() + total_storage_consumed = res._storage_power.sum() # curtailment gen_curtailed = (res._curtail != -1) & cls.gen_renewable @@ -5836,8 +5836,8 @@ def limit_curtail_storage(self, mw_curtailed_down[mw_curtailed_down < 0.] = 0. mw_curtailed_up = -1.0 * mw_curtailed mw_curtailed_up[mw_curtailed_up < 0.] = 0. - total_mw_curtailed_down = np.sum(mw_curtailed_down) - total_mw_curtailed_up = np.sum(mw_curtailed_up) + total_mw_curtailed_down = mw_curtailed_down.sum() + total_mw_curtailed_up = mw_curtailed_up.sum() total_mw_curtailed = total_mw_curtailed_down - total_mw_curtailed_up total_mw_act = total_mw_curtailed + total_mw_storage @@ -5866,7 +5866,7 @@ def limit_curtail_storage(self, do_storage_consum = res._storage_power > 0. remove_storage_mw = remove_mw * total_mw_storage / (total_mw_curtailed_down + total_mw_storage) tmp_ = -(res._storage_power[do_storage_consum] * - remove_storage_mw / np.sum(res._storage_power[do_storage_consum])) + remove_storage_mw / res._storage_power[do_storage_consum].sum()) res._storage_power[do_storage_consum] += tmp_ res_add_storage[do_storage_consum] = tmp_ @@ -5894,7 +5894,7 @@ def limit_curtail_storage(self, do_storage_prod = res._storage_power < 0. remove_storage_mw = add_mw * total_mw_storage / (total_mw_curtailed_up + total_mw_storage) tmp_ = (res._storage_power[do_storage_prod] * - remove_storage_mw / np.sum(res._storage_power[do_storage_prod])) + remove_storage_mw / res._storage_power[do_storage_prod].sum()) res._storage_power[do_storage_prod] += tmp_ res_add_storage[do_storage_prod] = tmp_ return res, res_add_curtailed, res_add_storage diff --git a/grid2op/Action/SerializableActionSpace.py b/grid2op/Action/SerializableActionSpace.py index 056506ac4..a2fbbfcc6 100644 --- a/grid2op/Action/SerializableActionSpace.py +++ b/grid2op/Action/SerializableActionSpace.py @@ -1092,15 +1092,15 @@ def get_all_unitary_topologies_set(action_space, sub_id=None): dt_bool ) # add a zero to first element -> break symmetry indx[tup] = True - if np.sum(indx) >= 2 and np.sum(~indx) >= 2: + if indx.sum() >= 2 and (~indx).sum() >= 2: # i need 2 elements on each bus at least (almost all the times, except when a powerline # is alone on its bus) new_topo = np.full(shape=num_el, fill_value=1, dtype=dt_int) new_topo[~indx] = 2 if ( - np.sum(indx[powerlines_id]) == 0 - or np.sum(~indx[powerlines_id]) == 0 + indx[powerlines_id].sum() == 0 + or (~indx[powerlines_id]).sum() == 0 ): # if there is a "node" without a powerline, the topology is not valid continue @@ -1112,8 +1112,8 @@ def get_all_unitary_topologies_set(action_space, sub_id=None): else: # i need to take into account the case where 1 powerline is alone on a bus too if ( - np.sum(indx[powerlines_id]) >= 1 - and np.sum(~indx[powerlines_id]) >= 1 + (indx[powerlines_id]).sum() >= 1 + and (~indx[powerlines_id]).sum() >= 1 ): new_topo = np.full(shape=num_el, fill_value=1, dtype=dt_int) new_topo[~indx] = 2 @@ -1317,7 +1317,7 @@ def _custom_deepcopy_for_copy(self, new_obj): def _aux_get_back_to_ref_state_curtail(self, res, obs): is_curtailed = obs.curtailment_limit != 1.0 - if np.any(is_curtailed): + if is_curtailed.any(): res["curtailment"] = [] if not self.supports_type("curtail"): warnings.warn( @@ -1333,7 +1333,7 @@ def _aux_get_back_to_ref_state_curtail(self, res, obs): def _aux_get_back_to_ref_state_line(self, res, obs): disc_lines = ~obs.line_status - if np.any(disc_lines): + if disc_lines.any(): li_disc = np.where(disc_lines)[0] res["powerline"] = [] for el in li_disc: @@ -1351,7 +1351,7 @@ def _aux_get_back_to_ref_state_line(self, res, obs): def _aux_get_back_to_ref_state_sub(self, res, obs): not_on_bus_1 = obs.topo_vect > 1 # disconnected lines are handled above - if np.any(not_on_bus_1): + if not_on_bus_1.any(): res["substation"] = [] subs_changed = type(self).grid_objects_types[ not_on_bus_1, type(self).SUB_COL @@ -1377,7 +1377,7 @@ def _aux_get_back_to_ref_state_sub(self, res, obs): def _aux_get_back_to_ref_state_redisp(self, res, obs, precision=1e-5): # TODO this is ugly, probably slow and could definitely be optimized notredisp_setpoint = obs.target_dispatch != 0.0 - if np.any(notredisp_setpoint): + if notredisp_setpoint.any(): need_redisp = np.where(notredisp_setpoint)[0] res["redispatching"] = [] # combine generators and do not exceed ramps (up or down) @@ -1442,7 +1442,7 @@ def _aux_get_back_to_ref_state_storage( # TODO refacto with the redispatching notredisp_setpoint = obs.storage_charge / obs.storage_Emax != storage_setpoint delta_time_hour = dt_float(obs.delta_time / 60.0) - if np.any(notredisp_setpoint): + if notredisp_setpoint.any(): need_ajust = np.where(notredisp_setpoint)[0] res["storage"] = [] # combine storage units and do not exceed maximum power diff --git a/grid2op/Action/_BackendAction.py b/grid2op/Action/_BackendAction.py index 7f399f983..b3f72b9a8 100644 --- a/grid2op/Action/_BackendAction.py +++ b/grid2op/Action/_BackendAction.py @@ -25,7 +25,7 @@ class ValueStore: def __init__(self, size, dtype): ## TODO at the init it's mandatory to have everything at "1" here # if topo is not "fully connected" it will not work - self.values = np.ones(size, dtype=dtype) + self.values = np.empty(size, dtype=dtype) self.changed = np.full(size, dtype=dt_bool, fill_value=False) self.last_index = 0 self.__size = size @@ -62,7 +62,7 @@ def reset(self): self.last_index = 0 def change_status(self, switch, lineor_id, lineex_id, old_vect): - if not np.any(switch): + if not switch.any(): # nothing is modified so i stop here return @@ -188,6 +188,18 @@ def __deepcopy__(self, memodict={}): res.__size = self.__size return res + def copy(self, other): + """deepcopy, shallow or deep, without having to initialize everything again""" + self.values[:] = other.values + self.changed[:] = other.changed + self.last_index = other.last_index + self.__size = other.__size + + def force_unchanged(self, mask, local_bus): + to_unchanged = local_bus == -1 + to_unchanged[~mask] = False + self.changed[to_unchanged] = False + class _BackendAction(GridObjects): """ @@ -206,6 +218,10 @@ def __init__(self): # topo at time t self.current_topo = ValueStore(self.dim_topo, dtype=dt_int) + + # by default everything is on busbar 1 + self.last_topo_registered.values[:] = 1 + self.current_topo.values[:] = 1 # injection at time t self.prod_p = ValueStore(self.n_gen, dtype=dt_float) @@ -239,59 +255,35 @@ def __init__(self): def __deepcopy__(self, memodict={}): res = type(self)() # last connected registered - res.last_topo_registered = copy.deepcopy(self.last_topo_registered) - res.current_topo = copy.deepcopy(self.current_topo) - res.prod_p = copy.deepcopy(self.prod_p) - res.prod_v = copy.deepcopy(self.prod_v) - res.load_p = copy.deepcopy(self.load_p) - res.load_q = copy.deepcopy(self.load_q) - res.storage_power = copy.deepcopy(self.storage_power) - res.activated_bus[:] = self.activated_bus - res.big_topo_to_subid[:] = self.big_topo_to_subid + res.last_topo_registered.copy(self.last_topo_registered) + res.current_topo.copy(self.current_topo) + res.prod_p.copy(self.prod_p) + res.prod_v.copy(self.prod_v) + res.load_p.copy(self.load_p) + res.load_q.copy(self.load_q) + res.storage_power.copy(self.storage_power) + res.activated_bus[:, :] = self.activated_bus + # res.big_topo_to_subid[:] = self.big_topo_to_subid # cste if self.shunts_data_available: - res.shunt_p = copy.deepcopy(self.shunt_p) - res.shunt_q = copy.deepcopy(self.shunt_q) - res.shunt_bus = copy.deepcopy(self.shunt_bus) + res.shunt_p.copy(self.shunt_p) + res.shunt_q.copy(self.shunt_q) + res.shunt_bus.copy(self.shunt_bus) res._status_or_before[:] = self._status_or_before res._status_ex_before[:] = self._status_ex_before res._status_or[:] = self._status_or res._status_ex[:] = self._status_ex - + res._loads_bus = copy.deepcopy(self._loads_bus) res._gens_bus = copy.deepcopy(self._gens_bus) res._lines_or_bus = copy.deepcopy(self._lines_or_bus) res._lines_ex_bus = copy.deepcopy(self._lines_ex_bus) res._storage_bus = copy.deepcopy(self._storage_bus) + return res def __copy__(self): - res = type(self)() - # last connected registered - res.last_topo_registered = copy.copy(self.last_topo_registered) - res.current_topo = copy.copy(self.current_topo) - res.prod_p = copy.copy(self.prod_p) - res.prod_v = copy.copy(self.prod_v) - res.load_p = copy.copy(self.load_p) - res.load_q = copy.copy(self.load_q) - res.storage_power = copy.copy(self.storage_power) - res.activated_bus[:] = self.activated_bus - res.big_topo_to_subid[:] = self.big_topo_to_subid - if self.shunts_data_available: - res.shunt_p = copy.copy(self.shunt_p) - res.shunt_q = copy.copy(self.shunt_q) - res.shunt_bus = copy.copy(self.shunt_bus) - - res._status_or_before[:] = self._status_or_before - res._status_ex_before[:] = self._status_ex_before - res._status_or[:] = self._status_or - res._status_ex[:] = self._status_ex - - res._loads_bus = copy.copy(self._loads_bus) - res._gens_bus = copy.copy(self._gens_bus) - res._lines_or_bus = copy.copy(self._lines_or_bus) - res._lines_ex_bus = copy.copy(self._lines_ex_bus) - res._storage_bus = copy.copy(self._storage_bus) + res = self.__deepcopy__() # nothing less to do return res def reorder(self, no_load, no_gen, no_topo, no_storage, no_shunt): @@ -490,7 +482,24 @@ def __iadd__(self, other): return self + def _assign_0_to_disco_el(self): + """do not consider disconnected elements are modified for there active / reactive / voltage values""" + gen_changed = self.current_topo.changed[type(self).gen_pos_topo_vect] + gen_bus = self.current_topo.values[type(self).gen_pos_topo_vect] + self.prod_p.force_unchanged(gen_changed, gen_bus) + self.prod_v.force_unchanged(gen_changed, gen_bus) + + load_changed = self.current_topo.changed[type(self).load_pos_topo_vect] + load_bus = self.current_topo.values[type(self).load_pos_topo_vect] + self.load_p.force_unchanged(load_changed, load_bus) + self.load_q.force_unchanged(load_changed, load_bus) + + sto_changed = self.current_topo.changed[type(self).storage_pos_topo_vect] + sto_bus = self.current_topo.values[type(self).storage_pos_topo_vect] + self.storage_power.force_unchanged(sto_changed, sto_bus) + def __call__(self): + self._assign_0_to_disco_el() injections = ( self.prod_p, self.prod_v, @@ -565,9 +574,10 @@ def get_storages_bus_global(self): return self._aux_to_global(tmp_, self.storage_to_subid) def _get_active_bus(self): - self.activated_bus[:] = False + self.activated_bus[:, :] = False tmp = self.current_topo.values - 1 - self.activated_bus[self.big_topo_to_subid, tmp] = True + is_el_conn = tmp >= 0 + self.activated_bus[self.big_topo_to_subid[is_el_conn], tmp[is_el_conn]] = True def update_state(self, powerline_disconnected): """ @@ -576,7 +586,7 @@ def update_state(self, powerline_disconnected): Update the internal state. Should be called after the cascading failures """ - if np.any(powerline_disconnected >= 0): + if (powerline_disconnected >= 0).any(): arr_ = np.zeros(powerline_disconnected.shape, dtype=dt_int) arr_[powerline_disconnected >= 0] = -1 self.current_topo.set_status( diff --git a/grid2op/Agent/recoPowerLinePerArea.py b/grid2op/Agent/recoPowerLinePerArea.py index 78c114ef9..31c79d047 100644 --- a/grid2op/Agent/recoPowerLinePerArea.py +++ b/grid2op/Agent/recoPowerLinePerArea.py @@ -44,7 +44,7 @@ def __init__(self, action_space: ActionSpace, areas_by_sub_id: dict): for line_id, subor_id in enumerate(type(action_space).line_or_to_subid): if subor_id in sub_this_area: self.lines_to_area_id[line_id] = aread_id - if np.any(self.lines_to_area_id == -1): + if (self.lines_to_area_id == -1).any(): raise AgentError("some powerline have no area id") self.nb_area = len(areas_by_sub_id) @@ -52,7 +52,7 @@ def act(self, observation: BaseObservation, reward: float, done : bool=False): line_stat_s = observation.line_status cooldown = observation.time_before_cooldown_line can_be_reco = ~line_stat_s & (cooldown == 0) - if not np.any(can_be_reco): + if not can_be_reco.any(): # no line to reconnect return self.action_space() area_used = np.full(self.nb_area, fill_value=False, dtype=bool) diff --git a/grid2op/Agent/recoPowerlineAgent.py b/grid2op/Agent/recoPowerlineAgent.py index 0272b5928..b4373f9bd 100644 --- a/grid2op/Agent/recoPowerlineAgent.py +++ b/grid2op/Agent/recoPowerlineAgent.py @@ -25,7 +25,7 @@ def _get_tested_action(self, observation): line_stat_s = observation.line_status cooldown = observation.time_before_cooldown_line can_be_reco = ~line_stat_s & (cooldown == 0) - if np.any(can_be_reco): + if can_be_reco.any(): res = [ self.action_space({"set_line_status": [(id_, +1)]}) for id_ in np.where(can_be_reco)[0] diff --git a/grid2op/Backend/Backend.py b/grid2op/Backend/Backend.py index d71e97af5..3dfbfebce 100644 --- a/grid2op/Backend/Backend.py +++ b/grid2op/Backend/Backend.py @@ -945,7 +945,7 @@ def next_grid_state(self, env, is_dc=False): ] = True # disconnect the current power lines - if np.sum(to_disc[lines_status]) == 0: + if to_disc[lines_status].sum() == 0: # no powerlines have been disconnected at this time step, i stop the computation there break disconnected_during_cf[to_disc] = ts @@ -1653,7 +1653,7 @@ def get_action_to_set(self): if self.shunts_data_available: p_s, q_s, sh_v, bus_s = self.shunt_info() dict_["shunt"] = {"shunt_bus": bus_s} - if np.sum(bus_s >= 1): + if (bus_s >= 1).sum(): p_s *= (self._sh_vnkv / sh_v) ** 2 q_s *= (self._sh_vnkv / sh_v) ** 2 p_s[bus_s == -1] = np.NaN @@ -1722,7 +1722,7 @@ def update_from_obs(self, obs, force_update=False): dict_["shunt"] = {"shunt_bus": obs._shunt_bus} shunt_co = obs._shunt_bus >= 1 - if np.sum(shunt_co): + if shunt_co.any(): mults = (self._sh_vnkv / obs._shunt_v) ** 2 sh_p = obs._shunt_p * mults sh_q = obs._shunt_q * mults @@ -1791,22 +1791,22 @@ def assert_grid_correct_after_powerflow(self): tmp = self.get_line_status() if tmp.shape[0] != self.n_line: raise IncorrectNumberOfLines('returned by "backend.get_line_status()"') - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise EnvironmentError(type(self).ERR_INIT_POWERFLOW) tmp = self.get_line_flow() if tmp.shape[0] != self.n_line: raise IncorrectNumberOfLines('returned by "backend.get_line_flow()"') - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise EnvironmentError(type(self).ERR_INIT_POWERFLOW) tmp = self.get_thermal_limit() if tmp.shape[0] != self.n_line: raise IncorrectNumberOfLines('returned by "backend.get_thermal_limit()"') - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise EnvironmentError(type(self).ERR_INIT_POWERFLOW) tmp = self.get_line_overflow() if tmp.shape[0] != self.n_line: raise IncorrectNumberOfLines('returned by "backend.get_line_overflow()"') - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise EnvironmentError(type(self).ERR_INIT_POWERFLOW) tmp = self.generators_info() @@ -1857,10 +1857,10 @@ def assert_grid_correct_after_powerflow(self): ) tmp = self.get_topo_vect() - if tmp.shape[0] != np.sum(self.sub_info): + if tmp.shape[0] != self.sub_info.sum(): raise IncorrectNumberOfElements('returned by "backend.get_topo_vect()"') - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise EnvError( 'Some components of "backend.get_topo_vect()" are not finite. This should be integer.' ) diff --git a/grid2op/Backend/PandaPowerBackend.py b/grid2op/Backend/PandaPowerBackend.py index 716e7c039..f220db936 100644 --- a/grid2op/Backend/PandaPowerBackend.py +++ b/grid2op/Backend/PandaPowerBackend.py @@ -276,7 +276,7 @@ def get_nb_active_bus(self): res: :class:`int` The total number of active buses. """ - return np.sum(self._grid.bus["in_service"]) + return self._grid.bus["in_service"].sum() @staticmethod def _load_grid_load_p_mw(grid): @@ -641,7 +641,7 @@ def _init_private_attrs(self): self._what_object_where[sub_id].append(("storage", "bus", i)) - self.dim_topo = np.sum(self.sub_info) + self.dim_topo = self.sub_info.sum() self._compute_pos_big_topo() # utilities for imeplementing apply_action @@ -823,11 +823,11 @@ def apply_action(self, backendAction=None): bus_is[i + self.__nb_bus_before] = bus2_status tmp_prod_p = self._get_vector_inj["prod_p"](self._grid) - if np.any(prod_p.changed): + if (prod_p.changed).any(): tmp_prod_p.iloc[prod_p.changed] = prod_p.values[prod_p.changed] tmp_prod_v = self._get_vector_inj["prod_v"](self._grid) - if np.any(prod_v.changed): + if (prod_v.changed).any(): tmp_prod_v.iloc[prod_v.changed] = ( prod_v.values[prod_v.changed] / self.prod_pu_to_kv[prod_v.changed] ) @@ -837,17 +837,17 @@ def apply_action(self, backendAction=None): self._grid["ext_grid"]["vm_pu"] = 1.0 * tmp_prod_v[self._id_bus_added] tmp_load_p = self._get_vector_inj["load_p"](self._grid) - if np.any(load_p.changed): + if (load_p.changed).any(): tmp_load_p.iloc[load_p.changed] = load_p.values[load_p.changed] tmp_load_q = self._get_vector_inj["load_q"](self._grid) - if np.any(load_q.changed): + if (load_q.changed).any(): tmp_load_q.iloc[load_q.changed] = load_q.values[load_q.changed] if self.n_storage > 0: # active setpoint tmp_stor_p = self._grid.storage["p_mw"] - if np.any(storage.changed): + if (storage.changed).any(): tmp_stor_p.iloc[storage.changed] = storage.values[storage.changed] # topology of the storage @@ -870,15 +870,15 @@ def apply_action(self, backendAction=None): if type(backendAction).shunts_data_available: shunt_p, shunt_q, shunt_bus = shunts__ - if np.any(shunt_p.changed): + if (shunt_p.changed).any(): self._grid.shunt["p_mw"].iloc[shunt_p.changed] = shunt_p.values[ shunt_p.changed ] - if np.any(shunt_q.changed): + if (shunt_q.changed).any(): self._grid.shunt["q_mvar"].iloc[shunt_q.changed] = shunt_q.values[ shunt_q.changed ] - if np.any(shunt_bus.changed): + if (shunt_bus.changed).any(): sh_service = shunt_bus.values[shunt_bus.changed] != -1 self._grid.shunt["in_service"].iloc[shunt_bus.changed] = sh_service chg_and_in_service = sh_service & shunt_bus.changed @@ -1010,14 +1010,14 @@ def runpf(self, is_dc=False): else: self._pf_init = "auto" - if np.any(~self._grid.load["in_service"]): + if (~self._grid.load["in_service"]).any(): # TODO see if there is a better way here -> do not handle this here, but rather in Backend._next_grid_state raise pp.powerflow.LoadflowNotConverged("Disconnected load: for now grid2op cannot handle properly" " disconnected load. If you want to disconnect one, say it" " consumes 0. instead. Please check loads: " f"{np.where(~self._grid.load['in_service'])[0]}" ) - if np.any(~self._grid.gen["in_service"]): + if (~self._grid.gen["in_service"]).any(): # TODO see if there is a better way here -> do not handle this here, but rather in Backend._next_grid_state raise pp.powerflow.LoadflowNotConverged("Disconnected gen: for now grid2op cannot handle properly" " disconnected generators. If you want to disconnect one, say it" @@ -1131,7 +1131,7 @@ def runpf(self, is_dc=False): self.storage_theta[:], ) = self._storages_info() deact_storage = ~np.isfinite(self.storage_v) - if np.any(np.abs(self.storage_p[deact_storage]) > self.tol): + if (np.abs(self.storage_p[deact_storage]) > self.tol).any(): raise pp.powerflow.LoadflowNotConverged( "Isolated storage set to absorb / produce something" ) diff --git a/grid2op/Chronics/GSFFWFWM.py b/grid2op/Chronics/GSFFWFWM.py index 6c9ff44dc..fc09e16e3 100644 --- a/grid2op/Chronics/GSFFWFWM.py +++ b/grid2op/Chronics/GSFFWFWM.py @@ -181,7 +181,7 @@ def _generate_matenance_static(name_line, idx_line_maintenance = np.array( [el in line_to_maintenance for el in columnsNames] ) - nb_line_maint = np.sum(idx_line_maintenance) + nb_line_maint = idx_line_maintenance.sum() if nb_line_maint == 0: # TODO log something there ! return res @@ -240,7 +240,7 @@ def _generate_matenance_static(name_line, size=n_lines_maintenance, ) - n_Generated_Maintenance = np.sum(are_lines_in_maintenance) + n_Generated_Maintenance = are_lines_in_maintenance.sum() # check if the number of maintenance is not above the max allowed. otherwise randomly pick up the right # number if n_Generated_Maintenance > maxDailyMaintenance: diff --git a/grid2op/Chronics/multiFolder.py b/grid2op/Chronics/multiFolder.py index f4612ea50..1ed6c3ba4 100644 --- a/grid2op/Chronics/multiFolder.py +++ b/grid2op/Chronics/multiFolder.py @@ -341,7 +341,7 @@ def sample_next_chronics(self, probabilities=None): probabilities = np.ones(self._order.shape[0]) # make sure it sums to 1 - probabilities /= np.sum(probabilities) + probabilities /= probabilities.sum() # take one at "random" among these selected = self.space_prng.choice(self._order, p=probabilities) id_sel = np.where(self._order == selected)[0] diff --git a/grid2op/Converter/AnalogStateConverter.py b/grid2op/Converter/AnalogStateConverter.py index d03507344..f3dbc1a8b 100644 --- a/grid2op/Converter/AnalogStateConverter.py +++ b/grid2op/Converter/AnalogStateConverter.py @@ -230,7 +230,7 @@ def size_obs(obs): obs.n_line * 5, ] ) - return np.sum(dims) + return dims.sum() @staticmethod def netbus_to_act_setbus(obs, net_bus): @@ -286,7 +286,7 @@ def netbus_rnd(obs, n_bus=2): # Pick the elements to change at random rnd_sub_elems = np.random.randint(0, n_elem, rnd_n_changes) # Set the topo vect - sub_topo_pos = np.sum(obs.sub_info[0:rnd_sub]) + sub_topo_pos = obs.sub_info[0:rnd_sub].sum() for elem_pos in rnd_sub_elems: rnd_bus = np.random.randint(n_bus) rnd_topo[rnd_bus][sub_topo_pos + elem_pos] = 1.0 diff --git a/grid2op/Converter/BackendConverter.py b/grid2op/Converter/BackendConverter.py index 141843889..f3ca3868d 100644 --- a/grid2op/Converter/BackendConverter.py +++ b/grid2op/Converter/BackendConverter.py @@ -487,7 +487,7 @@ def assert_grid_correct(self): assert np.all(sorted(self._topo_sr2tg[self._topo_tg2sr]) == np.arange(self.dim_topo)) topo_sr2tg_without_storage = self._topo_sr2tg[self._topo_sr2tg >= 0] - assert np.sum(self._topo_sr2tg == -1) == tg_cls.n_storage + assert (self._topo_sr2tg == -1).sum() == tg_cls.n_storage assert np.all(self._topo_tg2sr[topo_sr2tg_without_storage] >= 0) target_without_storage = np.array([i for i in range(tg_cls.dim_topo) if not i in tg_cls.storage_pos_topo_vect]) diff --git a/grid2op/Converter/ConnectivityConverter.py b/grid2op/Converter/ConnectivityConverter.py index 4a8640169..26c9b2604 100644 --- a/grid2op/Converter/ConnectivityConverter.py +++ b/grid2op/Converter/ConnectivityConverter.py @@ -378,7 +378,7 @@ def convert_act(self, encoded_act, explore=None): raise RuntimeError( f"Invalid encoded_act shape provided it should be {self.n}" ) - if np.any((encoded_act < -1.0) | (encoded_act > 1.0)): + if ((encoded_act < -1.0) | (encoded_act > 1.0)).abs(): errors = (encoded_act < -1.0) | (encoded_act > 1.0) indexes = np.where(errors)[0] raise RuntimeError( @@ -503,7 +503,7 @@ def _compute_disagreement(self, encoded_act, topo_vect): ) # for the elements that are not affected by the action (i don't know where they will be: maximum penalty) not_set = np.full( - np.sum(((bus_el1 == 0) | (bus_el2 == 0)) & set_component), + (((bus_el1 == 0) | (bus_el2 == 0)) & set_component).sum(), fill_value=2, dtype=dt_int, ) diff --git a/grid2op/Environment/BaseEnv.py b/grid2op/Environment/BaseEnv.py index d24d159a9..90cbdbacb 100644 --- a/grid2op/Environment/BaseEnv.py +++ b/grid2op/Environment/BaseEnv.py @@ -1674,7 +1674,7 @@ def set_thermal_limit(self, thermal_limit): "Attempt to set thermal limit on {} powerlines while there are {}" "on the grid".format(tmp.shape[0], self.n_line) ) - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise Grid2OpException( "Impossible to use non finite value for thermal limits." ) @@ -1748,7 +1748,7 @@ def _prepare_redisp(self, action, new_p, already_modified_gen): ): return valid, except_, info_ # check that everything is consistent with pmin, pmax: - if np.any(self._target_dispatch > self.gen_pmax - self.gen_pmin): + if (self._target_dispatch > self.gen_pmax - self.gen_pmin).any(): # action is invalid, the target redispatching would be above pmax for at least a generator cond_invalid = self._target_dispatch > self.gen_pmax - self.gen_pmin except_ = InvalidRedispatching( @@ -1760,7 +1760,7 @@ def _prepare_redisp(self, action, new_p, already_modified_gen): ) self._target_dispatch -= redisp_act_orig return valid, except_, info_ - if np.any(self._target_dispatch < self.gen_pmin - self.gen_pmax): + if (self._target_dispatch < self.gen_pmin - self.gen_pmax).any(): # action is invalid, the target redispatching would be below pmin for at least a generator cond_invalid = self._target_dispatch < self.gen_pmin - self.gen_pmax except_ = InvalidRedispatching( @@ -1774,7 +1774,7 @@ def _prepare_redisp(self, action, new_p, already_modified_gen): return valid, except_, info_ # i can't redispatch turned off generators [turned off generators need to be turned on before redispatching] - if np.any(redisp_act_orig[new_p == 0.0]) and self._forbid_dispatch_off: + if (redisp_act_orig[new_p == 0.0]).any() and self._forbid_dispatch_off: # action is invalid, a generator has been redispatched, but it's turned off except_ = InvalidRedispatching( "Impossible to dispatch a turned off generator" @@ -1785,7 +1785,7 @@ def _prepare_redisp(self, action, new_p, already_modified_gen): if self._forbid_dispatch_off is True: redisp_act_orig_cut = 1.0 * redisp_act_orig redisp_act_orig_cut[new_p == 0.0] = 0.0 - if np.any(redisp_act_orig_cut != redisp_act_orig): + if (redisp_act_orig_cut != redisp_act_orig).any(): info_.append( { "INFO: redispatching cut because generator will be turned_off": np.where( @@ -1804,7 +1804,7 @@ def _make_redisp(self, already_modified_gen, new_p): mismatch = self._actual_dispatch - self._target_dispatch mismatch = np.abs(mismatch) if ( - np.abs(np.sum(self._actual_dispatch)) >= self._tol_poly + np.abs((self._actual_dispatch).sum()) >= self._tol_poly or np.max(mismatch) >= self._tol_poly or np.abs(self._amount_storage) >= self._tol_poly or np.abs(self._sum_curtailment_mw) >= self._tol_poly @@ -1886,7 +1886,7 @@ def _compute_dispatch_vect(self, already_modified_gen, new_p): ) already_modified_gen_me = already_modified_gen[gen_participating] target_vals_me = target_vals[already_modified_gen_me] - nb_dispatchable = np.sum(gen_participating) + nb_dispatchable = gen_participating.sum() tmp_zeros = np.zeros((1, nb_dispatchable), dtype=dt_float) coeffs = 1.0 / ( self.gen_max_ramp_up + self.gen_max_ramp_down + self._epsilon_poly @@ -1909,7 +1909,7 @@ def _compute_dispatch_vect(self, already_modified_gen, new_p): # see https://stackoverflow.com/questions/11155721/positive-directional-derivative-for-linesearch # where they advised to scale the function - scale_objective = max(0.5 * np.sum(np.abs(target_vals_me_optim)) ** 2, 1.0) + scale_objective = max(0.5 * np.abs(target_vals_me_optim).sum() ** 2, 1.0) scale_objective = np.round(scale_objective, decimals=4) scale_objective = dt_float(scale_objective) @@ -1969,8 +1969,8 @@ def _compute_dispatch_vect(self, already_modified_gen, new_p): # choose a good initial point (close to the solution) # the idea here is to chose a initial point that would be close to the # desired solution (split the (sum of the) dispatch to the available generators) - x0 = np.zeros(np.sum(gen_participating)) - if np.any(self._target_dispatch != 0.) or np.any(already_modified_gen): + x0 = np.zeros(gen_participating.sum()) + if (self._target_dispatch != 0.).any() or already_modified_gen.any(): gen_for_x0 = self._target_dispatch[gen_participating] != 0. gen_for_x0 |= already_modified_gen[gen_participating] x0[gen_for_x0] = ( @@ -1984,9 +1984,9 @@ def _compute_dispatch_vect(self, already_modified_gen, new_p): # in this "if" block I set the other component of x0 to # their "right" value can_adjust = (x0 == 0.0) - if np.any(can_adjust): - init_sum = np.sum(x0) - denom_adjust = np.sum(1.0 / weights[can_adjust]) + if can_adjust.any(): + init_sum = x0.sum() + denom_adjust = (1.0 / weights[can_adjust]).sum() if denom_adjust <= 1e-2: # i don't want to divide by something too cloose to 0. denom_adjust = 1.0 @@ -2064,10 +2064,10 @@ def _detect_infeasible_dispatch(self, incr_in_chronics, avail_down, avail_up): """This function is an attempt to give more detailed log by detecting infeasible dispatch""" except_ = None sum_move = ( - np.sum(incr_in_chronics) + self._amount_storage - self._sum_curtailment_mw + incr_in_chronics.sum() + self._amount_storage - self._sum_curtailment_mw ) - avail_down_sum = np.sum(avail_down) - avail_up_sum = np.sum(avail_up) + avail_down_sum = avail_down.sum() + avail_up_sum = avail_up.sum() gen_setpoint = self._gen_activeprod_t_redisp[self.gen_redispatchable] if sum_move > avail_up_sum: # infeasible because too much is asked @@ -2237,11 +2237,10 @@ def _handle_updown_times(self, gen_up_before, redisp_act): gen_still_connected = gen_up_before & gen_up_after gen_still_disconnected = (~gen_up_before) & (~gen_up_after) - if ( - np.any( + if (( self._gen_downtime[gen_connected_this_timestep] < self.gen_min_downtime[gen_connected_this_timestep] - ) + ).any() and not self._ignore_min_up_down_times ): # i reconnected a generator before the minimum time allowed @@ -2260,10 +2259,10 @@ def _handle_updown_times(self, gen_up_before, redisp_act): self._gen_uptime[gen_connected_this_timestep] = 1 if ( - np.any( + ( self._gen_uptime[gen_disconnected_this] < self.gen_min_uptime[gen_disconnected_this] - ) + ).any() and not self._ignore_min_up_down_times ): # i disconnected a generator before the minimum time allowed @@ -2285,13 +2284,19 @@ def _handle_updown_times(self, gen_up_before, redisp_act): self._gen_downtime[gen_still_disconnected] += 1 return except_ - def get_obs(self, _update_state=True): + def get_obs(self, _update_state=True, _do_copy=True): """ Return the observations of the current environment made by the :class:`grid2op.Agent.BaseAgent`. .. note:: This function is called twice when the env is reset, otherwise once per step + _do_copy : + .. versionadded: 1.9.2 + + Whether or not to make a copy of the returned observation. By default it will do one. Be aware that + this might cause trouble if used incorrectly. + Returns ------- res: :class:`grid2op.Observation.BaseObservation` @@ -2328,8 +2333,11 @@ def get_obs(self, _update_state=True): self._last_obs = self._observation_space( env=self, _update_state=_update_state ) - - return self._last_obs.copy() + if _do_copy: + # return self._last_obs.copy() + return copy.deepcopy(self._last_obs) + else: + return self._last_obs def get_thermal_limit(self): """ @@ -2420,10 +2428,10 @@ def _compute_storage(self, action_storage_power): coeff_p_to_E = ( self.delta_time_seconds / 3600.0 ) # TODO optim this is const for all time steps - if np.any(storage_act): + if storage_act.any(): modif = True this_act_stor = action_storage_power[storage_act] - eff_ = np.ones(np.sum(storage_act)) + eff_ = np.ones(storage_act.sum()) if self._parameters.ACTIVATE_STORAGE_LOSS: fill_storage = ( this_act_stor > 0.0 @@ -2446,7 +2454,7 @@ def _compute_storage(self, action_storage_power): if modif: # indx when there is too much energy on the battery indx_too_high = self._storage_current_charge > self.storage_Emax - if np.any(indx_too_high): + if indx_too_high.any(): delta_ = ( self._storage_current_charge[indx_too_high] - self.storage_Emax[indx_too_high] @@ -2458,7 +2466,7 @@ def _compute_storage(self, action_storage_power): # indx when there is not enough energy on the battery indx_too_low = self._storage_current_charge < self.storage_Emin - if np.any(indx_too_low): + if indx_too_low.any(): delta_ = ( self._storage_current_charge[indx_too_low] - self.storage_Emin[indx_too_low] @@ -2473,7 +2481,7 @@ def _compute_storage(self, action_storage_power): ) # storage is "load convention", dispatch is "generator convention" # i need the generator to have the same sign as the action on the batteries - self._amount_storage = np.sum(self._storage_power) + self._amount_storage = self._storage_power.sum() else: # battery effect should be removed, so i multiply it by -1. self._amount_storage = 0.0 @@ -2510,10 +2518,10 @@ def _compute_max_ramp_this_step(self, new_p): self.gen_pmin[self.gen_redispatchable], ) - max_total_up = np.sum(th_max - new_p[self.gen_redispatchable]) - max_total_down = np.sum( + max_total_up = (th_max - new_p[self.gen_redispatchable]).sum() + max_total_down = ( th_min - new_p[self.gen_redispatchable] - ) # TODO is that it ? + ).sum() # TODO is that it ? return max_total_down, max_total_up def _aux_update_curtail_env_act(self, new_p): @@ -2543,7 +2551,7 @@ def _aux_compute_new_p_curtailment(self, new_p, curtailment_vect): def _aux_handle_curtailment_without_limit(self, action, new_p): """modifies the new_p argument !!!! (but not the action)""" if self.redispatching_unit_commitment_availble and ( - action._modif_curtailment or np.any(self._limit_curtailment != 1.0) + action._modif_curtailment or (self._limit_curtailment != 1.0).any() ): self._aux_update_curtailment_act(action) @@ -2552,8 +2560,8 @@ def _aux_handle_curtailment_without_limit(self, action, new_p): ) tmp_sum_curtailment_mw = dt_float( - np.sum(new_p[gen_curtailed]) - - np.sum(self._gen_before_curtailment[gen_curtailed]) + new_p[gen_curtailed].sum() + - self._gen_before_curtailment[gen_curtailed].sum() ) self._sum_curtailment_mw = ( @@ -2653,7 +2661,7 @@ def _aux_limit_curtail_storage_if_needed(self, new_p, new_p_th, gen_curtailed): avail_up = np.minimum(p_max_up, self.gen_max_ramp_up[gen_redisp]) sum_move = ( - np.sum(normal_increase) + self._amount_storage - self._sum_curtailment_mw + normal_increase.sum() + self._amount_storage - self._sum_curtailment_mw ) total_storage_curtail = self._amount_storage - self._sum_curtailment_mw update_env_act = False @@ -2661,19 +2669,19 @@ def _aux_limit_curtail_storage_if_needed(self, new_p, new_p_th, gen_curtailed): if abs(total_storage_curtail) >= self._tol_poly: # if there is an impact on the curtailment / storage (otherwise I cannot fix anything) too_much = 0.0 - if sum_move > np.sum(avail_up): + if sum_move > avail_up.sum(): # I need to limit curtailment (not enough ramps up available) - too_much = dt_float(sum_move - np.sum(avail_up) + self._tol_poly) + too_much = dt_float(sum_move - avail_up.sum() + self._tol_poly) self._limited_before = too_much - elif sum_move < np.sum(avail_down): + elif sum_move < avail_down.sum(): # I need to limit storage unit (not enough ramps down available) - too_much = dt_float(sum_move - np.sum(avail_down) - self._tol_poly) + too_much = dt_float(sum_move - avail_down.sum() - self._tol_poly) self._limited_before = too_much elif np.abs(self._limited_before) >= self._tol_poly: # adjust the "mess" I did before by not curtailing enough # max_action = self.gen_pmax[gen_curtailed] * self._limit_curtailment[gen_curtailed] update_env_act = True - too_much = min(np.sum(avail_up) - self._tol_poly, self._limited_before) + too_much = min(avail_up.sum() - self._tol_poly, self._limited_before) self._limited_before -= too_much too_much = self._limited_before @@ -3260,7 +3268,7 @@ def step(self, action: BaseAction) -> Tuple[BaseObservation, float, bool, dict]: self._is_alert_used_in_reward = ( self._reward_helper.template_reward.is_alert_used ) - self.current_obs = self.get_obs(_update_state=False) + self.current_obs = self.get_obs(_update_state=False, _do_copy=False) # update the observation so when it's plotted everything is "shutdown" self.current_obs.set_game_over(self) diff --git a/grid2op/Environment/BaseMultiProcessEnv.py b/grid2op/Environment/BaseMultiProcessEnv.py index 8c6130a75..da49f917a 100644 --- a/grid2op/Environment/BaseMultiProcessEnv.py +++ b/grid2op/Environment/BaseMultiProcessEnv.py @@ -158,7 +158,7 @@ def run(self): data = self.env.action_space.from_vect(data) obs, reward, done, info = self.env.step(data) obs_v = obs.to_vect() - if done or np.any(~np.isfinite(obs_v)): + if done or (~np.isfinite(obs_v)).any(): # if done do a reset res_obs = self.get_obs_ifnotconv() elif self._obs_to_vect: diff --git a/grid2op/Environment/Environment.py b/grid2op/Environment/Environment.py index 00ffac583..98f6eab2e 100644 --- a/grid2op/Environment/Environment.py +++ b/grid2op/Environment/Environment.py @@ -512,7 +512,7 @@ def _handle_compat_glop_version(self, need_process_backend): # deals with the "sub_pos" vector for sub_id in range(cls_bk.n_sub): - if np.any(cls_bk.storage_to_subid == sub_id): + if (cls_bk.storage_to_subid == sub_id).any(): stor_ids = np.where(cls_bk.storage_to_subid == sub_id)[0] stor_locs = cls_bk.storage_to_sub_pos[stor_ids] for stor_loc in sorted(stor_locs, reverse=True): @@ -534,7 +534,7 @@ def _handle_compat_glop_version(self, need_process_backend): # remove storage from the number of element in the substation for sub_id in range(cls_bk.n_sub): - cls_bk.sub_info[sub_id] -= np.sum(cls_bk.storage_to_subid == sub_id) + cls_bk.sub_info[sub_id] -= (cls_bk.storage_to_subid == sub_id).sum() # remove storage from the total number of element cls_bk.dim_topo -= cls_bk.n_storage diff --git a/grid2op/Environment/MultiEnvMultiProcess.py b/grid2op/Environment/MultiEnvMultiProcess.py index 1e351339c..cf07296b6 100644 --- a/grid2op/Environment/MultiEnvMultiProcess.py +++ b/grid2op/Environment/MultiEnvMultiProcess.py @@ -67,14 +67,14 @@ def __init__(self, envs, nb_envs, obs_as_class=True, return_info=True, logger=No 'convert it to such with error "{}"'.format(exc_) ) - if np.any(nb_envs < 0): + if (nb_envs < 0).any(): raise MultiEnvException( 'You ask to perform "{}" copy of an environment. This is a negative ' 'integer. I cannot do that. Please make sure "nb_envs" argument ' "is all made of strictly positive integers and not {}." "".format(np.min(nb_envs), nb_envs) ) - if np.any(nb_envs == 0): + if (nb_envs == 0).any(): raise MultiEnvException( "You ask to perform 0 copy of an environment. This is not supported at " 'the moment. Please make sure "nb_envs" argument ' diff --git a/grid2op/Environment/_ObsEnv.py b/grid2op/Environment/_ObsEnv.py index fd57345bf..6b9a18e26 100644 --- a/grid2op/Environment/_ObsEnv.py +++ b/grid2op/Environment/_ObsEnv.py @@ -327,7 +327,7 @@ def init( reconnected, first_ts_maintenance, ) = self._update_vector_with_timestep(time_step, is_overflow) - if np.any(first_ts_maintenance): + if first_ts_maintenance.any(): set_status = np.array(self._line_status_me, dtype=dt_int) set_status[first_ts_maintenance] = -1 topo_vect = np.array(self._topo_vect, dtype=dt_int) @@ -337,7 +337,7 @@ def init( set_status = self._line_status_me topo_vect = self._topo_vect - if np.any(still_in_maintenance): + if still_in_maintenance.any(): set_status[still_in_maintenance] = -1 topo_vect = np.array(self._topo_vect, dtype=dt_int) topo_vect[self.line_or_pos_topo_vect[still_in_maintenance]] = -1 @@ -451,7 +451,7 @@ def simulate(self, action): obs, reward, done, info = self.step(action) return obs, reward, done, info - def get_obs(self, _update_state=True): + def get_obs(self, _update_state=True, _do_copy=True): """ INTERNAL @@ -469,7 +469,12 @@ def get_obs(self, _update_state=True): "environment that cannot be copied.") if _update_state: self.current_obs.update(self, with_forecast=False) - res = self.current_obs.copy() + + if _do_copy: + # res = self.current_obs.copy() + res = copy.deepcopy(self.current_obs) + else: + res = self.current_obs return res def update_grid(self, env): diff --git a/grid2op/Observation/baseObservation.py b/grid2op/Observation/baseObservation.py index 4dff51ecf..ca2aa11ae 100644 --- a/grid2op/Observation/baseObservation.py +++ b/grid2op/Observation/baseObservation.py @@ -992,10 +992,10 @@ def state_of( ) ) - beg_ = int(np.sum(self.sub_info[:substation_id])) + beg_ = int(self.sub_info[:substation_id].sum()) end_ = int(beg_ + self.sub_info[substation_id]) topo_sub = self.topo_vect[beg_:end_] - if np.any(topo_sub > 0): + if (topo_sub > 0).any(): nb_bus = ( np.max(topo_sub[topo_sub > 0]) - np.min(topo_sub[topo_sub > 0]) + 1 ) @@ -1400,7 +1400,7 @@ def __compare_stats(self, other, name): # first special case: there can be Nan there me_finite = np.isfinite(attr_me) oth_finite = np.isfinite(attr_other) - if np.any(me_finite != oth_finite): + if (me_finite != oth_finite).any(): return False # special case of floating points, otherwise vector are never equal if not np.all( @@ -1538,7 +1538,7 @@ def where_different(self, other): for attr_nm in self._attr_eq: array_ = getattr(diff_, attr_nm) if array_.dtype == dt_bool: - if np.any(~array_): + if (~array_).any(): res.append(attr_nm) else: if (array_.shape[0] > 0) and np.max(np.abs(array_)): @@ -2024,13 +2024,13 @@ def flow_bus_matrix(self, active_flow=True, as_csr_matrix=False): if self.shunts_data_available: sh_vect = self._shunt_q - nb_lor = np.sum(lor_conn) - nb_lex = np.sum(lex_conn) + nb_lor = lor_conn.sum() + nb_lex = lex_conn.sum() data = np.zeros(nb_bus + nb_lor + nb_lex, dtype=dt_float) # if two generators / loads / storage unit are connected at the same bus # this is why i go with matrix product and sparse matrices - nb_prod = np.sum(prod_conn) + nb_prod = prod_conn.sum() if nb_prod: bus_prod = np.arange(prod_bus[prod_conn].max() + 1) map_mat = csr_matrix( @@ -2041,7 +2041,7 @@ def flow_bus_matrix(self, active_flow=True, as_csr_matrix=False): data[bus_prod] += map_mat.dot(prod_vect[prod_conn]) # handle load - nb_load = np.sum(load_conn) + nb_load = load_conn.sum() if nb_load: bus_load = np.arange(load_bus[load_conn].max() + 1) map_mat = csr_matrix( @@ -2052,7 +2052,7 @@ def flow_bus_matrix(self, active_flow=True, as_csr_matrix=False): data[bus_load] -= map_mat.dot(load_vect[load_conn]) # handle storage - nb_stor = np.sum(stor_conn) + nb_stor = stor_conn.sum() if nb_stor: bus_stor = np.arange(stor_bus[stor_conn].max() + 1) map_mat = csr_matrix( @@ -2064,7 +2064,7 @@ def flow_bus_matrix(self, active_flow=True, as_csr_matrix=False): if self.shunts_data_available: # handle shunts - nb_shunt = np.sum(sh_conn) + nb_shunt = sh_conn.sum() if nb_shunt: bus_shunt = np.arange(sh_bus[sh_conn].max() + 1) map_mat = csr_matrix( @@ -3632,7 +3632,7 @@ def add_act(self, act, issue_warn=True): & (line_ex_set_bus <= 0) & (res.topo_vect[self.line_ex_pos_topo_vect] == -1) ) - if np.any(tmp): + if tmp.any(): id_issue_ex = np.where(tmp)[0] if issue_warn: warnings.warn(error_no_bus_set.format(id_issue_ex)) @@ -3644,7 +3644,7 @@ def add_act(self, act, issue_warn=True): & (line_or_set_bus <= 0) & (res.topo_vect[self.line_or_pos_topo_vect] == -1) ) - if np.any(tmp): + if tmp.any(): id_issue_or = np.where(tmp)[0] if issue_warn: warnings.warn(error_no_bus_set.format(id_issue_or)) @@ -3702,7 +3702,7 @@ def add_act(self, act, issue_warn=True): res.line_status[disco_line] = False # handle reconnected powerlines - if np.any(reco_line): + if reco_line.any(): if "set_bus" in act.authorized_keys: line_ex_set_bus = 1 * act.line_ex_set_bus line_or_set_bus = 1 * act.line_or_set_bus @@ -3711,8 +3711,8 @@ def add_act(self, act, issue_warn=True): line_or_set_bus = np.zeros(res.n_line, dtype=dt_int) if issue_warn and ( - np.any(line_or_set_bus[reco_line] == 0) - or np.any(line_ex_set_bus[reco_line] == 0) + (line_or_set_bus[reco_line] == 0).any() + or (line_ex_set_bus[reco_line] == 0).any() ): warnings.warn( 'A powerline has been reconnected with a "change_status" action without ' @@ -3734,7 +3734,7 @@ def add_act(self, act, issue_warn=True): if "redispatch" in act.authorized_keys: redisp = act.redispatch - if np.any(redisp != 0) and issue_warn: + if (redisp != 0).any() and issue_warn: warnings.warn( "You did redispatching on this action. Redispatching is heavily transformed " "by the environment (consult the documentation about the modeling of the " @@ -3743,7 +3743,7 @@ def add_act(self, act, issue_warn=True): if "set_storage" in act.authorized_keys: storage_p = act.storage_p - if np.any(storage_p != 0) and issue_warn: + if (storage_p != 0).any() and issue_warn: warnings.warn( "You did action on storage units in this action. This implies performing some " "redispatching which is heavily transformed " diff --git a/grid2op/Opponent/BaseActionBudget.py b/grid2op/Opponent/BaseActionBudget.py index d110bd9ef..c9f7c5e3c 100644 --- a/grid2op/Opponent/BaseActionBudget.py +++ b/grid2op/Opponent/BaseActionBudget.py @@ -54,5 +54,5 @@ def __call__(self, attack): "".format(type(attack), self.action_space.actionClass) ) aff_lines, aff_subs = attack.get_topological_impact() - cost = np.sum(aff_lines) + np.sum(aff_subs) + cost = aff_lines.sum() + aff_subs.sum() return cost diff --git a/grid2op/Opponent/WeightedRandomOpponent.py b/grid2op/Opponent/WeightedRandomOpponent.py index ea970711c..a1e9cd549 100644 --- a/grid2op/Opponent/WeightedRandomOpponent.py +++ b/grid2op/Opponent/WeightedRandomOpponent.py @@ -172,7 +172,7 @@ def attack(self, observation, agent_action, env_action, budget, previous_fails): # If all attackable lines are disconnected, do not attack status = observation.line_status[self._lines_ids] - if not np.sum(status): + if not status.sum(): return None, 0 available_attacks = self._attacks[status] diff --git a/grid2op/Plot/BasePlot.py b/grid2op/Plot/BasePlot.py index f1fb6d98b..c5f9d78f4 100644 --- a/grid2op/Plot/BasePlot.py +++ b/grid2op/Plot/BasePlot.py @@ -631,7 +631,7 @@ def _get_topo_coord(self, sub_id, observation, elements): theta_z = [cmath.phase((el - z_sub)) for el in buses_z] # try to have nodes "in opposition" to one another - NN = np.array(nb_co) / np.sum(nb_co) + NN = np.array(nb_co) / nb_co.sum() diff_theta = theta_z[0] - theta_z[1] # alpha = cmath.pi + diff_theta alpha = -cmath.pi + diff_theta diff --git a/grid2op/PlotGrid/BasePlot.py b/grid2op/PlotGrid/BasePlot.py index c921a2066..365425b17 100644 --- a/grid2op/PlotGrid/BasePlot.py +++ b/grid2op/PlotGrid/BasePlot.py @@ -1045,7 +1045,7 @@ def plot_info( # rescaling to have range 0 - 1.0 tmp = observation.prod_p[np.isfinite(observation.prod_p)] - if np.any(np.isfinite(observation.prod_p)): + if (np.isfinite(observation.prod_p)).any(): observation.prod_p -= ( np.min(tmp) - 1e-1 ) # so the min is 1e-1 otherwise 0.0 is plotted as black diff --git a/grid2op/Reward/_alarmScore.py b/grid2op/Reward/_alarmScore.py index 4fa1f2e29..fead57d6b 100644 --- a/grid2op/Reward/_alarmScore.py +++ b/grid2op/Reward/_alarmScore.py @@ -107,11 +107,11 @@ def _lines_disconnected_first(self, disc_lines_at_cascading_time): self.disc_lines_all_before_cascade[step] >= 0 ] = True - if np.sum(disc_lines_to_consider_for_score) == 0: + if disc_lines_to_consider_for_score.sum() == 0: disc_lines_to_consider_for_score = disc_lines_at_cascading_time == 0 # if we are there, it is because we have identified before that the failure is due to disconnected powerlines - assert np.any(disc_lines_to_consider_for_score) + assert (disc_lines_to_consider_for_score).any() # we transform the vector so that disconnected lines have a zero, to be coherent with env._disc_lines return 1 - disc_lines_to_consider_for_score diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index d55d7ef71..e4b9edc27 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -56,15 +56,15 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): self.gen_res_p_before_curtail_list[env.nb_time_step] = gen_nres_p_before_curtail return dt_float(0.) else: - ratio_nres_usage = 100 * np.sum(self.gen_res_p_curtailed_list[1:]) / np.sum(self.gen_res_p_before_curtail_list[1:]) + ratio_nres_usage = 100 * self.gen_res_p_curtailed_list[1:].sum() / self.gen_res_p_before_curtail_list[1:].sum() return self._surlinear_func_curtailment(ratio_nres_usage) @staticmethod def _get_total_nres_usage(env): nres_mask = env.gen_renewable gen_p, *_ = env.backend.generators_info() - gen_nres_p_before_curtail = np.sum(env._gen_before_curtailment[nres_mask]) - gen_nres_p_effective = np.sum(gen_p[nres_mask]) + gen_nres_p_before_curtail = env._gen_before_curtailment[nres_mask].sum() + gen_nres_p_effective = gen_p[nres_mask].sum() return gen_nres_p_effective, gen_nres_p_before_curtail diff --git a/grid2op/Reward/alarmReward.py b/grid2op/Reward/alarmReward.py index 94e9a1eb3..d9d2cf87a 100644 --- a/grid2op/Reward/alarmReward.py +++ b/grid2op/Reward/alarmReward.py @@ -110,7 +110,7 @@ def _mult_for_zone(self, alarm, disc_lines, env): lines_disconnected_first = np.where(disc_lines == 0)[0] if ( - np.sum(alarm) > 1 + alarm.sum() > 1 ): # if we have more than one zone in the alarm, we cannot discrtiminate, no bonus points return res @@ -127,7 +127,7 @@ def _mult_for_zone(self, alarm, disc_lines, env): list_zone_ids = np.where(np.isin(env.alarms_area_names, list_zone_names))[0] # and finally, award some extra points if one of the zone, containing one of the powerline disconnected # by protection is in the alarm - if np.any(alarm[list_zone_ids]): + if alarm[list_zone_ids].any(): res *= self.mult_for_right_zone return res diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 1f3abb29e..49ce6c776 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -181,7 +181,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): # if there is no attack, I do nothing indexes_to_look = (np.arange(-self.time_window, 1) + self._current_id) % self._nrows_array # include current step (hence the np.arange(..., **1**)) ts_attack_in_order = self._ts_attack[indexes_to_look, :] - has_attack = np.any(ts_attack_in_order) + has_attack = (ts_attack_in_order).any() if has_attack: # I need to check the alarm for the attacked lines res = self._compute_score_attack_blackout(env, ts_attack_in_order, indexes_to_look) @@ -189,7 +189,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): # no blackout: i check the first step in the window before me to see if there is an attack, index_window = (self._current_id - self.time_window) % self._nrows_array lines_attack = self._ts_attack[index_window, :] - if np.any(lines_attack): + if lines_attack.any(): # prev_ind = (index_window - 1) % self._nrows_array # I don't need the "-1" because the action is already BEFORE the observation in the reward. prev_ind = index_window diff --git a/grid2op/Reward/distanceReward.py b/grid2op/Reward/distanceReward.py index 1979f415f..310421a7c 100644 --- a/grid2op/Reward/distanceReward.py +++ b/grid2op/Reward/distanceReward.py @@ -45,7 +45,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return self.reward_min # Get topo from env - obs = env.get_obs() + obs = env.get_obs(_do_copy=False) topo = obs.topo_vect idx = 0 diff --git a/grid2op/Reward/economicReward.py b/grid2op/Reward/economicReward.py index a1f219a2f..ff46d994b 100644 --- a/grid2op/Reward/economicReward.py +++ b/grid2op/Reward/economicReward.py @@ -52,14 +52,14 @@ def initialize(self, env): "Impossible to use the EconomicReward reward with an environment without generators" "cost. Please make sure env.redispatching_unit_commitment_availble is available." ) - self.worst_cost = dt_float(np.sum(env.gen_cost_per_MW * env.gen_pmax) * env.delta_time_seconds / 3600.0) + self.worst_cost = dt_float((env.gen_cost_per_MW * env.gen_pmax).sum() * env.delta_time_seconds / 3600.0) def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): if has_error or is_illegal or is_ambiguous: res = self.reward_min else: # compute the cost of the grid - res = dt_float(np.sum(env.get_obs().prod_p * env.gen_cost_per_MW) * env.delta_time_seconds / 3600.0) + res = dt_float((env.get_obs(_do_copy=False).prod_p * env.gen_cost_per_MW).sum() * env.delta_time_seconds / 3600.0) # we want to minimize the cost by maximizing the reward so let's take the opposite res *= dt_float(-1.0) # to be sure it's positive, add the highest possible cost diff --git a/grid2op/Reward/l2RPNReward.py b/grid2op/Reward/l2RPNReward.py index 674e7ae59..c15e5ade7 100644 --- a/grid2op/Reward/l2RPNReward.py +++ b/grid2op/Reward/l2RPNReward.py @@ -55,7 +55,7 @@ def initialize(self, env): def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): if not is_done and not has_error: line_cap = self.__get_lines_capacity_usage(env) - res = np.sum(line_cap) + res = line_cap.sum() else: # no more data to consider, no powerflow has been run, reward is what it is res = self.reward_min diff --git a/grid2op/Reward/l2RPNSandBoxScore.py b/grid2op/Reward/l2RPNSandBoxScore.py index 18b7a7d26..e94b2f2dc 100644 --- a/grid2op/Reward/l2RPNSandBoxScore.py +++ b/grid2op/Reward/l2RPNSandBoxScore.py @@ -56,7 +56,7 @@ def _get_gen_p(self, env): return gen_p def _get_losses(self, env, gen_p, load_p): - return (np.sum(gen_p, dtype=dt_float) - np.sum(load_p, dtype=dt_float)) * env.delta_time_seconds / 3600.0 + return (gen_p.sum(dtype=dt_float) - load_p.sum(dtype=dt_float)) * env.delta_time_seconds / 3600.0 def _get_marginal_cost(self, env): gen_activeprod_t = env._gen_activeprod_t @@ -67,7 +67,7 @@ def _get_marginal_cost(self, env): def _get_redisp_cost(self, env, p_t): actual_dispatch = env._actual_dispatch c_redispatching = ( - np.sum(np.abs(actual_dispatch)) * p_t * env.delta_time_seconds / 3600.0 + np.abs(actual_dispatch).sum() * p_t * env.delta_time_seconds / 3600.0 ) return c_redispatching @@ -86,7 +86,7 @@ def _get_loss_cost(self, env, p_t): return c_loss def _get_storage_cost(self, env, p_t): - c_storage = np.sum(np.abs(env._storage_power)) * p_t * env.delta_time_seconds / 3600.0 + c_storage = np.abs(env._storage_power).sum() * p_t * env.delta_time_seconds / 3600.0 return c_storage def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): diff --git a/grid2op/Reward/l2rpn_wcci2022_scorefun.py b/grid2op/Reward/l2rpn_wcci2022_scorefun.py index 0e30db41c..bb1f51406 100644 --- a/grid2op/Reward/l2rpn_wcci2022_scorefun.py +++ b/grid2op/Reward/l2rpn_wcci2022_scorefun.py @@ -39,5 +39,5 @@ def __init__(self, def _get_storage_cost(self, env, p_t): """storage cost is a flat 10 € / MWh instead of depending on the marginal cost""" - c_storage = np.sum(np.abs(env._storage_power)) * self.storage_cost * env.delta_time_seconds / 3600.0 + c_storage = np.abs(env._storage_power).sum() * self.storage_cost * env.delta_time_seconds / 3600.0 return c_storage diff --git a/grid2op/Reward/linesCapacityReward.py b/grid2op/Reward/linesCapacityReward.py index 50d1ce843..1d71d871f 100644 --- a/grid2op/Reward/linesCapacityReward.py +++ b/grid2op/Reward/linesCapacityReward.py @@ -52,9 +52,9 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): if has_error or is_illegal or is_ambiguous: return self.reward_min - obs = env.get_obs() - n_connected = np.sum(obs.line_status.astype(dt_float)) - usage = np.sum(obs.rho[obs.line_status == True]) + obs = env.get_obs(_do_copy=False) + n_connected = obs.line_status.sum(dytpe=dt_float) + usage = obs.rho[obs.line_status == True].sum() usage = np.clip(usage, 0.0, float(n_connected)) reward = np.interp( n_connected - usage, diff --git a/grid2op/Reward/linesReconnectedReward.py b/grid2op/Reward/linesReconnectedReward.py index ce27f26aa..3715961e1 100644 --- a/grid2op/Reward/linesReconnectedReward.py +++ b/grid2op/Reward/linesReconnectedReward.py @@ -48,7 +48,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return self.reward_min # Get obs from env - obs = env.get_obs() + obs = env.get_obs(_do_copy=False) # All lines ids lines_id = np.arange(env.n_line) diff --git a/grid2op/Reward/redispReward.py b/grid2op/Reward/redispReward.py index 564340a75..7c9e80fdd 100644 --- a/grid2op/Reward/redispReward.py +++ b/grid2op/Reward/redispReward.py @@ -148,10 +148,10 @@ def initialize(self, env): cls_ = type(self) worst_marginal_cost = np.max(env.gen_cost_per_MW) - worst_load = dt_float(np.sum(env.gen_pmax)) + worst_load = env.gen_pmax.sum(dtype=dt_float) # it's not the worst, but definitely an upper bound worst_losses = dt_float(cls_._worst_losses_ratio) * worst_load - worst_redisp = cls_._alpha_redisp * np.sum(env.gen_pmax) # not realistic, but an upper bound + worst_redisp = cls_._alpha_redisp * env.gen_pmax.sum() # not realistic, but an upper bound self.max_regret = (worst_losses + worst_redisp) * worst_marginal_cost * env.delta_time_seconds / 3600.0 self.reward_min = dt_float(cls_._min_reward) @@ -181,7 +181,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): gen_p, *_ = env.backend.generators_info() load_p, *_ = env.backend.loads_info() # don't forget to convert MW to MWh ! - losses = (np.sum(gen_p) - np.sum(load_p)) * env.delta_time_seconds / 3600.0 + losses = (gen_p.sum() - load_p.sum()) * env.delta_time_seconds / 3600.0 # compute the marginal cost gen_activeprod_t = env._gen_activeprod_t @@ -190,14 +190,14 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): # redispatching amount actual_dispatch = env._actual_dispatch redisp_cost = ( - self._alpha_redisp * np.sum(np.abs(actual_dispatch)) * marginal_cost * env.delta_time_seconds / 3600.0 + self._alpha_redisp * np.abs(actual_dispatch).sum() * marginal_cost * env.delta_time_seconds / 3600.0 ) # cost of losses losses_cost = losses * marginal_cost # cost of storage - c_storage = np.sum(np.abs(env._storage_power)) * marginal_cost * env.delta_time_seconds / 3600.0 + c_storage = np.abs(env._storage_power).sum() * marginal_cost * env.delta_time_seconds / 3600.0 # total "regret" regret = losses_cost + redisp_cost + c_storage @@ -206,6 +206,6 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): reward = self.max_regret - regret # divide it by load, to be less sensitive to load variation - res = dt_float(reward / np.sum(load_p)) + res = dt_float(reward / load_p.sum()) return res diff --git a/grid2op/Rules/LookParam.py b/grid2op/Rules/LookParam.py index fd4f91cce..13445e612 100644 --- a/grid2op/Rules/LookParam.py +++ b/grid2op/Rules/LookParam.py @@ -34,13 +34,13 @@ def __call__(self, action, env): powerline_status = env.get_current_line_status() aff_lines, aff_subs = action.get_topological_impact(powerline_status) - if np.sum(aff_lines) > env._parameters.MAX_LINE_STATUS_CHANGED: + if aff_lines.sum() > env._parameters.MAX_LINE_STATUS_CHANGED: ids = np.where(aff_lines)[0] return False, IllegalAction( "More than {} line status affected by the action: {}" "".format(env.parameters.MAX_LINE_STATUS_CHANGED, ids) ) - if np.sum(aff_subs) > env._parameters.MAX_SUB_CHANGED: + if aff_subs.sum() > env._parameters.MAX_SUB_CHANGED: ids = np.where(aff_subs)[0] return False, IllegalAction( "More than {} substation affected by the action: {}" diff --git a/grid2op/Rules/PreventDiscoStorageModif.py b/grid2op/Rules/PreventDiscoStorageModif.py index 3f610659d..ba52472f1 100644 --- a/grid2op/Rules/PreventDiscoStorageModif.py +++ b/grid2op/Rules/PreventDiscoStorageModif.py @@ -37,7 +37,7 @@ def __call__(self, action, env): ) not_set_status = storage_set_bus[storage_disco] <= 0 not_change_status = ~storage_change_bus[storage_disco] - if np.any(power_modif_disco & not_set_status & not_change_status): + if (power_modif_disco & not_set_status & not_change_status).any(): tmp_ = power_modif_disco & not_set_status & not_change_status return False, IllegalAction( f"Attempt to modify the power produced / absorbed by a storage unit " diff --git a/grid2op/Rules/PreventReconnection.py b/grid2op/Rules/PreventReconnection.py index 439ec42cc..464c3653e 100644 --- a/grid2op/Rules/PreventReconnection.py +++ b/grid2op/Rules/PreventReconnection.py @@ -35,7 +35,7 @@ def __call__(self, action, env): powerline_status = env.get_current_line_status() aff_lines, aff_subs = action.get_topological_impact(powerline_status) - if np.any(env._times_before_line_status_actionable[aff_lines] > 0): + if (env._times_before_line_status_actionable[aff_lines] > 0).any(): # i tried to act on a powerline too shortly after a previous action # or shut down due to an overflow or opponent or hazards or maintenance ids = np.where((env._times_before_line_status_actionable > 0) & aff_lines)[ @@ -47,7 +47,7 @@ def __call__(self, action, env): ) ) - if np.any(env._times_before_topology_actionable[aff_subs] > 0): + if (env._times_before_topology_actionable[aff_subs] > 0).any(): # I tried to act on a topology too shortly after a previous action ids = np.where((env._times_before_topology_actionable > 0) & aff_subs)[0] return False, IllegalAction( diff --git a/grid2op/Rules/rulesByArea.py b/grid2op/Rules/rulesByArea.py index 5995f62a2..0189178e6 100644 --- a/grid2op/Rules/rulesByArea.py +++ b/grid2op/Rules/rulesByArea.py @@ -100,13 +100,13 @@ def _lookparam_byarea(self, action, env): powerline_status = env.get_current_line_status() aff_lines, aff_subs = action.get_topological_impact(powerline_status) - if any([np.sum(aff_lines[line_ids]) > env._parameters.MAX_LINE_STATUS_CHANGED for line_ids in self.lines_id_by_area.values()]): + if any([(aff_lines[line_ids]).sum() > env._parameters.MAX_LINE_STATUS_CHANGED for line_ids in self.lines_id_by_area.values()]): ids = [[k for k in np.where(aff_lines)[0] if k in line_ids] for line_ids in self.lines_id_by_area.values()] return False, IllegalAction( "More than {} line status affected by the action in one area: {}" "".format(env.parameters.MAX_LINE_STATUS_CHANGED, ids) ) - if any([np.sum(aff_subs[sub_ids]) > env._parameters.MAX_SUB_CHANGED for sub_ids in self.substations_id_by_area.values()]): + if any([(aff_subs[sub_ids]).sum() > env._parameters.MAX_SUB_CHANGED for sub_ids in self.substations_id_by_area.values()]): ids = [[k for k in np.where(aff_subs)[0] if k in sub_ids] for sub_ids in self.substations_id_by_area.values()] return False, IllegalAction( "More than {} substation affected by the action in one area: {}" diff --git a/grid2op/Space/GridObjects.py b/grid2op/Space/GridObjects.py index 887583a1a..53edfb7cc 100644 --- a/grid2op/Space/GridObjects.py +++ b/grid2op/Space/GridObjects.py @@ -1144,8 +1144,8 @@ def from_vect(self, vect, check_legit=True): # if np.any(~np.isfinite(tmp)) and default_nan: # raise NonFiniteElement("None finite number in from_vect detected") - if attr_nm not in type(self).attr_nan_list_set and np.any( - ~np.isfinite(tmp) + if attr_nm not in type(self).attr_nan_list_set and ( + (~np.isfinite(tmp)).any() ): raise NonFiniteElement("None finite number in from_vect detected") @@ -1211,7 +1211,7 @@ def size(self): print("The size of the action space is {}".format(env.action_space.size())) """ - res = np.sum(self.shape()).astype(dt_int) + res = self.shape().sum(dtype=dt_int) return res @classmethod @@ -1234,7 +1234,7 @@ def _aux_pos_big_topo(cls, vect_to_subid, vect_to_sub_pos): """ res = np.zeros(shape=vect_to_subid.shape, dtype=dt_int) for i, (sub_id, my_pos) in enumerate(zip(vect_to_subid, vect_to_sub_pos)): - obj_before = np.sum(cls.sub_info[:sub_id]) + obj_before = cls.sub_info[:sub_id].sum() res[i] = obj_before + my_pos return res @@ -1890,7 +1890,7 @@ def assert_grid_correct_cls(cls): ) ) try: - if np.any(~np.isfinite(tmp)): + if (~np.isfinite(tmp)).any(): raise EnvError( "The grid could not be loaded properly." "One of the vector is made of non finite elements, check the sub_info, *_to_subid, " @@ -1911,7 +1911,7 @@ def assert_grid_correct_cls(cls): "and self.n_sub ({})".format(len(cls.sub_info), cls.n_sub) ) if ( - np.sum(cls.sub_info) + cls.sub_info.sum() != cls.n_load + cls.n_gen + 2 * cls.n_line + cls.n_storage ): err_msg = "The number of elements of elements is not consistent between self.sub_info where there are " @@ -1920,7 +1920,7 @@ def assert_grid_correct_cls(cls): "the _grid ({})." ) err_msg = err_msg.format( - np.sum(cls.sub_info), + cls.sub_info.sum(), cls.n_load + cls.n_gen + 2 * cls.n_line + cls.n_storage, ) raise IncorrectNumberOfElements(err_msg) @@ -2024,7 +2024,7 @@ def assert_grid_correct_cls(cls): cls.storage_pos_topo_vect.flatten(), ) ) - if len(np.unique(concat_topo)) != np.sum(cls.sub_info): + if len(np.unique(concat_topo)) !=cls.sub_info.sum(): raise EnvError( "2 different objects would have the same id in the topology vector, or there would be" "an empty component in this vector." @@ -2069,7 +2069,7 @@ def assert_grid_correct_cls(cls): ) # no empty bus: at least one element should be present on each bus - if np.any(cls.sub_info < 1): + if (cls.sub_info < 1).any(): if not grid2op.Space.space_utils._WARNING_ISSUED_FOR_SUB_NO_ELEM: warnings.warn( f"There are {np.sum(cls.sub_info < 1)} substations where no 'controlable' elements " @@ -2264,76 +2264,76 @@ def _check_validity_storage_data(cls): "self.storage_charging_efficiency.shape[0] != self.n_storage" ) - if np.any(~np.isfinite(cls.storage_Emax)): + if (~np.isfinite(cls.storage_Emax)).any(): raise BackendError("np.any(~np.isfinite(self.storage_Emax))") - if np.any(~np.isfinite(cls.storage_Emin)): + if (~np.isfinite(cls.storage_Emin)).any(): raise BackendError("np.any(~np.isfinite(self.storage_Emin))") - if np.any(~np.isfinite(cls.storage_max_p_prod)): + if (~np.isfinite(cls.storage_max_p_prod)).any(): raise BackendError("np.any(~np.isfinite(self.storage_max_p_prod))") - if np.any(~np.isfinite(cls.storage_max_p_absorb)): + if (~np.isfinite(cls.storage_max_p_absorb)).any(): raise BackendError("np.any(~np.isfinite(self.storage_max_p_absorb))") - if np.any(~np.isfinite(cls.storage_marginal_cost)): + if (~np.isfinite(cls.storage_marginal_cost)).any(): raise BackendError("np.any(~np.isfinite(self.storage_marginal_cost))") - if np.any(~np.isfinite(cls.storage_loss)): + if (~np.isfinite(cls.storage_loss)).any(): raise BackendError("np.any(~np.isfinite(self.storage_loss))") - if np.any(~np.isfinite(cls.storage_charging_efficiency)): + if (~np.isfinite(cls.storage_charging_efficiency)).any(): raise BackendError("np.any(~np.isfinite(self.storage_charging_efficiency))") - if np.any(~np.isfinite(cls.storage_discharging_efficiency)): + if (~np.isfinite(cls.storage_discharging_efficiency)).any(): raise BackendError( "np.any(~np.isfinite(self.storage_discharging_efficiency))" ) - if np.any(cls.storage_Emax < cls.storage_Emin): + if (cls.storage_Emax < cls.storage_Emin).any(): tmp = np.where(cls.storage_Emax < cls.storage_Emin)[0] raise BackendError( f"storage_Emax < storage_Emin for storage units with ids: {tmp}" ) - if np.any(cls.storage_Emax < 0.0): + if (cls.storage_Emax < 0.0).any(): tmp = np.where(cls.storage_Emax < 0.0)[0] raise BackendError( f"self.storage_Emax < 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_Emin < 0.0): + if (cls.storage_Emin < 0.0).any(): tmp = np.where(cls.storage_Emin < 0.0)[0] raise BackendError( f"self.storage_Emin < 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_max_p_prod < 0.0): + if (cls.storage_max_p_prod < 0.0).any(): tmp = np.where(cls.storage_max_p_prod < 0.0)[0] raise BackendError( f"self.storage_max_p_prod < 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_max_p_absorb < 0.0): + if (cls.storage_max_p_absorb < 0.0).any(): tmp = np.where(cls.storage_max_p_absorb < 0.0)[0] raise BackendError( f"self.storage_max_p_absorb < 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_loss < 0.0): + if (cls.storage_loss < 0.0).any(): tmp = np.where(cls.storage_loss < 0.0)[0] raise BackendError( f"self.storage_loss < 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_discharging_efficiency <= 0.0): + if (cls.storage_discharging_efficiency <= 0.0).any(): tmp = np.where(cls.storage_discharging_efficiency <= 0.0)[0] raise BackendError( f"self.storage_discharging_efficiency <= 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_discharging_efficiency > 1.0): + if (cls.storage_discharging_efficiency > 1.0).any(): tmp = np.where(cls.storage_discharging_efficiency > 1.0)[0] raise BackendError( f"self.storage_discharging_efficiency > 1. for storage units with ids: {tmp}" ) - if np.any(cls.storage_charging_efficiency < 0.0): + if (cls.storage_charging_efficiency < 0.0).any(): tmp = np.where(cls.storage_charging_efficiency < 0.0)[0] raise BackendError( f"self.storage_charging_efficiency < 0. for storage units with ids: {tmp}" ) - if np.any(cls.storage_charging_efficiency > 1.0): + if (cls.storage_charging_efficiency > 1.0).any(): tmp = np.where(cls.storage_charging_efficiency > 1.0)[0] raise BackendError( f"self.storage_charging_efficiency > 1. for storage units with ids: {tmp}" ) - if np.any(cls.storage_loss > cls.storage_max_p_absorb): + if (cls.storage_loss > cls.storage_max_p_absorb).any(): tmp = np.where(cls.storage_loss > cls.storage_max_p_absorb)[0] raise BackendError( f"Some storage units are such that their loss (self.storage_loss) is higher " @@ -2522,11 +2522,11 @@ def _check_validity_dispathcing_data(cls): "(gen_renewable) when redispatching is supposed to be available." ) - if np.any(cls.gen_min_uptime < 0): + if (cls.gen_min_uptime < 0).any(): raise InvalidRedispatching( "Minimum uptime of generator (gen_min_uptime) cannot be negative" ) - if np.any(cls.gen_min_downtime < 0): + if (cls.gen_min_downtime < 0).any(): raise InvalidRedispatching( "Minimum downtime of generator (gen_min_downtime) cannot be negative" ) @@ -2535,23 +2535,23 @@ def _check_validity_dispathcing_data(cls): if not el in ["solar", "wind", "hydro", "thermal", "nuclear"]: raise InvalidRedispatching("Unknown generator type : {}".format(el)) - if np.any(cls.gen_pmin < 0.0): + if (cls.gen_pmin < 0.0).any(): raise InvalidRedispatching("One of the Pmin (gen_pmin) is negative") - if np.any(cls.gen_pmax < 0.0): + if (cls.gen_pmax < 0.0).any(): raise InvalidRedispatching("One of the Pmax (gen_pmax) is negative") - if np.any(cls.gen_max_ramp_down < 0.0): + if (cls.gen_max_ramp_down < 0.0).any(): raise InvalidRedispatching( "One of the ramp up (gen_max_ramp_down) is negative" ) - if np.any(cls.gen_max_ramp_up < 0.0): + if (cls.gen_max_ramp_up < 0.0).any(): raise InvalidRedispatching( "One of the ramp down (gen_max_ramp_up) is negative" ) - if np.any(cls.gen_startup_cost < 0.0): + if (cls.gen_startup_cost < 0.0).any(): raise InvalidRedispatching( "One of the start up cost (gen_startup_cost) is negative" ) - if np.any(cls.gen_shutdown_cost < 0.0): + if (cls.gen_shutdown_cost < 0.0).any(): raise InvalidRedispatching( "One of the start up cost (gen_shutdown_cost) is negative" ) @@ -2602,10 +2602,10 @@ def _check_validity_dispathcing_data(cls): "{} should be convertible data should be convertible to " '{} with error: \n"{}"'.format(el, type_, exc_) ) - if np.any( + if ( cls.gen_max_ramp_up[cls.gen_redispatchable] > cls.gen_pmax[cls.gen_redispatchable] - ): + ).any(): raise InvalidRedispatching( "Invalid maximum ramp for some generator (above pmax)" ) @@ -3603,7 +3603,7 @@ class res(GridObjects): cls.n_load = len(cls.name_load) cls.n_line = len(cls.name_line) cls.n_sub = len(cls.name_sub) - cls.dim_topo = np.sum(cls.sub_info) + cls.dim_topo = cls.sub_info.sum() if dict_["gen_type"] is None: cls.redispatching_unit_commitment_availble = False diff --git a/grid2op/gym_compat/box_gym_actspace.py b/grid2op/gym_compat/box_gym_actspace.py index 142f484dd..8c8e438a1 100644 --- a/grid2op/gym_compat/box_gym_actspace.py +++ b/grid2op/gym_compat/box_gym_actspace.py @@ -231,8 +231,8 @@ def __init__( low_gen = -1.0 * act_sp.gen_max_ramp_down[act_sp.gen_redispatchable] high_gen = 1.0 * act_sp.gen_max_ramp_up[act_sp.gen_redispatchable] - nb_redisp = np.sum(act_sp.gen_redispatchable) - nb_curtail = np.sum(act_sp.gen_renewable) + nb_redisp = act_sp.gen_redispatchable.sum() + nb_curtail = act_sp.gen_renewable.sum() curtail = np.full(shape=(nb_curtail,), fill_value=0.0, dtype=dt_float) curtail_mw = np.full(shape=(nb_curtail,), fill_value=0.0, dtype=dt_float) self._dict_properties = { @@ -654,7 +654,7 @@ def normalize_attr(self, attr_nm: str): both_finite = finite_high & finite_low both_finite &= curr_high > curr_low - if np.any(~both_finite): + if (~both_finite).any(): warnings.warn(f"The normalization of attribute \"{both_finite}\" cannot be performed entirely as " f"there are some non finite value, or `high == `low` " f"for some components.") diff --git a/grid2op/gym_compat/box_gym_obsspace.py b/grid2op/gym_compat/box_gym_obsspace.py index 8b2b28d6d..a8a119720 100644 --- a/grid2op/gym_compat/box_gym_obsspace.py +++ b/grid2op/gym_compat/box_gym_obsspace.py @@ -713,7 +713,7 @@ def _get_info(self, functs): elif isinstance(high_, float): high_ = np.full(shape_, fill_value=high_, dtype=dtype_) - if np.any((tmp < low_) | (tmp > high_)): + if ((tmp < low_) | (tmp > high_)).any(): raise RuntimeError( f"Wrong value for low / high in the functs argument for key {el}. Please" f"fix the low_ / high_ in the tuple ( callable_, low_, high_, shape_, dtype_)." @@ -861,7 +861,7 @@ def normalize_attr(self, attr_nm: str): both_finite = finite_high & finite_low both_finite &= curr_high > curr_low - if np.any(~both_finite): + if (~both_finite).any(): warnings.warn(f"The normalization of attribute \"{both_finite}\" cannot be performed entirely as " f"there are some non finite value, or `high == `low` " f"for some components.") diff --git a/grid2op/gym_compat/continuous_to_discrete.py b/grid2op/gym_compat/continuous_to_discrete.py index 653346edd..ad83a37c7 100644 --- a/grid2op/gym_compat/continuous_to_discrete.py +++ b/grid2op/gym_compat/continuous_to_discrete.py @@ -134,7 +134,7 @@ def gym_to_g2op(self, gym_object): def g2op_to_gym(self, g2op_object): mask = self._bins_size >= g2op_object mask = 1 - mask - res = np.sum(mask, axis=0) + res = mask.sum(axis=0) res[self._ignored] = 0 return res diff --git a/grid2op/gym_compat/multidiscrete_gym_actspace.py b/grid2op/gym_compat/multidiscrete_gym_actspace.py index 0cf3545e6..a92620389 100644 --- a/grid2op/gym_compat/multidiscrete_gym_actspace.py +++ b/grid2op/gym_compat/multidiscrete_gym_actspace.py @@ -272,8 +272,8 @@ def __init__(self, grid2op_action_space, attr_to_keep=ALL_ATTR, nb_bins=None): f"how to convert it to a discrete space. See the documentation " f"for more information." ) - nb_redispatch = np.sum(act_sp.gen_redispatchable) - nb_renew = np.sum(act_sp.gen_renewable) + nb_redispatch = act_sp.gen_redispatchable.sum() + nb_renew = act_sp.gen_renewable.sum() if el == "redispatch": self.dict_properties[el] = ( [nb_bins[el] for _ in range(nb_redispatch)], diff --git a/grid2op/gym_compat/utils.py b/grid2op/gym_compat/utils.py index 0a35ebb5d..c8892e43b 100644 --- a/grid2op/gym_compat/utils.py +++ b/grid2op/gym_compat/utils.py @@ -99,7 +99,7 @@ def _compute_extra_power_for_losses(gridobj): """ import numpy as np - return 0.3 * np.sum(np.abs(gridobj.gen_pmax)) + return 0.3 * np.abs(gridobj.gen_pmax).sum() def sample_seed(max_, np_random): diff --git a/grid2op/simulator/simulator.py b/grid2op/simulator/simulator.py index aecca8d7b..66b203e06 100644 --- a/grid2op/simulator/simulator.py +++ b/grid2op/simulator/simulator.py @@ -291,7 +291,7 @@ def _update_obs(self): def _adjust_controlable_gen( self, new_gen_p: np.ndarray, target_dispatch: np.ndarray, sum_target: float ) -> Optional[float]: - nb_dispatchable = np.sum(self.current_obs.gen_redispatchable) + nb_dispatchable = self.current_obs.gen_redispatchable.sum() # which generators needs to be "optimized" -> the one where # the target function matter @@ -319,7 +319,7 @@ def _adjust_controlable_gen( weights = np.ones(nb_dispatchable) * coeffs[self.current_obs.gen_redispatchable] weights /= weights.sum() - scale_objective = max(0.5 * np.sum(np.abs(target_dispatch_redisp)) ** 2, 1.0) + scale_objective = max(0.5 * np.abs(target_dispatch_redisp).sum() ** 2, 1.0) scale_objective = np.round(scale_objective, decimals=4) tmp_zeros = np.zeros((1, nb_dispatchable), dtype=float) @@ -338,7 +338,7 @@ def target(actual_dispatchable): coeffs_quads = weights[gen_in_target] * quad_ coeffs_quads_const = coeffs_quads.sum() coeffs_quads_const /= scale_objective # scaling the function - coeffs_quads_const += 1e-2 * np.sum(actual_dispatchable**2 * weights) + coeffs_quads_const += 1e-2 * (actual_dispatchable**2 * weights).sum() return coeffs_quads_const def jac(actual_dispatchable): @@ -383,9 +383,9 @@ def f(init): # desired solution (split the (sum of the) dispatch to the available generators) x0 = 1.0 * target_dispatch_redisp can_adjust = x0 == 0.0 - if np.any(can_adjust): - init_sum = np.sum(x0) - denom_adjust = np.sum(1.0 / weights[can_adjust]) + if (can_adjust).any(): + init_sum = x0.sum() + denom_adjust = (1.0 / weights[can_adjust]).sum() if denom_adjust <= 1e-2: # i don't want to divide by something too cloose to 0. denom_adjust = 1.0 @@ -405,14 +405,14 @@ def _amount_curtailed( limit_curtail = curt_vect * act.gen_pmax curtailed = np.maximum(new_gen_p - limit_curtail, 0.0) curtailed[~act.gen_renewable] = 0.0 - amount_curtail = np.sum(curtailed) + amount_curtail = curtailed.sum() new_gen_p_after_curtail = 1.0 * new_gen_p new_gen_p_after_curtail -= curtailed return new_gen_p_after_curtail, amount_curtail def _amount_storage(self, act: BaseAction) -> Tuple[float, np.ndarray]: storage_act = 1.0 * act.storage_p - res = np.sum(self.current_obs.storage_power_target) + res = self.current_obs.storage_power_target.sum() current_charge = 1.0 * self.current_obs.storage_charge storage_power = np.zeros(act.n_storage) if np.all(np.abs(storage_act) <= self._tol_redisp): @@ -438,7 +438,7 @@ def _amount_storage(self, act: BaseAction) -> Tuple[float, np.ndarray]: storage_power = storage_act_E / coeff_p_to_E storage_power[do_charge] *= act.storage_charging_efficiency[do_charge] storage_power[do_discharge] /= act.storage_discharging_efficiency[do_discharge] - res += np.sum(storage_power) + res += storage_power.sum() return -res, storage_power, current_charge def _fix_redisp_curtailment_storage( @@ -466,7 +466,7 @@ def _fix_redisp_curtailment_storage( new_vect_redisp ] - if abs(np.sum(target_dispatch) - sum_target) >= self._tol_redisp: + if abs(target_dispatch.sum() - sum_target) >= self._tol_redisp: adjust = self._adjust_controlable_gen( new_gen_p_after_curtail, target_dispatch, sum_target ) diff --git a/grid2op/tests/test_simulate_disco_load.py b/grid2op/tests/test_simulate_disco_load.py new file mode 100644 index 000000000..435c0e3a3 --- /dev/null +++ b/grid2op/tests/test_simulate_disco_load.py @@ -0,0 +1,48 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + + +import numpy as np +import unittest +import warnings + +import grid2op +from lightsim2grid import LightSimBackend + +import pdb + +class TestSimulateDiscoLoad(unittest.TestCase): + def setUp(self) -> None: + """its important to keep the lightims2grid backend here. It tests indirectly that the objects + are properly set to "unchanged" without actually having to check the _BackendAction of + the obs.simulate underlying backend, which is quite annoying""" + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + # this needs to be tested with pandapower backend + self.env = grid2op.make("l2rpn_case14_sandbox", backend=LightSimBackend(), test=True) + self.env.seed(0) + self.env.set_id(0) + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_simulate_ok(self): + obs = self.env.reset() + simo, simr, simd, simi = obs.simulate(self.env.action_space()) + assert not simd + + simo, simr, simd, simi = obs.simulate(self.env.action_space({"set_bus": {"loads_id": [(0, -1)]}})) + assert simd + + simo, simr, simd, simi = obs.simulate(self.env.action_space()) + assert not simd + + +if __name__ == '__main__': + unittest.main() diff --git a/grid2op/utils/l2rpn_2020_scores.py b/grid2op/utils/l2rpn_2020_scores.py index b234c3f08..4eb99aa0b 100644 --- a/grid2op/utils/l2rpn_2020_scores.py +++ b/grid2op/utils/l2rpn_2020_scores.py @@ -244,8 +244,8 @@ def _compute_episode_score( min_losses_ratio = self.min_losses_ratio # remember that first observation do not count (it's generated by the environment) - ep_loads = np.sum(load_p_rp[ids == ep_id, :], axis=1)[1:] - ep_losses = np.sum(prod_p_rp[ids == ep_id, :], axis=1)[1:] - ep_loads + ep_loads = load_p_rp[ids == ep_id, :].sum(axis=1)[1:] + ep_losses = prod_p_rp[ids == ep_id, :].sum(axis=1)[1:] - ep_loads if self.max_step > 0: scores_dn = scores_dn[: self.max_step] @@ -255,13 +255,13 @@ def _compute_episode_score( ep_losses = ep_losses[: self.max_step] # do nothing operationnal cost - ep_do_nothing_operat_cost = np.sum(scores_dn) + ep_do_nothing_operat_cost = scores_dn.sum() ep_do_nothing_operat_cost += ( - np.sum(ep_loads[dn_step_played:]) * ep_marginal_cost + ep_loads[dn_step_played:].sum() * ep_marginal_cost ) # no overflow disconnection cost - ep_do_nothing_nodisc_cost = np.sum(scores_no_ov_rp) + ep_do_nothing_nodisc_cost = scores_no_ov_rp.sum() # this agent cumulated operationnal cost # same as above: i remove the last element which correspond to the last state, so irrelevant @@ -270,17 +270,17 @@ def _compute_episode_score( ) if dn_metadata["max_step"] == self.max_step: ep_cost = ep_cost[:-1] - ep_cost = np.sum(ep_cost) - ep_cost += np.sum(ep_loads[n_played:]) * ep_marginal_cost + ep_cost = ep_cost.Sum() + ep_cost += ep_loads[n_played:].sum() * ep_marginal_cost # Compute ranges worst_operat_cost = ( - np.sum(ep_loads) * ep_marginal_cost + ep_loads.sum() * ep_marginal_cost ) # operational cost corresponding to the min score zero_operat_score = ep_do_nothing_operat_cost nodisc_oeprat_cost = ep_do_nothing_nodisc_cost best_score = ( - np.sum(ep_losses) * min_losses_ratio + ep_losses.sum() * min_losses_ratio ) # operational cost corresponding to the max score # Linear interp episode reward to codalab score From fab1db46d3943e1b20b53ac7364763744c7959a5 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 18 Jul 2023 15:45:20 +0200 Subject: [PATCH 043/103] some more speed ups by avoiding copy of an observation --- CHANGELOG.rst | 6 +++++- _profiling/profiler_simulate.py | 4 ++-- grid2op/Environment/BaseEnv.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 65e943ed3..f43eb501e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -42,7 +42,11 @@ Change Log action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" has the priority and - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance -- [IMPROVED] overall performance of the `simulate` function by improving speed of copy of `_BackendAction` +- [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction` +- [IMPROVED] overall performance of `env.step` / `obs.simulate` by preventing unnecessary observation deep copy +- [IMPROVED] overall performance of `env.step` / `obs.simulate` by switching to `copy.deepcopy(obs)` instead of + `obs.copy()` + [1.9.1] - 2023-07-06 -------------------- - [BREAKING] (slightly): default `gym_compat` module now inherit from `gymnasium` (if diff --git a/_profiling/profiler_simulate.py b/_profiling/profiler_simulate.py index 1becddd89..bb60b3dad 100644 --- a/_profiling/profiler_simulate.py +++ b/_profiling/profiler_simulate.py @@ -79,8 +79,8 @@ def simulate(obs, action_space, nb_simu=NB_SIMULATE, cp=None): cp_env = cProfile.Profile() run_env(env, cp_env, cp_simu) nm_f, ext = os.path.splitext(__file__) - nm_out_simu = f"{nm_f}_{nm_bk_used}_{ENV_NAME}_{NB_SIMULATE}_simu_1.prof" - nm_out_env = f"{nm_f}_{nm_bk_used}_{ENV_NAME}_{NB_SIMULATE}_env_1.prof" + nm_out_simu = f"{nm_f}_{nm_bk_used}_{ENV_NAME}_{NB_SIMULATE}_simu.prof" + nm_out_env = f"{nm_f}_{nm_bk_used}_{ENV_NAME}_{NB_SIMULATE}_env.prof" cp_simu.dump_stats(nm_out_simu) cp_env.dump_stats(nm_out_env) print("You can view profiling results with:\n\tsnakeviz {}".format(nm_out_env)) diff --git a/grid2op/Environment/BaseEnv.py b/grid2op/Environment/BaseEnv.py index 90cbdbacb..0129d6ee0 100644 --- a/grid2op/Environment/BaseEnv.py +++ b/grid2op/Environment/BaseEnv.py @@ -2955,7 +2955,7 @@ def _aux_register_env_converged(self, disc_lines, action, init_line_status, new_ # finally, build the observation (it's a different one at each step, we cannot reuse the same one) # THIS SHOULD BE DONE AFTER EVERYTHING IS INITIALIZED ! - self.current_obs = self.get_obs() + self.current_obs = self.get_obs(_do_copy=False) # TODO storage: get back the result of the storage ! with the illegal action when a storage unit # TODO is non zero and disconnected, this should be ok. self._time_extract_obs += time.perf_counter() - beg_res From 39905e2900d2d300870d36a618055460ceba41f0 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 18 Jul 2023 16:30:12 +0200 Subject: [PATCH 044/103] fixing broken tests --- _profiling/profiler_gym_compat.py | 81 ++++++++++++++++++++++ grid2op/Chronics/multiFolder.py | 18 +++-- grid2op/Converter/ConnectivityConverter.py | 2 +- grid2op/Reward/linesCapacityReward.py | 2 +- grid2op/tests/test_simulate_disco_load.py | 18 ++++- grid2op/utils/l2rpn_2020_scores.py | 2 +- 6 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 _profiling/profiler_gym_compat.py diff --git a/_profiling/profiler_gym_compat.py b/_profiling/profiler_gym_compat.py new file mode 100644 index 000000000..31c0c96e8 --- /dev/null +++ b/_profiling/profiler_gym_compat.py @@ -0,0 +1,81 @@ +# Copyright (c) 2019-2020, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + + +""" +This file aims at profiling a case where the "simulate" function is heavily used. +""" + +import grid2op +from grid2op.gym_compat import GymEnv + +import warnings +try: + from lightsim2grid import LightSimBackend + bk_cls = LightSimBackend + nm_bk_used = "LightSimBackend" + print("LightSimBackend used") +except ImportError: + from grid2op.Backend import PandaPowerBackend + bk_cls = PandaPowerBackend + nm_bk_used = "PandaPowerBackend" + print("PandaPowerBackend used") + +import os +import cProfile +import pdb + + +NB_SIMULATE = 10 +ENV_NAME = "l2rpn_icaps_2021_small" +ENV_NAME = "l2rpn_idf_2023" + + +def make_env(env_name=ENV_NAME): + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + fake_env = grid2op.make(env_name, test=True) + param = fake_env.parameters + param.NO_OVERFLOW_DISCONNECTION = True + env = grid2op.make(env_name, backend=bk_cls(), param=param) + env.seed(0) + env.reset() + gym_env = GymEnv(env) + return gym_env, env + + +def run_env(gym_env, cp_gym_env, env, cp_env): + done = False + while not done: + act = {} + cp_gym_env.enable() + obs, reward, done, truncated, info = gym_env.step(act) + cp_gym_env.disable() + + done = False + while not done: + act = env.action_space() + cp_env.enable() + obs, reward, done, info = env.step(act) + cp_env.disable() + + +if __name__ == "__main__": + gym_env, env = make_env() + cp_gym = cProfile.Profile() + cp_env = cProfile.Profile() + run_env(gym_env, cp_gym, env, cp_env) + nm_f, ext = os.path.splitext(__file__) + nm_out_gym = f"gym_{nm_f}_{nm_bk_used}_{ENV_NAME}_gymenv.prof" + nm_out_env = f"gym_{nm_f}_{nm_bk_used}_{ENV_NAME}_env.prof" + cp_gym.dump_stats(nm_out_gym) + cp_env.dump_stats(nm_out_env) + print("You can view profiling grid2op raw results with:\n\tsnakeviz {}".format(nm_out_env)) + print("You can view profiling gym results with:\n\tsnakeviz {}".format(nm_out_gym)) +# base: 66.7 s +# sans copy dans simulate: 65.2 diff --git a/grid2op/Chronics/multiFolder.py b/grid2op/Chronics/multiFolder.py index 1ed6c3ba4..6be75bf3c 100644 --- a/grid2op/Chronics/multiFolder.py +++ b/grid2op/Chronics/multiFolder.py @@ -12,8 +12,8 @@ import numpy as np from datetime import timedelta, datetime -from grid2op.dtypes import dt_int -from grid2op.Exceptions import * +from grid2op.dtypes import dt_int, dt_float +from grid2op.Exceptions import ChronicsNotFoundError, ChronicsError from grid2op.Chronics.gridValue import GridValue from grid2op.Chronics.gridStateFromFile import GridStateFromFile @@ -339,9 +339,17 @@ def sample_next_chronics(self, probabilities=None): self._prev_cache_id = -1 if probabilities is None: probabilities = np.ones(self._order.shape[0]) - + try: + probabilities = np.array(probabilities, dtype=dt_float) + except Exception as exc_: + raise ChronicsError("Impossible to convert the probablities given to an array of float") from exc_ + + sum_prob = probabilities.sum() + if abs(sum_prob) <= 1e-5: + raise ChronicsError("Impossible to use the given probabilities argument, it sums to 0. (or close enough to it)") + # make sure it sums to 1 - probabilities /= probabilities.sum() + probabilities /= sum_prob # take one at "random" among these selected = self.space_prng.choice(self._order, p=probabilities) id_sel = np.where(self._order == selected)[0] @@ -377,7 +385,7 @@ def reset(self): self._order.append(i) if len(self._order) == 0: - raise RuntimeError( + raise ChronicsError( 'Impossible to initialize the Multifolder. Your "filter_fun" filters out all the ' "possible scenarios." ) diff --git a/grid2op/Converter/ConnectivityConverter.py b/grid2op/Converter/ConnectivityConverter.py index 26c9b2604..7aaaa15ea 100644 --- a/grid2op/Converter/ConnectivityConverter.py +++ b/grid2op/Converter/ConnectivityConverter.py @@ -378,7 +378,7 @@ def convert_act(self, encoded_act, explore=None): raise RuntimeError( f"Invalid encoded_act shape provided it should be {self.n}" ) - if ((encoded_act < -1.0) | (encoded_act > 1.0)).abs(): + if ((encoded_act < -1.0) | (encoded_act > 1.0)).any(): errors = (encoded_act < -1.0) | (encoded_act > 1.0) indexes = np.where(errors)[0] raise RuntimeError( diff --git a/grid2op/Reward/linesCapacityReward.py b/grid2op/Reward/linesCapacityReward.py index 1d71d871f..f4fb19d71 100644 --- a/grid2op/Reward/linesCapacityReward.py +++ b/grid2op/Reward/linesCapacityReward.py @@ -53,7 +53,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return self.reward_min obs = env.get_obs(_do_copy=False) - n_connected = obs.line_status.sum(dytpe=dt_float) + n_connected = dt_float(obs.line_status.sum()) usage = obs.rho[obs.line_status == True].sum() usage = np.clip(usage, 0.0, float(n_connected)) reward = np.interp( diff --git a/grid2op/tests/test_simulate_disco_load.py b/grid2op/tests/test_simulate_disco_load.py index 435c0e3a3..c0412bc7c 100644 --- a/grid2op/tests/test_simulate_disco_load.py +++ b/grid2op/tests/test_simulate_disco_load.py @@ -24,7 +24,8 @@ def setUp(self) -> None: with warnings.catch_warnings(): warnings.filterwarnings("ignore") # this needs to be tested with pandapower backend - self.env = grid2op.make("l2rpn_case14_sandbox", backend=LightSimBackend(), test=True) + # self.env = grid2op.make("l2rpn_case14_sandbox", backend=LightSimBackend(), test=True) # TODO when lightsim will be fixed ! + self.env = grid2op.make("l2rpn_case14_sandbox", test=True) self.env.seed(0) self.env.set_id(0) @@ -42,6 +43,21 @@ def test_simulate_ok(self): simo, simr, simd, simi = obs.simulate(self.env.action_space()) assert not simd + + def test_backend_action(self): + obs = self.env.reset() + simo, simr, simd, simi = obs.simulate(self.env.action_space()) + l_id = 0 + l_pos = type(self.env).load_pos_topo_vect[l_id] + assert obs._obs_env._backend_action_set.current_topo.values[l_pos] == 1 + assert obs._obs_env._backend_action_set.load_p.changed[l_id] + assert np.allclose(obs._obs_env._backend_action_set.load_p.values[l_id], 22.3), f"{obs._obs_env._backend_action_set.load_p.values[l_id]:.2f} vs 22.3" + + obs._obs_env._backend_action_set += self.env.action_space({"set_bus": {"loads_id": [(l_id, -1)]}}) + assert obs._obs_env._backend_action_set.current_topo.values[l_pos] == -1 + tmp = obs._obs_env._backend_action_set() # do as if the action has been processed + assert not obs._obs_env._backend_action_set.load_p.changed[l_id] # it's disconnected, so marked as unchanged now + assert np.allclose(obs._obs_env._backend_action_set.load_p.values[l_id], 22.3), f"{obs._obs_env._backend_action_set.load_p.values[l_id]:.2f} vs 22.3" if __name__ == '__main__': diff --git a/grid2op/utils/l2rpn_2020_scores.py b/grid2op/utils/l2rpn_2020_scores.py index 4eb99aa0b..77d63c5b1 100644 --- a/grid2op/utils/l2rpn_2020_scores.py +++ b/grid2op/utils/l2rpn_2020_scores.py @@ -270,7 +270,7 @@ def _compute_episode_score( ) if dn_metadata["max_step"] == self.max_step: ep_cost = ep_cost[:-1] - ep_cost = ep_cost.Sum() + ep_cost = ep_cost.sum() ep_cost += ep_loads[n_played:].sum() * ep_marginal_cost # Compute ranges From ba6e0764f4a800c1aeffdc3e9434037a2f40bb5a Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 18 Jul 2023 16:59:29 +0200 Subject: [PATCH 045/103] some fixes needed, spotted by sonarcloud --- grid2op/Action/BaseAction.py | 11 ++++---- grid2op/Environment/BaseEnv.py | 2 -- grid2op/Environment/_ObsEnv.py | 1 - grid2op/Reward/alertReward.py | 27 ++++++++++---------- grid2op/Reward/linesCapacityReward.py | 3 --- grid2op/Reward/redispReward.py | 2 +- grid2op/Space/GridObjects.py | 1 + grid2op/gym_compat/box_gym_actspace.py | 1 - grid2op/gym_compat/box_gym_obsspace.py | 5 +--- grid2op/gym_compat/continuous_to_discrete.py | 3 --- grid2op/gym_compat/utils.py | 4 +-- 11 files changed, 23 insertions(+), 37 deletions(-) diff --git a/grid2op/Action/BaseAction.py b/grid2op/Action/BaseAction.py index 38ac3c128..17c680e6c 100644 --- a/grid2op/Action/BaseAction.py +++ b/grid2op/Action/BaseAction.py @@ -846,9 +846,8 @@ def _assign_attr_from_name(self, attr_nm, vect): super()._assign_attr_from_name(attr_nm, vect) self._post_process_from_vect() else: - if np.isfinite(vect).any(): - if (vect != 0.0).any(): - self._dict_inj[attr_nm] = vect + if np.isfinite(vect).any() and (vect != 0.0).any(): + self._dict_inj[attr_nm] = vect def check_space_legit(self): """ @@ -2657,8 +2656,8 @@ def _check_for_ambiguity(self): else: if self._raise_alert.any(): raise AmbiguousActionRaiseAlert( - f"Unrecognize alert action: an action acts on the alert, yet it's not tagged " - f"as doing so. Expect wrong behaviour." + "Unrecognize alert action: an action acts on the alert, yet it's not tagged " + "as doing so. Expect wrong behaviour." ) def _is_storage_ambiguous(self): @@ -2955,7 +2954,7 @@ def __str__(self) -> str: else: line_str = "s: \n\t \t - " + "\n\t \t - ".join( [f": {i} (on line {l})" for i,l in zip(i_alert,li_line)]) - res.append(f"\t - Raise alert(s) " f"{line_str}") + res.append(f"\t - Raise alert(s) {line_str}") else: res.append("\t - Not raise any alert") return "\n".join(res) diff --git a/grid2op/Environment/BaseEnv.py b/grid2op/Environment/BaseEnv.py index 0129d6ee0..f0bd657b9 100644 --- a/grid2op/Environment/BaseEnv.py +++ b/grid2op/Environment/BaseEnv.py @@ -2334,7 +2334,6 @@ def get_obs(self, _update_state=True, _do_copy=True): env=self, _update_state=_update_state ) if _do_copy: - # return self._last_obs.copy() return copy.deepcopy(self._last_obs) else: return self._last_obs @@ -2877,7 +2876,6 @@ def _update_alert_properties(self, action, lines_attacked, subs_attacked): self._time_since_last_attack[~mask_first_ts_attack & (self._time_since_last_attack != -1)] += 1 # update the time already attacked - self._is_already_attacked[lines_attacked_al] = False self._is_already_attacked[lines_attacked_al] = True else: self._time_since_last_attack[self._time_since_last_attack != -1] += 1 diff --git a/grid2op/Environment/_ObsEnv.py b/grid2op/Environment/_ObsEnv.py index 6b9a18e26..21ba36536 100644 --- a/grid2op/Environment/_ObsEnv.py +++ b/grid2op/Environment/_ObsEnv.py @@ -471,7 +471,6 @@ def get_obs(self, _update_state=True, _do_copy=True): self.current_obs.update(self, with_forecast=False) if _do_copy: - # res = self.current_obs.copy() res = copy.deepcopy(self.current_obs) else: res = self.current_obs diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 49ce6c776..8fab14cbc 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -8,6 +8,7 @@ import numpy as np +from typing import Optional from grid2op.Reward.baseReward import BaseReward from grid2op.dtypes import dt_float, dt_bool, dt_int @@ -80,23 +81,23 @@ def __init__(self, reward_end_episode_bonus=1.0): BaseReward.__init__(self, logger=logger) - self.reward_min_no_blackout = dt_float(reward_min_no_blackout) - self.reward_min_blackout = dt_float(reward_min_blackout) - self.reward_max_no_blackout = dt_float(reward_max_no_blackout) - self.reward_max_blackout = dt_float(reward_max_blackout) - self.reward_end_episode_bonus = dt_float(reward_end_episode_bonus) - self.reward_no_game_over = dt_float(0.0) + self.reward_min_no_blackout : float = dt_float(reward_min_no_blackout) + self.reward_min_blackout : float = dt_float(reward_min_blackout) + self.reward_max_no_blackout : float = dt_float(reward_max_no_blackout) + self.reward_max_blackout : float = dt_float(reward_max_blackout) + self.reward_end_episode_bonus : float = dt_float(reward_end_episode_bonus) + self.reward_no_game_over : float = dt_float(0.0) - self._reward_range_blackout = (self.reward_max_blackout - self.reward_min_blackout) + self._reward_range_blackout : float = (self.reward_max_blackout - self.reward_min_blackout) - self.total_time_steps = dt_int(0.0) - self.time_window = None + self.total_time_steps : Optional[int] = dt_int(0) + self.time_window : Optional[int] = None - self._ts_attack : np.ndarray = None + self._ts_attack : Optional[np.ndarray] = None self._current_id : int = 0 - self._lines_currently_attacked : np.ndarray = None - self._alert_launched : np.ndarray = None - self._nrows_array : int = None + self._lines_currently_attacked : Optional[np.ndarray] = None + self._alert_launched : Optional[np.ndarray] = None + self._nrows_array : Optional[int] = None self._i_am_simulate : bool = False diff --git a/grid2op/Reward/linesCapacityReward.py b/grid2op/Reward/linesCapacityReward.py index f4fb19d71..e251f3870 100644 --- a/grid2op/Reward/linesCapacityReward.py +++ b/grid2op/Reward/linesCapacityReward.py @@ -45,9 +45,6 @@ def __init__(self, logger=None): self.reward_min = dt_float(0.0) self.reward_max = dt_float(1.0) - def initialize(self, env): - pass - def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): if has_error or is_illegal or is_ambiguous: return self.reward_min diff --git a/grid2op/Reward/redispReward.py b/grid2op/Reward/redispReward.py index 7c9e80fdd..a51ec00ec 100644 --- a/grid2op/Reward/redispReward.py +++ b/grid2op/Reward/redispReward.py @@ -111,7 +111,7 @@ def generate_class_custom_params( # on linux it's fine, i can create new classes for each meta parameters nm_res = f"RedispReward_{alpha_redisph:.2f}_{min_load_ratio:.2f}_{worst_losses_ratio:.2f}" nm_res += f"_{min_reward:.2f}_{least_losses_ratio:.2f}_{reward_illegal_ambiguous:.2f}" - nm_res = re.sub("\\.", "@", nm_res) + nm_res = nm_res.replace(".", "@") cls_attr_as_dict = { "_alpha_redisp": dt_float(alpha_redisph), "_min_load_ratio": dt_float(min_load_ratio), diff --git a/grid2op/Space/GridObjects.py b/grid2op/Space/GridObjects.py index 53edfb7cc..592528a1e 100644 --- a/grid2op/Space/GridObjects.py +++ b/grid2op/Space/GridObjects.py @@ -612,6 +612,7 @@ class GridObjects: alertable_line_ids = [] def __init__(self): + """nothing to do when an object of this class is created, the information is held by the class attributes""" pass @classmethod diff --git a/grid2op/gym_compat/box_gym_actspace.py b/grid2op/gym_compat/box_gym_actspace.py index 8c8e438a1..1838a4f33 100644 --- a/grid2op/gym_compat/box_gym_actspace.py +++ b/grid2op/gym_compat/box_gym_actspace.py @@ -10,7 +10,6 @@ import copy import warnings import numpy as np -# from gym.spaces import Box from grid2op.Action import BaseAction, ActionSpace from grid2op.dtypes import dt_int, dt_bool, dt_float diff --git a/grid2op/gym_compat/box_gym_obsspace.py b/grid2op/gym_compat/box_gym_obsspace.py index a8a119720..5a5a778a7 100644 --- a/grid2op/gym_compat/box_gym_obsspace.py +++ b/grid2op/gym_compat/box_gym_obsspace.py @@ -632,10 +632,7 @@ def __init__( # initialize the base container type(self)._BoxType.__init__(self, low=low, high=high, shape=shape, dtype=dtype) - # convert data in `_add` and `_multiply` to the right type - - # self._subtract = {k: v.astype(self.dtype) for k, v in self._subtract.items()} - # self._divide = {k: v.astype(self.dtype) for k, v in self._divide.items()} + # convert data in `_subtract` and `_divide` to the right type self._fix_value_sub_div(self._subtract, functs) self._fix_value_sub_div(self._divide, functs) diff --git a/grid2op/gym_compat/continuous_to_discrete.py b/grid2op/gym_compat/continuous_to_discrete.py index ad83a37c7..f27ba60cf 100644 --- a/grid2op/gym_compat/continuous_to_discrete.py +++ b/grid2op/gym_compat/continuous_to_discrete.py @@ -11,9 +11,6 @@ from grid2op.dtypes import dt_int from grid2op.gym_compat.utils import GYM_AVAILABLE, GYMNASIUM_AVAILABLE -# from gym.spaces import Box, MultiDiscrete -# from grid2op.gym_compat.base_gym_attr_converter import BaseGymAttrConverter - class __AuxContinuousToDiscreteConverter: """ diff --git a/grid2op/gym_compat/utils.py b/grid2op/gym_compat/utils.py index c8892e43b..2e42adac1 100644 --- a/grid2op/gym_compat/utils.py +++ b/grid2op/gym_compat/utils.py @@ -48,7 +48,7 @@ ) -# raise alert or alarm is not supported +# raise alert or alarm is not supported by ALL_ATTR_FOR_DISCRETE nor ATTR_DISCRETE ALL_ATTR_FOR_DISCRETE = ( "set_line_status", "change_line_status", @@ -69,8 +69,6 @@ "sub_change_bus", "one_sub_set", "one_sub_change", - # "raise_alarm" - # "raise_alert" ) ALL_ATTR_CONT = ( From c2f4640853ca466a6c1237c904b76998d2e3a1b3 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 18 Jul 2023 17:45:03 +0200 Subject: [PATCH 046/103] fix a warning when agent games over at step 1 or when no renewable energy is present in the scenario with newRenewableSourcesUsageScore --- .../Reward/_newRenewableSourcesUsageScore.py | 8 ++++-- ...est_RewardNewRenewableSourcesUsageScore.py | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index e4b9edc27..6a50dcf6c 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -56,7 +56,12 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): self.gen_res_p_before_curtail_list[env.nb_time_step] = gen_nres_p_before_curtail return dt_float(0.) else: - ratio_nres_usage = 100 * self.gen_res_p_curtailed_list[1:].sum() / self.gen_res_p_before_curtail_list[1:].sum() + total_sum = self.gen_res_p_before_curtail_list[1:].sum() + if abs(total_sum) <= 1e-6: + # no nres in the scenario agent cannot possibly make any curtailment + # it uses all the available renewable energy + return self._surlinear_func_curtailment(100.) + ratio_nres_usage = 100 * self.gen_res_p_curtailed_list[1:].sum() / total_sum return self._surlinear_func_curtailment(ratio_nres_usage) @staticmethod @@ -74,7 +79,6 @@ def _surlinear_func_curtailment(x, center=80, eps=1e-6): f_surlinear = lambda x: x * np.log(x) f_centralized = lambda x : f_surlinear(x) - f_surlinear(center) f_standardizer= lambda x : np.ones_like(x) * f_centralized(100) * (x >= center) - np.ones_like(x) * f_centralized(50) * (x < center) - return f_centralized(x) / f_standardizer(x) diff --git a/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py b/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py index bb4fe6b64..d3b7b41bf 100644 --- a/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py +++ b/grid2op/tests/test_RewardNewRenewableSourcesUsageScore.py @@ -42,6 +42,32 @@ def act(self, obs, reward, done): sim_obs_1, *_ = obs.simulate(act, time_step=1) return super().act(obs, reward, done) + +class TestJustGameOver(unittest.TestCase): + def setUp(self) -> None: + env_name = "l2rpn_case14_sandbox" + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + self.env = grid2op.make(env_name, + reward_class=_NewRenewableSourcesUsageScore, + test=True + ) + self.env.set_max_iter(20) + self.env.parameters.NO_OVERFLOW_DISCONNECTION = True + self.nres_id = np.arange(self.env.n_gen)[self.env.gen_renewable] + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_when_no_step(self): + obs = self.env.reset() + with warnings.catch_warnings(): + warnings.filterwarnings("error") + obs, reward, done, info = self.env.step(self.env.action_space({"set_bus": {"loads_id": [(0, -1)]}})) + assert done + assert reward == 1., f"{reward:.2f} vs 1." + class TestNewRenewableSourcesUsageScore(unittest.TestCase): def setUp(self) -> None: From a875e66c368dc059a461a343df50e645036186c4 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 18 Jul 2023 17:54:50 +0200 Subject: [PATCH 047/103] fix bug on unused classes spotted by sonarcloud --- grid2op/Reward/_assistantScore.py | 14 ++++---------- grid2op/utils/l2rpn_idf_2023_scores.py | 4 ---- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/grid2op/Reward/_assistantScore.py b/grid2op/Reward/_assistantScore.py index 707c46299..30d1f6f13 100644 --- a/grid2op/Reward/_assistantScore.py +++ b/grid2op/Reward/_assistantScore.py @@ -28,14 +28,11 @@ class _AssistantConfidenceScore(BaseReward): def __init__(self, logger=None): BaseReward.__init__(self, logger=logger) - def __initialize__(self, env): + def initialize(self, env): self.reset(env) - def reset(self): - pass - def __call__(self, env, obs, is_done): - pass + return 0. class _AssistantCostScore(BaseReward): """ @@ -55,11 +52,8 @@ class _AssistantCostScore(BaseReward): def __init__(self, logger=None): BaseReward.__init__(self, logger=logger) - def __initialize__(self, env): + def initialize(self, env): self.reset(env) - def reset(self): - pass - def __call__(self, env, obs, is_done): - pass \ No newline at end of file + return 0. diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 158749b06..4a6556978 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -103,13 +103,9 @@ def __init__( nb_process_stats=nb_process_stats, scores_func={ "grid_operational_cost": L2RPNSandBoxScore, - #"assistance_confidence": _AssistantConfidenceScore, - #"assistant_cost": _AssistantCostScore, "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, }, score_names=["grid_operational_cost_scores", - #"assistant_confidence_scores", - #"assistant_cost_scores", "new_renewable_sources_usage_scores"], add_nb_highres_sim=add_nb_highres_sim, ) From 3fa19ffda2a7d9c4a8a748ee0cf5291e13e40d72 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 19 Jul 2023 12:57:37 +0200 Subject: [PATCH 048/103] adding last version of alertTrustScore file from PR 489 to the last stable version - commented addon kpi code --- grid2op/Reward/_alertTrustScore.py | 119 +++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 30 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index f74c5e070..c91fc7ced 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -10,6 +10,8 @@ from grid2op.Reward import AlertReward from grid2op.dtypes import dt_float +SURVIVOR_TIMESTEPS = 12 #nb timesteps to be considered survivor of an attack + class _AlertTrustScore(AlertReward): """ @@ -23,18 +25,30 @@ class _AlertTrustScore(AlertReward): Implemented as a reward to make it easier to use in the context of the L2RPN competitions, this reward is based on the "alert feature" where the agent is asked to send information about potential line overload issue on the grid after unpredictable powerline disconnection (attack of the opponent). - The alerts are assessed once per attack. In this scheme, this "reward" computed the assistant"cost score", which penalized the number of alerts - the assistant have produced during an episode. It should not be used to train an agent. + The alerts are assessed once per attack and cumulated over the episode. In this scheme, this "reward" computed the assistant "score", + which assesses how well the agent is aware of its capacities to deal with a situation during an episode. + It should not be used to train an agent. """ - + + #TODO + #Parameters to use for challenge + #def __init__(self, + # logger=None, + # reward_min_no_blackout=-1.0, + # reward_min_blackout=-50, + # reward_max_no_blackout=0.0, + # reward_max_blackout=0.0, + # reward_end_episode_bonus=0.0, + # min_score=-3): def __init__(self, logger=None, reward_min_no_blackout=-1.0, - reward_min_blackout=-10.0, + reward_min_blackout=-10.0, reward_max_no_blackout=1.0, reward_max_blackout=2.0, - reward_end_episode_bonus=1.0): + reward_end_episode_bonus=1.0, + min_score=-1.0): super().__init__(logger, reward_min_no_blackout, @@ -43,54 +57,99 @@ def __init__(self, reward_max_blackout, reward_end_episode_bonus) - self.reward_min = dt_float(-1.0) - self.reward_max = dt_float(1.0) - self.score_min_ep = lambda k: reward_min_no_blackout * (k - 1) + reward_min_blackout - self.score_max_ep = lambda k: max(reward_max_no_blackout * (k - 1) + reward_max_blackout, - reward_max_no_blackout * k + reward_end_episode_bonus) + self.min_score = dt_float(min_score) + self.max_score = dt_float(1.0) def initialize(self, env): self._is_simul_env = self.is_simulated_env(env) - if self._is_simul_env: - return - self.reset(env) + + self.cumulated_reward = 0 + #KPIs + self.total_nb_attacks = 0 + + #TODO + #self.total_nb_alerts = 0 + #self.alert_attack_no_blackout = 0 + #self.alert_attack_blackout = 0 + #self.no_alert_attack_no_blackout = 0 + #self.no_alert_attack_blackout = 0 + #self.blackout_encountered = False return super().initialize(env) def reset(self, env): super().reset(env) - self.total_nb_attacks = 0 self.cumulated_reward = 0 - self.true_alert_true_attack = 0 - self.true_alert_false_attack = 0 - self.false_alert_true_attack = 0 - self.false_alert_false_attack = 0 + #KPIs + self.total_nb_attacks = 0 + + # TODO + #self.total_nb_alerts = 0 + #self.alert_attack_no_blackout = 0 + #self.alert_attack_blackout = 0 + #self.no_alert_attack_no_blackout = 0 + #self.no_alert_attack_blackout = 0 + #self.blackout_encountered = False def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): + + self.blackout_encountered = self.is_in_blackout(has_error, is_done) + score_ep = 0. if self._is_simul_env: return score_ep res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res + lines_attacked = env._time_since_last_attack == 0 self.total_nb_attacks += np.sum(lines_attacked) - self.true_alert_true_attack += np.sum(env._time_since_last_alert[lines_attacked]==0) - self.true_alert_false_attack += np.sum(env._time_since_last_alert[~lines_attacked]==0) - self.false_alert_true_attack += np.sum(env._time_since_last_alert[lines_attacked]!=0) - self.false_alert_false_attack += np.sum(env._time_since_last_alert[~lines_attacked]!=0) + + # TODO + #lines_alerted_beforeattack = np.equal(env._time_since_last_alert, env._time_since_last_attack + 1) and lines_attacked + #self.total_nb_alerts += np.sum(lines_alerted_beforeattack) if not is_done: + + # TODO + #lines_attacked_no_blackout = env._time_since_last_attack == SURVIVOR_TIMESTEPS +# + #self.alert_attack_no_blackout += np.sum(lines_alerted_beforeattack[lines_attacked_no_blackout]) + #self.no_alert_attack_no_blackout += np.sum(~lines_alerted_beforeattack[lines_attacked_no_blackout]) + return score_ep + else: - score_min_ep = self.score_min_ep(self.total_nb_attacks) - score_max_ep = self.score_max_ep(self.total_nb_attacks) - score_ep = self._normalisation_fun(self.cumulated_reward, score_min_ep, score_max_ep) - + cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks) + score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep,self.min_score,self.max_score) + + # TODO + #if self.blackout_encountered: + # lines_attacked_dangerzone = (env._time_since_last_attack >= 0) * (env._time_since_last_attack < SURVIVOR_TIMESTEPS) + # + # self.alert_attack_blackout += 1. * any(lines_alerted_beforeattack[lines_attacked_dangerzone]) + # self.no_alert_attack_blackout += 1. * any(~lines_alerted_beforeattack[lines_attacked_dangerzone]) + #else : + # lines_attacked_no_blackout = env._time_since_last_attack > 0 + # + # self.alert_attack_no_blackout += np.sum(lines_alerted_beforeattack[lines_attacked_no_blackout]) + # self.no_alert_attack_no_blackout += np.sum(~lines_alerted_beforeattack[lines_attacked_no_blackout]) + return score_ep @staticmethod - def _normalisation_fun(score, score_min_ep, score_max_ep): - standardized_score = (score - score_min_ep) / (score_max_ep - score_min_ep) - score_ep = standardized_score * 2. - 1. + def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score): + standardized_score = (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep) + #score_ep = standardized_score * 2. - 1. + score_ep = min_score + (max_score - min_score) * standardized_score return score_ep - + + def _compute_min_max_reward(self, nb_attacks): + if self.blackout_encountered: + cm_reward_min_ep = lambda k: self.reward_min_no_blackout * (k - 1) + self.reward_min_blackout + cm_reward_max_ep = lambda k: self.reward_max_no_blackout * (k - 1) + self.reward_max_blackout + else: + cm_reward_min_ep = lambda k: self.reward_min_no_blackout * k + cm_reward_max_ep = lambda k: self.reward_max_no_blackout * k + self.reward_end_episode_bonus + + return cm_reward_min_ep(nb_attacks), cm_reward_max_ep(nb_attacks) + From e7a8e13e47986147cd91e75621d1e7d76e38f187 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:13:31 +0200 Subject: [PATCH 049/103] add reset method to alertReward + tests --- grid2op/Reward/alertReward.py | 16 ++++++++++++++++ grid2op/tests/test_alert_feature.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 1f3abb29e..4f3a77b2f 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -116,6 +116,22 @@ def initialize(self, env: "grid2op.Environment.BaseEnv"): self._i_am_simulate = self.is_simulated_env(env) return super().initialize(env) + def reset(self, env): + self.total_time_steps = env.max_episode_duration() + self.time_window = env.parameters.ALERT_TIME_WINDOW + self._nrows_array = self.time_window + 2 + + # TODO simulate env stuff ! + + # TODO vectors proper size + self._ts_attack = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) + self._alert_launched = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) + self._current_id = 0 + self._lines_currently_attacked = np.full(type(env).dim_alerts, False, dtype=dt_bool) + + self._i_am_simulate = self.is_simulated_env(env) + return super().reset(env) + def _update_attack(self, env): if env.infos["opponent_attack_line"] is None: # no attack at this step diff --git a/grid2op/tests/test_alert_feature.py b/grid2op/tests/test_alert_feature.py index 9d4d2e178..bc7075c14 100644 --- a/grid2op/tests/test_alert_feature.py +++ b/grid2op/tests/test_alert_feature.py @@ -254,6 +254,33 @@ def _aux_obs_init(self, obs): def test_init_observation(self) -> None : obs : BaseObservation = self.env.reset() self._aux_obs_init(obs) + + def test_reset_obs(self) -> None : + obs1 : BaseObservation = self.env.reset() + assert (obs1.time_since_last_alert == np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1])).all() + + obs2, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [0]})) + + assert (obs2.time_since_last_alert == np.array([0, -1, -1, -1, -1, -1, -1, -1, -1, -1])).all() + + obs2bis, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [1]})) + assert (obs2bis.time_since_last_alert == np.array([1, 0, -1, -1, -1, -1, -1, -1, -1, -1])).all() + + obs3 : BaseObservation = self.env.reset() + assert (obs3.time_since_last_alert == obs1.time_since_last_alert).all() + + def test_reset_reward(self) -> None : + obs1 : BaseObservation = self.env.reset() + assert self.env._reward_helper.template_reward._current_id == 0 + obs2, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [0]})) + + assert self.env._reward_helper.template_reward._current_id == 1 + + obs, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [1]})) + assert self.env._reward_helper.template_reward._current_id == 2 + + obs3 : BaseObservation = self.env.reset() + assert self.env._reward_helper.template_reward._current_id == 0 def _aux_alert_0(self, obs): assert obs.active_alert[0] @@ -577,4 +604,4 @@ def test_when_attacks(self): # TODO test "as_dict" and "as_json" if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file From e627101cb42ec46ef2fd26dcebc33f2df358ca9a Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:29:34 +0200 Subject: [PATCH 050/103] do not recreate object at reset --- grid2op/Reward/alertReward.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 4f3a77b2f..a0ca641f1 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -124,14 +124,14 @@ def reset(self, env): # TODO simulate env stuff ! # TODO vectors proper size - self._ts_attack = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) - self._alert_launched = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) + self._ts_attack[:,:] = False + self._alert_launched[:,:] = False self._current_id = 0 - self._lines_currently_attacked = np.full(type(env).dim_alerts, False, dtype=dt_bool) + self._lines_currently_attacked[:] = False self._i_am_simulate = self.is_simulated_env(env) return super().reset(env) - + def _update_attack(self, env): if env.infos["opponent_attack_line"] is None: # no attack at this step From 53c80a649ab4e1646293cde88c8ba65b1c7a0efc Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:47:12 +0200 Subject: [PATCH 051/103] add default params to assistant reward test + debug reset --- grid2op/Reward/alertReward.py | 12 ++---- grid2op/tests/test_alert_score.py | 69 +++++++++++++++++++------------ 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index a0ca641f1..ddf90252f 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -100,6 +100,7 @@ def __init__(self, self._i_am_simulate : bool = False + def initialize(self, env: "grid2op.Environment.BaseEnv"): self.total_time_steps = env.max_episode_duration() self.time_window = env.parameters.ALERT_TIME_WINDOW @@ -115,15 +116,8 @@ def initialize(self, env: "grid2op.Environment.BaseEnv"): self._i_am_simulate = self.is_simulated_env(env) return super().initialize(env) - + def reset(self, env): - self.total_time_steps = env.max_episode_duration() - self.time_window = env.parameters.ALERT_TIME_WINDOW - self._nrows_array = self.time_window + 2 - - # TODO simulate env stuff ! - - # TODO vectors proper size self._ts_attack[:,:] = False self._alert_launched[:,:] = False self._current_id = 0 @@ -131,7 +125,7 @@ def reset(self, env): self._i_am_simulate = self.is_simulated_env(env) return super().reset(env) - + def _update_attack(self, env): if env.infos["opponent_attack_line"] is None: # no attack at this step diff --git a/grid2op/tests/test_alert_score.py b/grid2op/tests/test_alert_score.py index 0717bef38..4a31f6158 100644 --- a/grid2op/tests/test_alert_score.py +++ b/grid2op/tests/test_alert_score.py @@ -40,6 +40,11 @@ ATTACKED_LINE = "48_50_136" +DEFAULT_ALERT_REWARD_PARAMS = dict(reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=42.0) def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" @@ -128,7 +133,7 @@ def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -157,7 +162,7 @@ def test_assistant_reward_value_no_blackout_no_attack_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -203,7 +208,7 @@ def test_assistant_reward_value_no_blackout_attack_no_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnbana" ) as env : env.seed(0) @@ -242,7 +247,7 @@ def test_assistant_reward_value_no_blackout_attack_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnba" ) as env : env.seed(0) @@ -288,6 +293,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_late(self) -> None opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnbaatl" ) as env : env.seed(0) @@ -308,7 +314,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_late(self) -> None if step == 4 : assert reward == 1 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -333,6 +339,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_early(self)-> None opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnbaate" ) as env : env.seed(0) @@ -354,7 +361,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_early(self)-> None if step == 4: assert reward == 1 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -380,7 +387,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_no_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2astna" ) as env : env.seed(0) @@ -422,6 +429,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_1_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2ast1a" ) as env : env.seed(0) @@ -442,7 +450,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_1_alert(self) -> if step == 4 : assert reward == 0 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -466,6 +474,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2ast2a" ) as env : env.seed(0) @@ -486,7 +495,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> if step == 4 : assert reward == -1 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -512,7 +521,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_no_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dtna" ) as env : env.seed(0) @@ -558,7 +567,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_2_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dt2a" ) as env : env.seed(0) @@ -607,7 +616,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_first_attac opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dtafa" ) as env : env.seed(0) @@ -654,7 +663,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_second_atta opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dtasa" ) as env : env.seed(0) @@ -686,7 +695,7 @@ def test_raise_illicit_alert(self) -> None: self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -738,7 +747,7 @@ def test_assistant_reward_value_blackout_attack_no_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbana" ) as env : new_param = Parameters() @@ -783,6 +792,7 @@ def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbarga" ) as env : new_param = Parameters() @@ -834,6 +844,7 @@ def test_assistant_reward_value_blackout_attack_raise_alert_just_before_blackout opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbarajbb" ) as env : new_param = Parameters() @@ -885,6 +896,7 @@ def test_assistant_reward_value_blackout_attack_raise_alert_too_early(self) -> N opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbarate" ) as env : new_param = Parameters() @@ -935,6 +947,7 @@ def test_assistant_reward_value_blackout_2_lines_same_step_in_window_good_alert opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2lssiwga" ) as env : new_param = Parameters() @@ -986,6 +999,8 @@ def test_assistant_reward_value_blackout_2_lines_attacked_simulaneous_only_1_ale opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), + _add_to_name="_tarvb2laso1a" ) as env : new_param = Parameters() @@ -1038,7 +1053,7 @@ def test_assistant_reward_value_blackout_2_lines_different_step_in_window_good_ opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2ldsiwga" ) as env : env.seed(0) @@ -1090,7 +1105,7 @@ def test_assistant_reward_value_blackout_2_lines_attacked_different_step_in_wind opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2ladsiwo1aofal" ) as env : env.seed(0) @@ -1138,7 +1153,7 @@ def test_assistant_reward_value_blackout_2_lines_attacked_different_step_in_wind opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2ladsiwo1aosal" ) as env : env.seed(0) @@ -1184,7 +1199,7 @@ def test_assistant_reward_value_blackout_2_lines_attacked_different_1_in_window_ opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2lad1iw1ga" ) as env : env.seed(0) @@ -1223,7 +1238,7 @@ def test_assistant_reward_value_blackout_no_attack_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1254,7 +1269,7 @@ def test_assistant_reward_value_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1283,7 +1298,7 @@ def test_assistant_reward_value_blackout_attack_before_window_alert(self) -> Non self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1314,7 +1329,7 @@ def test_assistant_reward_value_blackout_attack_before_window_no_alert(self) -> self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1346,7 +1361,7 @@ def setUp(self) -> None: PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) self.env = make(self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42)) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS)) self.env.seed(0) return super().setUp() @@ -1387,7 +1402,7 @@ def setUp(self) -> None: PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) self.env = make(self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42)) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS)) self.env.seed(0) return super().setUp() @@ -1448,7 +1463,7 @@ def test_with_opp(self): opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name = "_test_with_opp") # without alert runner = Runner(**env.get_params_for_runner()) @@ -1468,4 +1483,4 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file From ae15dd3b9c416ab3fd3e6c414e4c45341a25206e Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 19 Jul 2023 13:50:00 +0200 Subject: [PATCH 052/103] integrating back reward parameters configuration in test + cumulated reward test for class TestAlertTrustScoreNoBlackout --- grid2op/tests/test_alert_trust_score.py | 164 ++++++++++++++++++------ 1 file changed, 128 insertions(+), 36 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index a50074d21..49ca7d84c 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -41,6 +41,14 @@ ATTACKED_LINE = "48_50_136" +DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=42.0, + min_score=-1.0) + + def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" ts_attack = np.array(kwargs_opponent["steps_attack"]) @@ -130,7 +138,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() @@ -142,8 +150,12 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : if i == env.max_episode_duration()-1: #assert score == 42 assert env._reward_helper.template_reward.total_nb_attacks==0 - assert env._reward_helper.template_reward.cumulated_reward==42 - + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == 0. + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] else : assert score == 0 else : @@ -162,7 +174,7 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() @@ -181,7 +193,11 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : if step == env.max_episode_duration(): #assert score == 42 assert env._reward_helper.template_reward.total_nb_attacks==0 - assert env._reward_helper.template_reward.cumulated_reward==42 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == 0. + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] else : assert score == 0 else : @@ -208,7 +224,7 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnbana" ) as env : env.seed(0) @@ -226,8 +242,12 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : if done: #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==43 - else : + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + else : assert score == 0 def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : @@ -247,7 +267,7 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnba" ) as env : env.seed(0) @@ -269,7 +289,12 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : #assert score == 41 assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==41 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + else : assert score == 0 @@ -284,7 +309,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : with make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, @@ -312,7 +337,12 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : if done: #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==43 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] else : assert score == 0 @@ -327,7 +357,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : with make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, @@ -357,7 +387,14 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : #assert score == 43 assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==43 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + else : assert score == 0 @@ -380,7 +417,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnb2astna" ) as env : env.seed(0) @@ -397,9 +434,15 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> if done: #assert score == 43 - - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==43 + total_nb_attacks=env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]*total_nb_attacks else : assert score == 0 @@ -413,7 +456,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N with make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, @@ -440,8 +483,16 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N if done: #assert score == 42 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==42 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks==2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks else : assert score == 0 @@ -455,7 +506,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N with make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, @@ -482,8 +533,15 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N if done: #assert score == 41 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==41 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks else : assert score == 0 @@ -506,7 +564,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnb2dtna" ) as env : env.seed(0) @@ -524,8 +582,15 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> if done: #assert score == 44 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==44 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ + total_nb_attacks*DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks else : assert score == 0 @@ -547,7 +612,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnb2dt2a" ) as env : env.seed(0) @@ -568,8 +633,16 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N if done: #assert score == 40 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==40 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + "reward_end_episode_bonus"] + \ + total_nb_attacks * DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks else : assert score == 0 @@ -591,7 +664,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnb2dtafa" ) as env : env.seed(0) @@ -610,8 +683,17 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack if done: #score == 42 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==42 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + "reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks else : assert score == 0 @@ -633,7 +715,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnb2dtasa" ) as env : env.seed(0) @@ -652,8 +734,18 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac if done: #assert score == 42 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==42 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + "reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE[ + "reward_max_no_blackout"] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + env._reward_helper.template_reward.total_nb_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks else : assert score == 0, f"error for step {step}: {score} vs 0" From 13d064eeebd4b8247c4d93d950807a199583a4de Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:53:35 +0200 Subject: [PATCH 053/103] add comment to tell this score is not used in the L2RPN idf 2023 competition --- grid2op/Reward/_alertCostScore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index dafa978f3..ac66e973a 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -27,7 +27,7 @@ class _AlertCostScore(BaseReward): disconnection (attack of the opponent). The alerts are assessed once per attack. In this scheme, this "reward" computed the assistant"cost score", which penalized the number of alerts the assistant have produced during an episode. It should not be used to train an agent. - + For information, it will not be used for the L2RPN_IDF_2023 competition. """ def __init__(self, logger=None): BaseReward.__init__(self, logger=logger) From f6be579b567273d0ecef66c84715d9f4c43235e5 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:58:30 +0200 Subject: [PATCH 054/103] add default params in all alert tests --- grid2op/tests/test_alert_feature.py | 9 +++++++-- grid2op/tests/test_alert_trust_score.py | 9 ++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/grid2op/tests/test_alert_feature.py b/grid2op/tests/test_alert_feature.py index bc7075c14..ebfe409e2 100644 --- a/grid2op/tests/test_alert_feature.py +++ b/grid2op/tests/test_alert_feature.py @@ -39,6 +39,11 @@ "54_58_154", ] +DEFAULT_ALERT_REWARD_PARAMS = dict(reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=42.0) def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" @@ -117,7 +122,7 @@ def setUp(self) -> None: opponent_action_class=PlayableAction, opponent_class=OpponentForTestAlert, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tafta") def tearDown(self) -> None: @@ -232,7 +237,7 @@ def setUp(self) -> None: opponent_action_class=PlayableAction, opponent_class=OpponentForTestAlert, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tafto") param = self.env.parameters param.ALERT_TIME_WINDOW = 2 diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index a50074d21..f350ad85d 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -41,6 +41,13 @@ ATTACKED_LINE = "48_50_136" +DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=42.0) + + def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" ts_attack = np.array(kwargs_opponent["steps_attack"]) @@ -130,7 +137,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() From 6be02a20f0700ede02cb8e38f3ffd15e9106f7d9 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 19 Jul 2023 17:02:32 +0200 Subject: [PATCH 055/103] improving cases for min and max cumulated reward, considering number of attacks in last window and adpting tests --- grid2op/Reward/_alertTrustScore.py | 25 +- grid2op/tests/test_alert_trust_score.py | 351 +++++++++++++++++++----- 2 files changed, 308 insertions(+), 68 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index c91fc7ced..261c9e4ba 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -62,10 +62,12 @@ def __init__(self, def initialize(self, env): self._is_simul_env = self.is_simulated_env(env) + #SURVIVOR_TIMESTEPS=env._al self.cumulated_reward = 0 #KPIs self.total_nb_attacks = 0 + self.nb_last_attacks = 0 #attacks in the AlertTimeWindow before done #TODO #self.total_nb_alerts = 0 @@ -81,6 +83,7 @@ def reset(self, env): self.cumulated_reward = 0 #KPIs self.total_nb_attacks = 0 + self.nb_last_attacks=0 # TODO #self.total_nb_alerts = 0 @@ -119,7 +122,8 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return score_ep else: - cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks) + self.nb_last_attacks=np.sum(self._ts_attack) + cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks,self.nb_last_attacks) score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep,self.min_score,self.max_score) # TODO @@ -138,15 +142,24 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): @staticmethod def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score): - standardized_score = (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep) + standardized_score = (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +1e-5) #score_ep = standardized_score * 2. - 1. score_ep = min_score + (max_score - min_score) * standardized_score return score_ep - def _compute_min_max_reward(self, nb_attacks): - if self.blackout_encountered: - cm_reward_min_ep = lambda k: self.reward_min_no_blackout * (k - 1) + self.reward_min_blackout - cm_reward_max_ep = lambda k: self.reward_max_no_blackout * (k - 1) + self.reward_max_blackout + def _compute_min_max_reward(self, nb_attacks,nb_last_attacks): + #TODO + #add case multiple attack before blackout: weighted sum + if (nb_attacks==0 and self.blackout_encountered): + cm_reward_min_ep= lambda k: k + cm_reward_max_ep= lambda k: k + elif(self.blackout_encountered): + if(nb_last_attacks==0): + cm_reward_min_ep = lambda k: self.reward_min_no_blackout * k + cm_reward_max_ep = lambda k: self.reward_max_no_blackout * k + elif(nb_last_attacks>=1): + cm_reward_min_ep = lambda k: self.reward_min_no_blackout * (k - nb_last_attacks) + self.reward_min_blackout + cm_reward_max_ep = lambda k: self.reward_max_no_blackout * (k - nb_last_attacks) + self.reward_max_blackout else: cm_reward_min_ep = lambda k: self.reward_min_no_blackout * k cm_reward_max_ep = lambda k: self.reward_max_no_blackout * k + self.reward_end_episode_bonus diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 49ca7d84c..e52e9dda2 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -49,6 +49,7 @@ min_score=-1.0) + def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" ts_attack = np.array(kwargs_opponent["steps_attack"]) @@ -149,11 +150,14 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : if info["opponent_attack_line"] is None : if i == env.max_episode_duration()-1: #assert score == 42 - assert env._reward_helper.template_reward.total_nb_attacks==0 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks= env._reward_helper.template_reward.nb_last_attacks + assert total_nb_attacks==0 + assert nb_last_attacks==0 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] else : @@ -192,10 +196,13 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : if info["opponent_attack_line"] is None : if step == env.max_episode_duration(): #assert score == 42 - assert env._reward_helper.template_reward.total_nb_attacks==0 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + assert total_nb_attacks == 0 + assert nb_last_attacks == 0 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] else : @@ -240,11 +247,15 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 43 - assert env._reward_helper.template_reward.total_nb_attacks==1 + #assert score == 43 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + total_nb_attacks=env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] else : @@ -287,11 +298,15 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : if done: #assert score == 41 - - assert env._reward_helper.template_reward.total_nb_attacks==1 + + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] @@ -336,11 +351,16 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : if done: #assert score == 43 - assert env._reward_helper.template_reward.total_nb_attacks==1 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 1 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] else : @@ -385,12 +405,16 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : if done: #assert score == 43 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 1 - assert env._reward_helper.template_reward.total_nb_attacks==1 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] @@ -434,12 +458,16 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> if done: #assert score == 43 - total_nb_attacks=env._reward_helper.template_reward.total_nb_attacks - assert total_nb_attacks==2 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]*total_nb_attacks @@ -484,12 +512,16 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N if done: #assert score == 42 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - assert total_nb_attacks==2 + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks @@ -534,11 +566,14 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N if done: #assert score == 41 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 assert total_nb_attacks == 2 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks @@ -583,11 +618,15 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> if done: #assert score == 44 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ total_nb_attacks*DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks @@ -634,12 +673,16 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N if done: #assert score == 40 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ "reward_end_episode_bonus"] + \ total_nb_attacks * DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks @@ -684,13 +727,17 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack if done: #score == 42 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ "reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks @@ -735,14 +782,18 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac if done: #assert score == 42 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ "reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE[ "reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - env._reward_helper.template_reward.total_nb_attacks) + total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks @@ -788,7 +839,7 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsbana" ) as env : new_param = Parameters() @@ -813,8 +864,16 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : if done: #assert score == -10 - assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==-10 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']# -10 + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] break else : assert score == 0 @@ -837,7 +896,7 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsbarga" ) as env : new_param = Parameters() @@ -865,8 +924,18 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : if done: #assert score == 2 - assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==2 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 + + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] break else : assert score == 0 @@ -890,7 +959,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsbarajbb" ) as env : new_param = Parameters() @@ -918,8 +987,18 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( if done: #assert score == -10 - assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==-10 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 + + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] break else : assert score == 0 @@ -943,7 +1022,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsbarate" ) as env : new_param = Parameters() @@ -970,8 +1049,19 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No if done: #assert score == -10 - assert env._reward_helper.template_reward.total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==-10 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 + + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout'] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] break else : assert score == 0 @@ -1023,8 +1113,23 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts if done: #assert score == 2 - assert env._reward_helper.template_reward.total_nb_attacks==2 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 2 + assert total_nb_attacks == 2 + assert env._reward_helper.template_reward.cumulated_reward==2 + + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout'] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + break else : assert score == 0 @@ -1077,8 +1182,21 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler if done: #assert score == -4 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==-4 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 2 + assert total_nb_attacks == 2 + + assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout'])/total_nb_attacks + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] break else : assert score == 0 @@ -1129,8 +1247,25 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a if done : #assert score == 2 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==2 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 2 + assert total_nb_attacks == 2 + + assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout'] + + DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout']) / total_nb_attacks + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + # attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout'] # +DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout'] # +DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1175,8 +1310,21 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo if done : #assert score == -4 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==-4 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 2 + assert total_nb_attacks == 2 + + assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout'])/total_nb_attacks + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1222,9 +1370,21 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo if done : #assert score == -4., f"error for step {step}: {score} vs -4" + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==-4 + assert nb_last_attacks == 2 + assert total_nb_attacks == 2 + + assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout'])/total_nb_attacks + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1271,9 +1431,23 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 if done : #assert score == 3 - assert env._reward_helper.template_reward.total_nb_attacks==2 - assert env._reward_helper.template_reward.cumulated_reward==3 assert done + + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 2 + + assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_no_blackout']) + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1300,14 +1474,27 @@ def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : elif i == 1: act = env.action_space({"raise_alert": [0]}) obs, score, done, info = env.step(act) - if info["opponent_attack_line"] is None : - #assert score == 0. - assert env._reward_helper.template_reward.total_nb_attacks==0. - assert env._reward_helper.template_reward.cumulated_reward==0. + if info["opponent_attack_line"] is None: + if done : #info["opponent_attack_line"] is None : + #assert score == 0. + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks==0. + assert env._reward_helper.template_reward.cumulated_reward==0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 else : raise Grid2OpException('No attack expected') - if done : + if done : break assert done @@ -1331,10 +1518,23 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : if i == 3 : act = self.get_blackout(env) obs, score, done, info = env.step(act) - if info["opponent_attack_line"] is None : - #assert score == 0. - assert env._reward_helper.template_reward.total_nb_attacks==0. - assert env._reward_helper.template_reward.cumulated_reward==0. + if info["opponent_attack_line"] is None : + if done: + #assert score == 0. + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 else : raise Grid2OpException('No attack expected') @@ -1344,7 +1544,7 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : assert done # return 0 - def test_assistant_trust_score_blackout_attack_before_window_alert(self) -> None : + def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> None : """Even if there is a blackout, an we raise an alert too early we expect a score of 0 because there is no attack""" with make( @@ -1366,8 +1566,21 @@ def test_assistant_trust_score_blackout_attack_before_window_alert(self) -> None obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : #assert score == 0. - assert env._reward_helper.template_reward.total_nb_attacks==0. - assert env._reward_helper.template_reward.cumulated_reward==0. + if done: + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 else : raise Grid2OpException('No attack expected') @@ -1377,7 +1590,7 @@ def test_assistant_trust_score_blackout_attack_before_window_alert(self) -> None assert done # return 0 - def test_assistant_trust_score_blackout_attack_before_window_no_alert(self) -> None : + def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) -> None : """Even if there is a blackout, an we raise an alert too late we expect a score of 0 because there is no attack""" with make( @@ -1401,8 +1614,22 @@ def test_assistant_trust_score_blackout_attack_before_window_no_alert(self) -> N if info["opponent_attack_line"] is None : #assert score == 0. - assert env._reward_helper.template_reward.total_nb_attacks==0. - assert env._reward_helper.template_reward.cumulated_reward==0. + if done: + + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 else : raise Grid2OpException('No attack expected') From 2720c551186685bd75d6b6c682d27b8535e209f1 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 19 Jul 2023 17:39:05 +0200 Subject: [PATCH 056/103] slight change in _normalisation_fun of alertTrustScore impacted alertCostScore - so doing some digital rounding --- grid2op/tests/test_RewardAlertCostScore.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index a225e9a6d..a497337cf 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -255,7 +255,7 @@ def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : for i in range(env.max_episode_duration()): obs, reward, done, info = env.step(env.action_space()) if done: - assert reward == 1., f"{reward} vs 1." + assert np.round(reward,3) == 1., f"{reward} vs 1." else: assert reward == 0., f"{reward} vs 0." @@ -355,7 +355,7 @@ def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if step == 4: - assert reward == 1, f"error for step {step}: {reward} vs 1" #we did rise alert at first attack on going blackout + assert np.round(reward,3) == 1, f"error for step {step}: {reward} vs 1" #we did rise alert at first attack on going blackout assert done break else : @@ -380,7 +380,7 @@ def test_dn_agent(self): obs = self.env.reset() runner = Runner(**self.env.get_params_for_runner()) res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) - assert res[0][2] == 1. #it got to the end + assert np.round(res[0][2],3) == 1. #it got to the end def test_simagent(self): #simulate blackout but act donothing @@ -396,14 +396,14 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - runner = Runner(**self.env.get_params_for_runner(), agentClass=SimAgent) res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) - assert res[0][2] == 1. + assert np.round(res[0][2],3) == 1. def test_episodeData(self): obs = self.env.reset() runner = Runner(**self.env.get_params_for_runner()) res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], add_detailed_output=True) - assert res[0][2] == 1. - assert res[0][5].rewards[8] == 1. + assert np.round(res[0][2],3) == 1. + assert np.round(res[0][5].rewards[8]) == 1. def test_with_save(self): obs = self.env.reset() @@ -411,10 +411,10 @@ def test_with_save(self): with tempfile.TemporaryDirectory() as f: res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], path_save=f) - assert res[0][2] == 1. + assert np.round(res[0][2],3) == 1. ep0, *_ = EpisodeData.list_episode(f) ep = EpisodeData.from_disk(*ep0) - assert ep.rewards[8] == 1. + assert np.round(ep.rewards[8]) == 1. if __name__ == "__main__": unittest.main() From ccc9ffe47b8413b3c67df7547ffade4c2b8081b3 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 19 Jul 2023 17:52:40 +0200 Subject: [PATCH 057/103] modifying one case in alertReward for simulatneaous attacks no blackout, modifying impacted tests, and testing alert_trust_score with new competition parameter configuration with corrected tests --- grid2op/Reward/alertReward.py | 10 ++++- grid2op/tests/test_alert_score.py | 4 +- grid2op/tests/test_alert_trust_score.py | 49 ++++++++++++++----------- 3 files changed, 38 insertions(+), 25 deletions(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 1f3abb29e..b8c850287 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -196,7 +196,15 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): alert_send = self._alert_launched[prev_ind, lines_attack] # update the state of the environment env._was_alert_used_after_attack[lines_attack] = 1 - alert_send * 2 - res = (self.reward_min_no_blackout - self.reward_max_no_blackout) * np.mean(alert_send) + self.reward_max_no_blackout + + res=0 + for alert in alert_send: + if(alert): + res += self.reward_min_no_blackout + else: + res += self.reward_max_no_blackout + #res = (self.reward_min_no_blackout - self.reward_max_no_blackout) * np.mean(alert_send) + self.reward_max_no_blackout + self._ts_attack[index_window, :] = False # attack has been taken into account we "cancel" it return res \ No newline at end of file diff --git a/grid2op/tests/test_alert_score.py b/grid2op/tests/test_alert_score.py index 0717bef38..25c851d32 100644 --- a/grid2op/tests/test_alert_score.py +++ b/grid2op/tests/test_alert_score.py @@ -396,7 +396,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_no_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if step == 3 : - assert reward == 1 + assert reward == 2 #2 and not 1, both alerts count if no blackout elif step == env.max_episode_duration(): assert reward == 42 else : @@ -484,7 +484,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if step == 4 : - assert reward == -1 + assert reward == -2 #-2 and not -1, both alerts count if no blackout elif step == env.max_episode_duration(): assert reward == 1 else : diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index e52e9dda2..ba48e2ee3 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -41,15 +41,21 @@ ATTACKED_LINE = "48_50_136" +#DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, +# reward_min_blackout=-10.0, +# reward_max_no_blackout=1.0, +# reward_max_blackout=2.0, +# reward_end_episode_bonus=42.0, +# min_score=-1.0) + DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, - reward_min_blackout=-10.0, - reward_max_no_blackout=1.0, - reward_max_blackout=2.0, - reward_end_episode_bonus=42.0, + reward_min_blackout=-50.0, + reward_max_no_blackout=0.0, + reward_max_blackout=0.0, + reward_end_episode_bonus=0.0, min_score=-1.0) - def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" ts_attack = np.array(kwargs_opponent["steps_attack"]) @@ -517,8 +523,8 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N assert nb_last_attacks == 0 assert total_nb_attacks == 2 - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ - DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) @@ -571,7 +577,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N assert nb_last_attacks == 0 assert total_nb_attacks == 2 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ - DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks @@ -1085,7 +1091,7 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsb2lssiwga" ) as env : new_param = Parameters() @@ -1119,10 +1125,9 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts assert nb_last_attacks == 2 assert total_nb_attacks == 2 - assert env._reward_helper.template_reward.cumulated_reward==2 - - assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_max_blackout'] + assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout'])/total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) @@ -1146,7 +1151,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler with make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, @@ -1220,7 +1225,7 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsb2ldsiwga" ) as env : env.seed(0) @@ -1288,7 +1293,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsb2ladsiwo1aofal" ) as env : env.seed(0) @@ -1348,7 +1353,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsb2ladsiwo1aosal" ) as env : env.seed(0) @@ -1408,7 +1413,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(reward_end_episode_bonus=42), + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsb2lad1iw1ga" ) as env : env.seed(0) @@ -1461,7 +1466,7 @@ def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() @@ -1507,7 +1512,7 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() @@ -1551,7 +1556,7 @@ def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> N self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() @@ -1597,7 +1602,7 @@ def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) - self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(reward_end_episode_bonus=42) + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() From 5c389a3e5089517f45cd87c99f3223b0fd5661a5 Mon Sep 17 00:00:00 2001 From: marota Date: Wed, 19 Jul 2023 21:12:54 +0200 Subject: [PATCH 058/103] last slight edit to alertTrustSCore when min and max cumulated reward are zero, and addition of assert on score in tests for each case --- grid2op/Reward/_alertTrustScore.py | 6 +- grid2op/tests/test_alert_trust_score.py | 104 +++++++++++++++--------- 2 files changed, 70 insertions(+), 40 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 261c9e4ba..4deea709f 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -142,9 +142,9 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): @staticmethod def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score): - standardized_score = (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +1e-5) - #score_ep = standardized_score * 2. - 1. - score_ep = min_score + (max_score - min_score) * standardized_score + standardized_score = np.round((cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +1e-5),4) + #in case cm_reward_min_ep=cm_reward_max_ep=0, score is 0.0 + score_ep = (cm_reward_min_ep!=cm_reward_max_ep)*min_score + (max_score - min_score) * standardized_score return score_ep def _compute_min_max_reward(self, nb_attacks,nb_last_attacks): diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 09e52f95b..ebda2a2f2 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -53,7 +53,7 @@ reward_max_no_blackout=0.0, reward_max_blackout=0.0, reward_end_episode_bonus=0.0, - min_score=-1.0) + min_score=-3.0) def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" @@ -154,7 +154,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : obs, score, done, info = env.step(env.action_space()) if info["opponent_attack_line"] is None : if i == env.max_episode_duration()-1: - #assert score == 42 + assert score == 0.0 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks= env._reward_helper.template_reward.nb_last_attacks assert total_nb_attacks==0 @@ -200,7 +200,7 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : if info["opponent_attack_line"] is None : if step == env.max_episode_duration(): - #assert score == 42 + assert score == 0.0 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert total_nb_attacks == 0 @@ -252,7 +252,7 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 43 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + assert np.round(score,3) == env._reward_helper.template_reward.max_score total_nb_attacks=env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -267,7 +267,7 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : assert score == 0 def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : - """When an alert occur at step 2, we raise an alert at step 1 + """When an attack occur at step 2, we raise an alert at step 1 We expect a score of 41 """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], @@ -302,7 +302,7 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 41 + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -355,7 +355,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 43 + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -409,7 +409,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 43 + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -462,7 +462,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 43 + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -515,7 +515,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 42 + assert score == (env._reward_helper.template_reward.max_score+DEFAULT_PARAMS_TRUSTSCORE["min_score"])/2 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -569,7 +569,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 41 + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -621,7 +621,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 44 + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -676,7 +676,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 40 + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -730,7 +730,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #score == 42 + assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -785,7 +785,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 42 + assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -868,7 +868,7 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == -10 + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -927,8 +927,8 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : else: assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - if done: - #assert score == 2 + if done: + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -991,7 +991,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == -10 + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -1053,7 +1053,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == -10 + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -1117,7 +1117,7 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == 2 + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -1186,13 +1186,15 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler if done: #assert score == -4 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 2 assert total_nb_attacks == 2 - assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + cm_reward=env._reward_helper.template_reward.cumulated_reward + assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ 'reward_min_blackout'])/total_nb_attacks @@ -1201,6 +1203,12 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + (env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE["min_score"]) * manual_standardized_score + + assert score == manual_score break else : assert score == 0 @@ -1250,16 +1258,15 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - #assert score == 2 + assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 2 assert total_nb_attacks == 2 - assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_max_blackout'] + - DEFAULT_PARAMS_TRUSTSCORE[ + cm_reward = env._reward_helper.template_reward.cumulated_reward + assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] +DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']) / total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( @@ -1270,6 +1277,13 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout'] # +DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1312,15 +1326,15 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo else: assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - if done : - #assert score == -4 + if done : total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 2 assert total_nb_attacks == 2 - assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + cm_reward = env._reward_helper.template_reward.cumulated_reward + assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ 'reward_min_blackout'])/total_nb_attacks @@ -1329,6 +1343,14 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + assert score == manual_score + break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1372,15 +1394,15 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo else: assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - if done : - #assert score == -4., f"error for step {step}: {score} vs -4" + if done : total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 2 assert total_nb_attacks == 2 - assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + cm_reward = env._reward_helper.template_reward.cumulated_reward + assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ 'reward_min_blackout'])/total_nb_attacks @@ -1389,6 +1411,14 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + + + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + assert score == manual_score break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1434,7 +1464,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done : - #assert score == 3 + assert score == env._reward_helper.template_reward.max_score assert done total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks @@ -1480,7 +1510,7 @@ def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None: if done : #info["opponent_attack_line"] is None : - #assert score == 0. + assert score == 0. total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -1524,7 +1554,7 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : if done: - #assert score == 0. + assert score == 0. total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -1569,7 +1599,7 @@ def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> N act = env.action_space({"raise_alert": [0]}) obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : - #assert score == 0. + assert score == 0. if done: total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks @@ -1617,7 +1647,7 @@ def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) - obs, score, done, info = env.step(act) if info["opponent_attack_line"] is None : - #assert score == 0. + assert score == 0. if done: total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks From 400c90fd8f5103c02519a4922a310d17412d6db0 Mon Sep 17 00:00:00 2001 From: marota Date: Thu, 20 Jul 2023 09:39:48 +0200 Subject: [PATCH 059/103] improving test with other score parametrization to better consider non_zero end_episode_bonus in expected score --- grid2op/tests/test_alert_trust_score.py | 118 +++++++++++++++++++++--- 1 file changed, 104 insertions(+), 14 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index ebda2a2f2..de5356c00 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -153,8 +153,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : for i in range(env.max_episode_duration()): obs, score, done, info = env.step(env.action_space()) if info["opponent_attack_line"] is None : - if i == env.max_episode_duration()-1: - assert score == 0.0 + if i == env.max_episode_duration()-1: total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks= env._reward_helper.template_reward.nb_last_attacks assert total_nb_attacks==0 @@ -165,6 +164,11 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + + if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): + assert score == 0.0 + else: + assert score == env._reward_helper.template_reward.max_score else : assert score == 0 else : @@ -199,17 +203,22 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : step += 1 if info["opponent_attack_line"] is None : - if step == env.max_episode_duration(): - assert score == 0.0 + if step == env.max_episode_duration(): total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert total_nb_attacks == 0 assert nb_last_attacks == 0 + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + + if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): + assert score == 0.0 + else: + assert score == env._reward_helper.template_reward.max_score else : assert score == 0 else : @@ -302,19 +311,31 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 1 + + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score + else : assert score == 0 @@ -430,7 +451,7 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : # 2 ligne attaquées def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> None : """ When we don't raise an alert for 2 attacks at the same time (step 1) - but no blackout occur, we expect a score of 43 + but no blackout occur, we expect a score of 44 """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], @@ -462,20 +483,31 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 2 + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ - DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]*total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]*total_nb_attacks + + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): + assert score == env._reward_helper.template_reward.max_score + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score else : assert score == 0 @@ -514,14 +546,14 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N else: assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - if done: - assert score == (env._reward_helper.template_reward.max_score+DEFAULT_PARAMS_TRUSTSCORE["min_score"])/2 + if done: total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 2 + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] @@ -530,6 +562,17 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): + assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score else : assert score == 0 @@ -569,12 +612,14 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 2 + + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( @@ -582,6 +627,17 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score else : assert score == 0 @@ -676,13 +732,14 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 2 + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ "reward_end_episode_bonus"] + \ total_nb_attacks * DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] @@ -691,6 +748,17 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score else : assert score == 0 @@ -730,13 +798,14 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 2 + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ "reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] @@ -746,6 +815,17 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): + assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + + assert score == manual_score else : assert score == 0 @@ -785,13 +865,13 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 2 + cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ "reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE[ @@ -802,6 +882,16 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): + assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + else: + manual_standardized_score = np.round( + (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + assert score == manual_score else : assert score == 0, f"error for step {step}: {score} vs 0" From dadf84d4b3bef34dcfdf651c606fe3d1d643e7f6 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 11:44:07 +0200 Subject: [PATCH 060/103] renaming to lower case file in Action, Backend and Environment --- CHANGELOG.rst | 12 +++++- grid2op/Action/__init__.py | 38 +++++++++---------- .../{_BackendAction.py => _backendAction.py} | 0 .../Action/{ActionSpace.py => actionSpace.py} | 4 +- .../Action/{BaseAction.py => baseAction.py} | 0 .../{CompleteAction.py => completeAction.py} | 2 +- .../{DispatchAction.py => dispatchAction.py} | 2 +- grid2op/Action/{DontAct.py => dontAct.py} | 2 +- .../{PlayableAction.py => playableAction.py} | 2 +- ...angeAction.py => powerlineChangeAction.py} | 2 +- ...py => powerlineChangeAndDispatchAction.py} | 2 +- ...owerlineChangeDispatchAndStorageAction.py} | 2 +- ...lineSetAction.py => powerlineSetAction.py} | 2 +- ...on.py => powerlineSetAndDispatchAction.py} | 2 +- ...ionSpace.py => serializableActionSpace.py} | 2 +- .../{TopologyAction.py => topologyAction.py} | 2 +- ...Action.py => topologyAndDispatchAction.py} | 2 +- ...hangeAction.py => topologyChangeAction.py} | 2 +- ....py => topologyChangeAndDispatchAction.py} | 2 +- ...ologySetAction.py => topologySetAction.py} | 2 +- ...ion.py => topologySetAndDispatchAction.py} | 2 +- ...tageOnlyAction.py => voltageOnlyAction.py} | 2 +- grid2op/Backend/__init__.py | 4 +- grid2op/Backend/{Backend.py => backend.py} | 2 +- ...werBackend.py => educPandaPowerBackend.py} | 2 +- ...daPowerBackend.py => pandaPowerBackend.py} | 2 +- grid2op/Environment/__init__.py | 12 +++--- grid2op/Environment/_forecast_env.py | 2 +- .../Environment/{_ObsEnv.py => _obsEnv.py} | 2 +- .../Environment/{BaseEnv.py => baseEnv.py} | 13 +++---- ...tiProcessEnv.py => baseMultiProcessEnv.py} | 2 +- .../{Environment.py => environment.py} | 4 +- ...ultiProcess.py => multiEnvMultiProcess.py} | 2 +- .../{MultiMixEnv.py => multiMixEnv.py} | 0 ...ltiProcess.py => singleEnvMultiProcess.py} | 2 +- grid2op/Environment/timedOutEnv.py | 2 +- grid2op/Observation/__init__.py | 2 + grid2op/Observation/observationSpace.py | 4 +- grid2op/Reward/_alarmScore.py | 12 ++---- .../Reward/_newRenewableSourcesUsageScore.py | 13 +------ grid2op/Reward/baseReward.py | 2 +- grid2op/Reward/n1Reward.py | 2 +- grid2op/tests/BaseBackendTest.py | 2 +- grid2op/tests/test_attached_envs.py | 4 +- grid2op/tests/test_attached_envs_compat.py | 4 +- 45 files changed, 88 insertions(+), 96 deletions(-) rename grid2op/Action/{_BackendAction.py => _backendAction.py} (100%) rename grid2op/Action/{ActionSpace.py => actionSpace.py} (98%) rename grid2op/Action/{BaseAction.py => baseAction.py} (100%) rename grid2op/Action/{CompleteAction.py => completeAction.py} (94%) rename grid2op/Action/{DispatchAction.py => dispatchAction.py} (94%) rename grid2op/Action/{DontAct.py => dontAct.py} (96%) rename grid2op/Action/{PlayableAction.py => playableAction.py} (98%) rename grid2op/Action/{PowerlineChangeAction.py => powerlineChangeAction.py} (94%) rename grid2op/Action/{PowerlineChangeAndDispatchAction.py => powerlineChangeAndDispatchAction.py} (94%) rename grid2op/Action/{PowerlineChangeDispatchAndStorageAction.py => powerlineChangeDispatchAndStorageAction.py} (93%) rename grid2op/Action/{PowerlineSetAction.py => powerlineSetAction.py} (94%) rename grid2op/Action/{PowerlineSetAndDispatchAction.py => powerlineSetAndDispatchAction.py} (95%) rename grid2op/Action/{SerializableActionSpace.py => serializableActionSpace.py} (99%) rename grid2op/Action/{TopologyAction.py => topologyAction.py} (95%) rename grid2op/Action/{TopologyAndDispatchAction.py => topologyAndDispatchAction.py} (95%) rename grid2op/Action/{TopologyChangeAction.py => topologyChangeAction.py} (94%) rename grid2op/Action/{TopologyChangeAndDispatchAction.py => topologyChangeAndDispatchAction.py} (95%) rename grid2op/Action/{TopologySetAction.py => topologySetAction.py} (94%) rename grid2op/Action/{TopologySetAndDispatchAction.py => topologySetAndDispatchAction.py} (95%) rename grid2op/Action/{VoltageOnlyAction.py => voltageOnlyAction.py} (98%) rename grid2op/Backend/{Backend.py => backend.py} (99%) rename grid2op/Backend/{EducPandaPowerBackend.py => educPandaPowerBackend.py} (99%) rename grid2op/Backend/{PandaPowerBackend.py => pandaPowerBackend.py} (99%) rename grid2op/Environment/{_ObsEnv.py => _obsEnv.py} (99%) rename grid2op/Environment/{BaseEnv.py => baseEnv.py} (99%) rename grid2op/Environment/{BaseMultiProcessEnv.py => baseMultiProcessEnv.py} (99%) rename grid2op/Environment/{Environment.py => environment.py} (99%) rename grid2op/Environment/{MultiEnvMultiProcess.py => multiEnvMultiProcess.py} (98%) rename grid2op/Environment/{MultiMixEnv.py => multiMixEnv.py} (100%) rename grid2op/Environment/{SingleEnvMultiProcess.py => singleEnvMultiProcess.py} (98%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f43eb501e..24f6d6755 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,13 +33,21 @@ Change Log [1.9.2] - 2023-07-xx --------------------- +- [BREAKING] rename with filename starting with lowercase all the files in the "`Backend`", "`Action`" and + "`Environment`" modules. This is both consistent with python practice but allows also to make the + difference between the files in the + module and the class imported. This should have little to no impact on all codes but to "upgrade" + instead of `from grid2op.Action.BaseAction import BaseAction` (which you should not have done in the first place) + just do `from grid2op.Action import BaseAction`. Expect other changes like this for other grid2op modules + in the near future. - [FIXED] broken environ "l2rpn_idf_2023" (with test=True) due to the presence of a `__pycache__` folder - [FIXED] time series `MultiFolder` will now ignore folder `__pycache__` - [FIXED] an issue with compatibility with previous versions (due to alert) -- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (self.is_simulated_env() +- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (`self.is_simulated_env()` was not working as expected due to a wrong init of the reward in `_ObsEnv`) - [FIXED] an issue when disconnecting loads / generators / storage units and changing their values in the same - action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" has the priority and + action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" have the priority (if + an action disconnect an element, it will not change its sepoint at the same time). - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance - [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction` diff --git a/grid2op/Action/__init__.py b/grid2op/Action/__init__.py index 830011a18..d082e05e8 100644 --- a/grid2op/Action/__init__.py +++ b/grid2op/Action/__init__.py @@ -23,29 +23,29 @@ ] # Internals -from grid2op.Action.BaseAction import BaseAction -from grid2op.Action.PlayableAction import PlayableAction -from grid2op.Action.VoltageOnlyAction import VoltageOnlyAction -from grid2op.Action.CompleteAction import CompleteAction -from grid2op.Action.ActionSpace import ActionSpace -from grid2op.Action.SerializableActionSpace import SerializableActionSpace +from grid2op.Action.baseAction import BaseAction +from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.voltageOnlyAction import VoltageOnlyAction +from grid2op.Action.completeAction import CompleteAction +from grid2op.Action.actionSpace import ActionSpace +from grid2op.Action.serializableActionSpace import SerializableActionSpace -from grid2op.Action.DontAct import DontAct -from grid2op.Action.PowerlineSetAction import PowerlineSetAction -from grid2op.Action.PowerlineChangeAction import PowerlineChangeAction -from grid2op.Action.PowerlineSetAndDispatchAction import PowerlineSetAndDispatchAction -from grid2op.Action.PowerlineChangeAndDispatchAction import ( +from grid2op.Action.dontAct import DontAct +from grid2op.Action.powerlineSetAction import PowerlineSetAction +from grid2op.Action.powerlineChangeAction import PowerlineChangeAction +from grid2op.Action.powerlineSetAndDispatchAction import PowerlineSetAndDispatchAction +from grid2op.Action.powerlineChangeAndDispatchAction import ( PowerlineChangeAndDispatchAction, ) -from grid2op.Action.PowerlineChangeDispatchAndStorageAction import ( +from grid2op.Action.powerlineChangeDispatchAndStorageAction import ( PowerlineChangeDispatchAndStorageAction, ) -from grid2op.Action.TopologyAction import TopologyAction -from grid2op.Action.TopologyAndDispatchAction import TopologyAndDispatchAction -from grid2op.Action.TopologySetAction import TopologySetAction -from grid2op.Action.TopologySetAndDispatchAction import TopologySetAndDispatchAction -from grid2op.Action.TopologyChangeAction import TopologyChangeAction -from grid2op.Action.TopologyChangeAndDispatchAction import ( +from grid2op.Action.topologyAction import TopologyAction +from grid2op.Action.topologyAndDispatchAction import TopologyAndDispatchAction +from grid2op.Action.topologySetAction import TopologySetAction +from grid2op.Action.topologySetAndDispatchAction import TopologySetAndDispatchAction +from grid2op.Action.topologyChangeAction import TopologyChangeAction +from grid2op.Action.topologyChangeAndDispatchAction import ( TopologyChangeAndDispatchAction, ) -from grid2op.Action.DispatchAction import DispatchAction +from grid2op.Action.dispatchAction import DispatchAction diff --git a/grid2op/Action/_BackendAction.py b/grid2op/Action/_backendAction.py similarity index 100% rename from grid2op/Action/_BackendAction.py rename to grid2op/Action/_backendAction.py diff --git a/grid2op/Action/ActionSpace.py b/grid2op/Action/actionSpace.py similarity index 98% rename from grid2op/Action/ActionSpace.py rename to grid2op/Action/actionSpace.py index 73b06e722..c7ade19a7 100644 --- a/grid2op/Action/ActionSpace.py +++ b/grid2op/Action/actionSpace.py @@ -9,8 +9,8 @@ import warnings import copy -from grid2op.Action.BaseAction import BaseAction -from grid2op.Action.SerializableActionSpace import SerializableActionSpace +from grid2op.Action.baseAction import BaseAction +from grid2op.Action.serializableActionSpace import SerializableActionSpace class ActionSpace(SerializableActionSpace): diff --git a/grid2op/Action/BaseAction.py b/grid2op/Action/baseAction.py similarity index 100% rename from grid2op/Action/BaseAction.py rename to grid2op/Action/baseAction.py diff --git a/grid2op/Action/CompleteAction.py b/grid2op/Action/completeAction.py similarity index 94% rename from grid2op/Action/CompleteAction.py rename to grid2op/Action/completeAction.py index d4e12ec54..548b59009 100644 --- a/grid2op/Action/CompleteAction.py +++ b/grid2op/Action/completeAction.py @@ -5,7 +5,7 @@ # you can obtain one at http://mozilla.org/MPL/2.0/. # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class CompleteAction(BaseAction): diff --git a/grid2op/Action/DispatchAction.py b/grid2op/Action/dispatchAction.py similarity index 94% rename from grid2op/Action/DispatchAction.py rename to grid2op/Action/dispatchAction.py index 9c4f7d6f7..b0ec07fc9 100644 --- a/grid2op/Action/DispatchAction.py +++ b/grid2op/Action/dispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class DispatchAction(PlayableAction): diff --git a/grid2op/Action/DontAct.py b/grid2op/Action/dontAct.py similarity index 96% rename from grid2op/Action/DontAct.py rename to grid2op/Action/dontAct.py index afe2c622c..09fd0d1c1 100644 --- a/grid2op/Action/DontAct.py +++ b/grid2op/Action/dontAct.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class DontAct(PlayableAction): diff --git a/grid2op/Action/PlayableAction.py b/grid2op/Action/playableAction.py similarity index 98% rename from grid2op/Action/PlayableAction.py rename to grid2op/Action/playableAction.py index 61f3dfccb..fd854863e 100644 --- a/grid2op/Action/PlayableAction.py +++ b/grid2op/Action/playableAction.py @@ -9,7 +9,7 @@ import warnings from grid2op.Exceptions import AmbiguousAction -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class PlayableAction(BaseAction): diff --git a/grid2op/Action/PowerlineChangeAction.py b/grid2op/Action/powerlineChangeAction.py similarity index 94% rename from grid2op/Action/PowerlineChangeAction.py rename to grid2op/Action/powerlineChangeAction.py index 6c00bc759..e678d6a03 100644 --- a/grid2op/Action/PowerlineChangeAction.py +++ b/grid2op/Action/powerlineChangeAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineChangeAction(PlayableAction): diff --git a/grid2op/Action/PowerlineChangeAndDispatchAction.py b/grid2op/Action/powerlineChangeAndDispatchAction.py similarity index 94% rename from grid2op/Action/PowerlineChangeAndDispatchAction.py rename to grid2op/Action/powerlineChangeAndDispatchAction.py index 3cd684dd4..759d241e0 100644 --- a/grid2op/Action/PowerlineChangeAndDispatchAction.py +++ b/grid2op/Action/powerlineChangeAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineChangeAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/PowerlineChangeDispatchAndStorageAction.py b/grid2op/Action/powerlineChangeDispatchAndStorageAction.py similarity index 93% rename from grid2op/Action/PowerlineChangeDispatchAndStorageAction.py rename to grid2op/Action/powerlineChangeDispatchAndStorageAction.py index 4049b0656..7a0dfa0d0 100644 --- a/grid2op/Action/PowerlineChangeDispatchAndStorageAction.py +++ b/grid2op/Action/powerlineChangeDispatchAndStorageAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineChangeDispatchAndStorageAction(PlayableAction): diff --git a/grid2op/Action/PowerlineSetAction.py b/grid2op/Action/powerlineSetAction.py similarity index 94% rename from grid2op/Action/PowerlineSetAction.py rename to grid2op/Action/powerlineSetAction.py index a506557e9..81c6b67b9 100644 --- a/grid2op/Action/PowerlineSetAction.py +++ b/grid2op/Action/powerlineSetAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineSetAction(PlayableAction): diff --git a/grid2op/Action/PowerlineSetAndDispatchAction.py b/grid2op/Action/powerlineSetAndDispatchAction.py similarity index 95% rename from grid2op/Action/PowerlineSetAndDispatchAction.py rename to grid2op/Action/powerlineSetAndDispatchAction.py index b29e24193..97920d65a 100644 --- a/grid2op/Action/PowerlineSetAndDispatchAction.py +++ b/grid2op/Action/powerlineSetAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineSetAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/SerializableActionSpace.py b/grid2op/Action/serializableActionSpace.py similarity index 99% rename from grid2op/Action/SerializableActionSpace.py rename to grid2op/Action/serializableActionSpace.py index a2fbbfcc6..7c11d2312 100644 --- a/grid2op/Action/SerializableActionSpace.py +++ b/grid2op/Action/serializableActionSpace.py @@ -14,7 +14,7 @@ from grid2op.dtypes import dt_int, dt_float, dt_bool from grid2op.Exceptions import AmbiguousAction, Grid2OpException from grid2op.Space import SerializableSpace -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class SerializableActionSpace(SerializableSpace): diff --git a/grid2op/Action/TopologyAction.py b/grid2op/Action/topologyAction.py similarity index 95% rename from grid2op/Action/TopologyAction.py rename to grid2op/Action/topologyAction.py index 1d52503d1..4fadb649d 100644 --- a/grid2op/Action/TopologyAction.py +++ b/grid2op/Action/topologyAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyAction(PlayableAction): diff --git a/grid2op/Action/TopologyAndDispatchAction.py b/grid2op/Action/topologyAndDispatchAction.py similarity index 95% rename from grid2op/Action/TopologyAndDispatchAction.py rename to grid2op/Action/topologyAndDispatchAction.py index b167fded1..b85443724 100644 --- a/grid2op/Action/TopologyAndDispatchAction.py +++ b/grid2op/Action/topologyAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/TopologyChangeAction.py b/grid2op/Action/topologyChangeAction.py similarity index 94% rename from grid2op/Action/TopologyChangeAction.py rename to grid2op/Action/topologyChangeAction.py index eaea3e3a7..c8ede25a2 100644 --- a/grid2op/Action/TopologyChangeAction.py +++ b/grid2op/Action/topologyChangeAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyChangeAction(PlayableAction): diff --git a/grid2op/Action/TopologyChangeAndDispatchAction.py b/grid2op/Action/topologyChangeAndDispatchAction.py similarity index 95% rename from grid2op/Action/TopologyChangeAndDispatchAction.py rename to grid2op/Action/topologyChangeAndDispatchAction.py index 4ec7e5148..11947f262 100644 --- a/grid2op/Action/TopologyChangeAndDispatchAction.py +++ b/grid2op/Action/topologyChangeAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyChangeAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/TopologySetAction.py b/grid2op/Action/topologySetAction.py similarity index 94% rename from grid2op/Action/TopologySetAction.py rename to grid2op/Action/topologySetAction.py index 533d4ca0b..204109694 100644 --- a/grid2op/Action/TopologySetAction.py +++ b/grid2op/Action/topologySetAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologySetAction(PlayableAction): diff --git a/grid2op/Action/TopologySetAndDispatchAction.py b/grid2op/Action/topologySetAndDispatchAction.py similarity index 95% rename from grid2op/Action/TopologySetAndDispatchAction.py rename to grid2op/Action/topologySetAndDispatchAction.py index a8b36cf48..dee7d797a 100644 --- a/grid2op/Action/TopologySetAndDispatchAction.py +++ b/grid2op/Action/topologySetAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologySetAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/VoltageOnlyAction.py b/grid2op/Action/voltageOnlyAction.py similarity index 98% rename from grid2op/Action/VoltageOnlyAction.py rename to grid2op/Action/voltageOnlyAction.py index 5ccc91b69..637d87871 100644 --- a/grid2op/Action/VoltageOnlyAction.py +++ b/grid2op/Action/voltageOnlyAction.py @@ -9,7 +9,7 @@ import warnings from grid2op.Exceptions import AmbiguousAction -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class VoltageOnlyAction(BaseAction): diff --git a/grid2op/Backend/__init__.py b/grid2op/Backend/__init__.py index 4cde4a3d4..8b681e473 100644 --- a/grid2op/Backend/__init__.py +++ b/grid2op/Backend/__init__.py @@ -1,4 +1,4 @@ __all__ = ["Backend", "PandaPowerBackend"] -from grid2op.Backend.Backend import Backend -from grid2op.Backend.PandaPowerBackend import PandaPowerBackend +from grid2op.Backend.backend import Backend +from grid2op.Backend.pandaPowerBackend import PandaPowerBackend diff --git a/grid2op/Backend/Backend.py b/grid2op/Backend/backend.py similarity index 99% rename from grid2op/Backend/Backend.py rename to grid2op/Backend/backend.py index 3dfbfebce..15e155e36 100644 --- a/grid2op/Backend/Backend.py +++ b/grid2op/Backend/backend.py @@ -1744,7 +1744,7 @@ def assert_grid_correct(self): """ # lazy loading from grid2op.Action import CompleteAction - from grid2op.Action._BackendAction import _BackendAction + from grid2op.Action._backendAction import _BackendAction orig_type = type(self) if orig_type.my_bk_act_class is None: diff --git a/grid2op/Backend/EducPandaPowerBackend.py b/grid2op/Backend/educPandaPowerBackend.py similarity index 99% rename from grid2op/Backend/EducPandaPowerBackend.py rename to grid2op/Backend/educPandaPowerBackend.py index a568bd1d5..effbaa67c 100644 --- a/grid2op/Backend/EducPandaPowerBackend.py +++ b/grid2op/Backend/educPandaPowerBackend.py @@ -18,7 +18,7 @@ import scipy from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Backend.Backend import Backend +from grid2op.Backend.backend import Backend from grid2op.Exceptions import * diff --git a/grid2op/Backend/PandaPowerBackend.py b/grid2op/Backend/pandaPowerBackend.py similarity index 99% rename from grid2op/Backend/PandaPowerBackend.py rename to grid2op/Backend/pandaPowerBackend.py index f220db936..f532115d5 100644 --- a/grid2op/Backend/PandaPowerBackend.py +++ b/grid2op/Backend/pandaPowerBackend.py @@ -18,7 +18,7 @@ import scipy from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Backend.Backend import Backend +from grid2op.Backend.backend import Backend from grid2op.Action import BaseAction from grid2op.Exceptions import * diff --git a/grid2op/Environment/__init__.py b/grid2op/Environment/__init__.py index a171bf117..1375aad0a 100644 --- a/grid2op/Environment/__init__.py +++ b/grid2op/Environment/__init__.py @@ -8,10 +8,10 @@ "TimedOutEnvironment" ] -from grid2op.Environment.BaseEnv import BaseEnv -from grid2op.Environment.Environment import Environment -from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment -from grid2op.Environment.SingleEnvMultiProcess import SingleEnvMultiProcess -from grid2op.Environment.MultiEnvMultiProcess import MultiEnvMultiProcess -from grid2op.Environment.MultiMixEnv import MultiMixEnvironment +from grid2op.Environment.baseEnv import BaseEnv +from grid2op.Environment.environment import Environment +from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.singleEnvMultiProcess import SingleEnvMultiProcess +from grid2op.Environment.multiEnvMultiProcess import MultiEnvMultiProcess +from grid2op.Environment.multiMixEnv import MultiMixEnvironment from grid2op.Environment.timedOutEnv import TimedOutEnvironment diff --git a/grid2op/Environment/_forecast_env.py b/grid2op/Environment/_forecast_env.py index 8223ee067..ad08fc7df 100644 --- a/grid2op/Environment/_forecast_env.py +++ b/grid2op/Environment/_forecast_env.py @@ -9,7 +9,7 @@ from typing import Tuple from grid2op.Action import BaseAction from grid2op.Observation import BaseObservation -from grid2op.Environment.Environment import Environment +from grid2op.Environment.environment import Environment class _ForecastEnv(Environment): diff --git a/grid2op/Environment/_ObsEnv.py b/grid2op/Environment/_obsEnv.py similarity index 99% rename from grid2op/Environment/_ObsEnv.py rename to grid2op/Environment/_obsEnv.py index 21ba36536..8db0060d4 100644 --- a/grid2op/Environment/_ObsEnv.py +++ b/grid2op/Environment/_obsEnv.py @@ -12,7 +12,7 @@ from grid2op.Exceptions.EnvExceptions import EnvError from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Environment.BaseEnv import BaseEnv +from grid2op.Environment.baseEnv import BaseEnv from grid2op.Chronics import ChangeNothing from grid2op.Rules import RulesChecker from grid2op.operator_attention import LinearAttentionBudget diff --git a/grid2op/Environment/BaseEnv.py b/grid2op/Environment/baseEnv.py similarity index 99% rename from grid2op/Environment/BaseEnv.py rename to grid2op/Environment/baseEnv.py index f0bd657b9..a25a90e73 100644 --- a/grid2op/Environment/BaseEnv.py +++ b/grid2op/Environment/baseEnv.py @@ -16,13 +16,12 @@ from typing import Optional, Tuple import warnings import numpy as np -from scipy.optimize import minimize -from scipy.optimize import LinearConstraint +from scipy.optimize import (minimize, LinearConstraint) from abc import ABC, abstractmethod -from grid2op.Action.ActionSpace import ActionSpace -from grid2op.Observation.baseObservation import BaseObservation -from grid2op.Observation.observationSpace import ObservationSpace -from grid2op.Observation.highresSimCounter import HighResSimCounter +from grid2op.Action import ActionSpace +from grid2op.Observation import (BaseObservation, + ObservationSpace, + HighResSimCounter) from grid2op.Backend import Backend from grid2op.dtypes import dt_int, dt_float, dt_bool from grid2op.Space import GridObjects, RandomObject @@ -35,7 +34,7 @@ from grid2op.Rules import AlwaysLegal from grid2op.Opponent import BaseOpponent from grid2op.operator_attention import LinearAttentionBudget -from grid2op.Action._BackendAction import _BackendAction +from grid2op.Action._backendAction import _BackendAction from grid2op.Chronics import ChronicsHandler from grid2op.Rules import AlwaysLegal, BaseRules diff --git a/grid2op/Environment/BaseMultiProcessEnv.py b/grid2op/Environment/baseMultiProcessEnv.py similarity index 99% rename from grid2op/Environment/BaseMultiProcessEnv.py rename to grid2op/Environment/baseMultiProcessEnv.py index da49f917a..2d09ef88e 100644 --- a/grid2op/Environment/BaseMultiProcessEnv.py +++ b/grid2op/Environment/baseMultiProcessEnv.py @@ -14,7 +14,7 @@ from grid2op.dtypes import dt_int from grid2op.Exceptions import Grid2OpException, MultiEnvException from grid2op.Space import GridObjects -from grid2op.Environment import Environment +from grid2op.Environment.environment import Environment from grid2op.Action import BaseAction diff --git a/grid2op/Environment/Environment.py b/grid2op/Environment/environment.py similarity index 99% rename from grid2op/Environment/Environment.py rename to grid2op/Environment/environment.py index 98f6eab2e..ca77cb4f9 100644 --- a/grid2op/Environment/Environment.py +++ b/grid2op/Environment/environment.py @@ -12,7 +12,7 @@ import re import grid2op -from grid2op.Opponent.OpponentSpace import OpponentSpace +from grid2op.Opponent import OpponentSpace from grid2op.dtypes import dt_float, dt_bool, dt_int from grid2op.Action import ( ActionSpace, @@ -28,7 +28,7 @@ from grid2op.Backend import Backend from grid2op.Chronics import ChronicsHandler from grid2op.VoltageControler import ControlVoltageFromFile, BaseVoltageController -from grid2op.Environment.BaseEnv import BaseEnv +from grid2op.Environment.baseEnv import BaseEnv from grid2op.Opponent import BaseOpponent, NeverAttackBudget from grid2op.operator_attention import LinearAttentionBudget diff --git a/grid2op/Environment/MultiEnvMultiProcess.py b/grid2op/Environment/multiEnvMultiProcess.py similarity index 98% rename from grid2op/Environment/MultiEnvMultiProcess.py rename to grid2op/Environment/multiEnvMultiProcess.py index cf07296b6..647113740 100644 --- a/grid2op/Environment/MultiEnvMultiProcess.py +++ b/grid2op/Environment/multiEnvMultiProcess.py @@ -11,7 +11,7 @@ from grid2op.dtypes import dt_int from grid2op.Exceptions import Grid2OpException, MultiEnvException from grid2op.Space import GridObjects -from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment from grid2op.Action import BaseAction diff --git a/grid2op/Environment/MultiMixEnv.py b/grid2op/Environment/multiMixEnv.py similarity index 100% rename from grid2op/Environment/MultiMixEnv.py rename to grid2op/Environment/multiMixEnv.py diff --git a/grid2op/Environment/SingleEnvMultiProcess.py b/grid2op/Environment/singleEnvMultiProcess.py similarity index 98% rename from grid2op/Environment/SingleEnvMultiProcess.py rename to grid2op/Environment/singleEnvMultiProcess.py index 940a771dd..f648b7e59 100644 --- a/grid2op/Environment/SingleEnvMultiProcess.py +++ b/grid2op/Environment/singleEnvMultiProcess.py @@ -8,7 +8,7 @@ import numpy as np -from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment class SingleEnvMultiProcess(BaseMultiProcessEnvironment): diff --git a/grid2op/Environment/timedOutEnv.py b/grid2op/Environment/timedOutEnv.py index acf41e37e..fcccd7641 100644 --- a/grid2op/Environment/timedOutEnv.py +++ b/grid2op/Environment/timedOutEnv.py @@ -9,7 +9,7 @@ import time from math import floor from typing import Tuple, Union, List -from grid2op.Environment.Environment import Environment +from grid2op.Environment.environment import Environment from grid2op.Action import BaseAction from grid2op.Observation import BaseObservation from grid2op.Exceptions import EnvError diff --git a/grid2op/Observation/__init__.py b/grid2op/Observation/__init__.py index 25548b022..fda4d0188 100644 --- a/grid2op/Observation/__init__.py +++ b/grid2op/Observation/__init__.py @@ -12,9 +12,11 @@ "NoisyObservation", "BaseObservation", "ObservationSpace", + "HighResSimCounter", ] from grid2op.Observation.completeObservation import CompleteObservation from grid2op.Observation.noisyObservation import NoisyObservation from grid2op.Observation.baseObservation import BaseObservation from grid2op.Observation.observationSpace import ObservationSpace +from grid2op.Observation.highresSimCounter import HighResSimCounter diff --git a/grid2op/Observation/observationSpace.py b/grid2op/Observation/observationSpace.py index 93c178508..db81a8991 100644 --- a/grid2op/Observation/observationSpace.py +++ b/grid2op/Observation/observationSpace.py @@ -82,7 +82,7 @@ def __init__( """ # lazy import to prevent circular references (Env -> Observation -> Obs Space -> _ObsEnv -> Env) - from grid2op.Environment._ObsEnv import _ObsEnv + from grid2op.Environment._obsEnv import _ObsEnv if actionClass is None: from grid2op.Action import CompleteAction @@ -150,7 +150,7 @@ def set_real_env_kwargs(self, env): if not self.with_forecast: return # I don't need the backend nor the chronics_handler - from grid2op.Environment.Environment import Environment + from grid2op.Environment import Environment self._real_env_kwargs = Environment.get_kwargs(env, False, False) # remove the parameters anyways (the 'forecast parameters will be used diff --git a/grid2op/Reward/_alarmScore.py b/grid2op/Reward/_alarmScore.py index fead57d6b..b4c69ff5d 100644 --- a/grid2op/Reward/_alarmScore.py +++ b/grid2op/Reward/_alarmScore.py @@ -65,14 +65,7 @@ def __init__(self, logger=None): self.disc_lines_all_before_cascade = [] self.n_line = None - - # This class remembers the past state of the grid, this does not make sense for the "simulate" env - # so i deactivate it in this case. - from grid2op.Environment._ObsEnv import ( - _ObsEnv, - ) # to avoid circular dependencies - - self._deactivate_reward_cls = (_ObsEnv,) + self._i_am_simulate = True def initialize(self, env): if not env._has_attention_budget: @@ -88,6 +81,7 @@ def reset(self, env): super().reset(env) self.window_disconnection = max(self.best_time - self.window_size, 4) self.disc_lines_all_before_cascade = [] + self._i_am_simulate = self.is_simulated_env(env) def _lines_disconnected_first(self, disc_lines_at_cascading_time): """ @@ -117,7 +111,7 @@ def _lines_disconnected_first(self, disc_lines_at_cascading_time): return 1 - disc_lines_to_consider_for_score def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - if self.is_simulated_env(env): + if self._i_am_simulate: return self.reward_no_game_over disc_lines_now = env._disc_lines diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index e4b9edc27..b60f2ef05 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -38,7 +38,7 @@ def initialize(self, env): self.reset(env) def reset(self, env): - self._is_simul_env = is_simulated_env(env) + self._is_simul_env = self.is_simulated_env(env) if self._is_simul_env: return @@ -76,15 +76,4 @@ def _surlinear_func_curtailment(x, center=80, eps=1e-6): f_standardizer= lambda x : np.ones_like(x) * f_centralized(100) * (x >= center) - np.ones_like(x) * f_centralized(50) * (x < center) return f_centralized(x) / f_standardizer(x) - - -#to wait before PR Laure -def is_simulated_env(env): - - # to prevent cyclical import - from grid2op.Environment._ObsEnv import _ObsEnv - from grid2op.Environment._forecast_env import _ForecastEnv - - # This reward is not compatible with simulations - return isinstance(env, (_ObsEnv, _ForecastEnv)) diff --git a/grid2op/Reward/baseReward.py b/grid2op/Reward/baseReward.py index 320bd5d07..164f54e0b 100644 --- a/grid2op/Reward/baseReward.py +++ b/grid2op/Reward/baseReward.py @@ -120,7 +120,7 @@ def __init__(self, logger: logging.Logger=None): def is_simulated_env(self, env): # to prevent cyclical import - from grid2op.Environment._ObsEnv import _ObsEnv + from grid2op.Environment._obsEnv import _ObsEnv from grid2op.Environment._forecast_env import _ForecastEnv return isinstance(env, (_ObsEnv, _ForecastEnv)) diff --git a/grid2op/Reward/n1Reward.py b/grid2op/Reward/n1Reward.py index b31a9904e..9d11561ef 100644 --- a/grid2op/Reward/n1Reward.py +++ b/grid2op/Reward/n1Reward.py @@ -8,7 +8,7 @@ import copy from grid2op.Reward import BaseReward -from grid2op.Action._BackendAction import _BackendAction +from grid2op.Action._backendAction import _BackendAction class N1Reward(BaseReward): diff --git a/grid2op/tests/BaseBackendTest.py b/grid2op/tests/BaseBackendTest.py index 3ea0ddd4b..01e849e20 100644 --- a/grid2op/tests/BaseBackendTest.py +++ b/grid2op/tests/BaseBackendTest.py @@ -57,7 +57,7 @@ def comb(n, k): from grid2op.Rules import RulesChecker from grid2op.MakeEnv import make from grid2op.Rules import AlwaysLegal -from grid2op.Action._BackendAction import _BackendAction +from grid2op.Action._backendAction import _BackendAction import pdb diff --git a/grid2op/tests/test_attached_envs.py b/grid2op/tests/test_attached_envs.py index 92c571088..42b18a67f 100644 --- a/grid2op/tests/test_attached_envs.py +++ b/grid2op/tests/test_attached_envs.py @@ -10,10 +10,10 @@ import unittest import grid2op -from grid2op.Action.PowerlineSetAction import PowerlineSetAction +from grid2op.Action.powerlineSetAction import PowerlineSetAction from grid2op.Action.PlayableAction import PlayableAction from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.DontAct import DontAct +from grid2op.Action.dontAct import DontAct from grid2op.Opponent import GeometricOpponent import pdb diff --git a/grid2op/tests/test_attached_envs_compat.py b/grid2op/tests/test_attached_envs_compat.py index d09a51015..84b3b0b3d 100644 --- a/grid2op/tests/test_attached_envs_compat.py +++ b/grid2op/tests/test_attached_envs_compat.py @@ -13,10 +13,10 @@ import numpy as np from grid2op.Space import GridObjects -from grid2op.Action.PowerlineSetAction import PowerlineSetAction +from grid2op.Action.powerlineSetAction import PowerlineSetAction from grid2op.Action.PlayableAction import PlayableAction from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.DontAct import DontAct +from grid2op.Action.dontAct import DontAct import pdb From 00bf79567bef9b5e01891065b386c35b8b993846 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 11:46:31 +0200 Subject: [PATCH 061/103] Revert "renaming to lower case file in Action, Backend and Environment" This reverts commit dadf84d4b3bef34dcfdf651c606fe3d1d643e7f6. --- CHANGELOG.rst | 12 +----- .../Action/{actionSpace.py => ActionSpace.py} | 4 +- .../Action/{baseAction.py => BaseAction.py} | 0 .../{completeAction.py => CompleteAction.py} | 2 +- .../{dispatchAction.py => DispatchAction.py} | 2 +- grid2op/Action/{dontAct.py => DontAct.py} | 2 +- .../{playableAction.py => PlayableAction.py} | 2 +- ...angeAction.py => PowerlineChangeAction.py} | 2 +- ...py => PowerlineChangeAndDispatchAction.py} | 2 +- ...owerlineChangeDispatchAndStorageAction.py} | 2 +- ...lineSetAction.py => PowerlineSetAction.py} | 2 +- ...on.py => PowerlineSetAndDispatchAction.py} | 2 +- ...ionSpace.py => SerializableActionSpace.py} | 2 +- .../{topologyAction.py => TopologyAction.py} | 2 +- ...Action.py => TopologyAndDispatchAction.py} | 2 +- ...hangeAction.py => TopologyChangeAction.py} | 2 +- ....py => TopologyChangeAndDispatchAction.py} | 2 +- ...ologySetAction.py => TopologySetAction.py} | 2 +- ...ion.py => TopologySetAndDispatchAction.py} | 2 +- ...tageOnlyAction.py => VoltageOnlyAction.py} | 2 +- .../{_backendAction.py => _BackendAction.py} | 0 grid2op/Action/__init__.py | 38 +++++++++---------- grid2op/Backend/{backend.py => Backend.py} | 2 +- ...werBackend.py => EducPandaPowerBackend.py} | 2 +- ...daPowerBackend.py => PandaPowerBackend.py} | 2 +- grid2op/Backend/__init__.py | 4 +- .../Environment/{baseEnv.py => BaseEnv.py} | 13 ++++--- ...tiProcessEnv.py => BaseMultiProcessEnv.py} | 2 +- .../{environment.py => Environment.py} | 4 +- ...ultiProcess.py => MultiEnvMultiProcess.py} | 2 +- .../{multiMixEnv.py => MultiMixEnv.py} | 0 ...ltiProcess.py => SingleEnvMultiProcess.py} | 2 +- .../Environment/{_obsEnv.py => _ObsEnv.py} | 2 +- grid2op/Environment/__init__.py | 12 +++--- grid2op/Environment/_forecast_env.py | 2 +- grid2op/Environment/timedOutEnv.py | 2 +- grid2op/Observation/__init__.py | 2 - grid2op/Observation/observationSpace.py | 4 +- grid2op/Reward/_alarmScore.py | 12 ++++-- .../Reward/_newRenewableSourcesUsageScore.py | 13 ++++++- grid2op/Reward/baseReward.py | 2 +- grid2op/Reward/n1Reward.py | 2 +- grid2op/tests/BaseBackendTest.py | 2 +- grid2op/tests/test_attached_envs.py | 4 +- grid2op/tests/test_attached_envs_compat.py | 4 +- 45 files changed, 96 insertions(+), 88 deletions(-) rename grid2op/Action/{actionSpace.py => ActionSpace.py} (98%) rename grid2op/Action/{baseAction.py => BaseAction.py} (100%) rename grid2op/Action/{completeAction.py => CompleteAction.py} (94%) rename grid2op/Action/{dispatchAction.py => DispatchAction.py} (94%) rename grid2op/Action/{dontAct.py => DontAct.py} (96%) rename grid2op/Action/{playableAction.py => PlayableAction.py} (98%) rename grid2op/Action/{powerlineChangeAction.py => PowerlineChangeAction.py} (94%) rename grid2op/Action/{powerlineChangeAndDispatchAction.py => PowerlineChangeAndDispatchAction.py} (94%) rename grid2op/Action/{powerlineChangeDispatchAndStorageAction.py => PowerlineChangeDispatchAndStorageAction.py} (93%) rename grid2op/Action/{powerlineSetAction.py => PowerlineSetAction.py} (94%) rename grid2op/Action/{powerlineSetAndDispatchAction.py => PowerlineSetAndDispatchAction.py} (95%) rename grid2op/Action/{serializableActionSpace.py => SerializableActionSpace.py} (99%) rename grid2op/Action/{topologyAction.py => TopologyAction.py} (95%) rename grid2op/Action/{topologyAndDispatchAction.py => TopologyAndDispatchAction.py} (95%) rename grid2op/Action/{topologyChangeAction.py => TopologyChangeAction.py} (94%) rename grid2op/Action/{topologyChangeAndDispatchAction.py => TopologyChangeAndDispatchAction.py} (95%) rename grid2op/Action/{topologySetAction.py => TopologySetAction.py} (94%) rename grid2op/Action/{topologySetAndDispatchAction.py => TopologySetAndDispatchAction.py} (95%) rename grid2op/Action/{voltageOnlyAction.py => VoltageOnlyAction.py} (98%) rename grid2op/Action/{_backendAction.py => _BackendAction.py} (100%) rename grid2op/Backend/{backend.py => Backend.py} (99%) rename grid2op/Backend/{educPandaPowerBackend.py => EducPandaPowerBackend.py} (99%) rename grid2op/Backend/{pandaPowerBackend.py => PandaPowerBackend.py} (99%) rename grid2op/Environment/{baseEnv.py => BaseEnv.py} (99%) rename grid2op/Environment/{baseMultiProcessEnv.py => BaseMultiProcessEnv.py} (99%) rename grid2op/Environment/{environment.py => Environment.py} (99%) rename grid2op/Environment/{multiEnvMultiProcess.py => MultiEnvMultiProcess.py} (98%) rename grid2op/Environment/{multiMixEnv.py => MultiMixEnv.py} (100%) rename grid2op/Environment/{singleEnvMultiProcess.py => SingleEnvMultiProcess.py} (98%) rename grid2op/Environment/{_obsEnv.py => _ObsEnv.py} (99%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 24f6d6755..f43eb501e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,21 +33,13 @@ Change Log [1.9.2] - 2023-07-xx --------------------- -- [BREAKING] rename with filename starting with lowercase all the files in the "`Backend`", "`Action`" and - "`Environment`" modules. This is both consistent with python practice but allows also to make the - difference between the files in the - module and the class imported. This should have little to no impact on all codes but to "upgrade" - instead of `from grid2op.Action.BaseAction import BaseAction` (which you should not have done in the first place) - just do `from grid2op.Action import BaseAction`. Expect other changes like this for other grid2op modules - in the near future. - [FIXED] broken environ "l2rpn_idf_2023" (with test=True) due to the presence of a `__pycache__` folder - [FIXED] time series `MultiFolder` will now ignore folder `__pycache__` - [FIXED] an issue with compatibility with previous versions (due to alert) -- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (`self.is_simulated_env()` +- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (self.is_simulated_env() was not working as expected due to a wrong init of the reward in `_ObsEnv`) - [FIXED] an issue when disconnecting loads / generators / storage units and changing their values in the same - action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" have the priority (if - an action disconnect an element, it will not change its sepoint at the same time). + action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" has the priority and - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance - [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction` diff --git a/grid2op/Action/actionSpace.py b/grid2op/Action/ActionSpace.py similarity index 98% rename from grid2op/Action/actionSpace.py rename to grid2op/Action/ActionSpace.py index c7ade19a7..73b06e722 100644 --- a/grid2op/Action/actionSpace.py +++ b/grid2op/Action/ActionSpace.py @@ -9,8 +9,8 @@ import warnings import copy -from grid2op.Action.baseAction import BaseAction -from grid2op.Action.serializableActionSpace import SerializableActionSpace +from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.SerializableActionSpace import SerializableActionSpace class ActionSpace(SerializableActionSpace): diff --git a/grid2op/Action/baseAction.py b/grid2op/Action/BaseAction.py similarity index 100% rename from grid2op/Action/baseAction.py rename to grid2op/Action/BaseAction.py diff --git a/grid2op/Action/completeAction.py b/grid2op/Action/CompleteAction.py similarity index 94% rename from grid2op/Action/completeAction.py rename to grid2op/Action/CompleteAction.py index 548b59009..d4e12ec54 100644 --- a/grid2op/Action/completeAction.py +++ b/grid2op/Action/CompleteAction.py @@ -5,7 +5,7 @@ # you can obtain one at http://mozilla.org/MPL/2.0/. # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.baseAction import BaseAction +from grid2op.Action.BaseAction import BaseAction class CompleteAction(BaseAction): diff --git a/grid2op/Action/dispatchAction.py b/grid2op/Action/DispatchAction.py similarity index 94% rename from grid2op/Action/dispatchAction.py rename to grid2op/Action/DispatchAction.py index b0ec07fc9..9c4f7d6f7 100644 --- a/grid2op/Action/dispatchAction.py +++ b/grid2op/Action/DispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class DispatchAction(PlayableAction): diff --git a/grid2op/Action/dontAct.py b/grid2op/Action/DontAct.py similarity index 96% rename from grid2op/Action/dontAct.py rename to grid2op/Action/DontAct.py index 09fd0d1c1..afe2c622c 100644 --- a/grid2op/Action/dontAct.py +++ b/grid2op/Action/DontAct.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class DontAct(PlayableAction): diff --git a/grid2op/Action/playableAction.py b/grid2op/Action/PlayableAction.py similarity index 98% rename from grid2op/Action/playableAction.py rename to grid2op/Action/PlayableAction.py index fd854863e..61f3dfccb 100644 --- a/grid2op/Action/playableAction.py +++ b/grid2op/Action/PlayableAction.py @@ -9,7 +9,7 @@ import warnings from grid2op.Exceptions import AmbiguousAction -from grid2op.Action.baseAction import BaseAction +from grid2op.Action.BaseAction import BaseAction class PlayableAction(BaseAction): diff --git a/grid2op/Action/powerlineChangeAction.py b/grid2op/Action/PowerlineChangeAction.py similarity index 94% rename from grid2op/Action/powerlineChangeAction.py rename to grid2op/Action/PowerlineChangeAction.py index e678d6a03..6c00bc759 100644 --- a/grid2op/Action/powerlineChangeAction.py +++ b/grid2op/Action/PowerlineChangeAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class PowerlineChangeAction(PlayableAction): diff --git a/grid2op/Action/powerlineChangeAndDispatchAction.py b/grid2op/Action/PowerlineChangeAndDispatchAction.py similarity index 94% rename from grid2op/Action/powerlineChangeAndDispatchAction.py rename to grid2op/Action/PowerlineChangeAndDispatchAction.py index 759d241e0..3cd684dd4 100644 --- a/grid2op/Action/powerlineChangeAndDispatchAction.py +++ b/grid2op/Action/PowerlineChangeAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class PowerlineChangeAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/powerlineChangeDispatchAndStorageAction.py b/grid2op/Action/PowerlineChangeDispatchAndStorageAction.py similarity index 93% rename from grid2op/Action/powerlineChangeDispatchAndStorageAction.py rename to grid2op/Action/PowerlineChangeDispatchAndStorageAction.py index 7a0dfa0d0..4049b0656 100644 --- a/grid2op/Action/powerlineChangeDispatchAndStorageAction.py +++ b/grid2op/Action/PowerlineChangeDispatchAndStorageAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class PowerlineChangeDispatchAndStorageAction(PlayableAction): diff --git a/grid2op/Action/powerlineSetAction.py b/grid2op/Action/PowerlineSetAction.py similarity index 94% rename from grid2op/Action/powerlineSetAction.py rename to grid2op/Action/PowerlineSetAction.py index 81c6b67b9..a506557e9 100644 --- a/grid2op/Action/powerlineSetAction.py +++ b/grid2op/Action/PowerlineSetAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class PowerlineSetAction(PlayableAction): diff --git a/grid2op/Action/powerlineSetAndDispatchAction.py b/grid2op/Action/PowerlineSetAndDispatchAction.py similarity index 95% rename from grid2op/Action/powerlineSetAndDispatchAction.py rename to grid2op/Action/PowerlineSetAndDispatchAction.py index 97920d65a..b29e24193 100644 --- a/grid2op/Action/powerlineSetAndDispatchAction.py +++ b/grid2op/Action/PowerlineSetAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class PowerlineSetAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/serializableActionSpace.py b/grid2op/Action/SerializableActionSpace.py similarity index 99% rename from grid2op/Action/serializableActionSpace.py rename to grid2op/Action/SerializableActionSpace.py index 7c11d2312..a2fbbfcc6 100644 --- a/grid2op/Action/serializableActionSpace.py +++ b/grid2op/Action/SerializableActionSpace.py @@ -14,7 +14,7 @@ from grid2op.dtypes import dt_int, dt_float, dt_bool from grid2op.Exceptions import AmbiguousAction, Grid2OpException from grid2op.Space import SerializableSpace -from grid2op.Action.baseAction import BaseAction +from grid2op.Action.BaseAction import BaseAction class SerializableActionSpace(SerializableSpace): diff --git a/grid2op/Action/topologyAction.py b/grid2op/Action/TopologyAction.py similarity index 95% rename from grid2op/Action/topologyAction.py rename to grid2op/Action/TopologyAction.py index 4fadb649d..1d52503d1 100644 --- a/grid2op/Action/topologyAction.py +++ b/grid2op/Action/TopologyAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class TopologyAction(PlayableAction): diff --git a/grid2op/Action/topologyAndDispatchAction.py b/grid2op/Action/TopologyAndDispatchAction.py similarity index 95% rename from grid2op/Action/topologyAndDispatchAction.py rename to grid2op/Action/TopologyAndDispatchAction.py index b85443724..b167fded1 100644 --- a/grid2op/Action/topologyAndDispatchAction.py +++ b/grid2op/Action/TopologyAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class TopologyAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/topologyChangeAction.py b/grid2op/Action/TopologyChangeAction.py similarity index 94% rename from grid2op/Action/topologyChangeAction.py rename to grid2op/Action/TopologyChangeAction.py index c8ede25a2..eaea3e3a7 100644 --- a/grid2op/Action/topologyChangeAction.py +++ b/grid2op/Action/TopologyChangeAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class TopologyChangeAction(PlayableAction): diff --git a/grid2op/Action/topologyChangeAndDispatchAction.py b/grid2op/Action/TopologyChangeAndDispatchAction.py similarity index 95% rename from grid2op/Action/topologyChangeAndDispatchAction.py rename to grid2op/Action/TopologyChangeAndDispatchAction.py index 11947f262..4ec7e5148 100644 --- a/grid2op/Action/topologyChangeAndDispatchAction.py +++ b/grid2op/Action/TopologyChangeAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class TopologyChangeAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/topologySetAction.py b/grid2op/Action/TopologySetAction.py similarity index 94% rename from grid2op/Action/topologySetAction.py rename to grid2op/Action/TopologySetAction.py index 204109694..533d4ca0b 100644 --- a/grid2op/Action/topologySetAction.py +++ b/grid2op/Action/TopologySetAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class TopologySetAction(PlayableAction): diff --git a/grid2op/Action/topologySetAndDispatchAction.py b/grid2op/Action/TopologySetAndDispatchAction.py similarity index 95% rename from grid2op/Action/topologySetAndDispatchAction.py rename to grid2op/Action/TopologySetAndDispatchAction.py index dee7d797a..a8b36cf48 100644 --- a/grid2op/Action/topologySetAndDispatchAction.py +++ b/grid2op/Action/TopologySetAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.PlayableAction import PlayableAction class TopologySetAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/voltageOnlyAction.py b/grid2op/Action/VoltageOnlyAction.py similarity index 98% rename from grid2op/Action/voltageOnlyAction.py rename to grid2op/Action/VoltageOnlyAction.py index 637d87871..5ccc91b69 100644 --- a/grid2op/Action/voltageOnlyAction.py +++ b/grid2op/Action/VoltageOnlyAction.py @@ -9,7 +9,7 @@ import warnings from grid2op.Exceptions import AmbiguousAction -from grid2op.Action.baseAction import BaseAction +from grid2op.Action.BaseAction import BaseAction class VoltageOnlyAction(BaseAction): diff --git a/grid2op/Action/_backendAction.py b/grid2op/Action/_BackendAction.py similarity index 100% rename from grid2op/Action/_backendAction.py rename to grid2op/Action/_BackendAction.py diff --git a/grid2op/Action/__init__.py b/grid2op/Action/__init__.py index d082e05e8..830011a18 100644 --- a/grid2op/Action/__init__.py +++ b/grid2op/Action/__init__.py @@ -23,29 +23,29 @@ ] # Internals -from grid2op.Action.baseAction import BaseAction -from grid2op.Action.playableAction import PlayableAction -from grid2op.Action.voltageOnlyAction import VoltageOnlyAction -from grid2op.Action.completeAction import CompleteAction -from grid2op.Action.actionSpace import ActionSpace -from grid2op.Action.serializableActionSpace import SerializableActionSpace +from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.VoltageOnlyAction import VoltageOnlyAction +from grid2op.Action.CompleteAction import CompleteAction +from grid2op.Action.ActionSpace import ActionSpace +from grid2op.Action.SerializableActionSpace import SerializableActionSpace -from grid2op.Action.dontAct import DontAct -from grid2op.Action.powerlineSetAction import PowerlineSetAction -from grid2op.Action.powerlineChangeAction import PowerlineChangeAction -from grid2op.Action.powerlineSetAndDispatchAction import PowerlineSetAndDispatchAction -from grid2op.Action.powerlineChangeAndDispatchAction import ( +from grid2op.Action.DontAct import DontAct +from grid2op.Action.PowerlineSetAction import PowerlineSetAction +from grid2op.Action.PowerlineChangeAction import PowerlineChangeAction +from grid2op.Action.PowerlineSetAndDispatchAction import PowerlineSetAndDispatchAction +from grid2op.Action.PowerlineChangeAndDispatchAction import ( PowerlineChangeAndDispatchAction, ) -from grid2op.Action.powerlineChangeDispatchAndStorageAction import ( +from grid2op.Action.PowerlineChangeDispatchAndStorageAction import ( PowerlineChangeDispatchAndStorageAction, ) -from grid2op.Action.topologyAction import TopologyAction -from grid2op.Action.topologyAndDispatchAction import TopologyAndDispatchAction -from grid2op.Action.topologySetAction import TopologySetAction -from grid2op.Action.topologySetAndDispatchAction import TopologySetAndDispatchAction -from grid2op.Action.topologyChangeAction import TopologyChangeAction -from grid2op.Action.topologyChangeAndDispatchAction import ( +from grid2op.Action.TopologyAction import TopologyAction +from grid2op.Action.TopologyAndDispatchAction import TopologyAndDispatchAction +from grid2op.Action.TopologySetAction import TopologySetAction +from grid2op.Action.TopologySetAndDispatchAction import TopologySetAndDispatchAction +from grid2op.Action.TopologyChangeAction import TopologyChangeAction +from grid2op.Action.TopologyChangeAndDispatchAction import ( TopologyChangeAndDispatchAction, ) -from grid2op.Action.dispatchAction import DispatchAction +from grid2op.Action.DispatchAction import DispatchAction diff --git a/grid2op/Backend/backend.py b/grid2op/Backend/Backend.py similarity index 99% rename from grid2op/Backend/backend.py rename to grid2op/Backend/Backend.py index 15e155e36..3dfbfebce 100644 --- a/grid2op/Backend/backend.py +++ b/grid2op/Backend/Backend.py @@ -1744,7 +1744,7 @@ def assert_grid_correct(self): """ # lazy loading from grid2op.Action import CompleteAction - from grid2op.Action._backendAction import _BackendAction + from grid2op.Action._BackendAction import _BackendAction orig_type = type(self) if orig_type.my_bk_act_class is None: diff --git a/grid2op/Backend/educPandaPowerBackend.py b/grid2op/Backend/EducPandaPowerBackend.py similarity index 99% rename from grid2op/Backend/educPandaPowerBackend.py rename to grid2op/Backend/EducPandaPowerBackend.py index effbaa67c..a568bd1d5 100644 --- a/grid2op/Backend/educPandaPowerBackend.py +++ b/grid2op/Backend/EducPandaPowerBackend.py @@ -18,7 +18,7 @@ import scipy from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Backend.backend import Backend +from grid2op.Backend.Backend import Backend from grid2op.Exceptions import * diff --git a/grid2op/Backend/pandaPowerBackend.py b/grid2op/Backend/PandaPowerBackend.py similarity index 99% rename from grid2op/Backend/pandaPowerBackend.py rename to grid2op/Backend/PandaPowerBackend.py index f532115d5..f220db936 100644 --- a/grid2op/Backend/pandaPowerBackend.py +++ b/grid2op/Backend/PandaPowerBackend.py @@ -18,7 +18,7 @@ import scipy from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Backend.backend import Backend +from grid2op.Backend.Backend import Backend from grid2op.Action import BaseAction from grid2op.Exceptions import * diff --git a/grid2op/Backend/__init__.py b/grid2op/Backend/__init__.py index 8b681e473..4cde4a3d4 100644 --- a/grid2op/Backend/__init__.py +++ b/grid2op/Backend/__init__.py @@ -1,4 +1,4 @@ __all__ = ["Backend", "PandaPowerBackend"] -from grid2op.Backend.backend import Backend -from grid2op.Backend.pandaPowerBackend import PandaPowerBackend +from grid2op.Backend.Backend import Backend +from grid2op.Backend.PandaPowerBackend import PandaPowerBackend diff --git a/grid2op/Environment/baseEnv.py b/grid2op/Environment/BaseEnv.py similarity index 99% rename from grid2op/Environment/baseEnv.py rename to grid2op/Environment/BaseEnv.py index a25a90e73..f0bd657b9 100644 --- a/grid2op/Environment/baseEnv.py +++ b/grid2op/Environment/BaseEnv.py @@ -16,12 +16,13 @@ from typing import Optional, Tuple import warnings import numpy as np -from scipy.optimize import (minimize, LinearConstraint) +from scipy.optimize import minimize +from scipy.optimize import LinearConstraint from abc import ABC, abstractmethod -from grid2op.Action import ActionSpace -from grid2op.Observation import (BaseObservation, - ObservationSpace, - HighResSimCounter) +from grid2op.Action.ActionSpace import ActionSpace +from grid2op.Observation.baseObservation import BaseObservation +from grid2op.Observation.observationSpace import ObservationSpace +from grid2op.Observation.highresSimCounter import HighResSimCounter from grid2op.Backend import Backend from grid2op.dtypes import dt_int, dt_float, dt_bool from grid2op.Space import GridObjects, RandomObject @@ -34,7 +35,7 @@ from grid2op.Rules import AlwaysLegal from grid2op.Opponent import BaseOpponent from grid2op.operator_attention import LinearAttentionBudget -from grid2op.Action._backendAction import _BackendAction +from grid2op.Action._BackendAction import _BackendAction from grid2op.Chronics import ChronicsHandler from grid2op.Rules import AlwaysLegal, BaseRules diff --git a/grid2op/Environment/baseMultiProcessEnv.py b/grid2op/Environment/BaseMultiProcessEnv.py similarity index 99% rename from grid2op/Environment/baseMultiProcessEnv.py rename to grid2op/Environment/BaseMultiProcessEnv.py index 2d09ef88e..da49f917a 100644 --- a/grid2op/Environment/baseMultiProcessEnv.py +++ b/grid2op/Environment/BaseMultiProcessEnv.py @@ -14,7 +14,7 @@ from grid2op.dtypes import dt_int from grid2op.Exceptions import Grid2OpException, MultiEnvException from grid2op.Space import GridObjects -from grid2op.Environment.environment import Environment +from grid2op.Environment import Environment from grid2op.Action import BaseAction diff --git a/grid2op/Environment/environment.py b/grid2op/Environment/Environment.py similarity index 99% rename from grid2op/Environment/environment.py rename to grid2op/Environment/Environment.py index ca77cb4f9..98f6eab2e 100644 --- a/grid2op/Environment/environment.py +++ b/grid2op/Environment/Environment.py @@ -12,7 +12,7 @@ import re import grid2op -from grid2op.Opponent import OpponentSpace +from grid2op.Opponent.OpponentSpace import OpponentSpace from grid2op.dtypes import dt_float, dt_bool, dt_int from grid2op.Action import ( ActionSpace, @@ -28,7 +28,7 @@ from grid2op.Backend import Backend from grid2op.Chronics import ChronicsHandler from grid2op.VoltageControler import ControlVoltageFromFile, BaseVoltageController -from grid2op.Environment.baseEnv import BaseEnv +from grid2op.Environment.BaseEnv import BaseEnv from grid2op.Opponent import BaseOpponent, NeverAttackBudget from grid2op.operator_attention import LinearAttentionBudget diff --git a/grid2op/Environment/multiEnvMultiProcess.py b/grid2op/Environment/MultiEnvMultiProcess.py similarity index 98% rename from grid2op/Environment/multiEnvMultiProcess.py rename to grid2op/Environment/MultiEnvMultiProcess.py index 647113740..cf07296b6 100644 --- a/grid2op/Environment/multiEnvMultiProcess.py +++ b/grid2op/Environment/MultiEnvMultiProcess.py @@ -11,7 +11,7 @@ from grid2op.dtypes import dt_int from grid2op.Exceptions import Grid2OpException, MultiEnvException from grid2op.Space import GridObjects -from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment from grid2op.Action import BaseAction diff --git a/grid2op/Environment/multiMixEnv.py b/grid2op/Environment/MultiMixEnv.py similarity index 100% rename from grid2op/Environment/multiMixEnv.py rename to grid2op/Environment/MultiMixEnv.py diff --git a/grid2op/Environment/singleEnvMultiProcess.py b/grid2op/Environment/SingleEnvMultiProcess.py similarity index 98% rename from grid2op/Environment/singleEnvMultiProcess.py rename to grid2op/Environment/SingleEnvMultiProcess.py index f648b7e59..940a771dd 100644 --- a/grid2op/Environment/singleEnvMultiProcess.py +++ b/grid2op/Environment/SingleEnvMultiProcess.py @@ -8,7 +8,7 @@ import numpy as np -from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment class SingleEnvMultiProcess(BaseMultiProcessEnvironment): diff --git a/grid2op/Environment/_obsEnv.py b/grid2op/Environment/_ObsEnv.py similarity index 99% rename from grid2op/Environment/_obsEnv.py rename to grid2op/Environment/_ObsEnv.py index 8db0060d4..21ba36536 100644 --- a/grid2op/Environment/_obsEnv.py +++ b/grid2op/Environment/_ObsEnv.py @@ -12,7 +12,7 @@ from grid2op.Exceptions.EnvExceptions import EnvError from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Environment.baseEnv import BaseEnv +from grid2op.Environment.BaseEnv import BaseEnv from grid2op.Chronics import ChangeNothing from grid2op.Rules import RulesChecker from grid2op.operator_attention import LinearAttentionBudget diff --git a/grid2op/Environment/__init__.py b/grid2op/Environment/__init__.py index 1375aad0a..a171bf117 100644 --- a/grid2op/Environment/__init__.py +++ b/grid2op/Environment/__init__.py @@ -8,10 +8,10 @@ "TimedOutEnvironment" ] -from grid2op.Environment.baseEnv import BaseEnv -from grid2op.Environment.environment import Environment -from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment -from grid2op.Environment.singleEnvMultiProcess import SingleEnvMultiProcess -from grid2op.Environment.multiEnvMultiProcess import MultiEnvMultiProcess -from grid2op.Environment.multiMixEnv import MultiMixEnvironment +from grid2op.Environment.BaseEnv import BaseEnv +from grid2op.Environment.Environment import Environment +from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.SingleEnvMultiProcess import SingleEnvMultiProcess +from grid2op.Environment.MultiEnvMultiProcess import MultiEnvMultiProcess +from grid2op.Environment.MultiMixEnv import MultiMixEnvironment from grid2op.Environment.timedOutEnv import TimedOutEnvironment diff --git a/grid2op/Environment/_forecast_env.py b/grid2op/Environment/_forecast_env.py index ad08fc7df..8223ee067 100644 --- a/grid2op/Environment/_forecast_env.py +++ b/grid2op/Environment/_forecast_env.py @@ -9,7 +9,7 @@ from typing import Tuple from grid2op.Action import BaseAction from grid2op.Observation import BaseObservation -from grid2op.Environment.environment import Environment +from grid2op.Environment.Environment import Environment class _ForecastEnv(Environment): diff --git a/grid2op/Environment/timedOutEnv.py b/grid2op/Environment/timedOutEnv.py index fcccd7641..acf41e37e 100644 --- a/grid2op/Environment/timedOutEnv.py +++ b/grid2op/Environment/timedOutEnv.py @@ -9,7 +9,7 @@ import time from math import floor from typing import Tuple, Union, List -from grid2op.Environment.environment import Environment +from grid2op.Environment.Environment import Environment from grid2op.Action import BaseAction from grid2op.Observation import BaseObservation from grid2op.Exceptions import EnvError diff --git a/grid2op/Observation/__init__.py b/grid2op/Observation/__init__.py index fda4d0188..25548b022 100644 --- a/grid2op/Observation/__init__.py +++ b/grid2op/Observation/__init__.py @@ -12,11 +12,9 @@ "NoisyObservation", "BaseObservation", "ObservationSpace", - "HighResSimCounter", ] from grid2op.Observation.completeObservation import CompleteObservation from grid2op.Observation.noisyObservation import NoisyObservation from grid2op.Observation.baseObservation import BaseObservation from grid2op.Observation.observationSpace import ObservationSpace -from grid2op.Observation.highresSimCounter import HighResSimCounter diff --git a/grid2op/Observation/observationSpace.py b/grid2op/Observation/observationSpace.py index db81a8991..93c178508 100644 --- a/grid2op/Observation/observationSpace.py +++ b/grid2op/Observation/observationSpace.py @@ -82,7 +82,7 @@ def __init__( """ # lazy import to prevent circular references (Env -> Observation -> Obs Space -> _ObsEnv -> Env) - from grid2op.Environment._obsEnv import _ObsEnv + from grid2op.Environment._ObsEnv import _ObsEnv if actionClass is None: from grid2op.Action import CompleteAction @@ -150,7 +150,7 @@ def set_real_env_kwargs(self, env): if not self.with_forecast: return # I don't need the backend nor the chronics_handler - from grid2op.Environment import Environment + from grid2op.Environment.Environment import Environment self._real_env_kwargs = Environment.get_kwargs(env, False, False) # remove the parameters anyways (the 'forecast parameters will be used diff --git a/grid2op/Reward/_alarmScore.py b/grid2op/Reward/_alarmScore.py index b4c69ff5d..fead57d6b 100644 --- a/grid2op/Reward/_alarmScore.py +++ b/grid2op/Reward/_alarmScore.py @@ -65,7 +65,14 @@ def __init__(self, logger=None): self.disc_lines_all_before_cascade = [] self.n_line = None - self._i_am_simulate = True + + # This class remembers the past state of the grid, this does not make sense for the "simulate" env + # so i deactivate it in this case. + from grid2op.Environment._ObsEnv import ( + _ObsEnv, + ) # to avoid circular dependencies + + self._deactivate_reward_cls = (_ObsEnv,) def initialize(self, env): if not env._has_attention_budget: @@ -81,7 +88,6 @@ def reset(self, env): super().reset(env) self.window_disconnection = max(self.best_time - self.window_size, 4) self.disc_lines_all_before_cascade = [] - self._i_am_simulate = self.is_simulated_env(env) def _lines_disconnected_first(self, disc_lines_at_cascading_time): """ @@ -111,7 +117,7 @@ def _lines_disconnected_first(self, disc_lines_at_cascading_time): return 1 - disc_lines_to_consider_for_score def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - if self._i_am_simulate: + if self.is_simulated_env(env): return self.reward_no_game_over disc_lines_now = env._disc_lines diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index b60f2ef05..e4b9edc27 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -38,7 +38,7 @@ def initialize(self, env): self.reset(env) def reset(self, env): - self._is_simul_env = self.is_simulated_env(env) + self._is_simul_env = is_simulated_env(env) if self._is_simul_env: return @@ -76,4 +76,15 @@ def _surlinear_func_curtailment(x, center=80, eps=1e-6): f_standardizer= lambda x : np.ones_like(x) * f_centralized(100) * (x >= center) - np.ones_like(x) * f_centralized(50) * (x < center) return f_centralized(x) / f_standardizer(x) + + +#to wait before PR Laure +def is_simulated_env(env): + + # to prevent cyclical import + from grid2op.Environment._ObsEnv import _ObsEnv + from grid2op.Environment._forecast_env import _ForecastEnv + + # This reward is not compatible with simulations + return isinstance(env, (_ObsEnv, _ForecastEnv)) diff --git a/grid2op/Reward/baseReward.py b/grid2op/Reward/baseReward.py index 164f54e0b..320bd5d07 100644 --- a/grid2op/Reward/baseReward.py +++ b/grid2op/Reward/baseReward.py @@ -120,7 +120,7 @@ def __init__(self, logger: logging.Logger=None): def is_simulated_env(self, env): # to prevent cyclical import - from grid2op.Environment._obsEnv import _ObsEnv + from grid2op.Environment._ObsEnv import _ObsEnv from grid2op.Environment._forecast_env import _ForecastEnv return isinstance(env, (_ObsEnv, _ForecastEnv)) diff --git a/grid2op/Reward/n1Reward.py b/grid2op/Reward/n1Reward.py index 9d11561ef..b31a9904e 100644 --- a/grid2op/Reward/n1Reward.py +++ b/grid2op/Reward/n1Reward.py @@ -8,7 +8,7 @@ import copy from grid2op.Reward import BaseReward -from grid2op.Action._backendAction import _BackendAction +from grid2op.Action._BackendAction import _BackendAction class N1Reward(BaseReward): diff --git a/grid2op/tests/BaseBackendTest.py b/grid2op/tests/BaseBackendTest.py index 01e849e20..3ea0ddd4b 100644 --- a/grid2op/tests/BaseBackendTest.py +++ b/grid2op/tests/BaseBackendTest.py @@ -57,7 +57,7 @@ def comb(n, k): from grid2op.Rules import RulesChecker from grid2op.MakeEnv import make from grid2op.Rules import AlwaysLegal -from grid2op.Action._backendAction import _BackendAction +from grid2op.Action._BackendAction import _BackendAction import pdb diff --git a/grid2op/tests/test_attached_envs.py b/grid2op/tests/test_attached_envs.py index 42b18a67f..92c571088 100644 --- a/grid2op/tests/test_attached_envs.py +++ b/grid2op/tests/test_attached_envs.py @@ -10,10 +10,10 @@ import unittest import grid2op -from grid2op.Action.powerlineSetAction import PowerlineSetAction +from grid2op.Action.PowerlineSetAction import PowerlineSetAction from grid2op.Action.PlayableAction import PlayableAction from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.dontAct import DontAct +from grid2op.Action.DontAct import DontAct from grid2op.Opponent import GeometricOpponent import pdb diff --git a/grid2op/tests/test_attached_envs_compat.py b/grid2op/tests/test_attached_envs_compat.py index 84b3b0b3d..d09a51015 100644 --- a/grid2op/tests/test_attached_envs_compat.py +++ b/grid2op/tests/test_attached_envs_compat.py @@ -13,10 +13,10 @@ import numpy as np from grid2op.Space import GridObjects -from grid2op.Action.powerlineSetAction import PowerlineSetAction +from grid2op.Action.PowerlineSetAction import PowerlineSetAction from grid2op.Action.PlayableAction import PlayableAction from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.dontAct import DontAct +from grid2op.Action.DontAct import DontAct import pdb From a88293a28f3751bfb5ed17e1a6c05a70fbf14ef1 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 11:44:07 +0200 Subject: [PATCH 062/103] renaming to lower case file in Action, Backend and Environment --- CHANGELOG.rst | 12 +++++- grid2op/Action/__init__.py | 38 +++++++++---------- .../{_BackendAction.py => _backendAction.py} | 0 .../Action/{ActionSpace.py => actionSpace.py} | 4 +- .../Action/{BaseAction.py => baseAction.py} | 0 .../{CompleteAction.py => completeAction.py} | 2 +- .../{DispatchAction.py => dispatchAction.py} | 2 +- grid2op/Action/{DontAct.py => dontAct.py} | 2 +- .../{PlayableAction.py => playableAction.py} | 2 +- ...angeAction.py => powerlineChangeAction.py} | 2 +- ...py => powerlineChangeAndDispatchAction.py} | 2 +- ...owerlineChangeDispatchAndStorageAction.py} | 2 +- ...lineSetAction.py => powerlineSetAction.py} | 2 +- ...on.py => powerlineSetAndDispatchAction.py} | 2 +- ...ionSpace.py => serializableActionSpace.py} | 2 +- .../{TopologyAction.py => topologyAction.py} | 2 +- ...Action.py => topologyAndDispatchAction.py} | 2 +- ...hangeAction.py => topologyChangeAction.py} | 2 +- ....py => topologyChangeAndDispatchAction.py} | 2 +- ...ologySetAction.py => topologySetAction.py} | 2 +- ...ion.py => topologySetAndDispatchAction.py} | 2 +- ...tageOnlyAction.py => voltageOnlyAction.py} | 2 +- grid2op/Backend/__init__.py | 4 +- grid2op/Backend/{Backend.py => backend.py} | 2 +- ...werBackend.py => educPandaPowerBackend.py} | 2 +- ...daPowerBackend.py => pandaPowerBackend.py} | 2 +- grid2op/Environment/__init__.py | 12 +++--- grid2op/Environment/_forecast_env.py | 2 +- .../Environment/{_ObsEnv.py => _obsEnv.py} | 2 +- .../Environment/{BaseEnv.py => baseEnv.py} | 13 +++---- ...tiProcessEnv.py => baseMultiProcessEnv.py} | 2 +- .../{Environment.py => environment.py} | 4 +- ...ultiProcess.py => multiEnvMultiProcess.py} | 2 +- .../{MultiMixEnv.py => multiMixEnv.py} | 0 ...ltiProcess.py => singleEnvMultiProcess.py} | 2 +- grid2op/Environment/timedOutEnv.py | 2 +- grid2op/Observation/__init__.py | 2 + grid2op/Observation/observationSpace.py | 4 +- grid2op/Reward/_alarmScore.py | 12 ++---- .../Reward/_newRenewableSourcesUsageScore.py | 13 +------ grid2op/Reward/baseReward.py | 2 +- grid2op/Reward/n1Reward.py | 2 +- grid2op/tests/BaseBackendTest.py | 2 +- grid2op/tests/test_attached_envs.py | 4 +- grid2op/tests/test_attached_envs_compat.py | 4 +- 45 files changed, 88 insertions(+), 96 deletions(-) rename grid2op/Action/{_BackendAction.py => _backendAction.py} (100%) rename grid2op/Action/{ActionSpace.py => actionSpace.py} (98%) rename grid2op/Action/{BaseAction.py => baseAction.py} (100%) rename grid2op/Action/{CompleteAction.py => completeAction.py} (94%) rename grid2op/Action/{DispatchAction.py => dispatchAction.py} (94%) rename grid2op/Action/{DontAct.py => dontAct.py} (96%) rename grid2op/Action/{PlayableAction.py => playableAction.py} (98%) rename grid2op/Action/{PowerlineChangeAction.py => powerlineChangeAction.py} (94%) rename grid2op/Action/{PowerlineChangeAndDispatchAction.py => powerlineChangeAndDispatchAction.py} (94%) rename grid2op/Action/{PowerlineChangeDispatchAndStorageAction.py => powerlineChangeDispatchAndStorageAction.py} (93%) rename grid2op/Action/{PowerlineSetAction.py => powerlineSetAction.py} (94%) rename grid2op/Action/{PowerlineSetAndDispatchAction.py => powerlineSetAndDispatchAction.py} (95%) rename grid2op/Action/{SerializableActionSpace.py => serializableActionSpace.py} (99%) rename grid2op/Action/{TopologyAction.py => topologyAction.py} (95%) rename grid2op/Action/{TopologyAndDispatchAction.py => topologyAndDispatchAction.py} (95%) rename grid2op/Action/{TopologyChangeAction.py => topologyChangeAction.py} (94%) rename grid2op/Action/{TopologyChangeAndDispatchAction.py => topologyChangeAndDispatchAction.py} (95%) rename grid2op/Action/{TopologySetAction.py => topologySetAction.py} (94%) rename grid2op/Action/{TopologySetAndDispatchAction.py => topologySetAndDispatchAction.py} (95%) rename grid2op/Action/{VoltageOnlyAction.py => voltageOnlyAction.py} (98%) rename grid2op/Backend/{Backend.py => backend.py} (99%) rename grid2op/Backend/{EducPandaPowerBackend.py => educPandaPowerBackend.py} (99%) rename grid2op/Backend/{PandaPowerBackend.py => pandaPowerBackend.py} (99%) rename grid2op/Environment/{_ObsEnv.py => _obsEnv.py} (99%) rename grid2op/Environment/{BaseEnv.py => baseEnv.py} (99%) rename grid2op/Environment/{BaseMultiProcessEnv.py => baseMultiProcessEnv.py} (99%) rename grid2op/Environment/{Environment.py => environment.py} (99%) rename grid2op/Environment/{MultiEnvMultiProcess.py => multiEnvMultiProcess.py} (98%) rename grid2op/Environment/{MultiMixEnv.py => multiMixEnv.py} (100%) rename grid2op/Environment/{SingleEnvMultiProcess.py => singleEnvMultiProcess.py} (98%) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f43eb501e..24f6d6755 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,13 +33,21 @@ Change Log [1.9.2] - 2023-07-xx --------------------- +- [BREAKING] rename with filename starting with lowercase all the files in the "`Backend`", "`Action`" and + "`Environment`" modules. This is both consistent with python practice but allows also to make the + difference between the files in the + module and the class imported. This should have little to no impact on all codes but to "upgrade" + instead of `from grid2op.Action.BaseAction import BaseAction` (which you should not have done in the first place) + just do `from grid2op.Action import BaseAction`. Expect other changes like this for other grid2op modules + in the near future. - [FIXED] broken environ "l2rpn_idf_2023" (with test=True) due to the presence of a `__pycache__` folder - [FIXED] time series `MultiFolder` will now ignore folder `__pycache__` - [FIXED] an issue with compatibility with previous versions (due to alert) -- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (self.is_simulated_env() +- [FIXED] an issue with the `_ObsEnv` when using reward that could not be used in forecast (`self.is_simulated_env()` was not working as expected due to a wrong init of the reward in `_ObsEnv`) - [FIXED] an issue when disconnecting loads / generators / storage units and changing their values in the same - action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" has the priority and + action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" have the priority (if + an action disconnect an element, it will not change its sepoint at the same time). - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance - [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction` diff --git a/grid2op/Action/__init__.py b/grid2op/Action/__init__.py index 830011a18..d082e05e8 100644 --- a/grid2op/Action/__init__.py +++ b/grid2op/Action/__init__.py @@ -23,29 +23,29 @@ ] # Internals -from grid2op.Action.BaseAction import BaseAction -from grid2op.Action.PlayableAction import PlayableAction -from grid2op.Action.VoltageOnlyAction import VoltageOnlyAction -from grid2op.Action.CompleteAction import CompleteAction -from grid2op.Action.ActionSpace import ActionSpace -from grid2op.Action.SerializableActionSpace import SerializableActionSpace +from grid2op.Action.baseAction import BaseAction +from grid2op.Action.playableAction import PlayableAction +from grid2op.Action.voltageOnlyAction import VoltageOnlyAction +from grid2op.Action.completeAction import CompleteAction +from grid2op.Action.actionSpace import ActionSpace +from grid2op.Action.serializableActionSpace import SerializableActionSpace -from grid2op.Action.DontAct import DontAct -from grid2op.Action.PowerlineSetAction import PowerlineSetAction -from grid2op.Action.PowerlineChangeAction import PowerlineChangeAction -from grid2op.Action.PowerlineSetAndDispatchAction import PowerlineSetAndDispatchAction -from grid2op.Action.PowerlineChangeAndDispatchAction import ( +from grid2op.Action.dontAct import DontAct +from grid2op.Action.powerlineSetAction import PowerlineSetAction +from grid2op.Action.powerlineChangeAction import PowerlineChangeAction +from grid2op.Action.powerlineSetAndDispatchAction import PowerlineSetAndDispatchAction +from grid2op.Action.powerlineChangeAndDispatchAction import ( PowerlineChangeAndDispatchAction, ) -from grid2op.Action.PowerlineChangeDispatchAndStorageAction import ( +from grid2op.Action.powerlineChangeDispatchAndStorageAction import ( PowerlineChangeDispatchAndStorageAction, ) -from grid2op.Action.TopologyAction import TopologyAction -from grid2op.Action.TopologyAndDispatchAction import TopologyAndDispatchAction -from grid2op.Action.TopologySetAction import TopologySetAction -from grid2op.Action.TopologySetAndDispatchAction import TopologySetAndDispatchAction -from grid2op.Action.TopologyChangeAction import TopologyChangeAction -from grid2op.Action.TopologyChangeAndDispatchAction import ( +from grid2op.Action.topologyAction import TopologyAction +from grid2op.Action.topologyAndDispatchAction import TopologyAndDispatchAction +from grid2op.Action.topologySetAction import TopologySetAction +from grid2op.Action.topologySetAndDispatchAction import TopologySetAndDispatchAction +from grid2op.Action.topologyChangeAction import TopologyChangeAction +from grid2op.Action.topologyChangeAndDispatchAction import ( TopologyChangeAndDispatchAction, ) -from grid2op.Action.DispatchAction import DispatchAction +from grid2op.Action.dispatchAction import DispatchAction diff --git a/grid2op/Action/_BackendAction.py b/grid2op/Action/_backendAction.py similarity index 100% rename from grid2op/Action/_BackendAction.py rename to grid2op/Action/_backendAction.py diff --git a/grid2op/Action/ActionSpace.py b/grid2op/Action/actionSpace.py similarity index 98% rename from grid2op/Action/ActionSpace.py rename to grid2op/Action/actionSpace.py index 73b06e722..c7ade19a7 100644 --- a/grid2op/Action/ActionSpace.py +++ b/grid2op/Action/actionSpace.py @@ -9,8 +9,8 @@ import warnings import copy -from grid2op.Action.BaseAction import BaseAction -from grid2op.Action.SerializableActionSpace import SerializableActionSpace +from grid2op.Action.baseAction import BaseAction +from grid2op.Action.serializableActionSpace import SerializableActionSpace class ActionSpace(SerializableActionSpace): diff --git a/grid2op/Action/BaseAction.py b/grid2op/Action/baseAction.py similarity index 100% rename from grid2op/Action/BaseAction.py rename to grid2op/Action/baseAction.py diff --git a/grid2op/Action/CompleteAction.py b/grid2op/Action/completeAction.py similarity index 94% rename from grid2op/Action/CompleteAction.py rename to grid2op/Action/completeAction.py index d4e12ec54..548b59009 100644 --- a/grid2op/Action/CompleteAction.py +++ b/grid2op/Action/completeAction.py @@ -5,7 +5,7 @@ # you can obtain one at http://mozilla.org/MPL/2.0/. # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class CompleteAction(BaseAction): diff --git a/grid2op/Action/DispatchAction.py b/grid2op/Action/dispatchAction.py similarity index 94% rename from grid2op/Action/DispatchAction.py rename to grid2op/Action/dispatchAction.py index 9c4f7d6f7..b0ec07fc9 100644 --- a/grid2op/Action/DispatchAction.py +++ b/grid2op/Action/dispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class DispatchAction(PlayableAction): diff --git a/grid2op/Action/DontAct.py b/grid2op/Action/dontAct.py similarity index 96% rename from grid2op/Action/DontAct.py rename to grid2op/Action/dontAct.py index afe2c622c..09fd0d1c1 100644 --- a/grid2op/Action/DontAct.py +++ b/grid2op/Action/dontAct.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class DontAct(PlayableAction): diff --git a/grid2op/Action/PlayableAction.py b/grid2op/Action/playableAction.py similarity index 98% rename from grid2op/Action/PlayableAction.py rename to grid2op/Action/playableAction.py index 61f3dfccb..fd854863e 100644 --- a/grid2op/Action/PlayableAction.py +++ b/grid2op/Action/playableAction.py @@ -9,7 +9,7 @@ import warnings from grid2op.Exceptions import AmbiguousAction -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class PlayableAction(BaseAction): diff --git a/grid2op/Action/PowerlineChangeAction.py b/grid2op/Action/powerlineChangeAction.py similarity index 94% rename from grid2op/Action/PowerlineChangeAction.py rename to grid2op/Action/powerlineChangeAction.py index 6c00bc759..e678d6a03 100644 --- a/grid2op/Action/PowerlineChangeAction.py +++ b/grid2op/Action/powerlineChangeAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineChangeAction(PlayableAction): diff --git a/grid2op/Action/PowerlineChangeAndDispatchAction.py b/grid2op/Action/powerlineChangeAndDispatchAction.py similarity index 94% rename from grid2op/Action/PowerlineChangeAndDispatchAction.py rename to grid2op/Action/powerlineChangeAndDispatchAction.py index 3cd684dd4..759d241e0 100644 --- a/grid2op/Action/PowerlineChangeAndDispatchAction.py +++ b/grid2op/Action/powerlineChangeAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineChangeAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/PowerlineChangeDispatchAndStorageAction.py b/grid2op/Action/powerlineChangeDispatchAndStorageAction.py similarity index 93% rename from grid2op/Action/PowerlineChangeDispatchAndStorageAction.py rename to grid2op/Action/powerlineChangeDispatchAndStorageAction.py index 4049b0656..7a0dfa0d0 100644 --- a/grid2op/Action/PowerlineChangeDispatchAndStorageAction.py +++ b/grid2op/Action/powerlineChangeDispatchAndStorageAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineChangeDispatchAndStorageAction(PlayableAction): diff --git a/grid2op/Action/PowerlineSetAction.py b/grid2op/Action/powerlineSetAction.py similarity index 94% rename from grid2op/Action/PowerlineSetAction.py rename to grid2op/Action/powerlineSetAction.py index a506557e9..81c6b67b9 100644 --- a/grid2op/Action/PowerlineSetAction.py +++ b/grid2op/Action/powerlineSetAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineSetAction(PlayableAction): diff --git a/grid2op/Action/PowerlineSetAndDispatchAction.py b/grid2op/Action/powerlineSetAndDispatchAction.py similarity index 95% rename from grid2op/Action/PowerlineSetAndDispatchAction.py rename to grid2op/Action/powerlineSetAndDispatchAction.py index b29e24193..97920d65a 100644 --- a/grid2op/Action/PowerlineSetAndDispatchAction.py +++ b/grid2op/Action/powerlineSetAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class PowerlineSetAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/SerializableActionSpace.py b/grid2op/Action/serializableActionSpace.py similarity index 99% rename from grid2op/Action/SerializableActionSpace.py rename to grid2op/Action/serializableActionSpace.py index a2fbbfcc6..7c11d2312 100644 --- a/grid2op/Action/SerializableActionSpace.py +++ b/grid2op/Action/serializableActionSpace.py @@ -14,7 +14,7 @@ from grid2op.dtypes import dt_int, dt_float, dt_bool from grid2op.Exceptions import AmbiguousAction, Grid2OpException from grid2op.Space import SerializableSpace -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class SerializableActionSpace(SerializableSpace): diff --git a/grid2op/Action/TopologyAction.py b/grid2op/Action/topologyAction.py similarity index 95% rename from grid2op/Action/TopologyAction.py rename to grid2op/Action/topologyAction.py index 1d52503d1..4fadb649d 100644 --- a/grid2op/Action/TopologyAction.py +++ b/grid2op/Action/topologyAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyAction(PlayableAction): diff --git a/grid2op/Action/TopologyAndDispatchAction.py b/grid2op/Action/topologyAndDispatchAction.py similarity index 95% rename from grid2op/Action/TopologyAndDispatchAction.py rename to grid2op/Action/topologyAndDispatchAction.py index b167fded1..b85443724 100644 --- a/grid2op/Action/TopologyAndDispatchAction.py +++ b/grid2op/Action/topologyAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/TopologyChangeAction.py b/grid2op/Action/topologyChangeAction.py similarity index 94% rename from grid2op/Action/TopologyChangeAction.py rename to grid2op/Action/topologyChangeAction.py index eaea3e3a7..c8ede25a2 100644 --- a/grid2op/Action/TopologyChangeAction.py +++ b/grid2op/Action/topologyChangeAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyChangeAction(PlayableAction): diff --git a/grid2op/Action/TopologyChangeAndDispatchAction.py b/grid2op/Action/topologyChangeAndDispatchAction.py similarity index 95% rename from grid2op/Action/TopologyChangeAndDispatchAction.py rename to grid2op/Action/topologyChangeAndDispatchAction.py index 4ec7e5148..11947f262 100644 --- a/grid2op/Action/TopologyChangeAndDispatchAction.py +++ b/grid2op/Action/topologyChangeAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologyChangeAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/TopologySetAction.py b/grid2op/Action/topologySetAction.py similarity index 94% rename from grid2op/Action/TopologySetAction.py rename to grid2op/Action/topologySetAction.py index 533d4ca0b..204109694 100644 --- a/grid2op/Action/TopologySetAction.py +++ b/grid2op/Action/topologySetAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologySetAction(PlayableAction): diff --git a/grid2op/Action/TopologySetAndDispatchAction.py b/grid2op/Action/topologySetAndDispatchAction.py similarity index 95% rename from grid2op/Action/TopologySetAndDispatchAction.py rename to grid2op/Action/topologySetAndDispatchAction.py index a8b36cf48..dee7d797a 100644 --- a/grid2op/Action/TopologySetAndDispatchAction.py +++ b/grid2op/Action/topologySetAndDispatchAction.py @@ -6,7 +6,7 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction class TopologySetAndDispatchAction(PlayableAction): diff --git a/grid2op/Action/VoltageOnlyAction.py b/grid2op/Action/voltageOnlyAction.py similarity index 98% rename from grid2op/Action/VoltageOnlyAction.py rename to grid2op/Action/voltageOnlyAction.py index 5ccc91b69..637d87871 100644 --- a/grid2op/Action/VoltageOnlyAction.py +++ b/grid2op/Action/voltageOnlyAction.py @@ -9,7 +9,7 @@ import warnings from grid2op.Exceptions import AmbiguousAction -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action.baseAction import BaseAction class VoltageOnlyAction(BaseAction): diff --git a/grid2op/Backend/__init__.py b/grid2op/Backend/__init__.py index 4cde4a3d4..8b681e473 100644 --- a/grid2op/Backend/__init__.py +++ b/grid2op/Backend/__init__.py @@ -1,4 +1,4 @@ __all__ = ["Backend", "PandaPowerBackend"] -from grid2op.Backend.Backend import Backend -from grid2op.Backend.PandaPowerBackend import PandaPowerBackend +from grid2op.Backend.backend import Backend +from grid2op.Backend.pandaPowerBackend import PandaPowerBackend diff --git a/grid2op/Backend/Backend.py b/grid2op/Backend/backend.py similarity index 99% rename from grid2op/Backend/Backend.py rename to grid2op/Backend/backend.py index 3dfbfebce..15e155e36 100644 --- a/grid2op/Backend/Backend.py +++ b/grid2op/Backend/backend.py @@ -1744,7 +1744,7 @@ def assert_grid_correct(self): """ # lazy loading from grid2op.Action import CompleteAction - from grid2op.Action._BackendAction import _BackendAction + from grid2op.Action._backendAction import _BackendAction orig_type = type(self) if orig_type.my_bk_act_class is None: diff --git a/grid2op/Backend/EducPandaPowerBackend.py b/grid2op/Backend/educPandaPowerBackend.py similarity index 99% rename from grid2op/Backend/EducPandaPowerBackend.py rename to grid2op/Backend/educPandaPowerBackend.py index a568bd1d5..effbaa67c 100644 --- a/grid2op/Backend/EducPandaPowerBackend.py +++ b/grid2op/Backend/educPandaPowerBackend.py @@ -18,7 +18,7 @@ import scipy from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Backend.Backend import Backend +from grid2op.Backend.backend import Backend from grid2op.Exceptions import * diff --git a/grid2op/Backend/PandaPowerBackend.py b/grid2op/Backend/pandaPowerBackend.py similarity index 99% rename from grid2op/Backend/PandaPowerBackend.py rename to grid2op/Backend/pandaPowerBackend.py index f220db936..f532115d5 100644 --- a/grid2op/Backend/PandaPowerBackend.py +++ b/grid2op/Backend/pandaPowerBackend.py @@ -18,7 +18,7 @@ import scipy from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Backend.Backend import Backend +from grid2op.Backend.backend import Backend from grid2op.Action import BaseAction from grid2op.Exceptions import * diff --git a/grid2op/Environment/__init__.py b/grid2op/Environment/__init__.py index a171bf117..1375aad0a 100644 --- a/grid2op/Environment/__init__.py +++ b/grid2op/Environment/__init__.py @@ -8,10 +8,10 @@ "TimedOutEnvironment" ] -from grid2op.Environment.BaseEnv import BaseEnv -from grid2op.Environment.Environment import Environment -from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment -from grid2op.Environment.SingleEnvMultiProcess import SingleEnvMultiProcess -from grid2op.Environment.MultiEnvMultiProcess import MultiEnvMultiProcess -from grid2op.Environment.MultiMixEnv import MultiMixEnvironment +from grid2op.Environment.baseEnv import BaseEnv +from grid2op.Environment.environment import Environment +from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.singleEnvMultiProcess import SingleEnvMultiProcess +from grid2op.Environment.multiEnvMultiProcess import MultiEnvMultiProcess +from grid2op.Environment.multiMixEnv import MultiMixEnvironment from grid2op.Environment.timedOutEnv import TimedOutEnvironment diff --git a/grid2op/Environment/_forecast_env.py b/grid2op/Environment/_forecast_env.py index 8223ee067..ad08fc7df 100644 --- a/grid2op/Environment/_forecast_env.py +++ b/grid2op/Environment/_forecast_env.py @@ -9,7 +9,7 @@ from typing import Tuple from grid2op.Action import BaseAction from grid2op.Observation import BaseObservation -from grid2op.Environment.Environment import Environment +from grid2op.Environment.environment import Environment class _ForecastEnv(Environment): diff --git a/grid2op/Environment/_ObsEnv.py b/grid2op/Environment/_obsEnv.py similarity index 99% rename from grid2op/Environment/_ObsEnv.py rename to grid2op/Environment/_obsEnv.py index 21ba36536..8db0060d4 100644 --- a/grid2op/Environment/_ObsEnv.py +++ b/grid2op/Environment/_obsEnv.py @@ -12,7 +12,7 @@ from grid2op.Exceptions.EnvExceptions import EnvError from grid2op.dtypes import dt_int, dt_float, dt_bool -from grid2op.Environment.BaseEnv import BaseEnv +from grid2op.Environment.baseEnv import BaseEnv from grid2op.Chronics import ChangeNothing from grid2op.Rules import RulesChecker from grid2op.operator_attention import LinearAttentionBudget diff --git a/grid2op/Environment/BaseEnv.py b/grid2op/Environment/baseEnv.py similarity index 99% rename from grid2op/Environment/BaseEnv.py rename to grid2op/Environment/baseEnv.py index f0bd657b9..a25a90e73 100644 --- a/grid2op/Environment/BaseEnv.py +++ b/grid2op/Environment/baseEnv.py @@ -16,13 +16,12 @@ from typing import Optional, Tuple import warnings import numpy as np -from scipy.optimize import minimize -from scipy.optimize import LinearConstraint +from scipy.optimize import (minimize, LinearConstraint) from abc import ABC, abstractmethod -from grid2op.Action.ActionSpace import ActionSpace -from grid2op.Observation.baseObservation import BaseObservation -from grid2op.Observation.observationSpace import ObservationSpace -from grid2op.Observation.highresSimCounter import HighResSimCounter +from grid2op.Action import ActionSpace +from grid2op.Observation import (BaseObservation, + ObservationSpace, + HighResSimCounter) from grid2op.Backend import Backend from grid2op.dtypes import dt_int, dt_float, dt_bool from grid2op.Space import GridObjects, RandomObject @@ -35,7 +34,7 @@ from grid2op.Rules import AlwaysLegal from grid2op.Opponent import BaseOpponent from grid2op.operator_attention import LinearAttentionBudget -from grid2op.Action._BackendAction import _BackendAction +from grid2op.Action._backendAction import _BackendAction from grid2op.Chronics import ChronicsHandler from grid2op.Rules import AlwaysLegal, BaseRules diff --git a/grid2op/Environment/BaseMultiProcessEnv.py b/grid2op/Environment/baseMultiProcessEnv.py similarity index 99% rename from grid2op/Environment/BaseMultiProcessEnv.py rename to grid2op/Environment/baseMultiProcessEnv.py index da49f917a..2d09ef88e 100644 --- a/grid2op/Environment/BaseMultiProcessEnv.py +++ b/grid2op/Environment/baseMultiProcessEnv.py @@ -14,7 +14,7 @@ from grid2op.dtypes import dt_int from grid2op.Exceptions import Grid2OpException, MultiEnvException from grid2op.Space import GridObjects -from grid2op.Environment import Environment +from grid2op.Environment.environment import Environment from grid2op.Action import BaseAction diff --git a/grid2op/Environment/Environment.py b/grid2op/Environment/environment.py similarity index 99% rename from grid2op/Environment/Environment.py rename to grid2op/Environment/environment.py index 98f6eab2e..ca77cb4f9 100644 --- a/grid2op/Environment/Environment.py +++ b/grid2op/Environment/environment.py @@ -12,7 +12,7 @@ import re import grid2op -from grid2op.Opponent.OpponentSpace import OpponentSpace +from grid2op.Opponent import OpponentSpace from grid2op.dtypes import dt_float, dt_bool, dt_int from grid2op.Action import ( ActionSpace, @@ -28,7 +28,7 @@ from grid2op.Backend import Backend from grid2op.Chronics import ChronicsHandler from grid2op.VoltageControler import ControlVoltageFromFile, BaseVoltageController -from grid2op.Environment.BaseEnv import BaseEnv +from grid2op.Environment.baseEnv import BaseEnv from grid2op.Opponent import BaseOpponent, NeverAttackBudget from grid2op.operator_attention import LinearAttentionBudget diff --git a/grid2op/Environment/MultiEnvMultiProcess.py b/grid2op/Environment/multiEnvMultiProcess.py similarity index 98% rename from grid2op/Environment/MultiEnvMultiProcess.py rename to grid2op/Environment/multiEnvMultiProcess.py index cf07296b6..647113740 100644 --- a/grid2op/Environment/MultiEnvMultiProcess.py +++ b/grid2op/Environment/multiEnvMultiProcess.py @@ -11,7 +11,7 @@ from grid2op.dtypes import dt_int from grid2op.Exceptions import Grid2OpException, MultiEnvException from grid2op.Space import GridObjects -from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment from grid2op.Action import BaseAction diff --git a/grid2op/Environment/MultiMixEnv.py b/grid2op/Environment/multiMixEnv.py similarity index 100% rename from grid2op/Environment/MultiMixEnv.py rename to grid2op/Environment/multiMixEnv.py diff --git a/grid2op/Environment/SingleEnvMultiProcess.py b/grid2op/Environment/singleEnvMultiProcess.py similarity index 98% rename from grid2op/Environment/SingleEnvMultiProcess.py rename to grid2op/Environment/singleEnvMultiProcess.py index 940a771dd..f648b7e59 100644 --- a/grid2op/Environment/SingleEnvMultiProcess.py +++ b/grid2op/Environment/singleEnvMultiProcess.py @@ -8,7 +8,7 @@ import numpy as np -from grid2op.Environment.BaseMultiProcessEnv import BaseMultiProcessEnvironment +from grid2op.Environment.baseMultiProcessEnv import BaseMultiProcessEnvironment class SingleEnvMultiProcess(BaseMultiProcessEnvironment): diff --git a/grid2op/Environment/timedOutEnv.py b/grid2op/Environment/timedOutEnv.py index acf41e37e..fcccd7641 100644 --- a/grid2op/Environment/timedOutEnv.py +++ b/grid2op/Environment/timedOutEnv.py @@ -9,7 +9,7 @@ import time from math import floor from typing import Tuple, Union, List -from grid2op.Environment.Environment import Environment +from grid2op.Environment.environment import Environment from grid2op.Action import BaseAction from grid2op.Observation import BaseObservation from grid2op.Exceptions import EnvError diff --git a/grid2op/Observation/__init__.py b/grid2op/Observation/__init__.py index 25548b022..fda4d0188 100644 --- a/grid2op/Observation/__init__.py +++ b/grid2op/Observation/__init__.py @@ -12,9 +12,11 @@ "NoisyObservation", "BaseObservation", "ObservationSpace", + "HighResSimCounter", ] from grid2op.Observation.completeObservation import CompleteObservation from grid2op.Observation.noisyObservation import NoisyObservation from grid2op.Observation.baseObservation import BaseObservation from grid2op.Observation.observationSpace import ObservationSpace +from grid2op.Observation.highresSimCounter import HighResSimCounter diff --git a/grid2op/Observation/observationSpace.py b/grid2op/Observation/observationSpace.py index 93c178508..db81a8991 100644 --- a/grid2op/Observation/observationSpace.py +++ b/grid2op/Observation/observationSpace.py @@ -82,7 +82,7 @@ def __init__( """ # lazy import to prevent circular references (Env -> Observation -> Obs Space -> _ObsEnv -> Env) - from grid2op.Environment._ObsEnv import _ObsEnv + from grid2op.Environment._obsEnv import _ObsEnv if actionClass is None: from grid2op.Action import CompleteAction @@ -150,7 +150,7 @@ def set_real_env_kwargs(self, env): if not self.with_forecast: return # I don't need the backend nor the chronics_handler - from grid2op.Environment.Environment import Environment + from grid2op.Environment import Environment self._real_env_kwargs = Environment.get_kwargs(env, False, False) # remove the parameters anyways (the 'forecast parameters will be used diff --git a/grid2op/Reward/_alarmScore.py b/grid2op/Reward/_alarmScore.py index fead57d6b..b4c69ff5d 100644 --- a/grid2op/Reward/_alarmScore.py +++ b/grid2op/Reward/_alarmScore.py @@ -65,14 +65,7 @@ def __init__(self, logger=None): self.disc_lines_all_before_cascade = [] self.n_line = None - - # This class remembers the past state of the grid, this does not make sense for the "simulate" env - # so i deactivate it in this case. - from grid2op.Environment._ObsEnv import ( - _ObsEnv, - ) # to avoid circular dependencies - - self._deactivate_reward_cls = (_ObsEnv,) + self._i_am_simulate = True def initialize(self, env): if not env._has_attention_budget: @@ -88,6 +81,7 @@ def reset(self, env): super().reset(env) self.window_disconnection = max(self.best_time - self.window_size, 4) self.disc_lines_all_before_cascade = [] + self._i_am_simulate = self.is_simulated_env(env) def _lines_disconnected_first(self, disc_lines_at_cascading_time): """ @@ -117,7 +111,7 @@ def _lines_disconnected_first(self, disc_lines_at_cascading_time): return 1 - disc_lines_to_consider_for_score def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): - if self.is_simulated_env(env): + if self._i_am_simulate: return self.reward_no_game_over disc_lines_now = env._disc_lines diff --git a/grid2op/Reward/_newRenewableSourcesUsageScore.py b/grid2op/Reward/_newRenewableSourcesUsageScore.py index e4b9edc27..b60f2ef05 100644 --- a/grid2op/Reward/_newRenewableSourcesUsageScore.py +++ b/grid2op/Reward/_newRenewableSourcesUsageScore.py @@ -38,7 +38,7 @@ def initialize(self, env): self.reset(env) def reset(self, env): - self._is_simul_env = is_simulated_env(env) + self._is_simul_env = self.is_simulated_env(env) if self._is_simul_env: return @@ -76,15 +76,4 @@ def _surlinear_func_curtailment(x, center=80, eps=1e-6): f_standardizer= lambda x : np.ones_like(x) * f_centralized(100) * (x >= center) - np.ones_like(x) * f_centralized(50) * (x < center) return f_centralized(x) / f_standardizer(x) - - -#to wait before PR Laure -def is_simulated_env(env): - - # to prevent cyclical import - from grid2op.Environment._ObsEnv import _ObsEnv - from grid2op.Environment._forecast_env import _ForecastEnv - - # This reward is not compatible with simulations - return isinstance(env, (_ObsEnv, _ForecastEnv)) diff --git a/grid2op/Reward/baseReward.py b/grid2op/Reward/baseReward.py index 320bd5d07..164f54e0b 100644 --- a/grid2op/Reward/baseReward.py +++ b/grid2op/Reward/baseReward.py @@ -120,7 +120,7 @@ def __init__(self, logger: logging.Logger=None): def is_simulated_env(self, env): # to prevent cyclical import - from grid2op.Environment._ObsEnv import _ObsEnv + from grid2op.Environment._obsEnv import _ObsEnv from grid2op.Environment._forecast_env import _ForecastEnv return isinstance(env, (_ObsEnv, _ForecastEnv)) diff --git a/grid2op/Reward/n1Reward.py b/grid2op/Reward/n1Reward.py index b31a9904e..9d11561ef 100644 --- a/grid2op/Reward/n1Reward.py +++ b/grid2op/Reward/n1Reward.py @@ -8,7 +8,7 @@ import copy from grid2op.Reward import BaseReward -from grid2op.Action._BackendAction import _BackendAction +from grid2op.Action._backendAction import _BackendAction class N1Reward(BaseReward): diff --git a/grid2op/tests/BaseBackendTest.py b/grid2op/tests/BaseBackendTest.py index 3ea0ddd4b..01e849e20 100644 --- a/grid2op/tests/BaseBackendTest.py +++ b/grid2op/tests/BaseBackendTest.py @@ -57,7 +57,7 @@ def comb(n, k): from grid2op.Rules import RulesChecker from grid2op.MakeEnv import make from grid2op.Rules import AlwaysLegal -from grid2op.Action._BackendAction import _BackendAction +from grid2op.Action._backendAction import _BackendAction import pdb diff --git a/grid2op/tests/test_attached_envs.py b/grid2op/tests/test_attached_envs.py index 92c571088..42b18a67f 100644 --- a/grid2op/tests/test_attached_envs.py +++ b/grid2op/tests/test_attached_envs.py @@ -10,10 +10,10 @@ import unittest import grid2op -from grid2op.Action.PowerlineSetAction import PowerlineSetAction +from grid2op.Action.powerlineSetAction import PowerlineSetAction from grid2op.Action.PlayableAction import PlayableAction from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.DontAct import DontAct +from grid2op.Action.dontAct import DontAct from grid2op.Opponent import GeometricOpponent import pdb diff --git a/grid2op/tests/test_attached_envs_compat.py b/grid2op/tests/test_attached_envs_compat.py index d09a51015..84b3b0b3d 100644 --- a/grid2op/tests/test_attached_envs_compat.py +++ b/grid2op/tests/test_attached_envs_compat.py @@ -13,10 +13,10 @@ import numpy as np from grid2op.Space import GridObjects -from grid2op.Action.PowerlineSetAction import PowerlineSetAction +from grid2op.Action.powerlineSetAction import PowerlineSetAction from grid2op.Action.PlayableAction import PlayableAction from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.DontAct import DontAct +from grid2op.Action.dontAct import DontAct import pdb From b3fd8bfc92eea8c94ca04a75ab916170e583aada Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 12:16:35 +0200 Subject: [PATCH 063/103] fixing broken tests after renaming of the files in module --- grid2op/Action/_BackendAction.py | 13 ++++++++++ grid2op/tests/test_BackendConverter.py | 24 +++++++++---------- grid2op/tests/test_ChronicsHandler.py | 4 ++-- grid2op/tests/test_Converter.py | 3 +-- grid2op/tests/test_GridObjects.py | 2 +- grid2op/tests/test_GymConverter.py | 6 +---- grid2op/tests/test_attached_envs.py | 6 ++--- grid2op/tests/test_attached_envs_compat.py | 6 ++--- grid2op/tests/test_educpp_backend.py | 2 +- .../test_highres_sim_counter_in_scores.py | 2 +- grid2op/tests/test_noisy_obs.py | 3 +-- grid2op/tests/test_redisp_extreme.py | 2 +- grid2op/tests/test_score_wcci_2022.py | 3 +-- grid2op/tests/test_ts_handlers.py | 3 +-- 14 files changed, 40 insertions(+), 39 deletions(-) create mode 100644 grid2op/Action/_BackendAction.py diff --git a/grid2op/Action/_BackendAction.py b/grid2op/Action/_BackendAction.py new file mode 100644 index 000000000..97de586fb --- /dev/null +++ b/grid2op/Action/_BackendAction.py @@ -0,0 +1,13 @@ +# Copyright (c) 2019-2020, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +""" +This file is here to maintain compatibility with lightsim2grid (but will disappear "soon") +""" + +from grid2op.Action._backendAction import _BackendAction diff --git a/grid2op/tests/test_BackendConverter.py b/grid2op/tests/test_BackendConverter.py index 9da79000f..b6811381f 100644 --- a/grid2op/tests/test_BackendConverter.py +++ b/grid2op/tests/test_BackendConverter.py @@ -15,18 +15,18 @@ from grid2op.Backend import PandaPowerBackend from grid2op.tests.helper_path_test import HelperTests -from grid2op.tests.BaseBackendTest import BaseTestNames -from grid2op.tests.BaseBackendTest import BaseTestLoadingCase -from grid2op.tests.BaseBackendTest import BaseTestLoadingBackendFunc -from grid2op.tests.BaseBackendTest import BaseTestTopoAction -from grid2op.tests.BaseBackendTest import BaseTestEnvPerformsCorrectCascadingFailures -from grid2op.tests.BaseBackendTest import BaseTestChangeBusAffectRightBus -from grid2op.tests.BaseBackendTest import BaseTestShuntAction -from grid2op.tests.BaseBackendTest import BaseTestResetEqualsLoadGrid -from grid2op.tests.BaseBackendTest import BaseTestVoltageOWhenDisco -from grid2op.tests.BaseBackendTest import BaseTestChangeBusSlack -from grid2op.tests.BaseBackendTest import BaseIssuesTest -from grid2op.tests.BaseBackendTest import BaseStatusActions +from grid2op.tests.BaseBackendTest import (BaseTestNames, + BaseTestLoadingCase, + BaseTestLoadingBackendFunc, + BaseTestTopoAction, + BaseTestEnvPerformsCorrectCascadingFailures, + BaseTestChangeBusAffectRightBus, + BaseTestShuntAction, + BaseTestResetEqualsLoadGrid, + BaseTestVoltageOWhenDisco, + BaseTestChangeBusSlack, + BaseIssuesTest, + BaseStatusActions) PATH_DATA_TEST_INIT = PATH_DATA_TEST PATH_DATA_TEST = PATH_DATA_TEST_PP diff --git a/grid2op/tests/test_ChronicsHandler.py b/grid2op/tests/test_ChronicsHandler.py index 53c8cb62b..a9349f105 100644 --- a/grid2op/tests/test_ChronicsHandler.py +++ b/grid2op/tests/test_ChronicsHandler.py @@ -23,12 +23,12 @@ GridStateFromFileWithForecasts, Multifolder, GridValue, + MultifolderWithCache, + GridStateFromFileWithForecastsWithoutMaintenance ) -from grid2op.Chronics import MultifolderWithCache from grid2op.Backend import PandaPowerBackend from grid2op.Parameters import Parameters from grid2op.Rules import AlwaysLegal -from grid2op.Chronics import GridStateFromFileWithForecastsWithoutMaintenance from grid2op.Runner import Runner import warnings diff --git a/grid2op/tests/test_Converter.py b/grid2op/tests/test_Converter.py index e57e6e5a2..58a6e758c 100644 --- a/grid2op/tests/test_Converter.py +++ b/grid2op/tests/test_Converter.py @@ -9,13 +9,12 @@ import warnings import os import json -from grid2op.Action.BaseAction import BaseAction +from grid2op.Action import BaseAction, PlayableAction from grid2op.tests.helper_path_test import * from grid2op.MakeEnv import make from grid2op.Parameters import Parameters from grid2op.Converter import ConnectivityConverter, IdToAct -from grid2op.Action import PlayableAction import tempfile import pdb diff --git a/grid2op/tests/test_GridObjects.py b/grid2op/tests/test_GridObjects.py index c405afcc2..d606e7fe3 100644 --- a/grid2op/tests/test_GridObjects.py +++ b/grid2op/tests/test_GridObjects.py @@ -14,7 +14,7 @@ import warnings import grid2op -from grid2op.Backend.EducPandaPowerBackend import EducPandaPowerBackend +from grid2op.Backend.educPandaPowerBackend import EducPandaPowerBackend from grid2op.Exceptions import EnvError diff --git a/grid2op/tests/test_GymConverter.py b/grid2op/tests/test_GymConverter.py index 03509c153..dce5b1399 100644 --- a/grid2op/tests/test_GymConverter.py +++ b/grid2op/tests/test_GymConverter.py @@ -9,7 +9,7 @@ # TODO test the json part but... https://github.com/openai/gym-http-api/issues/62 or https://github.com/openai/gym/issues/1841 import tempfile import json -from grid2op.gym_compat.discrete_gym_actspace import DiscreteActSpace +from grid2op.gym_compat import (DiscreteActSpace, GymActionSpace, GymObservationSpace, GymEnv, ContinuousToDiscreteConverter) from grid2op.tests.helper_path_test import * from grid2op.Action import PlayableAction @@ -17,10 +17,6 @@ from grid2op.tests.helper_path_test import * from grid2op.MakeEnv import make from grid2op.Converter import IdToAct, ToVect -from grid2op.gym_compat import GymActionSpace, GymObservationSpace -from grid2op.gym_compat import GymEnv -from grid2op.gym_compat import ContinuousToDiscreteConverter - import pdb import warnings diff --git a/grid2op/tests/test_attached_envs.py b/grid2op/tests/test_attached_envs.py index 42b18a67f..028878c94 100644 --- a/grid2op/tests/test_attached_envs.py +++ b/grid2op/tests/test_attached_envs.py @@ -10,10 +10,8 @@ import unittest import grid2op -from grid2op.Action.powerlineSetAction import PowerlineSetAction -from grid2op.Action.PlayableAction import PlayableAction -from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.dontAct import DontAct +from grid2op.Action import (PowerlineSetAction, PlayableAction, DontAct) +from grid2op.Observation import CompleteObservation from grid2op.Opponent import GeometricOpponent import pdb diff --git a/grid2op/tests/test_attached_envs_compat.py b/grid2op/tests/test_attached_envs_compat.py index 84b3b0b3d..6c1850ab6 100644 --- a/grid2op/tests/test_attached_envs_compat.py +++ b/grid2op/tests/test_attached_envs_compat.py @@ -13,10 +13,8 @@ import numpy as np from grid2op.Space import GridObjects -from grid2op.Action.powerlineSetAction import PowerlineSetAction -from grid2op.Action.PlayableAction import PlayableAction -from grid2op.Observation.completeObservation import CompleteObservation -from grid2op.Action.dontAct import DontAct +from grid2op.Action import PowerlineSetAction, DontAct, PlayableAction +from grid2op.Observation import CompleteObservation import pdb diff --git a/grid2op/tests/test_educpp_backend.py b/grid2op/tests/test_educpp_backend.py index 0876c5651..fb1916b4f 100644 --- a/grid2op/tests/test_educpp_backend.py +++ b/grid2op/tests/test_educpp_backend.py @@ -13,7 +13,7 @@ import unittest import grid2op -from grid2op.Backend.EducPandaPowerBackend import EducPandaPowerBackend +from grid2op.Backend.educPandaPowerBackend import EducPandaPowerBackend import pdb class EducPPTester(unittest.TestCase): diff --git a/grid2op/tests/test_highres_sim_counter_in_scores.py b/grid2op/tests/test_highres_sim_counter_in_scores.py index e2ab9215c..dae7ae611 100644 --- a/grid2op/tests/test_highres_sim_counter_in_scores.py +++ b/grid2op/tests/test_highres_sim_counter_in_scores.py @@ -14,7 +14,7 @@ from grid2op.Action import ActionSpace, BaseAction from grid2op.utils import ScoreL2RPN2023, ScoreL2RPN2022, ScoreICAPS2021, ScoreL2RPN2020 from grid2op.Observation import BaseObservation -from grid2op.Agent.doNothing import DoNothingAgent, BaseAgent +from grid2op.Agent import DoNothingAgent, BaseAgent from grid2op.Chronics import FromHandlers from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler, DoNothingHandler diff --git a/grid2op/tests/test_noisy_obs.py b/grid2op/tests/test_noisy_obs.py index 3dda12c68..f78edd668 100644 --- a/grid2op/tests/test_noisy_obs.py +++ b/grid2op/tests/test_noisy_obs.py @@ -13,8 +13,7 @@ import grid2op from grid2op.Runner import Runner -from grid2op.Observation import CompleteObservation -from grid2op.Observation import NoisyObservation +from grid2op.Observation import (CompleteObservation, NoisyObservation) class TestNoisy(unittest.TestCase): diff --git a/grid2op/tests/test_redisp_extreme.py b/grid2op/tests/test_redisp_extreme.py index d278c19f5..9662a4f52 100644 --- a/grid2op/tests/test_redisp_extreme.py +++ b/grid2op/tests/test_redisp_extreme.py @@ -10,7 +10,7 @@ import os import numpy as np import grid2op -from grid2op.Action.PlayableAction import PlayableAction +from grid2op.Action.playableAction import PlayableAction from grid2op.tests.helper_path_test import * import unittest diff --git a/grid2op/tests/test_score_wcci_2022.py b/grid2op/tests/test_score_wcci_2022.py index b9d35f647..307c30b4c 100644 --- a/grid2op/tests/test_score_wcci_2022.py +++ b/grid2op/tests/test_score_wcci_2022.py @@ -11,8 +11,7 @@ import numpy as np import grid2op -from grid2op.Agent.baseAgent import BaseAgent -from grid2op.Agent.doNothing import DoNothingAgent +from grid2op.Agent import (BaseAgent, DoNothingAgent) from grid2op.Reward import L2RPNWCCI2022ScoreFun from grid2op.utils import ScoreL2RPN2022 diff --git a/grid2op/tests/test_ts_handlers.py b/grid2op/tests/test_ts_handlers.py index 8d0575e3c..e1626457c 100644 --- a/grid2op/tests/test_ts_handlers.py +++ b/grid2op/tests/test_ts_handlers.py @@ -15,8 +15,7 @@ import grid2op from grid2op.Exceptions import NoForecastAvailable -from grid2op.Chronics import GridStateFromFileWithForecasts, GridStateFromFile, GridStateFromFileWithForecastsWithoutMaintenance -from grid2op.Chronics.time_series_from_handlers import FromHandlers +from grid2op.Chronics import GridStateFromFileWithForecasts, GridStateFromFile, GridStateFromFileWithForecastsWithoutMaintenance, FromHandlers from grid2op.Chronics.handlers import (CSVHandler, DoNothingHandler, CSVForecastHandler, From e536a3b1ab254cf2e6af57f2ab77e641b01995d6 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 16:00:31 +0200 Subject: [PATCH 064/103] improving the alert agent --- grid2op/Agent/alertAgent.py | 100 ++++++++++++++++----------- grid2op/tests/test_baseline_alert.py | 85 ++++++++++++++--------- 2 files changed, 111 insertions(+), 74 deletions(-) diff --git a/grid2op/Agent/alertAgent.py b/grid2op/Agent/alertAgent.py index 875678b58..012995722 100644 --- a/grid2op/Agent/alertAgent.py +++ b/grid2op/Agent/alertAgent.py @@ -1,25 +1,20 @@ -# Copyright (c) 2019-2020, RTE (https://www.rte-france.com) +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + import numpy as np +from grid2op.Action import BaseAction from grid2op.Agent.recoPowerlineAgent import RecoPowerlineAgent -import pandas as pd - -#try: -# from lightsim2grid import LightSimBackend -# -# bkclass = LightSimBackend -# # raise ImportError() -#except ImportError as excq_: -# from grid2op.Backend import PandaPowerBackend +from grid2op.Agent.baseAgent import BaseAgent +from grid2op.Observation import BaseObservation +from grid2op.dtypes import dt_int - -class AlertAgent(RecoPowerlineAgent): +class AlertAgent(BaseAgent): """ This is a :class:`AlertAgent` example, which will attempt to reconnect powerlines and send alerts on the worst possible attacks: for each disconnected powerline that can be reconnected, it will simulate the effect of reconnecting it. And reconnect the one that lead to the @@ -27,43 +22,66 @@ class AlertAgent(RecoPowerlineAgent): """ - def __init__(self, action_space,percentage_alert=30,simu_step=0): - RecoPowerlineAgent.__init__(self, action_space) + def __init__(self, + action_space, + grid_controler=RecoPowerlineAgent, + percentage_alert=30, + simu_step=1, + threshold=0.99): + super().__init__(action_space) + if isinstance(grid_controler, type): + self.grid_controler = grid_controler(action_space) + else: + self.grid_controler = grid_controler + self.percentage_alert = percentage_alert - self.simu_step=simu_step - - def act(self, observation, reward, done=False): - action=super().act(observation, reward, done=False) - alertable_line_ids=observation.alertable_line_ids - - #simu d'analyse de sécurité à chaque pas de temps sur les lignes attaquées - n_alertable_lines=len(alertable_line_ids) - nb_overloads=np.zeros(n_alertable_lines) - rho_max_N_1=np.zeros(n_alertable_lines) + self.simu_step = simu_step + self.threshold = threshold # if the max flow after a line disconnection is below threshold, then the alert is not raised + + # store the result of the simulation of powerline disconnection + self.alertable_line_ids = type(action_space).alertable_line_ids + self.n_alertable_lines = len(self.alertable_line_ids) + self.nb_overloads = np.zeros(self.n_alertable_lines, dtype=dt_int) + self.rho_max_N_1 = np.zeros(self.n_alertable_lines) + self.N_1_actions = [self.action_space({"set_line_status": [(id_, -1)]}) for id_ in self.alertable_line_ids] + self._first_k = np.zeros(self.n_alertable_lines, dtype=bool) + self._first_k[:int(self.percentage_alert / 100. * self.n_alertable_lines)] = True + + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + action = self.grid_controler.act(observation, reward, done) + self.nb_overloads[:] = 0 + self.rho_max_N_1[:] = 0. + # test which backend to know which method to call - N_1_actions=[self.action_space({"set_line_status": [(id_, -1)]}) for id_ in alertable_line_ids] - for i, action_to_simulate in enumerate(N_1_actions): - - #check that line is not already disconnected - if (observation.line_status[alertable_line_ids[i]]): + for i, tmp_act in enumerate(self.N_1_actions): + # only simulate if the line is connected + if observation.line_status[self.alertable_line_ids[i]]: + action_to_simulate = tmp_act + action_to_simulate += action + action_to_simulate.remove_line_status_from_topo(observation) ( simul_obs, simul_reward, - simul_has_error, + simul_done, simul_info, - ) = observation.simulate(action_to_simulate,time_step=self.simu_step) - - rho_simu=simul_obs.rho - if(not simul_has_error): - nb_overloads[i]=np.sum(rho_simu >= 1) - rho_max_N_1[i]=np.max(rho_simu) - - df_to_sort=pd.DataFrame({"nb_overloads":nb_overloads,"rho_max_N_1":rho_max_N_1}) - indices=df_to_sort.sort_values(['nb_overloads','rho_max_N_1'], ascending=False).index + ) = observation.simulate(action_to_simulate, time_step=self.simu_step) - #alerts to send - indices_to_keep=list(indices[0:int(self.percentage_alert/100*n_alertable_lines)]) + rho_simu = simul_obs.rho + if not simul_done: + self.nb_overloads[i] = (rho_simu >= 1).sum() + self.rho_max_N_1[i] = (rho_simu).max() + else: + self.nb_overloads[i] = type(observation).n_line + self.rho_max_N_1[i] = 5. + + # sort the index by nb_overloads and, if nb_overloads is equal, sort by rho_max + ind = (self.nb_overloads * 1000. + self.rho_max_N_1).argsort() + ind = ind[::-1] + + # send alerts when the powerline is among the top k (not to send too many alerts) and + # the max rho after the powerline disconnection is too high (above threshold) + indices_to_keep = ind[self._first_k & (self.rho_max_N_1[ind] >= self.threshold)] action.raise_alert = [i for i in indices_to_keep] return action diff --git a/grid2op/tests/test_baseline_alert.py b/grid2op/tests/test_baseline_alert.py index 7f3691aa3..d780de995 100644 --- a/grid2op/tests/test_baseline_alert.py +++ b/grid2op/tests/test_baseline_alert.py @@ -1,47 +1,66 @@ -from grid2op.tests.helper_path_test import * +# Copyright (c) 2019-2020, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import unittest +import numpy as np + from grid2op import make -from grid2op.Reward import AlertReward from grid2op.Runner import Runner from grid2op.Agent.alertAgent import AlertAgent # test alert agent no blackout class TestAlertNoBlackout(unittest.TestCase): def setUp(self) -> None: - self.env_nm = os.path.join( - PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" - ) + self.env_nm = "l2rpn_idf_2023" def test_alert_Agent(self) -> None: + pct_alerts = [100./23., 100./21., 300./21., 30., 50., 80.] + ref_alert_counts = {pct_alerts[0]: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + pct_alerts[1]: [0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + pct_alerts[2]: [0, 0, 0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + pct_alerts[3]: [0, 0, 1, 0, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + pct_alerts[4]: [1, 2, 2, 0, 3, 3, 3, 3, 3, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + pct_alerts[5]: [1, 2, 2, 0, 3, 3, 3, 3, 3, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1], + } + # 0 in the first (no budget) + # one per step max in the second (budget for only 1) + # 3 per step max in the third (budget for only 1) with the one from the first present with make( self.env_nm, test=True, - difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + difficulty="1" ) as env: - env.seed(0) - env.reset() - - percentage_alert =30 # 30% of lines with alert per step - my_agent = AlertAgent(env.action_space, percentage_alert=percentage_alert) - runner = Runner(**env.get_params_for_runner(), agentClass=None ,agentInstance=my_agent) - - res = runner.run(nb_episode=1, nb_process=1, path_save=None,agent_seeds=[0],env_seeds=[0],max_iter=3, - add_detailed_output=True) - id_chron, name_chron, cum_reward, nb_time_step, max_ts, episode_data = res[0] - - # test if the number of alerts sent on lines are recovered - alerts_count =np.sum([obs.active_alert for obs in episode_data.observations[1:]] - ,axis=0) - print(alerts_count) - assert(np.all(alerts_count==[3, 3, 2, 0, 1, 0, 0, 0, 0, 0])) - - # test that we observe the expected alert rate - nb_alertable_lines =len(env.alertable_line_names) - ratio_alerts_step =np.sum(alerts_count ) /(nb_time_step*nb_alertable_lines) - assert(np.round(ratio_alerts_step ,decimals=1 )==np.round(percentage_alert/100 ,decimals=1)) - - #check that alert agent is not doing any intervention on the grid in this short time frame - #as the reco power line, it should only do actions to reconnect lines when allowed, but cannot happen in this short time frame - has_action_impact=[act.impact_on_objects()['has_impact'] for act in episode_data.actions] - assert(~np.any(has_action_impact)) \ No newline at end of file + for percentage_alert in pct_alerts: + env.seed(0) + env.reset() + my_agent = AlertAgent(env.action_space, percentage_alert=percentage_alert) + runner = Runner(**env.get_params_for_runner(), agentClass=None ,agentInstance=my_agent) + + res = runner.run(nb_episode=1, nb_process=1, path_save=None, agent_seeds=[0],env_seeds=[0], max_iter=3, + add_detailed_output=True) + id_chron, name_chron, cum_reward, nb_time_step, max_ts, episode_data = res[0] + + # test if the number of alerts sent on lines are recovered + alerts_count = np.sum([obs.active_alert for obs in episode_data.observations[1:]] + ,axis=0) + assert(np.all(alerts_count == ref_alert_counts[percentage_alert])), f"for {percentage_alert} : {alerts_count} vs {ref_alert_counts[percentage_alert]}" + + # test that we observe the expected alert rate + nb_alertable_lines =len(env.alertable_line_names) + ratio_alerts_step =np.sum(alerts_count ) /(nb_time_step*nb_alertable_lines) + assert(np.round(ratio_alerts_step, decimals=1) <= np.round(percentage_alert/100. ,decimals=1)) + + #check that alert agent is not doing any intervention on the grid in this short time frame + #as the reco power line, it should only do actions to reconnect lines when allowed, but cannot happen in this short time frame + has_action_impact=[act.impact_on_objects()['has_impact'] for act in episode_data.actions] + assert(~np.any(has_action_impact)) + + +if __name__ == "__main__": + unittest.main() From efa823cd51c7c9f058694b7d39e06818d7653258 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:13:31 +0200 Subject: [PATCH 065/103] add reset method to alertReward + tests --- grid2op/Reward/alertReward.py | 16 ++++++++++++++++ grid2op/tests/test_alert_feature.py | 29 ++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 8fab14cbc..a9ad3309a 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -117,6 +117,22 @@ def initialize(self, env: "grid2op.Environment.BaseEnv"): self._i_am_simulate = self.is_simulated_env(env) return super().initialize(env) + def reset(self, env): + self.total_time_steps = env.max_episode_duration() + self.time_window = env.parameters.ALERT_TIME_WINDOW + self._nrows_array = self.time_window + 2 + + # TODO simulate env stuff ! + + # TODO vectors proper size + self._ts_attack = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) + self._alert_launched = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) + self._current_id = 0 + self._lines_currently_attacked = np.full(type(env).dim_alerts, False, dtype=dt_bool) + + self._i_am_simulate = self.is_simulated_env(env) + return super().reset(env) + def _update_attack(self, env): if env.infos["opponent_attack_line"] is None: # no attack at this step diff --git a/grid2op/tests/test_alert_feature.py b/grid2op/tests/test_alert_feature.py index 9d4d2e178..bc7075c14 100644 --- a/grid2op/tests/test_alert_feature.py +++ b/grid2op/tests/test_alert_feature.py @@ -254,6 +254,33 @@ def _aux_obs_init(self, obs): def test_init_observation(self) -> None : obs : BaseObservation = self.env.reset() self._aux_obs_init(obs) + + def test_reset_obs(self) -> None : + obs1 : BaseObservation = self.env.reset() + assert (obs1.time_since_last_alert == np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1])).all() + + obs2, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [0]})) + + assert (obs2.time_since_last_alert == np.array([0, -1, -1, -1, -1, -1, -1, -1, -1, -1])).all() + + obs2bis, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [1]})) + assert (obs2bis.time_since_last_alert == np.array([1, 0, -1, -1, -1, -1, -1, -1, -1, -1])).all() + + obs3 : BaseObservation = self.env.reset() + assert (obs3.time_since_last_alert == obs1.time_since_last_alert).all() + + def test_reset_reward(self) -> None : + obs1 : BaseObservation = self.env.reset() + assert self.env._reward_helper.template_reward._current_id == 0 + obs2, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [0]})) + + assert self.env._reward_helper.template_reward._current_id == 1 + + obs, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [1]})) + assert self.env._reward_helper.template_reward._current_id == 2 + + obs3 : BaseObservation = self.env.reset() + assert self.env._reward_helper.template_reward._current_id == 0 def _aux_alert_0(self, obs): assert obs.active_alert[0] @@ -577,4 +604,4 @@ def test_when_attacks(self): # TODO test "as_dict" and "as_json" if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file From fefeeab59e6bf6970260698a09eaaabd58bf3cdf Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:29:34 +0200 Subject: [PATCH 066/103] do not recreate object at reset --- grid2op/Reward/alertReward.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index a9ad3309a..fc72fea13 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -125,14 +125,14 @@ def reset(self, env): # TODO simulate env stuff ! # TODO vectors proper size - self._ts_attack = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) - self._alert_launched = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) + self._ts_attack[:,:] = False + self._alert_launched[:,:] = False self._current_id = 0 - self._lines_currently_attacked = np.full(type(env).dim_alerts, False, dtype=dt_bool) + self._lines_currently_attacked[:] = False self._i_am_simulate = self.is_simulated_env(env) return super().reset(env) - + def _update_attack(self, env): if env.infos["opponent_attack_line"] is None: # no attack at this step From b85a22ad33e5daf3a77b71241341807d19aee3e8 Mon Sep 17 00:00:00 2001 From: Laure CROCHEPIERRE Date: Wed, 19 Jul 2023 13:47:12 +0200 Subject: [PATCH 067/103] add default params to assistant reward test + debug reset --- grid2op/Reward/alertReward.py | 12 ++---- grid2op/tests/test_alert_score.py | 69 +++++++++++++++++++------------ 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index fc72fea13..83f6c4484 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -101,6 +101,7 @@ def __init__(self, self._i_am_simulate : bool = False + def initialize(self, env: "grid2op.Environment.BaseEnv"): self.total_time_steps = env.max_episode_duration() self.time_window = env.parameters.ALERT_TIME_WINDOW @@ -116,15 +117,8 @@ def initialize(self, env: "grid2op.Environment.BaseEnv"): self._i_am_simulate = self.is_simulated_env(env) return super().initialize(env) - + def reset(self, env): - self.total_time_steps = env.max_episode_duration() - self.time_window = env.parameters.ALERT_TIME_WINDOW - self._nrows_array = self.time_window + 2 - - # TODO simulate env stuff ! - - # TODO vectors proper size self._ts_attack[:,:] = False self._alert_launched[:,:] = False self._current_id = 0 @@ -132,7 +126,7 @@ def reset(self, env): self._i_am_simulate = self.is_simulated_env(env) return super().reset(env) - + def _update_attack(self, env): if env.infos["opponent_attack_line"] is None: # no attack at this step diff --git a/grid2op/tests/test_alert_score.py b/grid2op/tests/test_alert_score.py index 0717bef38..4a31f6158 100644 --- a/grid2op/tests/test_alert_score.py +++ b/grid2op/tests/test_alert_score.py @@ -40,6 +40,11 @@ ATTACKED_LINE = "48_50_136" +DEFAULT_ALERT_REWARD_PARAMS = dict(reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=42.0) def _get_steps_attack(kwargs_opponent, multi=False): """computes the steps for which there will be attacks""" @@ -128,7 +133,7 @@ def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -157,7 +162,7 @@ def test_assistant_reward_value_no_blackout_no_attack_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -203,7 +208,7 @@ def test_assistant_reward_value_no_blackout_attack_no_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnbana" ) as env : env.seed(0) @@ -242,7 +247,7 @@ def test_assistant_reward_value_no_blackout_attack_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnba" ) as env : env.seed(0) @@ -288,6 +293,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_late(self) -> None opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnbaatl" ) as env : env.seed(0) @@ -308,7 +314,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_late(self) -> None if step == 4 : assert reward == 1 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -333,6 +339,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_early(self)-> None opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnbaate" ) as env : env.seed(0) @@ -354,7 +361,7 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_early(self)-> None if step == 4: assert reward == 1 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -380,7 +387,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_no_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2astna" ) as env : env.seed(0) @@ -422,6 +429,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_1_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2ast1a" ) as env : env.seed(0) @@ -442,7 +450,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_1_alert(self) -> if step == 4 : assert reward == 0 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -466,6 +474,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2ast2a" ) as env : env.seed(0) @@ -486,7 +495,7 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> if step == 4 : assert reward == -1 elif step == env.max_episode_duration(): - assert reward == 1 + assert reward == 42 else : assert reward == 0 @@ -512,7 +521,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_no_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dtna" ) as env : env.seed(0) @@ -558,7 +567,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_2_alert(self) -> opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dt2a" ) as env : env.seed(0) @@ -607,7 +616,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_first_attac opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dtafa" ) as env : env.seed(0) @@ -654,7 +663,7 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_second_atta opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvnb2dtasa" ) as env : env.seed(0) @@ -686,7 +695,7 @@ def test_raise_illicit_alert(self) -> None: self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -738,7 +747,7 @@ def test_assistant_reward_value_blackout_attack_no_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbana" ) as env : new_param = Parameters() @@ -783,6 +792,7 @@ def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbarga" ) as env : new_param = Parameters() @@ -834,6 +844,7 @@ def test_assistant_reward_value_blackout_attack_raise_alert_just_before_blackout opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbarajbb" ) as env : new_param = Parameters() @@ -885,6 +896,7 @@ def test_assistant_reward_value_blackout_attack_raise_alert_too_early(self) -> N opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvbarate" ) as env : new_param = Parameters() @@ -935,6 +947,7 @@ def test_assistant_reward_value_blackout_2_lines_same_step_in_window_good_alert opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2lssiwga" ) as env : new_param = Parameters() @@ -986,6 +999,8 @@ def test_assistant_reward_value_blackout_2_lines_attacked_simulaneous_only_1_ale opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), + _add_to_name="_tarvb2laso1a" ) as env : new_param = Parameters() @@ -1038,7 +1053,7 @@ def test_assistant_reward_value_blackout_2_lines_different_step_in_window_good_ opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2ldsiwga" ) as env : env.seed(0) @@ -1090,7 +1105,7 @@ def test_assistant_reward_value_blackout_2_lines_attacked_different_step_in_wind opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2ladsiwo1aofal" ) as env : env.seed(0) @@ -1138,7 +1153,7 @@ def test_assistant_reward_value_blackout_2_lines_attacked_different_step_in_wind opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2ladsiwo1aosal" ) as env : env.seed(0) @@ -1184,7 +1199,7 @@ def test_assistant_reward_value_blackout_2_lines_attacked_different_1_in_window_ opponent_action_class=PlayableAction, opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tarvb2lad1iw1ga" ) as env : env.seed(0) @@ -1223,7 +1238,7 @@ def test_assistant_reward_value_blackout_no_attack_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1254,7 +1269,7 @@ def test_assistant_reward_value_blackout_no_attack_no_alert(self) -> None : self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1283,7 +1298,7 @@ def test_assistant_reward_value_blackout_attack_before_window_alert(self) -> Non self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1314,7 +1329,7 @@ def test_assistant_reward_value_blackout_attack_before_window_no_alert(self) -> self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS) ) as env: env.seed(0) env.reset() @@ -1346,7 +1361,7 @@ def setUp(self) -> None: PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) self.env = make(self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42)) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS)) self.env.seed(0) return super().setUp() @@ -1387,7 +1402,7 @@ def setUp(self) -> None: PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) self.env = make(self.env_nm, test=True, difficulty="1", - reward_class=AlertReward(reward_end_episode_bonus=42)) + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS)) self.env.seed(0) return super().setUp() @@ -1448,7 +1463,7 @@ def test_with_opp(self): opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name = "_test_with_opp") # without alert runner = Runner(**env.get_params_for_runner()) @@ -1468,4 +1483,4 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - if __name__ == "__main__": - unittest.main() + unittest.main() \ No newline at end of file From 0f590fcbadc128955da83d4034ca8691d1be2b79 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 17:09:53 +0200 Subject: [PATCH 068/103] cherry picking Laure commits --- grid2op/Reward/alertReward.py | 5 ----- grid2op/tests/test_alert_feature.py | 6 ++++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/grid2op/Reward/alertReward.py b/grid2op/Reward/alertReward.py index 83f6c4484..3f7d90924 100644 --- a/grid2op/Reward/alertReward.py +++ b/grid2op/Reward/alertReward.py @@ -106,10 +106,6 @@ def initialize(self, env: "grid2op.Environment.BaseEnv"): self.total_time_steps = env.max_episode_duration() self.time_window = env.parameters.ALERT_TIME_WINDOW self._nrows_array = self.time_window + 2 - - # TODO simulate env stuff ! - - # TODO vectors proper size self._ts_attack = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) self._alert_launched = np.full((self._nrows_array, type(env).dim_alerts), False, dtype=dt_bool) self._current_id = 0 @@ -123,7 +119,6 @@ def reset(self, env): self._alert_launched[:,:] = False self._current_id = 0 self._lines_currently_attacked[:] = False - self._i_am_simulate = self.is_simulated_env(env) return super().reset(env) diff --git a/grid2op/tests/test_alert_feature.py b/grid2op/tests/test_alert_feature.py index bc7075c14..c73375841 100644 --- a/grid2op/tests/test_alert_feature.py +++ b/grid2op/tests/test_alert_feature.py @@ -260,7 +260,6 @@ def test_reset_obs(self) -> None : assert (obs1.time_since_last_alert == np.array([-1, -1, -1, -1, -1, -1, -1, -1, -1, -1])).all() obs2, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [0]})) - assert (obs2.time_since_last_alert == np.array([0, -1, -1, -1, -1, -1, -1, -1, -1, -1])).all() obs2bis, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [1]})) @@ -272,15 +271,18 @@ def test_reset_obs(self) -> None : def test_reset_reward(self) -> None : obs1 : BaseObservation = self.env.reset() assert self.env._reward_helper.template_reward._current_id == 0 + obs2, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [0]})) - assert self.env._reward_helper.template_reward._current_id == 1 + assert self.env._reward_helper.template_reward._alert_launched.sum() == 1 obs, reward, done, info = self.env.step(self.env.action_space({"raise_alert": [1]})) assert self.env._reward_helper.template_reward._current_id == 2 + assert self.env._reward_helper.template_reward._alert_launched.sum() == 2 obs3 : BaseObservation = self.env.reset() assert self.env._reward_helper.template_reward._current_id == 0 + assert self.env._reward_helper.template_reward._alert_launched.sum() == 0 def _aux_alert_0(self, obs): assert obs.active_alert[0] From 2bf4b0666240984bb3a3204bf151bdcebb2ec223 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Thu, 20 Jul 2023 18:08:33 +0200 Subject: [PATCH 069/103] updating changelog [skip ci] --- CHANGELOG.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 24f6d6755..3401a3ae6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -48,6 +48,7 @@ Change Log - [FIXED] an issue when disconnecting loads / generators / storage units and changing their values in the same action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" have the priority (if an action disconnect an element, it will not change its sepoint at the same time). +- [FIXED] a bug in `AlertReward` due to `reset` not being called. - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance - [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction` From aa83a0d490a158c6c3a3898a6456c6ab31359d38 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 21 Jul 2023 09:21:53 +0200 Subject: [PATCH 070/103] renaming some file to facilitate PR about the score --- .../tests/_aux_opponent_for_test_alerts.py | 122 ++++++++++++++++++ ...est_alert_score.py => test_AlertReward.py} | 98 +++----------- ...alert_feature.py => test_alert_obs_act.py} | 66 +--------- ...df_2023.py => test_score_idf_2023_nres.py} | 0 4 files changed, 141 insertions(+), 145 deletions(-) create mode 100644 grid2op/tests/_aux_opponent_for_test_alerts.py rename grid2op/tests/{test_alert_score.py => test_AlertReward.py} (94%) rename grid2op/tests/{test_alert_feature.py => test_alert_obs_act.py} (91%) rename grid2op/tests/{test_score_idf_2023.py => test_score_idf_2023_nres.py} (100%) diff --git a/grid2op/tests/_aux_opponent_for_test_alerts.py b/grid2op/tests/_aux_opponent_for_test_alerts.py new file mode 100644 index 000000000..fd63bba56 --- /dev/null +++ b/grid2op/tests/_aux_opponent_for_test_alerts.py @@ -0,0 +1,122 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import numpy as np +import copy +from grid2op.Opponent import BaseOpponent + + +def _get_steps_attack(kwargs_opponent, multi=False): + """computes the steps for which there will be attacks""" + ts_attack = np.array(kwargs_opponent["steps_attack"]) + res = [] + for i, ts in enumerate(ts_attack): + if not multi: + res.append(ts + np.arange(kwargs_opponent["duration"])) + else: + res.append(ts + np.arange(kwargs_opponent["duration"][i])) + return np.unique(np.concatenate(res).flatten()) + + +class OpponentForTestAlert(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.env = None + self.lines_attacked = None + self.custom_attack = None + self.attack_duration = None + self.attack_steps = None + self.attack_id = None + + def _custom_deepcopy_for_copy(self, new_obj, dict_=None): + new_obj.env = dict_["partial_env"] + new_obj.lines_attacked = copy.deepcopy(self.lines_attacked) + new_obj.custom_attack = [act.copy() for act in self.custom_attack] + new_obj.attack_duration = copy.deepcopy(self.attack_duration) + new_obj.attack_steps = copy.deepcopy(self.attack_steps) + new_obj.attack_id = copy.deepcopy(self.attack_id) + return super()._custom_deepcopy_for_copy(new_obj, dict_) + + def init(self, + partial_env, + lines_attacked, + attack_duration=[], + attack_steps=[], + attack_id=[]): + self.lines_attacked = lines_attacked + self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in attack_id] + self.attack_duration = attack_duration + self.attack_steps = attack_steps + self.attack_id = attack_id + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + current_step = self.env.nb_time_step + if current_step not in self.attack_steps: + return None, None + index = self.attack_steps.index(current_step) + return self.custom_attack[index], self.attack_duration[index] + + +class TestOpponent(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked, duration=10, steps_attack=[0,1]): + attacked_line = lines_attacked[0] + self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + return self.custom_attack, self.duration + + +class TestOpponentMultiLines(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked, duration=[10,10], steps_attack=[0,1]): + attacked_line = lines_attacked[0] + self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in lines_attacked] + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + index = self.steps_attack.index(current_step) + + return self.custom_attack[index], self.duration[index] diff --git a/grid2op/tests/test_alert_score.py b/grid2op/tests/test_AlertReward.py similarity index 94% rename from grid2op/tests/test_alert_score.py rename to grid2op/tests/test_AlertReward.py index 4a31f6158..f95f3a568 100644 --- a/grid2op/tests/test_alert_score.py +++ b/grid2op/tests/test_AlertReward.py @@ -19,11 +19,13 @@ from grid2op.Parameters import Parameters from grid2op.Exceptions import Grid2OpException from grid2op.Runner import Runner # TODO -from grid2op.Opponent import BaseOpponent, GeometricOpponent from grid2op.Action import BaseAction, PlayableAction from grid2op.Agent import BaseAgent from grid2op.Episode import EpisodeData +from _aux_opponent_for_test_alerts import (_get_steps_attack, + TestOpponent, + TestOpponentMultiLines) ALL_ATTACKABLE_LINES= [ "62_58_180", @@ -46,72 +48,6 @@ reward_max_blackout=2.0, reward_end_episode_bonus=42.0) -def _get_steps_attack(kwargs_opponent, multi=False): - """computes the steps for which there will be attacks""" - ts_attack = np.array(kwargs_opponent["steps_attack"]) - res = [] - for i, ts in enumerate(ts_attack): - if not multi: - res.append(ts + np.arange(kwargs_opponent["duration"])) - else: - res.append(ts + np.arange(kwargs_opponent["duration"][i])) - return np.unique(np.concatenate(res).flatten()) - - -class TestOpponent(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=10, steps_attack=[0,1]): - attacked_line = lines_attacked[0] - self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - return self.custom_attack, self.duration - - -class TestOpponentMultiLines(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=[10,10], steps_attack=[0,1]): - attacked_line = lines_attacked[0] - self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in lines_attacked] - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - index = self.steps_attack.index(current_step) - - return self.custom_attack[index], self.duration[index] - # Test alert blackout / tets alert no blackout class TestAlertNoBlackout(unittest.TestCase): @@ -327,8 +263,8 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_early(self)-> None """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[2]) + duration=3, + steps_attack=[2]) with make(self.env_nm, test=True, difficulty="1", @@ -375,8 +311,8 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_no_alert(self) -> """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[1]) + duration=3, + steps_attack=[1]) with make(self.env_nm, test=True, difficulty="1", @@ -462,8 +398,8 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> until the end of the episode where we have a bonus (here artificially 42) """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[2]) + duration=3, + steps_attack=[2]) with make(self.env_nm, test=True, difficulty="1", @@ -604,8 +540,8 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_first_attac """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=[1,1], - steps_attack=[2, 3]) + duration=[1,1], + steps_attack=[2, 3]) with make(self.env_nm, test=True, difficulty="1", @@ -651,8 +587,8 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_second_atta until the end of the episode where we have a bonus (here artificially 42) """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=[1,1], - steps_attack=[2, 3]) + duration=[1,1], + steps_attack=[2, 3]) with make(self.env_nm, test=True, difficulty="1", @@ -884,8 +820,8 @@ def test_assistant_reward_value_blackout_attack_raise_alert_too_early(self) -> N """ # return -10 kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[3]) + duration=3, + steps_attack=[3]) with make(self.env_nm, test=True, difficulty="1", @@ -987,8 +923,8 @@ def test_assistant_reward_value_blackout_2_lines_attacked_simulaneous_only_1_ale we expect a reward of -4 when the blackout occur at step 4 """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[3, 3]) + duration=3, + steps_attack=[3, 3]) with make(self.env_nm, test=True, difficulty="1", diff --git a/grid2op/tests/test_alert_feature.py b/grid2op/tests/test_alert_obs_act.py similarity index 91% rename from grid2op/tests/test_alert_feature.py rename to grid2op/tests/test_alert_obs_act.py index c73375841..60e54fb31 100644 --- a/grid2op/tests/test_alert_feature.py +++ b/grid2op/tests/test_alert_obs_act.py @@ -10,21 +10,15 @@ import numpy as np import unittest import os -import copy -import tempfile from grid2op.Observation import BaseObservation from grid2op.tests.helper_path_test import * from grid2op import make from grid2op.Reward import AlertReward -from grid2op.Parameters import Parameters -from grid2op.Exceptions import Grid2OpException from grid2op.Runner import Runner # TODO -from grid2op.Opponent import BaseOpponent, GeometricOpponent -from grid2op.Action import BaseAction, PlayableAction -from grid2op.Agent import BaseAgent -from grid2op.Episode import EpisodeData +from grid2op.Action import PlayableAction +from _aux_opponent_for_test_alerts import OpponentForTestAlert ALL_ATTACKABLE_LINES = [ "62_58_180", @@ -40,62 +34,6 @@ ] -def _get_steps_attack(kwargs_opponent, multi=False): - """computes the steps for which there will be attacks""" - ts_attack = np.array(kwargs_opponent["steps_attack"]) - res = [] - for i, ts in enumerate(ts_attack): - if not multi: - res.append(ts + np.arange(kwargs_opponent["duration"])) - else: - res.append(ts + np.arange(kwargs_opponent["duration"][i])) - return np.unique(np.concatenate(res).flatten()) - - -class OpponentForTestAlert(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.env = None - self.lines_attacked = None - self.custom_attack = None - self.attack_duration = None - self.attack_steps = None - self.attack_id = None - - def _custom_deepcopy_for_copy(self, new_obj, dict_=None): - new_obj.env = dict_["partial_env"] - new_obj.lines_attacked = copy.deepcopy(self.lines_attacked) - new_obj.custom_attack = [act.copy() for act in self.custom_attack] - new_obj.attack_duration = copy.deepcopy(self.attack_duration) - new_obj.attack_steps = copy.deepcopy(self.attack_steps) - new_obj.attack_id = copy.deepcopy(self.attack_id) - return super()._custom_deepcopy_for_copy(new_obj, dict_) - - def init(self, - partial_env, - lines_attacked=ALL_ATTACKABLE_LINES, - attack_duration=[], - attack_steps=[], - attack_id=[]): - self.lines_attacked = lines_attacked - self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in attack_id] - self.attack_duration = attack_duration - self.attack_steps = attack_steps - self.attack_id = attack_id - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - current_step = self.env.nb_time_step - if current_step not in self.attack_steps: - return None, None - index = self.attack_steps.index(current_step) - return self.custom_attack[index], self.attack_duration[index] - - # Test alert blackout / tets alert no blackout class TestAction(unittest.TestCase): """test the basic bahavior of the assistant alert feature when no attack occur """ diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023_nres.py similarity index 100% rename from grid2op/tests/test_score_idf_2023.py rename to grid2op/tests/test_score_idf_2023_nres.py From f2829feca9be5975cce4b3c6daf9e23718601462 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 21 Jul 2023 09:21:53 +0200 Subject: [PATCH 071/103] renaming some file to facilitate PR about the score --- .../tests/_aux_opponent_for_test_alerts.py | 122 ++++++++++++++++++ ...est_alert_score.py => test_AlertReward.py} | 98 +++----------- ...alert_feature.py => test_alert_obs_act.py} | 66 +--------- ...df_2023.py => test_score_idf_2023_nres.py} | 0 4 files changed, 141 insertions(+), 145 deletions(-) create mode 100644 grid2op/tests/_aux_opponent_for_test_alerts.py rename grid2op/tests/{test_alert_score.py => test_AlertReward.py} (94%) rename grid2op/tests/{test_alert_feature.py => test_alert_obs_act.py} (91%) rename grid2op/tests/{test_score_idf_2023.py => test_score_idf_2023_nres.py} (100%) diff --git a/grid2op/tests/_aux_opponent_for_test_alerts.py b/grid2op/tests/_aux_opponent_for_test_alerts.py new file mode 100644 index 000000000..fd63bba56 --- /dev/null +++ b/grid2op/tests/_aux_opponent_for_test_alerts.py @@ -0,0 +1,122 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import numpy as np +import copy +from grid2op.Opponent import BaseOpponent + + +def _get_steps_attack(kwargs_opponent, multi=False): + """computes the steps for which there will be attacks""" + ts_attack = np.array(kwargs_opponent["steps_attack"]) + res = [] + for i, ts in enumerate(ts_attack): + if not multi: + res.append(ts + np.arange(kwargs_opponent["duration"])) + else: + res.append(ts + np.arange(kwargs_opponent["duration"][i])) + return np.unique(np.concatenate(res).flatten()) + + +class OpponentForTestAlert(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.env = None + self.lines_attacked = None + self.custom_attack = None + self.attack_duration = None + self.attack_steps = None + self.attack_id = None + + def _custom_deepcopy_for_copy(self, new_obj, dict_=None): + new_obj.env = dict_["partial_env"] + new_obj.lines_attacked = copy.deepcopy(self.lines_attacked) + new_obj.custom_attack = [act.copy() for act in self.custom_attack] + new_obj.attack_duration = copy.deepcopy(self.attack_duration) + new_obj.attack_steps = copy.deepcopy(self.attack_steps) + new_obj.attack_id = copy.deepcopy(self.attack_id) + return super()._custom_deepcopy_for_copy(new_obj, dict_) + + def init(self, + partial_env, + lines_attacked, + attack_duration=[], + attack_steps=[], + attack_id=[]): + self.lines_attacked = lines_attacked + self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in attack_id] + self.attack_duration = attack_duration + self.attack_steps = attack_steps + self.attack_id = attack_id + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + current_step = self.env.nb_time_step + if current_step not in self.attack_steps: + return None, None + index = self.attack_steps.index(current_step) + return self.custom_attack[index], self.attack_duration[index] + + +class TestOpponent(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked, duration=10, steps_attack=[0,1]): + attacked_line = lines_attacked[0] + self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + return self.custom_attack, self.duration + + +class TestOpponentMultiLines(BaseOpponent): + """An opponent that can select the line attack, the time and duration of the attack.""" + + def __init__(self, action_space): + super().__init__(action_space) + self.custom_attack = None + self.duration = None + self.steps_attack = None + + def init(self, partial_env, lines_attacked, duration=[10,10], steps_attack=[0,1]): + attacked_line = lines_attacked[0] + self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in lines_attacked] + self.duration = duration + self.steps_attack = steps_attack + self.env = partial_env + + def attack(self, observation, agent_action, env_action, budget, previous_fails): + if observation is None: + return None, None + + current_step = self.env.nb_time_step + if current_step not in self.steps_attack: + return None, None + + index = self.steps_attack.index(current_step) + + return self.custom_attack[index], self.duration[index] diff --git a/grid2op/tests/test_alert_score.py b/grid2op/tests/test_AlertReward.py similarity index 94% rename from grid2op/tests/test_alert_score.py rename to grid2op/tests/test_AlertReward.py index 4a31f6158..f95f3a568 100644 --- a/grid2op/tests/test_alert_score.py +++ b/grid2op/tests/test_AlertReward.py @@ -19,11 +19,13 @@ from grid2op.Parameters import Parameters from grid2op.Exceptions import Grid2OpException from grid2op.Runner import Runner # TODO -from grid2op.Opponent import BaseOpponent, GeometricOpponent from grid2op.Action import BaseAction, PlayableAction from grid2op.Agent import BaseAgent from grid2op.Episode import EpisodeData +from _aux_opponent_for_test_alerts import (_get_steps_attack, + TestOpponent, + TestOpponentMultiLines) ALL_ATTACKABLE_LINES= [ "62_58_180", @@ -46,72 +48,6 @@ reward_max_blackout=2.0, reward_end_episode_bonus=42.0) -def _get_steps_attack(kwargs_opponent, multi=False): - """computes the steps for which there will be attacks""" - ts_attack = np.array(kwargs_opponent["steps_attack"]) - res = [] - for i, ts in enumerate(ts_attack): - if not multi: - res.append(ts + np.arange(kwargs_opponent["duration"])) - else: - res.append(ts + np.arange(kwargs_opponent["duration"][i])) - return np.unique(np.concatenate(res).flatten()) - - -class TestOpponent(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=10, steps_attack=[0,1]): - attacked_line = lines_attacked[0] - self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - return self.custom_attack, self.duration - - -class TestOpponentMultiLines(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=[10,10], steps_attack=[0,1]): - attacked_line = lines_attacked[0] - self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in lines_attacked] - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - index = self.steps_attack.index(current_step) - - return self.custom_attack[index], self.duration[index] - # Test alert blackout / tets alert no blackout class TestAlertNoBlackout(unittest.TestCase): @@ -327,8 +263,8 @@ def test_assistant_reward_value_no_blackout_attack_alert_too_early(self)-> None """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[2]) + duration=3, + steps_attack=[2]) with make(self.env_nm, test=True, difficulty="1", @@ -375,8 +311,8 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_no_alert(self) -> """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[1]) + duration=3, + steps_attack=[1]) with make(self.env_nm, test=True, difficulty="1", @@ -462,8 +398,8 @@ def test_assistant_reward_value_no_blackout_2_attack_same_time_2_alert(self) -> until the end of the episode where we have a bonus (here artificially 42) """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[2]) + duration=3, + steps_attack=[2]) with make(self.env_nm, test=True, difficulty="1", @@ -604,8 +540,8 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_first_attac """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=[1,1], - steps_attack=[2, 3]) + duration=[1,1], + steps_attack=[2, 3]) with make(self.env_nm, test=True, difficulty="1", @@ -651,8 +587,8 @@ def test_assistant_reward_value_no_blackout_2_attack_diff_time_alert_second_atta until the end of the episode where we have a bonus (here artificially 42) """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=[1,1], - steps_attack=[2, 3]) + duration=[1,1], + steps_attack=[2, 3]) with make(self.env_nm, test=True, difficulty="1", @@ -884,8 +820,8 @@ def test_assistant_reward_value_blackout_attack_raise_alert_too_early(self) -> N """ # return -10 kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[3]) + duration=3, + steps_attack=[3]) with make(self.env_nm, test=True, difficulty="1", @@ -987,8 +923,8 @@ def test_assistant_reward_value_blackout_2_lines_attacked_simulaneous_only_1_ale we expect a reward of -4 when the blackout occur at step 4 """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[3, 3]) + duration=3, + steps_attack=[3, 3]) with make(self.env_nm, test=True, difficulty="1", diff --git a/grid2op/tests/test_alert_feature.py b/grid2op/tests/test_alert_obs_act.py similarity index 91% rename from grid2op/tests/test_alert_feature.py rename to grid2op/tests/test_alert_obs_act.py index c73375841..60e54fb31 100644 --- a/grid2op/tests/test_alert_feature.py +++ b/grid2op/tests/test_alert_obs_act.py @@ -10,21 +10,15 @@ import numpy as np import unittest import os -import copy -import tempfile from grid2op.Observation import BaseObservation from grid2op.tests.helper_path_test import * from grid2op import make from grid2op.Reward import AlertReward -from grid2op.Parameters import Parameters -from grid2op.Exceptions import Grid2OpException from grid2op.Runner import Runner # TODO -from grid2op.Opponent import BaseOpponent, GeometricOpponent -from grid2op.Action import BaseAction, PlayableAction -from grid2op.Agent import BaseAgent -from grid2op.Episode import EpisodeData +from grid2op.Action import PlayableAction +from _aux_opponent_for_test_alerts import OpponentForTestAlert ALL_ATTACKABLE_LINES = [ "62_58_180", @@ -40,62 +34,6 @@ ] -def _get_steps_attack(kwargs_opponent, multi=False): - """computes the steps for which there will be attacks""" - ts_attack = np.array(kwargs_opponent["steps_attack"]) - res = [] - for i, ts in enumerate(ts_attack): - if not multi: - res.append(ts + np.arange(kwargs_opponent["duration"])) - else: - res.append(ts + np.arange(kwargs_opponent["duration"][i])) - return np.unique(np.concatenate(res).flatten()) - - -class OpponentForTestAlert(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.env = None - self.lines_attacked = None - self.custom_attack = None - self.attack_duration = None - self.attack_steps = None - self.attack_id = None - - def _custom_deepcopy_for_copy(self, new_obj, dict_=None): - new_obj.env = dict_["partial_env"] - new_obj.lines_attacked = copy.deepcopy(self.lines_attacked) - new_obj.custom_attack = [act.copy() for act in self.custom_attack] - new_obj.attack_duration = copy.deepcopy(self.attack_duration) - new_obj.attack_steps = copy.deepcopy(self.attack_steps) - new_obj.attack_id = copy.deepcopy(self.attack_id) - return super()._custom_deepcopy_for_copy(new_obj, dict_) - - def init(self, - partial_env, - lines_attacked=ALL_ATTACKABLE_LINES, - attack_duration=[], - attack_steps=[], - attack_id=[]): - self.lines_attacked = lines_attacked - self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in attack_id] - self.attack_duration = attack_duration - self.attack_steps = attack_steps - self.attack_id = attack_id - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - current_step = self.env.nb_time_step - if current_step not in self.attack_steps: - return None, None - index = self.attack_steps.index(current_step) - return self.custom_attack[index], self.attack_duration[index] - - # Test alert blackout / tets alert no blackout class TestAction(unittest.TestCase): """test the basic bahavior of the assistant alert feature when no attack occur """ diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023_nres.py similarity index 100% rename from grid2op/tests/test_score_idf_2023.py rename to grid2op/tests/test_score_idf_2023_nres.py From 0085986792cf006d239f9fb4a35c3701f5d5cb85 Mon Sep 17 00:00:00 2001 From: marota Date: Fri, 21 Jul 2023 10:23:37 +0200 Subject: [PATCH 072/103] making required changes for _alertTrustScore --- grid2op/Reward/_alertTrustScore.py | 62 ++++++++++++++---------------- 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 4deea709f..751d738f7 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -10,8 +10,6 @@ from grid2op.Reward import AlertReward from grid2op.dtypes import dt_float -SURVIVOR_TIMESTEPS = 12 #nb timesteps to be considered survivor of an attack - class _AlertTrustScore(AlertReward): """ @@ -31,25 +29,15 @@ class _AlertTrustScore(AlertReward): """ - #TODO - #Parameters to use for challenge - #def __init__(self, - # logger=None, - # reward_min_no_blackout=-1.0, - # reward_min_blackout=-50, - # reward_max_no_blackout=0.0, - # reward_max_blackout=0.0, - # reward_end_episode_bonus=0.0, - # min_score=-3): def __init__(self, logger=None, reward_min_no_blackout=-1.0, - reward_min_blackout=-10.0, - reward_max_no_blackout=1.0, - reward_max_blackout=2.0, - reward_end_episode_bonus=1.0, - min_score=-1.0): - + reward_min_blackout=-50, + reward_max_no_blackout=0.0, + reward_max_blackout=0.0, + reward_end_episode_bonus=0.0, + min_score=-3): + super().__init__(logger, reward_min_no_blackout, reward_min_blackout, @@ -83,7 +71,7 @@ def reset(self, env): self.cumulated_reward = 0 #KPIs self.total_nb_attacks = 0 - self.nb_last_attacks=0 + self.nb_last_attacks = 0 # TODO #self.total_nb_alerts = 0 @@ -95,6 +83,10 @@ def reset(self, env): def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): + score_ep = 0. + if self._is_simul_env: + return score_ep + self.blackout_encountered = self.is_in_blackout(has_error, is_done) score_ep = 0. @@ -105,7 +97,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): self.cumulated_reward += res lines_attacked = env._time_since_last_attack == 0 - self.total_nb_attacks += np.sum(lines_attacked) + self.total_nb_attacks += lines_attacked.sum() # TODO #lines_alerted_beforeattack = np.equal(env._time_since_last_alert, env._time_since_last_attack + 1) and lines_attacked @@ -141,28 +133,30 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return score_ep @staticmethod - def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score): - standardized_score = np.round((cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +1e-5),4) + def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score,tol=1e-5): + standardized_score = np.round((cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +tol),4) #in case cm_reward_min_ep=cm_reward_max_ep=0, score is 0.0 - score_ep = (cm_reward_min_ep!=cm_reward_max_ep)*min_score + (max_score - min_score) * standardized_score + if(cm_reward_min_ep==cm_reward_max_ep): + score_ep = 0. + else: + score_ep = min_score + (max_score - min_score) * standardized_score return score_ep def _compute_min_max_reward(self, nb_attacks,nb_last_attacks): - #TODO - #add case multiple attack before blackout: weighted sum + if (nb_attacks==0 and self.blackout_encountered): - cm_reward_min_ep= lambda k: k - cm_reward_max_ep= lambda k: k + cm_reward_min_ep = 0. + cm_reward_max_ep= 0. elif(self.blackout_encountered): if(nb_last_attacks==0): - cm_reward_min_ep = lambda k: self.reward_min_no_blackout * k - cm_reward_max_ep = lambda k: self.reward_max_no_blackout * k + cm_reward_min_ep = self.reward_min_no_blackout * nb_attacks + cm_reward_max_ep = self.reward_max_no_blackout * nb_attacks elif(nb_last_attacks>=1): - cm_reward_min_ep = lambda k: self.reward_min_no_blackout * (k - nb_last_attacks) + self.reward_min_blackout - cm_reward_max_ep = lambda k: self.reward_max_no_blackout * (k - nb_last_attacks) + self.reward_max_blackout + cm_reward_min_ep = self.reward_min_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_min_blackout + cm_reward_max_ep = self.reward_max_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_max_blackout else: - cm_reward_min_ep = lambda k: self.reward_min_no_blackout * k - cm_reward_max_ep = lambda k: self.reward_max_no_blackout * k + self.reward_end_episode_bonus + cm_reward_min_ep = self.reward_min_no_blackout * nb_attacks + cm_reward_max_ep = self.reward_max_no_blackout * nb_attacks + self.reward_end_episode_bonus - return cm_reward_min_ep(nb_attacks), cm_reward_max_ep(nb_attacks) + return cm_reward_min_ep, cm_reward_max_ep From 7bf108543e5824beae420b6aa5571b9b572db878 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 21 Jul 2023 10:52:51 +0200 Subject: [PATCH 073/103] adding back Antoine's tests --- .../tests/test_score_idf_2023_assistant.py | 81 +++++++++++++++++++ grid2op/tests/test_score_idf_2023_nres.py | 14 ++-- 2 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 grid2op/tests/test_score_idf_2023_assistant.py diff --git a/grid2op/tests/test_score_idf_2023_assistant.py b/grid2op/tests/test_score_idf_2023_assistant.py new file mode 100644 index 000000000..54f20c404 --- /dev/null +++ b/grid2op/tests/test_score_idf_2023_assistant.py @@ -0,0 +1,81 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import warnings +import numpy as np +import unittest + +import grid2op +from grid2op.utils import ScoreL2RPN2023 +from grid2op.Agent.doNothing import DoNothingAgent +from grid2op.Chronics import FromHandlers +from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler + + +class TestScoreL2RPN2023Assist(unittest.TestCase): + """test the "assistant" part of the l2rpn_idf_2023""" + def setUp(self) -> None: + env_name = "l2rpn_idf_2023" + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + self.env = grid2op.make(env_name, + test=True, + data_feeding_kwargs={"gridvalueClass": FromHandlers, + "gen_p_handler": CSVHandler("prod_p"), + "load_p_handler": CSVHandler("load_p"), + "gen_v_handler": CSVHandler("prod_v"), + "load_q_handler": CSVHandler("load_q"), + "h_forecast": (5,), + "gen_p_for_handler": PerfectForecastHandler("prod_p_forecasted", quiet_warnings=True), + "gen_v_for_handler": PerfectForecastHandler("prod_v_forecasted", quiet_warnings=True), + "load_p_for_handler": PerfectForecastHandler("load_p_forecasted", quiet_warnings=True), + "load_q_for_handler": PerfectForecastHandler("load_q_forecasted", quiet_warnings=True), + },) + self.env.set_max_iter(20) + params = self.env.parameters + params.NO_OVERFLOW_DISCONNECTION = True + params.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION = True + self.seed = 0 + self.scen_id = 0 + self.nb_scenario = 2 + self.max_iter = 10 + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + + def test_score_helper(self): + """basic tests for ScoreL2RPN2023 class""" + self.env.reset() + my_score = ScoreL2RPN2023( + self.env, + nb_scenario=self.nb_scenario, + env_seeds=[0 for _ in range(self.nb_scenario)], + agent_seeds=[0 for _ in range(self.nb_scenario)], + max_step=self.max_iter, + weight_op_score=0.6, + weight_assistant_score=0.25, + weight_nres_score=0.15, + scale_nres_score=100, + scale_assistant_score=100, + min_nres_score=-100., + min_assistant_cost_score=-100) + try: + # test do nothing indeed gets 100. + res_dn = my_score.get(DoNothingAgent(self.env.action_space)) + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): + assert nres_score == 100. + assert ep_score == 0.6 * op_score + 0.15 * nres_score + 0.25 * assistant_score + assert assistant_score == 100. #no blackout with no disconnections + assert op_score == 0 + finally: + my_score.clear_all() + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/grid2op/tests/test_score_idf_2023_nres.py b/grid2op/tests/test_score_idf_2023_nres.py index a298c5545..61537814f 100644 --- a/grid2op/tests/test_score_idf_2023_nres.py +++ b/grid2op/tests/test_score_idf_2023_nres.py @@ -46,8 +46,8 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - act = self.action_space({"curtail": curtail}) return act -class TestScoreL2RPN2023(unittest.TestCase): - +class TestScoreL2RPN2023NRES(unittest.TestCase): + """test the "nres" part of the l2rpn_idf_2023""" def setUp(self) -> None: env_name = "l2rpn_case14_sandbox" with warnings.catch_warnings(): @@ -97,7 +97,7 @@ def test_score_helper(self): # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): assert nres_score == 100. assert ep_score == 0.8 * op_score + 0.2 * nres_score @@ -198,22 +198,22 @@ def test_spec(self): tol = 3e-5 # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_dn[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): assert abs(nres_score - 100.) <= tol # test 80% gets indeed close to 0 res_80 = my_score.get(CurtailAgent(self.env.action_space, 0.8)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_80[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_80[0]): assert abs(nres_score) <= tol # test 50% gets indeed close to -100 res_50 = my_score.get(CurtailAgent(self.env.action_space, 0.5)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_50[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_50[0]): assert abs(nres_score + 100.) <= tol # test bellow 50% still gets close to -100 res_30 = my_score.get(CurtailAgent(self.env.action_space, 0.3)) - for scen_id, (ep_score, op_score, nres_score, assistant_confidence_score, assistant_cost_score) in enumerate(res_30[0]): + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_30[0]): assert abs(nres_score + 100.) <= tol finally: my_score.clear_all() From 388101925d4ef61185e7252e910625f760231272 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Fri, 21 Jul 2023 11:34:57 +0200 Subject: [PATCH 074/103] fix issue rte-france#494 --- CHANGELOG.rst | 1 + grid2op/Rules/rulesByArea.py | 26 ++++++++++++++++--- grid2op/data/l2rpn_idf_2023/config.py | 6 ++--- grid2op/tests/test_issue_494.py | 36 +++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 grid2op/tests/test_issue_494.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 3401a3ae6..bc2a3f11d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -49,6 +49,7 @@ Change Log action: the behaviour could depend on the backend. As of 1.9.2 the "disconnections" have the priority (if an action disconnect an element, it will not change its sepoint at the same time). - [FIXED] a bug in `AlertReward` due to `reset` not being called. +- [FIXED] issue https://github.com/rte-france/Grid2Op/issues/494 - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance - [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction` diff --git a/grid2op/Rules/rulesByArea.py b/grid2op/Rules/rulesByArea.py index 0189178e6..8335a1697 100644 --- a/grid2op/Rules/rulesByArea.py +++ b/grid2op/Rules/rulesByArea.py @@ -8,6 +8,9 @@ import numpy as np from itertools import chain +import warnings +import copy + from grid2op.Rules.BaseRules import BaseRules from grid2op.Rules.LookParam import LookParam from grid2op.Rules.PreventReconnection import PreventReconnection @@ -16,6 +19,7 @@ IllegalAction, Grid2OpException ) + class RulesByArea(BaseRules): """ This subclass combine :class:`PreventReconnection`, :class: `PreventDiscoStorageModif` to be applied on the whole grid at once, @@ -51,12 +55,25 @@ def __init__(self, areas_list): ---------- areas_list : list of areas, each placeholder containing the ids of substations of each defined area """ - self.substations_id_by_area = {i : sorted(k) for i,k in enumerate(areas_list)} - + if isinstance(areas_list, list): + self.substations_id_by_area = {i : sorted(k) for i, k in enumerate(areas_list)} + elif isinstance(areas_list, dict): + self.substations_id_by_area = {i : copy.deepcopy(k) for i, k in areas_list.items()} + else: + raise Grid2OpException("Impossible to create a rules when area_list is neither a list nor a dict") + needs_cleaning = False + for area_nm, area_subs in self.substations_id_by_area.items(): + if not np.array_equal(np.unique(area_subs), area_subs): + warnings.warn(f"There are duplicate substation for area {area_nm}") + needs_cleaning = True + if needs_cleaning: + self.substations_id_by_area = {i : np.unique(k) for i, k in self.substations_id_by_area.items()} + def initialize(self, env): """ - This function is used to inform the class instance about the environment specification and check no substation of the grid are left ouside an area. + This function is used to inform the class instance about the environment + specification and check no substation of the grid are left ouside an area. Parameters ---------- env: :class:`grid2op.Environment.Environment` @@ -66,7 +83,8 @@ def initialize(self, env): n_sub = env.n_sub n_sub_rule = np.sum([len(set(list_ids)) for list_ids in self.substations_id_by_area.values()]) if n_sub_rule != n_sub: - raise Grid2OpException("The number of listed ids of substations in rule initialization does not match the number of substations of the chosen environement. Look for missing ids or doublon") + raise Grid2OpException("The number of listed ids of substations in rule initialization does not match the number of " + "substations of the chosen environement. Look for missing ids or doublon") else: self.lines_id_by_area = {key : sorted(list(chain(*[[item for item in np.where(env.line_or_to_subid == subid)[0] ] for subid in subid_list]))) for key,subid_list in self.substations_id_by_area.items()} diff --git a/grid2op/data/l2rpn_idf_2023/config.py b/grid2op/data/l2rpn_idf_2023/config.py index 5af280dba..733829b90 100644 --- a/grid2op/data/l2rpn_idf_2023/config.py +++ b/grid2op/data/l2rpn_idf_2023/config.py @@ -71,13 +71,13 @@ this_rules = RulesByArea([[0, 1, 2, 3, 10, 11, 116, 13, 12, 14, 4, 5, 6, 15, 7, 8, 9, 23, 27, 28, 26, 30, 114, 113, 31, 112, 16, 29, 25, 24, 17, - 18, 19, 20, 21, 22, 24, 71, 70, 72], + 18, 19, 20, 21, 22, 71, 70, 72], [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 64, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 66, 65], [69, 73, 74, 117, 75, 76, 77, 78, 79, 80, 98, 97, 96, 95, 94, - 93, 99, 98, 105, 103, 104, 106, 107, 108, 111, 109, 110, 102, - 100, 92, 91, 101, 100, 90, 89, 88, 87, 84, 83, 82, 81, 85, 86, + 93, 99, 105, 103, 104, 106, 107, 108, 111, 109, 110, 102, + 100, 92, 91, 101, 90, 89, 88, 87, 84, 83, 82, 81, 85, 86, 68, 67, 115] ]) diff --git a/grid2op/tests/test_issue_494.py b/grid2op/tests/test_issue_494.py new file mode 100644 index 000000000..e6d9ee1b3 --- /dev/null +++ b/grid2op/tests/test_issue_494.py @@ -0,0 +1,36 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import numpy as np +import grid2op +import unittest +import warnings +import pdb + + +class Issue494Tester(unittest.TestCase): + def setUp(self) -> None: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + self.env = grid2op.make("l2rpn_idf_2023", test=True) + self.env.seed(0) + self.env.set_id(0) + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_act_legal(self): + obs = self.env.reset() + for sub_id in [24, 98, 100]: + obs, reward, done, info = self.env.step(self.env.action_space({"set_bus": {"substations_id": [(sub_id, np.ones(type(obs).sub_info[sub_id], dtype=int))]}})) + assert not info["exception"], f'for {sub_id=} {info["exception"]} vs []' + + +if __name__ == '__main__': + unittest.main() From 085f9d1a081f60350bb223eb03b7560955396dca Mon Sep 17 00:00:00 2001 From: marota Date: Fri, 21 Jul 2023 12:20:01 +0200 Subject: [PATCH 075/103] making required changes for l2rpn_idf_2023_scores.py --- grid2op/utils/l2rpn_idf_2023_scores.py | 40 ++++++++------------------ 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 719c4d5c6..835766654 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -82,15 +82,21 @@ def __init__( verbose=0, max_step=-1, nb_process_stats=1, + scores_func={ + "grid_operational_cost": L2RPNSandBoxScore, + "assistant_confidence": _AlertTrustScore, + "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, + }, + score_names=["grid_operational_cost_scores", + "assistant_confidence_scores", + "new_renewable_sources_usage_scores"], + add_nb_highres_sim=False, scale_assistant_score=100.0, scale_nres_score=100., weight_op_score=0.6, weight_assistant_score=0.25, weight_nres_score=0.15, - # weight_confidence_assistant_score=0.7, min_nres_score=-100, - min_assistant_cost_score=-100, - add_nb_highres_sim=False, ): ScoreL2RPN2020.__init__( self, @@ -102,16 +108,8 @@ def __init__( verbose=verbose, max_step=max_step, nb_process_stats=nb_process_stats, - scores_func={ - "grid_operational_cost": L2RPNSandBoxScore, - "assistant_confidence": _AlertTrustScore, - # "assistant_cost": _AlertCostScore, - "new_renewable_sources_usage": _NewRenewableSourcesUsageScore, - }, - score_names=["grid_operational_cost_scores", - "assistant_confidence_scores", - # "assistant_cost_scores", - "new_renewable_sources_usage_scores"], + scores_func=scores_func, + score_names=score_names, add_nb_highres_sim=add_nb_highres_sim, ) @@ -120,16 +118,13 @@ def __init__( raise Grid2OpException( 'The weights of each component of the score shall sum to 1' ) - # assert(all([weight_confidence_assistant_score>=0., weight_confidence_assistant_score<=1.])) self.scale_assistant_score = scale_assistant_score self.scale_nres_score = scale_nres_score self.weight_op_score = weight_op_score self.weight_assistant_score = weight_assistant_score self.weight_nres_score = weight_nres_score - # self.weight_confidence_assistant_score = weight_confidence_assistant_score self.min_nres_score = min_nres_score - # self.min_assistant_cost_score = min_assistant_cost_score def _compute_episode_score( self, @@ -171,24 +166,13 @@ def _compute_episode_score( nres_score = max(nres_score, self.min_nres_score / self.scale_nres_score) nres_score = self.scale_nres_score * nres_score - # assistant_confidence_score + # assistant_score assistant_confidence_score_nm = "assistant_confidence_scores" real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_confidence_score_nm) key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" assistant_confidence_score = float(other_rewards[-1][key_score_file]) assistant_score = self.scale_assistant_score * assistant_confidence_score - # assistant_cost_score - # assistant_cost_score_nm = "assistant_cost_scores" - # real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_cost_score_nm) - # key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" - # assistant_cost_score = float(other_rewards[-1][key_score_file]) - # assistant_cost_score = max(assistant_cost_score, self.min_assistant_cost_score / self.scale_assistant_score) - # assistant_cost_score = self.scale_assistant_score * assistant_cost_score - - # assistant_score = self.weight_confidence_assistant_score * assistant_confidence_score +\ - # (1. - self.weight_confidence_assistant_score) * assistant_cost_score - ep_score = ( self.weight_op_score * op_score + self.weight_nres_score * nres_score + self.weight_assistant_score * assistant_score ) From 4633186fbb34dda78babb09b9419bb98d008c009 Mon Sep 17 00:00:00 2001 From: marota Date: Fri, 21 Jul 2023 12:36:17 +0200 Subject: [PATCH 076/103] in case an episode finishes with no attacks, making the choice of maximum score in all cases --- grid2op/Reward/_alertTrustScore.py | 11 +++++++---- grid2op/tests/test_alert_trust_score.py | 24 +++++------------------- 2 files changed, 12 insertions(+), 23 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 751d738f7..12eb0a15e 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -116,7 +116,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): else: self.nb_last_attacks=np.sum(self._ts_attack) cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks,self.nb_last_attacks) - score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep,self.min_score,self.max_score) + score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep,self.min_score,self.max_score,self.blackout_encountered) # TODO #if self.blackout_encountered: @@ -133,11 +133,14 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return score_ep @staticmethod - def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score,tol=1e-5): + def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score,is_blackout,tol=1e-5): standardized_score = np.round((cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +tol),4) - #in case cm_reward_min_ep=cm_reward_max_ep=0, score is 0.0 + #in case cm_reward_min_ep=cm_reward_max_ep=0, score is maximum if(cm_reward_min_ep==cm_reward_max_ep): - score_ep = 0. + if (is_blackout): + score_ep = 0.0 + else: + score_ep = max_score else: score_ep = min_score + (max_score - min_score) * standardized_score return score_ep diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index de5356c00..9a02a2093 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -40,14 +40,6 @@ ATTACKED_LINE = "48_50_136" - -#DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, -# reward_min_blackout=-10.0, -# reward_max_no_blackout=1.0, -# reward_max_blackout=2.0, -# reward_end_episode_bonus=42.0, -# min_score=-1.0) - DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, reward_min_blackout=-50.0, reward_max_no_blackout=0.0, @@ -134,8 +126,8 @@ def setUp(self) -> None: ) def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : - """ When no blackout and no attack occur, and no alert is raised we expect a reward of 0 - until the end of the episode where we have a bonus (here artificially 42) + """ When no blackout and no attack occur, and no alert is raised we expect a maximum score + until the end of the episode where we have a bonus Raises: Grid2OpException: raise an exception if an attack occur @@ -165,10 +157,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] - if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): - assert score == 0.0 - else: - assert score == env._reward_helper.template_reward.max_score + assert score == env._reward_helper.template_reward.max_score else : assert score == 0 else : @@ -177,7 +166,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : assert done def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : - """ When an alert is raised while no attack / nor blackout occur, we expect a score of 0 + """ When an alert is raised while no attack / nor blackout occur, we expect a maximum score until the end of the episode where we have a 42s Raises: @@ -215,10 +204,7 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] - if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): - assert score == 0.0 - else: - assert score == env._reward_helper.template_reward.max_score + assert score == env._reward_helper.template_reward.max_score else : assert score == 0 else : From da58e0b267ad974a98f562ad6882a7344dd1146f Mon Sep 17 00:00:00 2001 From: marota Date: Fri, 21 Jul 2023 14:28:33 +0200 Subject: [PATCH 077/103] Update test_alert_obs_act.py Adding back previous changes from Laure with her validation to have a configurable test test_alert_obs_act --- grid2op/tests/test_alert_obs_act.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/grid2op/tests/test_alert_obs_act.py b/grid2op/tests/test_alert_obs_act.py index 60e54fb31..e2fbc9dfa 100644 --- a/grid2op/tests/test_alert_obs_act.py +++ b/grid2op/tests/test_alert_obs_act.py @@ -34,6 +34,13 @@ ] +DEFAULT_ALERT_REWARD_PARAMS = dict(reward_min_no_blackout=-1.0, + reward_min_blackout=-10.0, + reward_max_no_blackout=1.0, + reward_max_blackout=2.0, + reward_end_episode_bonus=42.0) + + # Test alert blackout / tets alert no blackout class TestAction(unittest.TestCase): """test the basic bahavior of the assistant alert feature when no attack occur """ @@ -55,7 +62,7 @@ def setUp(self) -> None: opponent_action_class=PlayableAction, opponent_class=OpponentForTestAlert, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tafta") def tearDown(self) -> None: @@ -170,7 +177,7 @@ def setUp(self) -> None: opponent_action_class=PlayableAction, opponent_class=OpponentForTestAlert, kwargs_opponent=kwargs_opponent, - reward_class=AlertReward(reward_end_episode_bonus=42), + reward_class=AlertReward(**DEFAULT_ALERT_REWARD_PARAMS), _add_to_name="_tafto") param = self.env.parameters param.ALERT_TIME_WINDOW = 2 @@ -544,4 +551,4 @@ def test_when_attacks(self): # TODO test "as_dict" and "as_json" if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From daef8be1e65e32d9d289ba20bb1125fa78eac10e Mon Sep 17 00:00:00 2001 From: marota Date: Fri, 21 Jul 2023 17:10:13 +0200 Subject: [PATCH 078/103] making score computation more consistent with the choices in the implementation of the reward --- grid2op/Reward/_alertTrustScore.py | 6 +- grid2op/tests/test_alert_trust_score.py | 101 ++++-------------------- 2 files changed, 20 insertions(+), 87 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 12eb0a15e..c8fc98119 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -96,8 +96,8 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res - lines_attacked = env._time_since_last_attack == 0 - self.total_nb_attacks += lines_attacked.sum() + is_attack = (env._time_since_last_attack == 0).any()#even if there are simultaneous attacks, we consider this as a single attack event + self.total_nb_attacks += is_attack # TODO #lines_alerted_beforeattack = np.equal(env._time_since_last_alert, env._time_since_last_attack + 1) and lines_attacked @@ -114,7 +114,7 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return score_ep else: - self.nb_last_attacks=np.sum(self._ts_attack) + self.nb_last_attacks=np.sum(np.any(self._ts_attack,axis=1)) cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks,self.nb_last_attacks) score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep,self.min_score,self.max_score,self.blackout_encountered) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 9a02a2093..c4fa94d39 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -24,6 +24,10 @@ from grid2op.Agent import BaseAgent from grid2op.Episode import EpisodeData +from _aux_opponent_for_test_alerts import (_get_steps_attack, + TestOpponent, + TestOpponentMultiLines) + ALL_ATTACKABLE_LINES= [ "62_58_180", @@ -47,75 +51,6 @@ reward_end_episode_bonus=0.0, min_score=-3.0) -def _get_steps_attack(kwargs_opponent, multi=False): - """computes the steps for which there will be attacks""" - ts_attack = np.array(kwargs_opponent["steps_attack"]) - res = [] - for i, ts in enumerate(ts_attack): - if not multi: - res.append(ts + np.arange(kwargs_opponent["duration"])) - else: - res.append(ts + np.arange(kwargs_opponent["duration"][i])) - return np.unique(np.concatenate(res).flatten()) - - -class TestOpponent(GeometricOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=10, steps_attack=[0,1]): - super().init(partial_env, lines_attacked, ) - attacked_line = lines_attacked[0] - self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - return self.custom_attack, self.duration - - -class TestOpponentMultiLines(GeometricOpponentMultiArea): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=[10,10], steps_attack=[0,1]): - super().init(partial_env, [[l] for l in lines_attacked]) - attacked_line = lines_attacked[0] - self.custom_attack = [ self.action_space({"set_line_status" : [(l, -1)]}) for l in lines_attacked] - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - index = self.steps_attack.index(current_step) - - return self.custom_attack[index], self.duration[index] - - # Test alert blackout / tets alert no blackout class TestAlertTrustScoreNoBlackout(unittest.TestCase): """test the basic bahavior of the assistant alert feature when no attack occur """ @@ -473,7 +408,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 - assert total_nb_attacks == 2 + assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ @@ -537,11 +472,11 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 - assert total_nb_attacks == 2 + assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event cm_reward=env._reward_helper.template_reward.cumulated_reward - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ - DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert env._reward_helper.template_reward.cumulated_reward==(DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"])/2 + DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) @@ -603,11 +538,11 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 - assert total_nb_attacks == 2 + assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event cm_reward=env._reward_helper.template_reward.cumulated_reward - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ - DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + (DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks)/total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks @@ -1197,12 +1132,12 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 2 - assert total_nb_attacks == 2 + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_max_blackout'])/total_nb_attacks + 'reward_max_blackout'])/2#2 here because there are two attacks at the same time, so we take the mean of the individual alert scores cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) @@ -1261,18 +1196,16 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: - #assert score == -4 - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 2 - assert total_nb_attacks == 2 + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event cm_reward=env._reward_helper.template_reward.cumulated_reward assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_min_blackout'])/total_nb_attacks + 'reward_min_blackout'])/2 #2 here because there are two attacks at the same time, so we take the mean of the individual alert scores cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) From 95956d075b2c33ab876e60b8d688bd084e5e235b Mon Sep 17 00:00:00 2001 From: marota Date: Fri, 21 Jul 2023 17:21:52 +0200 Subject: [PATCH 079/103] adding min_assistant_score in l2rpn_idf_2023_scores.py and a score_idf_2023 test file with an existing test that was not reintegrated --- grid2op/tests/test_score_idf_2023.py | 91 ++++++++++++++++++++++++++ grid2op/utils/l2rpn_idf_2023_scores.py | 2 + 2 files changed, 93 insertions(+) create mode 100644 grid2op/tests/test_score_idf_2023.py diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py new file mode 100644 index 000000000..e6abfa099 --- /dev/null +++ b/grid2op/tests/test_score_idf_2023.py @@ -0,0 +1,91 @@ +# Copyright (c) 2023, 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 Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. + +import warnings +import numpy as np +import unittest + +import grid2op +from grid2op.Action import ActionSpace, BaseAction +from grid2op.utils import ScoreL2RPN2023 +from grid2op.Observation import BaseObservation +from grid2op.Agent.doNothing import DoNothingAgent, BaseAgent +from grid2op.Chronics import FromHandlers +from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler +from grid2op.Reward import _NewRenewableSourcesUsageScore + +class TestScoreL2RPN2023(unittest.TestCase): + + def setUp(self) -> None: + env_name = "l2rpn_case14_sandbox" + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + self.env = grid2op.make(env_name, + test=True, + data_feeding_kwargs={"gridvalueClass": FromHandlers, + "gen_p_handler": CSVHandler("prod_p"), + "load_p_handler": CSVHandler("load_p"), + "gen_v_handler": CSVHandler("prod_v"), + "load_q_handler": CSVHandler("load_q"), + "h_forecast": (5,), + "gen_p_for_handler": PerfectForecastHandler( + "prod_p_forecasted", quiet_warnings=True), + "gen_v_for_handler": PerfectForecastHandler( + "prod_v_forecasted", quiet_warnings=True), + "load_p_for_handler": PerfectForecastHandler( + "load_p_forecasted", quiet_warnings=True), + "load_q_for_handler": PerfectForecastHandler( + "load_q_forecasted", quiet_warnings=True), + }, ) + self.env.set_max_iter(20) + params = self.env.parameters + params.NO_OVERFLOW_DISCONNECTION = True + params.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION = True + self.seed = 0 + self.scen_id = 0 + self.nb_scenario = 2 + self.max_iter = 10 + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + + def test_score_helper(self): + """basic tests for ScoreL2RPN2023 class""" + self.env.reset() + my_score = ScoreL2RPN2023( + self.env, + nb_scenario=self.nb_scenario, + env_seeds=[0 for _ in range(self.nb_scenario)], + agent_seeds=[0 for _ in range(self.nb_scenario)], + max_step=self.max_iter, + weight_op_score=0.6, + weight_assistant_score=0.25, + weight_nres_score=0.15, + scale_nres_score=100, + scale_assistant_score=100, + min_nres_score=-100., + min_assistant_cost_score=-300) + try: + # test do nothing indeed gets 100. + res_dn = my_score.get(DoNothingAgent(self.env.action_space)) + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): + assert nres_score == 100. + assert ep_score == 0.6 * op_score + 0.15 * nres_score + 0.25 * assistant_score + assert assistant_score == 100. # no blackout with no disconnections + assert op_score == 0 + + + finally: + my_score.clear_all() + + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 835766654..b4476b4fe 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -97,6 +97,7 @@ def __init__( weight_assistant_score=0.25, weight_nres_score=0.15, min_nres_score=-100, + min_assistant_cost_score=-300 ): ScoreL2RPN2020.__init__( self, @@ -171,6 +172,7 @@ def _compute_episode_score( real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_confidence_score_nm) key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" assistant_confidence_score = float(other_rewards[-1][key_score_file]) + assistant_confidence_score = max(assistant_confidence_score, self.min_nres_score / self.scale_nres_score) assistant_score = self.scale_assistant_score * assistant_confidence_score ep_score = ( From 369914b9f75854a08f1c87bc1bfa2f699cffb620 Mon Sep 17 00:00:00 2001 From: Talha Rehman <109908732+TalhaRehmanMTRKT@users.noreply.github.com> Date: Sun, 23 Jul 2023 03:13:49 +0500 Subject: [PATCH 080/103] Added the storage units plotting --- grid2op/PlotGrid/PlotPlotly.py | 119 +++++++++++++++++++++++++++++++-- 1 file changed, 115 insertions(+), 4 deletions(-) diff --git a/grid2op/PlotGrid/PlotPlotly.py b/grid2op/PlotGrid/PlotPlotly.py index 02c97e58e..db6c0bec3 100644 --- a/grid2op/PlotGrid/PlotPlotly.py +++ b/grid2op/PlotGrid/PlotPlotly.py @@ -58,10 +58,12 @@ def __init__( gen_radius=12, show_gen_txt=False, show_load_txt=False, + show_storage_txt=False, ): super().__init__(observation_space, width, height, scale, grid_layout) self.show_gen_txt = show_gen_txt self.show_load_txt = show_load_txt + self.show_storage_txt = show_storage_txt self._responsive = responsive self._sub_radius = sub_radius self._sub_fill_color = "PaleTurquoise" @@ -81,6 +83,12 @@ def __init__( self._gen_line_width = 1 self._gen_prefix = "b" + self._storage_radius = 12 + self._storage_fill_color = "Purple" + self._storage_line_color = "black" + self._storage_line_width = 1 + self._storage_prefix = "d" + self._line_prefix = "a" self.line_color_scheme = ( pc.sequential.Blues_r[:4] @@ -643,12 +651,73 @@ def update_powerline( def draw_legend(self, figure, observation): figure.update_layout(showlegend=False) + + def _draw_storage_txt(self, name, pos_x, pos_y, text, text_pos): + return go.Scatter( + x=[pos_x], + y=[pos_y], + text=[text], + name=name, + mode="text", + hoverinfo="skip", + textposition=text_pos, + showlegend=False, + ) + + def _draw_storage_circle(self, pos_x, pos_y, name, text): + marker_dict = dict( + size=self._storage_radius, + color=self._storage_fill_color, + showscale=False, + line=dict(width=self._storage_line_width, color=self._storage_line_color), + ) + return go.Scatter( + x=[pos_x], + y=[pos_y], + mode="markers", + text=[text], + name=self._storage_prefix + name, + marker=marker_dict, + showlegend=False, + ) + + def _draw_storage_line(self, pos_x, pos_y, sub_x, sub_y): + style_line = dict(color="black", width=self._storage_line_width) + + line_trace = go.Scatter( + x=[pos_x, sub_x], + y=[pos_y, sub_y], + hoverinfo="skip", + line=style_line, + showlegend=False, + ) + return line_trace + + def _draw_storage_bus(self, pos_x, pos_y, dir_x, dir_y, bus, storage_name): + bus = bus if bus > 0 else 0 + marker_dict = dict( + size=self._line_bus_radius, + color=self._line_bus_colors[bus], + showscale=False, + ) + center_x = pos_x + dir_x * (self._sub_radius - self._line_bus_radius) + center_y = pos_y + dir_y * (self._sub_radius - self._line_bus_radius) + trace_name = self._storage_prefix + self._bus_prefix + storage_name + return go.Scatter( + x=[center_x], + y=[center_y], + marker=marker_dict, + name=trace_name, + hoverinfo="skip", + showlegend=False, + ) + def draw_storage( self, figure, observation, - storage_name, storage_id, + storage_name, storage_bus, storage_value, storage_unit, @@ -658,6 +727,48 @@ def draw_storage( sub_y, ): # TODO storage doc - # TODO storage plot - # TODO update the plotly with storage units - pass + dir_x, dir_y = pltu.norm_from_points(sub_x, sub_y, pos_x, pos_y) + nd_x, nd_y = pltu.norm_from_points(sub_x, sub_y, pos_x, pos_y) + storage_text = "" + if storage_value is not None: + txt_x = pos_x + nd_x * (self._storage_radius / 2) + txt_y = pos_y + nd_y * (self._storage_radius / 2) + text_pos = self._textpos_from_dir(dir_x, dir_y) + storage_text = storage_name + "
    " + storage_text += pltu.format_value_unit(storage_value, storage_unit) + if self.show_storage_txt: + trace1 = self._draw_storage_txt(storage_name, txt_x, txt_y, storage_text, text_pos) + figure.add_trace(trace1) + trace2 = self._draw_storage_line(pos_x, pos_y, sub_x, sub_y) + figure.add_trace(trace2) + trace3 = self._draw_storage_circle(pos_x, pos_y, storage_name, storage_text) + figure.add_trace(trace3) + trace4 = self._draw_storage_bus(sub_x, sub_y, dir_x, dir_y, storage_bus, storage_name) + figure.add_trace(trace4) + + def update_storage( + self, + figure, + observation, + storage_name, + storage_id, + storage_bus, + storage_value, + storage_unit, + pos_x, + pos_y, + sub_x, + sub_y, + ): + + storage_text = "" + if storage_value is not None: + storage_text = storage_name + "
    " + storage_text += pltu.format_value_unit(storage_value, storage_unit) + figure.update_traces(text=storage_text, selector=dict(name=storage_name)) + circle_name = self._storage_prefix + storage_name + if self.show_storage_txt: + figure.update_traces(text=storage_text, selector=dict(name=circle_name)) + storage_marker = dict(color=self._line_bus_colors[storage_bus]) + storage_select_name = self._storage_prefix + self._bus_prefix + storage_name + figure.update_traces(marker=storage_marker, selector=dict(name=storage_select_name)) From 150e0c268f2c6e196e0feb33bb0029fcb14cda02 Mon Sep 17 00:00:00 2001 From: marota Date: Sun, 23 Jul 2023 14:17:35 +0200 Subject: [PATCH 081/103] updating an alertTrusScore test in test_RewardAlertCostScore.py to consider the real min score. Removing Opponent copy paste --- grid2op/tests/test_RewardAlertCostScore.py | 55 ++-------------------- 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index a497337cf..558c272ee 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -21,64 +21,17 @@ from grid2op.Parameters import Parameters from grid2op.Opponent import BaseOpponent, GeometricOpponent from grid2op.Action import BaseAction, PlayableAction - - -ALL_ATTACKABLE_LINES= [ - "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", - ] +from _aux_opponent_for_test_alerts import (_get_steps_attack, + TestOpponent + ) ATTACKED_LINE = "48_50_136" -def _get_steps_attack(kwargs_opponent, multi=False): - """computes the steps for which there will be attacks""" - ts_attack = np.array(kwargs_opponent["steps_attack"]) - res = [] - for i, ts in enumerate(ts_attack): - if not multi: - res.append(ts + np.arange(kwargs_opponent["duration"])) - else: - res.append(ts + np.arange(kwargs_opponent["duration"][i])) - return np.unique(np.concatenate(res).flatten()) - class AlertAgent(BaseAgent): def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: if observation.current_step == 2: return self.action_space({"raise_alert": [0]}) return super().act(observation, reward, done) - -class TestOpponent(BaseOpponent): - """An opponent that can select the line attack, the time and duration of the attack.""" - - def __init__(self, action_space): - super().__init__(action_space) - self.custom_attack = None - self.duration = None - self.steps_attack = None - - def init(self, partial_env, lines_attacked=[ATTACKED_LINE], duration=10, steps_attack=[0,1]): - attacked_line = lines_attacked[0] - self.custom_attack = self.action_space({"set_line_status" : [(l, -1) for l in lines_attacked]}) - self.duration = duration - self.steps_attack = steps_attack - self.env = partial_env - - def attack(self, observation, agent_action, env_action, budget, previous_fails): - if observation is None: - return None, None - current_step = self.env.nb_time_step - if current_step not in self.steps_attack: - return None, None - - return self.custom_attack, self.duration class TestAlertCostScore(unittest.TestCase): @@ -303,7 +256,7 @@ def test_assistant_reward_value_blackout_attack_no_alert(self) -> None : if step == 4: # When the blackout occurs, reward is -1 because we didn't raise an attack so min - assert reward == -1, f"error for step {step}: {reward} vs -1" + assert reward == env._reward_helper.template_reward.min_score, f"error for step {step}: {reward} vs -1" assert done break else : From 5cb1d728fdf7dbc9bf74f5390a51421558431fc2 Mon Sep 17 00:00:00 2001 From: marota Date: Sun, 23 Jul 2023 15:48:04 +0200 Subject: [PATCH 082/103] improved test_alert_trust_score test genericity, specificity and description --- grid2op/tests/test_alert_trust_score.py | 264 ++++++++++++------------ 1 file changed, 129 insertions(+), 135 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index c4fa94d39..cf7863f08 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -19,7 +19,6 @@ from grid2op.Parameters import Parameters from grid2op.Exceptions import Grid2OpException from grid2op.Runner import Runner # TODO -from grid2op.Opponent import BaseOpponent, GeometricOpponent, GeometricOpponentMultiArea from grid2op.Action import BaseAction, PlayableAction from grid2op.Agent import BaseAgent from grid2op.Episode import EpisodeData @@ -28,20 +27,6 @@ TestOpponent, TestOpponentMultiLines) - -ALL_ATTACKABLE_LINES= [ - "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", - ] - ATTACKED_LINE = "48_50_136" DEFAULT_PARAMS_TRUSTSCORE = dict(reward_min_no_blackout=-1.0, @@ -51,9 +36,19 @@ reward_end_episode_bonus=0.0, min_score=-3.0) -# Test alert blackout / tets alert no blackout +#a near copy of _normalisation_fun function when for to a given trustscore parametrization it is not easy to guess the score before hand +# especially when reward_end_episode_bonus is non null for some non blackout cases +def manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score): + + manual_standardized_score= np.round((cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) + manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( + max_score - DEFAULT_PARAMS_TRUSTSCORE[ + "min_score"]) * manual_standardized_score + return manual_score + +# Test alertTrustScore when no blackout and when blackout class TestAlertTrustScoreNoBlackout(unittest.TestCase): - """test the basic bahavior of the assistant alert feature when no attack occur """ + """test the basic behavior of the assistant alert feature when no blackout occur """ def setUp(self) -> None: self.env_nm = os.path.join( @@ -62,7 +57,7 @@ def setUp(self) -> None: def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : """ When no blackout and no attack occur, and no alert is raised we expect a maximum score - until the end of the episode where we have a bonus + at the end of the episode and cumulated reward equal to the end of episode bonus Raises: Grid2OpException: raise an exception if an attack occur @@ -102,7 +97,7 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : """ When an alert is raised while no attack / nor blackout occur, we expect a maximum score - until the end of the episode where we have a 42s + at the end of the episode and cumulated reward equal to the end of episode bonus Raises: Grid2OpException: raise an exception if an attack occur @@ -149,8 +144,9 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : # If attack def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : """ When we don't raise an alert for an attack (at step 1) - but no blackout occur, we expect a final score of 43 - otherwise 0 at other time steps + and no blackout occur, we expect a maximum score + at the end of the episode, a cumulated reward equal to reward_max_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], @@ -197,8 +193,10 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : assert score == 0 def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : - """When an attack occur at step 2, we raise an alert at step 1 - We expect a score of 41 + """When we raise an alert for an attack (at step 1) + and no blackout occur, we expect a minimum score + at the end of the episode if end of episode bonus is null (or above otherwise), a cumulated reward equal to reward_min_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], duration=3, @@ -249,20 +247,18 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : """ When we raise an alert too late for an attack (at step 2) but no blackout occur, - we expect a score of 43 + we expect a maximum score at the end of the episode, + a cumulated reward equal to reward_max_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps + """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], @@ -315,7 +311,10 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : """ When we raise an alert too early for an attack (at step 2) - but no blackout occur, we expect a score of 43 + we expect a maximum score at the end of the episode, + a cumulated reward equal to reward_max_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps + """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], @@ -371,8 +370,11 @@ def test_assistant_trust_score_no_blackout_attack_alert_too_early(self)-> None : # 2 ligne attaquées def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> None : - """ When we don't raise an alert for 2 attacks at the same time (step 1) - but no blackout occur, we expect a score of 44 + """ When we don't raise an alert for 2 attacks at the same time (step 1) (considered as a single attack event) + but no blackout occur, we expect a maximum score + at the end of the episode, a cumulated reward equal to reward_max_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps + """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], @@ -410,7 +412,6 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> assert nb_last_attacks == 0 assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event - cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] +\ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]*total_nb_attacks cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( @@ -419,22 +420,16 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]*total_nb_attacks - if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == env._reward_helper.template_reward.max_score - else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + assert score == env._reward_helper.template_reward.max_score else : assert score == 0 def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> None : - """ When we raise only 1 alert for 2 attacks at the same time (step 2) - but no blackout occur, we expect a score of 42 + """ When we raise only 1 alert for 2 attacks at the same time (step 2) (considered as a single attack event) + but no blackout occur, we expect a mean score + at the end of the episode if no end of episode bonus, + a cumulated reward equal to (reward_max_no_blackout + reward_min_no_blackout)/2 end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=3, @@ -484,22 +479,22 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + max_score=env._reward_helper.template_reward.max_score + mean_score=(max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + assert score == mean_score else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + assert score > mean_score #assuming reward_end_episode_bonus is always positive of course + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) else : assert score == 0 def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> None : - """ When we raise 2 alerts for 2 attacks at the same time (step 2) - but no blackout occur, we expect a score of 41 + """ When we raise 2 alerts for 2 attacks at the same time (step 2) (considered as a single attack event) + but no blackout occur, we expect a minimum score + at the end of the episode if no end of episode bonus, + a cumulated reward equal to reward_min_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=3, @@ -542,7 +537,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ - (DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"]*total_nb_attacks)/total_nb_attacks + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks @@ -552,20 +547,17 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> None : - """ When we don't raise an alert for 2 attacks at two times resp. (steps 1 and 2) - but no blackout occur, we expect a score of 44 + """ When we raise 2 alerts for 2 attacks at the same time (step 2) + but no blackout occur, we expect a maximum score at the end of the episode, + a cumulated reward equal to 2*reward_max_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], @@ -616,8 +608,10 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> assert score == 0 def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> None : - """ When we raise 2 alert for 2 attacks at two times (step 2 and 3) - but no blackout occur, we expect a reward of 40 + """ When we raise 2 alerts for 2 attacks at the same time (step 2) + but no blackout occur, we expect a minimum score at the end of the episode if no bonus, + a cumulated reward equal to 2*reward_min_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], @@ -673,19 +667,16 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack(self) -> None : - """ When we raise 1 alert on the first attack while we have 2 attacks at two times (steps 2 and 3) - but no blackout occur, we expect a score of 42 + """ When we raise 2 alerts for 2 attacks at the same time (step 2) + but no blackout occur, we expect a mean score at the end of the episode if no bonus, + a cumulated reward equal to reward_max_no_blackout + reward_min_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], @@ -737,23 +728,22 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + max_score=env._reward_helper.template_reward.max_score + mean_score=(max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + assert score == mean_score else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + assert score > mean_score #assuming reward_end_episode_bonus is always positive of course + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) else : assert score == 0 def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attack(self) -> None : """ When we raise 1 alert on the second attack while we have 2 attacks at two times (steps 2 and 3) - but no blackout occur, we expect a score of 42 + but no blackout occur, we expect a mean score at the end of the episode if no bonus, + a cumulated reward equal to reward_max_no_blackout + reward_min_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=[1,1], @@ -804,15 +794,14 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + max_score=env._reward_helper.template_reward.max_score + mean_score=(max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == (env._reward_helper.template_reward.max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + assert score == mean_score else: - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - assert score == manual_score + assert score > mean_score + assert score == manual_score(cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -896,8 +885,9 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : # return 2 def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : """When 1 line is attacked at step 3 and we raise a good alert - and a blackout occur at step 4 - we expect a score of 2 + and a blackout occur at step 4, we expect a maximum score, + a cumulated reward equal to reward_max_blackout + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], duration=3, @@ -960,7 +950,9 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout(self) -> None : """ When 1 line is attacked at step 3 and we raise 1 alert too late - we expect a score of -10 + and a blackout occur at step 4, we expect a minimum score, + a cumulated reward equal to reward_min_blackout + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], duration=3, @@ -1022,7 +1014,9 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> None : """ When 1 line is attacked at step 3 and we raise 1 alert too early - we expect a score of -10 + and a blackout occur at step 4, we expect a minimum score, + a cumulated reward equal to reward_min_blackout + score is otherwise 0 at other time steps """ # return -10 kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], @@ -1086,7 +1080,9 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts(self) -> None : """ When 2 lines are attacked simustaneously at step 2 and we raise 2 alert - we expect a score of 2 after the blackout + and a blackout occur at step 4, we expect a maximum score, + a cumulated reward equal to reward_max_blackout + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=3, @@ -1152,8 +1148,10 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts # return -4 def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_alert(self) -> None: """ - When 2 lines are attacked simustaneously at step 2 and we raise only 1 alert - we expect a score of -4 + When 2 lines are attacked simustaneously (considered as a single attack event) at step 2 and we raise only 1 alert + and a blackout occur at step 4, we expect a mean score, + a cumulated reward equal to (reward_max_blackout + reward_min_blackout)/2 + score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=3, @@ -1213,11 +1211,11 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + (env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE["min_score"]) * manual_standardized_score - - assert score == manual_score + max_score=env._reward_helper.template_reward.max_score + mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+max_score)/2 + #assert score > DEFAULT_PARAMS_TRUSTSCORE['min_score'] + assert score == mean_score + #assert score == manual_score(cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) break else : assert score == 0 @@ -1226,7 +1224,9 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_alerts(self) -> None : """ When 2 lines are attacked at different steps 3 and 4 and we raise 2 alert - we expect a score of 2 + and a blackout occur at step 4, we expect a maximum score, + a cumulated reward equal to (2*reward_max_blackout)/2 + score is otherwise 0 at other time step """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=[1,1], @@ -1286,13 +1286,8 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout'] # +DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - - assert score == manual_score + max_score=env._reward_helper.template_reward.max_score + assert score == max_score break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1300,7 +1295,9 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_window_only_1_alert_on_first_attacked_line(self) -> None: """ When 2 lines are attacked at different steps 3 and 4 and we raise 1 alert on the first attack - we expect a score of -4 on blackout at step 4 + and a blackout occur at step 4, we expect a mean score, + a cumulated reward equal to (reward_max_blackout + reward_min_blackout)/2 + score is otherwise 0 at other time step """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=[1,1], @@ -1353,12 +1350,10 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - assert score == manual_score + mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+env._reward_helper.template_reward.max_score)/2 + #assert score > DEFAULT_PARAMS_TRUSTSCORE['min_score'] + assert score == mean_score + #assert score == manual_score(cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) break else : @@ -1368,7 +1363,9 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_window_only_1_alert_on_second_attacked_line(self) -> None: """ When 2 lines are attacked at different steps 2 and 3 and we raise 1 alert on the second attack - we expect a score of -4 + and a blackout occur at step 4, we expect a mean score, + a cumulated reward equal to (reward_max_blackout + reward_min_blackout)/2 + score is otherwise 0 at other time step """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=[1,1], @@ -1421,13 +1418,8 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] - - manual_standardized_score = np.round( - (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep + 1e-5), 4) - manual_score = DEFAULT_PARAMS_TRUSTSCORE["min_score"] + ( - env._reward_helper.template_reward.max_score - DEFAULT_PARAMS_TRUSTSCORE[ - "min_score"]) * manual_standardized_score - assert score == manual_score + mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+env._reward_helper.template_reward.max_score)/2 + assert score == mean_score break else : assert score == 0, f"error for step {step}: {score} vs 0" @@ -1435,8 +1427,10 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo # return 2 def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1_good_alert(self) -> None: """ - When 2 lines are attacked at different steps 3 and 6 and we raise 1 alert on the second attack - we expect score of 3 + When 2 lines are attacked at different steps 3 and 6 and we raise 1 alert at step 5 on the second attack + and a blackout occur at step 6, we expect a maximum score, + a cumulated reward equal to reward_max_blackout + reward_max_no_blackout + score is otherwise 0 at other time step """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], duration=[1, 1], @@ -1499,7 +1493,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : """Even if there is a blackout, an we raise an alert - we expect a score of 0 because there is no attack""" + we expect a score of 0 because there is no attack and we don't finish the scenario""" with make( self.env_nm, test=True, @@ -1545,7 +1539,7 @@ def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : # return 0 def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : """Even if there is a blackout, an we don't raise an alert - we expect a score of 0 because there is no attack""" + we expect a score of 0 because there is no attack and we don't finish the scenario""" with make( self.env_nm, test=True, @@ -1589,7 +1583,7 @@ def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : # return 0 def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> None : """Even if there is a blackout, an we raise an alert too early - we expect a score of 0 because there is no attack""" + we expect a score of 0 because there is no attack and we don't finish the scenario""" with make( self.env_nm, test=True, @@ -1635,7 +1629,7 @@ def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> N # return 0 def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) -> None : """Even if there is a blackout, an we raise an alert too late - we expect a score of 0 because there is no attack""" + we expect a score of 0 because there is no attack and we don't finish the scenario""" with make( self.env_nm, test=True, From 8356c07be0791c028a32a3fa720347549c2f8b6d Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 09:13:27 +0200 Subject: [PATCH 083/103] adding prerequisite warning on used grid2op environment for running test_alert_trust_score --- grid2op/tests/test_alert_trust_score.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index cf7863f08..08d524477 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -51,6 +51,9 @@ class TestAlertTrustScoreNoBlackout(unittest.TestCase): """test the basic behavior of the assistant alert feature when no blackout occur """ def setUp(self) -> None: + """ WARNING: Parameter ALERT_TIME_WINDOW should be set to 2 in these test for the environment used + Max Iter should be set to 10 + """ self.env_nm = os.path.join( PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) @@ -811,9 +814,12 @@ class TestAlertTrustScoreBlackout(unittest.TestCase): """test the basic bahavior of the assistant alert feature when a blackout occur""" def setUp(self) -> None: + """ WARNING: Parameter ALERT_TIME_WINDOW should be set to 2 in these test for the environment used + Max Iter should be set to 10""" self.env_nm = os.path.join( PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) + def get_dn(self, env): return env.action_space({}) From ecf26bcca9b79256ec4b551807e134c4d2776a50 Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 10:28:24 +0200 Subject: [PATCH 084/103] making tests in grid2op/tests/test_score_idf_2023_assistant.py file --- .../tests/test_score_idf_2023_assistant.py | 129 +++++++++++++++--- grid2op/utils/l2rpn_idf_2023_scores.py | 5 +- 2 files changed, 110 insertions(+), 24 deletions(-) diff --git a/grid2op/tests/test_score_idf_2023_assistant.py b/grid2op/tests/test_score_idf_2023_assistant.py index 54f20c404..8a27026b9 100644 --- a/grid2op/tests/test_score_idf_2023_assistant.py +++ b/grid2op/tests/test_score_idf_2023_assistant.py @@ -12,38 +12,76 @@ import grid2op from grid2op.utils import ScoreL2RPN2023 -from grid2op.Agent.doNothing import DoNothingAgent +from grid2op.Agent.doNothing import DoNothingAgent, BaseAgent +from grid2op.Observation import BaseObservation +from grid2op.Action import BaseAction from grid2op.Chronics import FromHandlers from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler +from _aux_opponent_for_test_alerts import TestOpponent +class Alert_Blackout_Agent(BaseAgent): + def __init__(self, action_space,do_Alerts=False,blackout_step=None): + super().__init__(action_space) + self.do_Alerts = do_Alerts + self.blackout_step = blackout_step + + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + act=self.action_space({}) + + if self.do_Alerts: + act+=self.action_space({"raise_alert": [i for i in range(len(observation.alertable_line_ids))]})#we don't know which line will get attacked, so we raise all alerts to be sure to raise an alert for the line attacked + + if((self.blackout_step is not None) and (observation.current_step == self.blackout_step)): + blackout_action = self.action_space({}) + blackout_action.gen_set_bus = [(0, -1)] + act+=blackout_action + + return act + + +def get_blackout(self, env): + blackout_action = env.action_space({}) + blackout_action.gen_set_bus = [(0, -1)] + return blackout_action class TestScoreL2RPN2023Assist(unittest.TestCase): """test the "assistant" part of the l2rpn_idf_2023""" def setUp(self) -> None: env_name = "l2rpn_idf_2023" + ATTACKED_LINE = "48_50_136" + with warnings.catch_warnings(): warnings.filterwarnings("ignore") + + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[2]) + opponent_class = TestOpponent, + #kwargs_opponent = kwargs_opponent, + self.env = grid2op.make(env_name, test=True, - data_feeding_kwargs={"gridvalueClass": FromHandlers, - "gen_p_handler": CSVHandler("prod_p"), - "load_p_handler": CSVHandler("load_p"), - "gen_v_handler": CSVHandler("prod_v"), - "load_q_handler": CSVHandler("load_q"), - "h_forecast": (5,), - "gen_p_for_handler": PerfectForecastHandler("prod_p_forecasted", quiet_warnings=True), - "gen_v_for_handler": PerfectForecastHandler("prod_v_forecasted", quiet_warnings=True), - "load_p_for_handler": PerfectForecastHandler("load_p_forecasted", quiet_warnings=True), - "load_q_for_handler": PerfectForecastHandler("load_q_forecasted", quiet_warnings=True), - },) - self.env.set_max_iter(20) + #Error currently at doing make with kwargs below + #data_feeding_kwargs={"gridvalueClass": FromHandlers, + # "gen_p_handler": CSVHandler("prod_p"), + # "load_p_handler": CSVHandler("load_p"), + # "gen_v_handler": CSVHandler("prod_v"), + # "load_q_handler": CSVHandler("load_q"), + # "h_forecast": (5,), + # "gen_p_for_handler": PerfectForecastHandler("prod_p_forecasted", quiet_warnings=True), + # "gen_v_for_handler": PerfectForecastHandler("prod_v_forecasted", quiet_warnings=True), + # "load_p_for_handler": PerfectForecastHandler("load_p_forecasted", quiet_warnings=True), + # "load_q_for_handler": PerfectForecastHandler("load_q_forecasted", quiet_warnings=True), + # }, + ) + self.env.set_max_iter(30) params = self.env.parameters params.NO_OVERFLOW_DISCONNECTION = True params.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION = True self.seed = 0 self.scen_id = 0 self.nb_scenario = 2 - self.max_iter = 10 + self.max_iter = 30 #if attacks are at timestep 13, needs at least 26 timsteps to get beyond the alert time window and see some relevant score in case of no blackout def tearDown(self) -> None: self.env.close() @@ -51,7 +89,8 @@ def tearDown(self) -> None: def test_score_helper(self): - """basic tests for ScoreL2RPN2023 class""" + """basic tests for ScoreL2RPN2023 class for assistant score with nres score set to 0" + With those seeds, we observe an attack in both episodes at timestep 13""" self.env.reset() my_score = ScoreL2RPN2023( self.env, @@ -60,22 +99,68 @@ def test_score_helper(self): agent_seeds=[0 for _ in range(self.nb_scenario)], max_step=self.max_iter, weight_op_score=0.6, - weight_assistant_score=0.25, - weight_nres_score=0.15, + weight_assistant_score=0.4, + weight_nres_score=0., scale_nres_score=100, scale_assistant_score=100, min_nres_score=-100., - min_assistant_cost_score=-100) + min_assistant_score=-300) try: + # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_dn[0]): - assert nres_score == 100. - assert ep_score == 0.6 * op_score + 0.15 * nres_score + 0.25 * assistant_score assert assistant_score == 100. #no blackout with no disconnections - assert op_score == 0 + assert ep_score == 0.6 * op_score + 0.4 * assistant_score + + #raising alerts for attack but it should not as it gets no blackout. With the score L2RPN IDF parametrization, it gives a score of -300 + res_agent = my_score.get(Alert_Blackout_Agent(self.env.action_space, do_Alerts=True))#attacks are at timestep 13 for both scenarios with those seeds + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_agent[0]): + assert(assistant_score == -300) + assert ep_score == 0.6 * op_score + 0.4 * assistant_score + + #raising no alert for attack and it gets no blackout. With the score L2RPN IDF parametrization, it gives a score of 100 + res_agent = my_score.get(Alert_Blackout_Agent(self.env.action_space, do_Alerts=False))#attacks are at timestep 13 for both scenarios with those seeds + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_agent[0]): + assert(assistant_score == 100) + assert ep_score == 0.6 * op_score + 0.4 * assistant_score + + #raising alert for attack and it gets a blackout. With the score L2RPN IDF parametrization, it gives a score of 100 + res_agent = my_score.get(Alert_Blackout_Agent(self.env.action_space, do_Alerts=True,blackout_step=15))#attacks are at timestep 13 for both scenarios with those seeds + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_agent[0]): + assert(assistant_score == 100) + assert ep_score == 0.6 * op_score + 0.4 * assistant_score + + + finally: + my_score.clear_all() + + def test_min_score(self): + """test the score does not go bellow the minimum in input + With those seeds, we observe an attack in both episodes at timestep 13""" + + try: + self.env.reset() + my_score = ScoreL2RPN2023( + self.env, + nb_scenario=self.nb_scenario, + env_seeds=[0 for _ in range(self.nb_scenario)], + agent_seeds=[0 for _ in range(self.nb_scenario)], + max_step=self.max_iter, + weight_op_score=0.8, + weight_assistant_score=0, + weight_nres_score=0.2, + scale_nres_score=100, + scale_assistant_score=100, + min_nres_score=-100., + min_assistant_score=-300) + + res_agent = my_score.get(Alert_Blackout_Agent(self.env.action_space, blackout_step=14)) + for scen_id, (ep_score, op_score, nres_score, assistant_score) in enumerate(res_agent[0]): + assert(assistant_score == -300)#gets minimum score because blackout after attack with no alerts finally: - my_score.clear_all() + my_score.clear_all() + if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index b4476b4fe..94538c970 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -97,7 +97,7 @@ def __init__( weight_assistant_score=0.25, weight_nres_score=0.15, min_nres_score=-100, - min_assistant_cost_score=-300 + min_assistant_score=-300 ): ScoreL2RPN2020.__init__( self, @@ -126,6 +126,7 @@ def __init__( self.weight_assistant_score = weight_assistant_score self.weight_nres_score = weight_nres_score self.min_nres_score = min_nres_score + self.min_assistant_score = min_assistant_score def _compute_episode_score( self, @@ -172,7 +173,7 @@ def _compute_episode_score( real_nm = EpisodeStatistics._nm_score_from_attr_name(assistant_confidence_score_nm) key_score_file = f"{EpisodeStatistics.KEY_SCORE}_{real_nm}" assistant_confidence_score = float(other_rewards[-1][key_score_file]) - assistant_confidence_score = max(assistant_confidence_score, self.min_nres_score / self.scale_nres_score) + assistant_confidence_score = max(assistant_confidence_score, self.min_assistant_score / self.scale_assistant_score) assistant_score = self.scale_assistant_score * assistant_confidence_score ep_score = ( From 269c9e43bc5eab514c5464d8a603d9b624368ee1 Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 14:39:33 +0200 Subject: [PATCH 085/103] correcting spelling of min_assistant_score argument in test_score_idf_2023.py --- grid2op/tests/test_score_idf_2023.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index e6abfa099..58ffaa3b4 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -71,7 +71,7 @@ def test_score_helper(self): scale_nres_score=100, scale_assistant_score=100, min_nres_score=-100., - min_assistant_cost_score=-300) + min_assistant_score=-300) try: # test do nothing indeed gets 100. res_dn = my_score.get(DoNothingAgent(self.env.action_space)) From 708998825e2aa0e30b4867a6d55cf712b11e80ce Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 14:57:18 +0200 Subject: [PATCH 086/103] switching to l2rpn_idf_2023 env in test_score_idf_2023 --- grid2op/tests/test_score_idf_2023.py | 33 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index 58ffaa3b4..617ce68e4 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -22,26 +22,27 @@ class TestScoreL2RPN2023(unittest.TestCase): def setUp(self) -> None: - env_name = "l2rpn_case14_sandbox" + env_name = "l2rpn_idf_2023" with warnings.catch_warnings(): warnings.filterwarnings("ignore") self.env = grid2op.make(env_name, test=True, - data_feeding_kwargs={"gridvalueClass": FromHandlers, - "gen_p_handler": CSVHandler("prod_p"), - "load_p_handler": CSVHandler("load_p"), - "gen_v_handler": CSVHandler("prod_v"), - "load_q_handler": CSVHandler("load_q"), - "h_forecast": (5,), - "gen_p_for_handler": PerfectForecastHandler( - "prod_p_forecasted", quiet_warnings=True), - "gen_v_for_handler": PerfectForecastHandler( - "prod_v_forecasted", quiet_warnings=True), - "load_p_for_handler": PerfectForecastHandler( - "load_p_forecasted", quiet_warnings=True), - "load_q_for_handler": PerfectForecastHandler( - "load_q_forecasted", quiet_warnings=True), - }, ) + #data_feeding_kwargs={"gridvalueClass": FromHandlers, + # "gen_p_handler": CSVHandler("prod_p"), + # "load_p_handler": CSVHandler("load_p"), + # "gen_v_handler": CSVHandler("prod_v"), + # "load_q_handler": CSVHandler("load_q"), + # "h_forecast": (5,), + # "gen_p_for_handler": PerfectForecastHandler( + # "prod_p_forecasted", quiet_warnings=True), + # "gen_v_for_handler": PerfectForecastHandler( + # "prod_v_forecasted", quiet_warnings=True), + # "load_p_for_handler": PerfectForecastHandler( + # "load_p_forecasted", quiet_warnings=True), + # "load_q_for_handler": PerfectForecastHandler( + # "load_q_forecasted", quiet_warnings=True), + # }, + ) self.env.set_max_iter(20) params = self.env.parameters params.NO_OVERFLOW_DISCONNECTION = True From a48c0053e6cc5c4951f8a100e0d8b8945b885912 Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 18:11:40 +0200 Subject: [PATCH 087/103] adding warning and TODOs in AlertCostScore Files. Plus removing alertTrusScore tests in test_RewardAlertCostScore --- grid2op/Reward/_alertCostScore.py | 9 +- grid2op/tests/test_RewardAlertCostScore.py | 202 +-------------------- 2 files changed, 12 insertions(+), 199 deletions(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index ac66e973a..9202ddc00 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -11,7 +11,12 @@ from grid2op.Reward._newRenewableSourcesUsageScore import _NewRenewableSourcesUsageScore from grid2op.dtypes import dt_float from grid2op.Exceptions import Grid2OpException - +import warnings + +#TODO +# Test this class comprehensively if usage is revived. +# Was originally thought for use in L2RPN 2023 Competition, but eventually not selected for use. +# Tests were disregarded at some stage of these developments. class _AlertCostScore(BaseReward): """ @@ -36,6 +41,8 @@ def __init__(self, logger=None): self._is_simul_env = False self.total_nb_alertes_possible = None self.total_nb_alerts = None + + warnings.warn("This class is not tested, use it with care") def initialize(self, env): diff --git a/grid2op/tests/test_RewardAlertCostScore.py b/grid2op/tests/test_RewardAlertCostScore.py index 558c272ee..160872fa6 100644 --- a/grid2op/tests/test_RewardAlertCostScore.py +++ b/grid2op/tests/test_RewardAlertCostScore.py @@ -33,6 +33,10 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - return self.action_space({"raise_alert": [0]}) return super().act(observation, reward, done) +#TODO +# Review these tests comprehensively when usage is revived. +# Was originally thought for use in L2RPN 2023 Competition. But eventually not selected for use. +# Tests were disregarded at some stage of these developments. class TestAlertCostScore(unittest.TestCase): @@ -169,205 +173,7 @@ def test_with_save(self): ep0, *_ = EpisodeData.list_episode(f) ep = EpisodeData.from_disk(*ep0) assert ep.rewards[8] == 1. - - -class TestAlertTrustScore(unittest.TestCase): - def setUp(self) -> None: - self.env_nm = os.path.join( - PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" - ) - - def tearDown(self) -> None: - return super().tearDown() - - def get_dn(self, env): - return env.action_space({}) - - def get_blackout(self, env): - blackout_action = env.action_space({}) - blackout_action.gen_set_bus = [(0, -1)] - return blackout_action - - def test_assistant_reward_value_no_blackout_no_attack_no_alert(self) -> None : - """ When no blackout and no attack occur, and no alert is raised we expect a reward of 0 - until the end of the episode where we get the max reward 1 as score. - - Raises: - Grid2OpException: raise an exception if an attack occur - """ - with grid2op.make( - self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore - ) as env: - env.seed(0) - env.reset() - - done = False - for i in range(env.max_episode_duration()): - obs, reward, done, info = env.step(env.action_space()) - if done: - assert np.round(reward,3) == 1., f"{reward} vs 1." - else: - assert reward == 0., f"{reward} vs 0." - def test_assistant_reward_value_blackout_attack_no_alert(self) -> None : - """ - When 1 line is attacked at step 3 and we don't raise any alert - and a blackout occur at step 4 - we expect a score of -10 at step 4 - """ - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[3]) - with grid2op.make(self.env_nm, - test=True, - difficulty="1", - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponent, - kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore, - _add_to_name="_tarvbana" - ) as env : - new_param = Parameters() - new_param.MAX_LINE_STATUS_CHANGED = 10 - env.change_parameters(new_param) - env.seed(0) - env.reset() - step = 0 - for i in range(env.max_episode_duration()): - attackable_line_id = 0 - act = self.get_dn(env) - if step == 3 : - act = self.get_blackout(env) - obs, reward, done, info = env.step(act) - step += 1 - - if step in _get_steps_attack(kwargs_opponent): - assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" - else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - - if step == 4: - # When the blackout occurs, reward is -1 because we didn't raise an attack so min - assert reward == env._reward_helper.template_reward.min_score, f"error for step {step}: {reward} vs -1" - assert done - break - else : - assert reward == 0, f"error for step {step}: {reward} vs 0" - - def test_assistant_reward_value_blackout_attack_raise_good_alert(self) -> None : - """ - When 1 line is attacked at step 3 and we do raise an alert - and a blackout occur at step 4 - we expect a score max at step 4 - """ - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[3]) - with grid2op.make(self.env_nm, - test=True, - difficulty="1", - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponent, - kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore, - _add_to_name="_tarvbarga" - ) as env : - new_param = Parameters() - new_param.MAX_LINE_STATUS_CHANGED = 10 - - env.change_parameters(new_param) - env.seed(0) - env.reset() - step = 0 - for i in range(env.max_episode_duration()): - attackable_line_id = 0 - act = self.get_dn(env) - if i == 3 : - act = self.get_blackout(env) - elif i == 2: - # I raise the alert (on the right line) just before the opponent attack - # opp attack at step = 3, so i = 2 - act = env.action_space({"raise_alert": [attackable_line_id]}) - obs, reward, done, info = env.step(act) - step += 1 - if step in _get_steps_attack(kwargs_opponent): - assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" - else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - - if step == 4: - assert np.round(reward,3) == 1, f"error for step {step}: {reward} vs 1" #we did rise alert at first attack on going blackout - assert done - break - else : - assert reward == 0, f"error for step {step}: {reward} vs 0" - - -class TestRunnerAlertTrust(unittest.TestCase): - def setUp(self) -> None: - self.env_nm = os.path.join( - PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" - ) - self.env = grid2op.make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore) - self.env.seed(0) - return super().setUp() - - def tearDown(self) -> None: - self.env.close() - return super().tearDown() - - def test_dn_agent(self): - obs = self.env.reset() - runner = Runner(**self.env.get_params_for_runner()) - res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) - assert np.round(res[0][2],3) == 1. #it got to the end - - def test_simagent(self): - #simulate blackout but act donothing - obs = self.env.reset() - - class SimAgent(BaseAgent): - def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: - go_act = self.action_space({"set_bus": {"generators_id": [(0, -1)]}}) - simO, simr, simd, simi = obs.simulate(go_act) - simO, simr, simd, simi = obs.simulate(self.action_space()) - return super().act(observation, reward, done) - - runner = Runner(**self.env.get_params_for_runner(), - agentClass=SimAgent) - res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) - assert np.round(res[0][2],3) == 1. - - def test_episodeData(self): - obs = self.env.reset() - runner = Runner(**self.env.get_params_for_runner()) - res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], add_detailed_output=True) - assert np.round(res[0][2],3) == 1. - assert np.round(res[0][5].rewards[8]) == 1. - - def test_with_save(self): - obs = self.env.reset() - runner = Runner(**self.env.get_params_for_runner()) - with tempfile.TemporaryDirectory() as f: - res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], - path_save=f) - assert np.round(res[0][2],3) == 1. - ep0, *_ = EpisodeData.list_episode(f) - ep = EpisodeData.from_disk(*ep0) - assert np.round(ep.rewards[8]) == 1. - if __name__ == "__main__": unittest.main() From 43a03adf5dd574017995f3c04e6f574a1150d4ac Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 18:13:08 +0200 Subject: [PATCH 088/103] reintegrating runner test for alertTrustScore removed from test_RewardAlertCostScore --- grid2op/tests/test_alert_trust_score.py | 59 ++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 08d524477..2602c8aa6 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -18,7 +18,7 @@ from grid2op.Reward import _AlertTrustScore from grid2op.Parameters import Parameters from grid2op.Exceptions import Grid2OpException -from grid2op.Runner import Runner # TODO +from grid2op.Runner import Runner from grid2op.Action import BaseAction, PlayableAction from grid2op.Agent import BaseAgent from grid2op.Episode import EpisodeData @@ -36,7 +36,7 @@ reward_end_episode_bonus=0.0, min_score=-3.0) -#a near copy of _normalisation_fun function when for to a given trustscore parametrization it is not easy to guess the score before hand +#a near copy of _normalisation_fun function when, for to a given trustscore parametrization, it is not easy to guess the score before hand, for a given scenario # especially when reward_end_episode_bonus is non null for some non blackout cases def manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score): @@ -1682,5 +1682,60 @@ def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) - assert done +class TestRunnerAlertTrust(unittest.TestCase): + def setUp(self) -> None: + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + self.env = make(self.env_nm, test=True, difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE)) + self.env.seed(0) + return super().setUp() + + def tearDown(self) -> None: + self.env.close() + return super().tearDown() + + def test_dn_agent(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) + assert np.round(res[0][2], 3) == 1. # it got to the end + + def test_simagent(self): + # simulate blackout but act donothing + obs = self.env.reset() + + class SimAgent(BaseAgent): + def act(self, observation: BaseObservation, reward: float, done: bool = False) -> BaseAction: + go_act = self.action_space({"set_bus": {"generators_id": [(0, -1)]}}) + simO, simr, simd, simi = obs.simulate(go_act) + simO, simr, simd, simi = obs.simulate(self.action_space()) + return super().act(observation, reward, done) + + runner = Runner(**self.env.get_params_for_runner(), + agentClass=SimAgent) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0]) + assert np.round(res[0][2], 3) == 1. + + def test_episodeData(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], add_detailed_output=True) + assert np.round(res[0][2], 3) == 1. + assert np.round(res[0][5].rewards[8]) == 1. + + def test_with_save(self): + obs = self.env.reset() + runner = Runner(**self.env.get_params_for_runner()) + with tempfile.TemporaryDirectory() as f: + res = runner.run(nb_episode=1, episode_id=[0], max_iter=10, env_seeds=[0], + path_save=f) + assert np.round(res[0][2], 3) == 1. + ep0, *_ = EpisodeData.list_episode(f) + ep = EpisodeData.from_disk(*ep0) + assert np.round(ep.rewards[8]) == 1. + + if __name__ == "__main__": unittest.main() From d096f7140e807d8482246ee603e9d7e8d8183d42 Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 18:17:20 +0200 Subject: [PATCH 089/103] reintegrating runner test for alertTrustScore removed from test_RewardAlertCostScore --- grid2op/tests/test_alert_trust_score.py | 32 +++++++++++-------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 2602c8aa6..942ade50b 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -36,7 +36,8 @@ reward_end_episode_bonus=0.0, min_score=-3.0) -#a near copy of _normalisation_fun function when, for to a given trustscore parametrization, it is not easy to guess the score before hand, for a given scenario +#a near copy of _normalisation_fun function from alertTrusScore. Use when, for to a given trustscore parametrization, +# it is not easy to guess the score before hand, for a given scenario. # especially when reward_end_episode_bonus is non null for some non blackout cases def manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score): @@ -470,7 +471,7 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 - assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event + assert total_nb_attacks == 1 #1 because two simultaneaous attacks is considered as a signgle attack event cm_reward=env._reward_helper.template_reward.cumulated_reward assert env._reward_helper.template_reward.cumulated_reward==(DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + \ @@ -1144,8 +1145,8 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] break else : @@ -1214,14 +1215,12 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] max_score=env._reward_helper.template_reward.max_score mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+max_score)/2 - #assert score > DEFAULT_PARAMS_TRUSTSCORE['min_score'] assert score == mean_score - #assert score == manual_score(cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) break else : assert score == 0 @@ -1288,9 +1287,9 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a total_nb_attacks,nb_last_attacks) # attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_min_blackout'] # +DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + 'reward_min_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_max_blackout'] # +DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + 'reward_max_blackout'] max_score=env._reward_helper.template_reward.max_score assert score == max_score @@ -1353,19 +1352,16 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+env._reward_helper.template_reward.max_score)/2 - #assert score > DEFAULT_PARAMS_TRUSTSCORE['min_score'] assert score == mean_score - #assert score == manual_score(cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) break else : assert score == 0, f"error for step {step}: {score} vs 0" -# return -4 def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_window_only_1_alert_on_second_attacked_line(self) -> None: """ When 2 lines are attacked at different steps 2 and 3 and we raise 1 alert on the second attack @@ -1421,8 +1417,8 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+env._reward_helper.template_reward.max_score)/2 assert score == mean_score @@ -1490,7 +1486,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']+DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout']#+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] break else : assert score == 0, f"error for step {step}: {score} vs 0" From 3cf76d42e916bd6ac1aeaf550d23b4104771ffc2 Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 19:00:14 +0200 Subject: [PATCH 090/103] removing tolerance and rounding, as 0 denominator case is already taken into account so no need --- grid2op/Reward/_alertTrustScore.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index c8fc98119..655ababb4 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -50,7 +50,6 @@ def __init__(self, def initialize(self, env): self._is_simul_env = self.is_simulated_env(env) - #SURVIVOR_TIMESTEPS=env._al self.cumulated_reward = 0 #KPIs @@ -133,15 +132,16 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return score_ep @staticmethod - def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score,is_blackout,tol=1e-5): - standardized_score = np.round((cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep +tol),4) - #in case cm_reward_min_ep=cm_reward_max_ep=0, score is maximum + def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score,is_blackout): + + #in case cm_reward_min_ep=cm_reward_max_ep=0, score can be maximum or 0 if(cm_reward_min_ep==cm_reward_max_ep): if (is_blackout): score_ep = 0.0 else: score_ep = max_score else: + standardized_score = (cm_reward - cm_reward_min_ep) / (cm_reward_max_ep - cm_reward_min_ep)#denominator cannot be 0 given first if condition score_ep = min_score + (max_score - min_score) * standardized_score return score_ep From d17932afc3f20da2d9511a1eb4540e7df862f8fb Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 21:19:57 +0200 Subject: [PATCH 091/103] adding danger comment in _alertCostScore --- grid2op/Reward/_alertCostScore.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grid2op/Reward/_alertCostScore.py b/grid2op/Reward/_alertCostScore.py index 9202ddc00..5967bd229 100644 --- a/grid2op/Reward/_alertCostScore.py +++ b/grid2op/Reward/_alertCostScore.py @@ -21,7 +21,8 @@ class _AlertCostScore(BaseReward): """ INTERNAL - + .. danger:: This function is not used and not tested + .. warning:: /!\\\\ Internal, do not use unless you know what you are doing /!\\\\ It **must not** serve as a reward. This scored needs to be **MAXIMIZED**, as it is a negative! Also, this "reward" is not scaled or anything. Use it as your From fea7b365e948e292f6e7fdf5c245acaaec15a14e Mon Sep 17 00:00:00 2001 From: marota Date: Mon, 24 Jul 2023 21:37:55 +0200 Subject: [PATCH 092/103] making syntax more pythonic, simplifying min_max_reward, adding self.blackout_encountered in init --- grid2op/Reward/_alertTrustScore.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 655ababb4..49ef97be7 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -47,6 +47,7 @@ def __init__(self, self.min_score = dt_float(min_score) self.max_score = dt_float(1.0) + self.blackout_encountered = False def initialize(self, env): self._is_simul_env = self.is_simulated_env(env) @@ -135,8 +136,8 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,max_score,is_blackout): #in case cm_reward_min_ep=cm_reward_max_ep=0, score can be maximum or 0 - if(cm_reward_min_ep==cm_reward_max_ep): - if (is_blackout): + if cm_reward_min_ep == cm_reward_max_ep: + if is_blackout: score_ep = 0.0 else: score_ep = max_score @@ -147,14 +148,11 @@ def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,m def _compute_min_max_reward(self, nb_attacks,nb_last_attacks): - if (nb_attacks==0 and self.blackout_encountered): - cm_reward_min_ep = 0. - cm_reward_max_ep= 0. - elif(self.blackout_encountered): - if(nb_last_attacks==0): + if self.blackout_encountered: + if nb_last_attacks == 0: cm_reward_min_ep = self.reward_min_no_blackout * nb_attacks cm_reward_max_ep = self.reward_max_no_blackout * nb_attacks - elif(nb_last_attacks>=1): + elif nb_last_attacks >= 1: cm_reward_min_ep = self.reward_min_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_min_blackout cm_reward_max_ep = self.reward_max_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_max_blackout else: From bb7b2c404abf0dc153aeb8e15d360006513fc5b3 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 09:21:48 +0200 Subject: [PATCH 093/103] adding explanations for max min cumulated reward computation --- grid2op/Reward/_alertTrustScore.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 49ef97be7..9776c337c 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -149,10 +149,10 @@ def _normalisation_fun(cm_reward, cm_reward_min_ep, cm_reward_max_ep,min_score,m def _compute_min_max_reward(self, nb_attacks,nb_last_attacks): if self.blackout_encountered: - if nb_last_attacks == 0: + if nb_last_attacks == 0: #in the case the blackout is not tied to a recent attack cm_reward_min_ep = self.reward_min_no_blackout * nb_attacks cm_reward_max_ep = self.reward_max_no_blackout * nb_attacks - elif nb_last_attacks >= 1: + elif nb_last_attacks >= 1:#in the case one or several recent attacks can be tied to the blackout cm_reward_min_ep = self.reward_min_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_min_blackout cm_reward_max_ep = self.reward_max_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_max_blackout else: From 944b66a4083729f2361ce5c67face59473cbf477 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 13:40:27 +0200 Subject: [PATCH 094/103] making required changes in _alertTrustScore.py --- grid2op/Reward/_alertTrustScore.py | 41 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/grid2op/Reward/_alertTrustScore.py b/grid2op/Reward/_alertTrustScore.py index 9776c337c..525e5d5f9 100644 --- a/grid2op/Reward/_alertTrustScore.py +++ b/grid2op/Reward/_alertTrustScore.py @@ -68,6 +68,7 @@ def initialize(self, env): def reset(self, env): super().reset(env) + self.blackout_encountered = False self.cumulated_reward = 0 #KPIs self.total_nb_attacks = 0 @@ -88,10 +89,6 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): return score_ep self.blackout_encountered = self.is_in_blackout(has_error, is_done) - - score_ep = 0. - if self._is_simul_env: - return score_ep res = super().__call__(action, env, has_error, is_done, is_illegal, is_ambiguous) self.cumulated_reward += res @@ -103,33 +100,37 @@ def __call__(self, action, env, has_error, is_done, is_illegal, is_ambiguous): #lines_alerted_beforeattack = np.equal(env._time_since_last_alert, env._time_since_last_attack + 1) and lines_attacked #self.total_nb_alerts += np.sum(lines_alerted_beforeattack) - if not is_done: + if is_done: + indexes_to_look = (np.arange(-self.time_window, 1) + self._current_id) % self._nrows_array # include current step (hence the np.arange(..., **1**)) + ts_attack_in_order = self._ts_attack[indexes_to_look, :] + self.nb_last_attacks = ts_attack_in_order.any(axis=1).sum() - # TODO - #lines_attacked_no_blackout = env._time_since_last_attack == SURVIVOR_TIMESTEPS -# - #self.alert_attack_no_blackout += np.sum(lines_alerted_beforeattack[lines_attacked_no_blackout]) - #self.no_alert_attack_no_blackout += np.sum(~lines_alerted_beforeattack[lines_attacked_no_blackout]) - - return score_ep - - else: - self.nb_last_attacks=np.sum(np.any(self._ts_attack,axis=1)) - cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks,self.nb_last_attacks) - score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep,self.min_score,self.max_score,self.blackout_encountered) + cm_reward_min_ep, cm_reward_max_ep = self._compute_min_max_reward(self.total_nb_attacks, + self.nb_last_attacks) + score_ep = self._normalisation_fun(self.cumulated_reward, cm_reward_min_ep, cm_reward_max_ep, + self.min_score, self.max_score, self.blackout_encountered) # TODO - #if self.blackout_encountered: + # if self.blackout_encountered: # lines_attacked_dangerzone = (env._time_since_last_attack >= 0) * (env._time_since_last_attack < SURVIVOR_TIMESTEPS) # # self.alert_attack_blackout += 1. * any(lines_alerted_beforeattack[lines_attacked_dangerzone]) # self.no_alert_attack_blackout += 1. * any(~lines_alerted_beforeattack[lines_attacked_dangerzone]) - #else : + # else : # lines_attacked_no_blackout = env._time_since_last_attack > 0 # # self.alert_attack_no_blackout += np.sum(lines_alerted_beforeattack[lines_attacked_no_blackout]) # self.no_alert_attack_no_blackout += np.sum(~lines_alerted_beforeattack[lines_attacked_no_blackout]) + + return score_ep + else: + # TODO + # lines_attacked_no_blackout = env._time_since_last_attack == SURVIVOR_TIMESTEPS + # + # self.alert_attack_no_blackout += np.sum(lines_alerted_beforeattack[lines_attacked_no_blackout]) + # self.no_alert_attack_no_blackout += np.sum(~lines_alerted_beforeattack[lines_attacked_no_blackout]) + return score_ep @staticmethod @@ -152,7 +153,7 @@ def _compute_min_max_reward(self, nb_attacks,nb_last_attacks): if nb_last_attacks == 0: #in the case the blackout is not tied to a recent attack cm_reward_min_ep = self.reward_min_no_blackout * nb_attacks cm_reward_max_ep = self.reward_max_no_blackout * nb_attacks - elif nb_last_attacks >= 1:#in the case one or several recent attacks can be tied to the blackout + elif nb_last_attacks >= 1:#in the case the blackout can be tied to one or several recent attacks cm_reward_min_ep = self.reward_min_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_min_blackout cm_reward_max_ep = self.reward_max_no_blackout * (nb_attacks - nb_last_attacks) + self.reward_max_blackout else: From 1adcdcf16282b50a066ad0ab0527a68124fa7af2 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 14:01:11 +0200 Subject: [PATCH 095/103] making required changes for test_score_idf_2023_assistant.py --- .../tests/_aux_opponent_for_test_alerts.py | 5 +++ .../tests/test_score_idf_2023_assistant.py | 36 ++++--------------- 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/grid2op/tests/_aux_opponent_for_test_alerts.py b/grid2op/tests/_aux_opponent_for_test_alerts.py index fd63bba56..13d8b50db 100644 --- a/grid2op/tests/_aux_opponent_for_test_alerts.py +++ b/grid2op/tests/_aux_opponent_for_test_alerts.py @@ -22,6 +22,11 @@ def _get_steps_attack(kwargs_opponent, multi=False): res.append(ts + np.arange(kwargs_opponent["duration"][i])) return np.unique(np.concatenate(res).flatten()) +def _get_blackout(action_space): + blackout_action = action_space({}) + blackout_action.gen_set_bus = [(0, -1)] + return blackout_action + class OpponentForTestAlert(BaseOpponent): """An opponent that can select the line attack, the time and duration of the attack.""" diff --git a/grid2op/tests/test_score_idf_2023_assistant.py b/grid2op/tests/test_score_idf_2023_assistant.py index 8a27026b9..4de9fee57 100644 --- a/grid2op/tests/test_score_idf_2023_assistant.py +++ b/grid2op/tests/test_score_idf_2023_assistant.py @@ -17,7 +17,7 @@ from grid2op.Action import BaseAction from grid2op.Chronics import FromHandlers from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler -from _aux_opponent_for_test_alerts import TestOpponent +from _aux_opponent_for_test_alerts import TestOpponent, _get_blackout class Alert_Blackout_Agent(BaseAgent): def __init__(self, action_space,do_Alerts=False,blackout_step=None): @@ -32,18 +32,12 @@ def act(self, observation: BaseObservation, reward: float, done: bool = False) - act+=self.action_space({"raise_alert": [i for i in range(len(observation.alertable_line_ids))]})#we don't know which line will get attacked, so we raise all alerts to be sure to raise an alert for the line attacked if((self.blackout_step is not None) and (observation.current_step == self.blackout_step)): - blackout_action = self.action_space({}) - blackout_action.gen_set_bus = [(0, -1)] - act+=blackout_action + #blackout_action = self.action_space({}) + #blackout_action.gen_set_bus = [(0, -1)] + act+=_get_blackout(self.action_space) return act - -def get_blackout(self, env): - blackout_action = env.action_space({}) - blackout_action.gen_set_bus = [(0, -1)] - return blackout_action - class TestScoreL2RPN2023Assist(unittest.TestCase): """test the "assistant" part of the l2rpn_idf_2023""" def setUp(self) -> None: @@ -53,27 +47,9 @@ def setUp(self) -> None: with warnings.catch_warnings(): warnings.filterwarnings("ignore") - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[2]) - opponent_class = TestOpponent, - #kwargs_opponent = kwargs_opponent, - self.env = grid2op.make(env_name, - test=True, - #Error currently at doing make with kwargs below - #data_feeding_kwargs={"gridvalueClass": FromHandlers, - # "gen_p_handler": CSVHandler("prod_p"), - # "load_p_handler": CSVHandler("load_p"), - # "gen_v_handler": CSVHandler("prod_v"), - # "load_q_handler": CSVHandler("load_q"), - # "h_forecast": (5,), - # "gen_p_for_handler": PerfectForecastHandler("prod_p_forecasted", quiet_warnings=True), - # "gen_v_for_handler": PerfectForecastHandler("prod_v_forecasted", quiet_warnings=True), - # "load_p_for_handler": PerfectForecastHandler("load_p_forecasted", quiet_warnings=True), - # "load_q_for_handler": PerfectForecastHandler("load_q_forecasted", quiet_warnings=True), - # }, - ) + test=True) + self.env.set_max_iter(30) params = self.env.parameters params.NO_OVERFLOW_DISCONNECTION = True From 626e9e2e6c226380dfb6a28eba028df50bcd0b0e Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 15:09:51 +0200 Subject: [PATCH 096/103] cleaning up test_score_idf_2023.py --- grid2op/tests/test_score_idf_2023.py | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/grid2op/tests/test_score_idf_2023.py b/grid2op/tests/test_score_idf_2023.py index 617ce68e4..8fbcbbb00 100644 --- a/grid2op/tests/test_score_idf_2023.py +++ b/grid2op/tests/test_score_idf_2023.py @@ -11,13 +11,8 @@ import unittest import grid2op -from grid2op.Action import ActionSpace, BaseAction from grid2op.utils import ScoreL2RPN2023 -from grid2op.Observation import BaseObservation -from grid2op.Agent.doNothing import DoNothingAgent, BaseAgent -from grid2op.Chronics import FromHandlers -from grid2op.Chronics.handlers import CSVHandler, PerfectForecastHandler -from grid2op.Reward import _NewRenewableSourcesUsageScore +from grid2op.Agent.doNothing import DoNothingAgent class TestScoreL2RPN2023(unittest.TestCase): @@ -26,23 +21,8 @@ def setUp(self) -> None: with warnings.catch_warnings(): warnings.filterwarnings("ignore") self.env = grid2op.make(env_name, - test=True, - #data_feeding_kwargs={"gridvalueClass": FromHandlers, - # "gen_p_handler": CSVHandler("prod_p"), - # "load_p_handler": CSVHandler("load_p"), - # "gen_v_handler": CSVHandler("prod_v"), - # "load_q_handler": CSVHandler("load_q"), - # "h_forecast": (5,), - # "gen_p_for_handler": PerfectForecastHandler( - # "prod_p_forecasted", quiet_warnings=True), - # "gen_v_for_handler": PerfectForecastHandler( - # "prod_v_forecasted", quiet_warnings=True), - # "load_p_for_handler": PerfectForecastHandler( - # "load_p_forecasted", quiet_warnings=True), - # "load_q_for_handler": PerfectForecastHandler( - # "load_q_forecasted", quiet_warnings=True), - # }, - ) + test=True) + self.env.set_max_iter(20) params = self.env.parameters params.NO_OVERFLOW_DISCONNECTION = True From ccd7121619a90c82725630476daa4450188da2c0 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 15:16:51 +0200 Subject: [PATCH 097/103] making required changes in l2rpn_idf_2023_scores.py --- grid2op/utils/l2rpn_idf_2023_scores.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index 94538c970..b456738c9 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -6,8 +6,9 @@ # SPDX-License-Identifier: MPL-2.0 # This file is part of Grid2Op, Grid2Op a testbed platform to model sequential decision making in power systems. +import numpy as np from grid2op.utils.l2rpn_2020_scores import ScoreL2RPN2020 -from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AlertTrustScore # , _AlertCostScore +from grid2op.Reward import L2RPNSandBoxScore, _NewRenewableSourcesUsageScore, _AlertTrustScore from grid2op.utils.underlying_statistics import EpisodeStatistics from grid2op.Exceptions import Grid2OpException @@ -113,12 +114,16 @@ def __init__( score_names=score_names, add_nb_highres_sim=add_nb_highres_sim, ) - - test_weights = weight_op_score + weight_assistant_score + weight_nres_score + weights=np.array([weight_op_score,weight_assistant_score,weight_nres_score]) + test_weights = weights.sum() if test_weights != 1.0: raise Grid2OpException( 'The weights of each component of the score shall sum to 1' ) + if np.any(test_weights <0): + raise Grid2OpException( + 'All weights should be positive' + ) self.scale_assistant_score = scale_assistant_score self.scale_nres_score = scale_nres_score From 0b01da2046b4e7a51d620a716684e2f29702e222 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 16:03:47 +0200 Subject: [PATCH 098/103] making 3 test classes (no blackout, blackout not after attack, blackout attack) and 3 first tests of these classes to test max, min and middle scores --- grid2op/tests/test_alert_trust_score.py | 1143 +++++++++++++---------- 1 file changed, 649 insertions(+), 494 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 942ade50b..112895b0f 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -59,6 +59,7 @@ def setUp(self) -> None: PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) + #this is the test case no blakcout where it reaches max score def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : """ When no blackout and no attack occur, and no alert is raised we expect a maximum score at the end of the episode and cumulated reward equal to the end of episode bonus @@ -98,8 +99,139 @@ def test_assistant_trust_score_no_blackout_no_attack_no_alert(self) -> None : raise Grid2OpException('No attack expected') assert done - - def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : + + # this is the test case no blakcout where it reaches min score + def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : + """When we raise an alert for an attack (at step 1) + and no blackout occur, we expect a minimum score + at the end of the episode if end of episode bonus is null (or above otherwise), a cumulated reward equal to reward_min_no_blackout + end of episode bonus. + score is otherwise 0 at other time steps + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), + _add_to_name="_tatsnba" + ) as env : + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = env.action_space() + if i == 1 : + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 1 + + cm_reward=env._reward_helper.template_reward.cumulated_reward + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + + if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + else: + assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) + + else : + assert score == 0 + + # this is the test case no blakcout where it reaches mean score ( a score in the middle) + def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> None: + """ When we raise only 1 alert for 2 attacks at the same time (step 2) (considered as a single attack event) + but no blackout occur, we expect a mean score + at the end of the episode if no end of episode bonus, + a cumulated reward equal to (reward_max_no_blackout + reward_min_no_blackout)/2 end of episode bonus. + score is otherwise 0 at other time steps + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE] + ['48_53_141'], + duration=3, + steps_attack=[2]) + with make(self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsnb2ast1a" + ) as env: + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = env.action_space() + if step == 1: + act = env.action_space({"raise_alert": [attackable_line_id]}) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 1 # 1 because two simultaneaous attacks is considered as a signgle attack event + + cm_reward = env._reward_helper.template_reward.cumulated_reward + assert env._reward_helper.template_reward.cumulated_reward == ( + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"]) / 2 + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE[ + "reward_min_no_blackout"] * total_nb_attacks + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks + + max_score = env._reward_helper.template_reward.max_score + mean_score = (max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 + if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): + assert score == mean_score + else: + assert score > mean_score # assuming reward_end_episode_bonus is always positive of course + assert score == manual_score(cm_reward, cm_reward_min_ep, cm_reward_max_ep, max_score) + else: + assert score == 0 + + def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None: """ When an alert is raised while no attack / nor blackout occur, we expect a maximum score at the end of the episode and cumulated reward equal to the end of episode bonus @@ -107,68 +239,70 @@ def test_assistant_trust_score_no_blackout_no_attack_alert(self) -> None : Grid2OpException: raise an exception if an attack occur """ with make( - self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) ) as env: env.seed(0) env.reset() done = False - attackable_line_id=0 + attackable_line_id = 0 step = 0 for i in range(env.max_episode_duration()): act = env.action_space() - if step == 1 : + if step == 1: act = env.action_space({"raise_alert": [attackable_line_id]}) obs, score, done, info = env.step(act) step += 1 - if info["opponent_attack_line"] is None : + if info["opponent_attack_line"] is None: if step == env.max_episode_duration(): total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert total_nb_attacks == 0 assert nb_last_attacks == 0 - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + "reward_end_episode_bonus"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) + total_nb_attacks, nb_last_attacks) assert cm_reward_min_ep == 0. assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] assert score == env._reward_helper.template_reward.max_score - else : + else: assert score == 0 - else : + else: raise Grid2OpException('No attack expected') - + assert done -# If attack - def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : + + # If attack + def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None: """ When we don't raise an alert for an attack (at step 1) and no blackout occur, we expect a maximum score at the end of the episode, a cumulated reward equal to reward_max_no_blackout + end of episode bonus. score is otherwise 0 at other time steps """ - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, steps_attack=[1]) with make(self.env_nm, test=True, - difficulty="1", - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponent, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), _add_to_name="_tatsnbana" - ) as env : + ) as env: env.seed(0) env.reset() step = 0 @@ -176,85 +310,26 @@ def test_assistant_trust_score_no_blackout_attack_no_alert(self) -> None : act = env.action_space() obs, score, done, info = env.step(act) step += 1 - if step in _get_steps_attack(kwargs_opponent): + if step in _get_steps_attack(kwargs_opponent): assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - - if done: - assert np.round(score,3) == env._reward_helper.template_reward.max_score - total_nb_attacks=env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 0 - assert total_nb_attacks==1 - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] - else : - assert score == 0 + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : - """When we raise an alert for an attack (at step 1) - and no blackout occur, we expect a minimum score - at the end of the episode if end of episode bonus is null (or above otherwise), a cumulated reward equal to reward_min_no_blackout + end of episode bonus. - score is otherwise 0 at other time steps - """ - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, - steps_attack=[2]) - with make(self.env_nm, - test=True, - difficulty="1", - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponent, - kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), - _add_to_name="_tatsnba" - ) as env : - env.seed(0) - env.reset() - step = 0 - for i in range(env.max_episode_duration()): - attackable_line_id = 0 - act = env.action_space() - if i == 1 : - act = env.action_space({"raise_alert": [attackable_line_id]}) - obs, score, done, info = env.step(act) - step += 1 - if step in _get_steps_attack(kwargs_opponent): - assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" - else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - if done: - + assert np.round(score, 3) == env._reward_helper.template_reward.max_score total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 assert total_nb_attacks == 1 - - cm_reward=env._reward_helper.template_reward.cumulated_reward - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+ DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + "reward_end_episode_bonus"] + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) + total_nb_attacks, nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] - - if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] - else: - assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) - - else : + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] + else: assert score == 0 def test_assistant_trust_score_no_blackout_attack_alert_too_late(self) -> None : @@ -427,17 +502,17 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_no_alert(self) -> assert score == env._reward_helper.template_reward.max_score else : assert score == 0 - - def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> None : - """ When we raise only 1 alert for 2 attacks at the same time (step 2) (considered as a single attack event) - but no blackout occur, we expect a mean score + + def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> None : + """ When we raise 2 alerts for 2 attacks at the same time (step 2) (considered as a single attack event) + but no blackout occur, we expect a minimum score at the end of the episode if no end of episode bonus, - a cumulated reward equal to (reward_max_no_blackout + reward_min_no_blackout)/2 end of episode bonus. + a cumulated reward equal to reward_min_no_blackout + end of episode bonus. score is otherwise 0 at other time steps """ kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[2]) + duration=3, + steps_attack=[2]) with make(self.env_nm, test=True, difficulty="1", @@ -449,16 +524,16 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N opponent_action_class=PlayableAction, opponent_class=TestOpponent, kwargs_opponent=kwargs_opponent, - _add_to_name="_tatsnb2ast1a" + _add_to_name="_tatsnb2ast2a" ) as env : env.seed(0) env.reset() step = 0 for i in range(env.max_episode_duration()): - attackable_line_id = 0 + attackable_line_ids = [0, 1] act = env.action_space() if step == 1 : - act = env.action_space({"raise_alert": [attackable_line_id]}) + act = env.action_space({"raise_alert": attackable_line_ids}) obs, score, done, info = env.step(act) step += 1 if step in _get_steps_attack(kwargs_opponent): @@ -467,128 +542,63 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" if done: + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 0 - assert total_nb_attacks == 1 #1 because two simultaneaous attacks is considered as a signgle attack event + assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event cm_reward=env._reward_helper.template_reward.cumulated_reward - assert env._reward_helper.template_reward.cumulated_reward==(DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] + \ - DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"])/2 + DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] - + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ + DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( total_nb_attacks,nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks - max_score=env._reward_helper.template_reward.max_score - mean_score=(max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == mean_score + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] else: - assert score > mean_score #assuming reward_end_episode_bonus is always positive of course - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) + assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 - def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> None : - """ When we raise 2 alerts for 2 attacks at the same time (step 2) (considered as a single attack event) - but no blackout occur, we expect a minimum score - at the end of the episode if no end of episode bonus, - a cumulated reward equal to reward_min_no_blackout + end of episode bonus. + + def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> None : + """ When we raise 2 alerts for 2 attacks at the same time (step 2) + but no blackout occur, we expect a maximum score at the end of the episode, + a cumulated reward equal to 2*reward_max_no_blackout + end of episode bonus. score is otherwise 0 at other time steps """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[2]) + duration=[1, 1], + steps_attack=[1, 2]) with make(self.env_nm, test=True, difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), opponent_attack_cooldown=0, opponent_attack_duration=99999, opponent_budget_per_ts=1000, opponent_init_budget=10000., opponent_action_class=PlayableAction, - opponent_class=TestOpponent, + opponent_class=TestOpponentMultiLines, kwargs_opponent=kwargs_opponent, - _add_to_name="_tatsnb2ast2a" + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), + _add_to_name="_tatsnb2dtna" ) as env : env.seed(0) env.reset() step = 0 for i in range(env.max_episode_duration()): - attackable_line_ids = [0, 1] act = env.action_space() - if step == 1 : - act = env.action_space({"raise_alert": attackable_line_ids}) obs, score, done, info = env.step(act) step += 1 - if step in _get_steps_attack(kwargs_opponent): - assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" - else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - - if done: - - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 0 - assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event - - cm_reward=env._reward_helper.template_reward.cumulated_reward - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ - DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] * total_nb_attacks - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ - DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks - - if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] - else: - assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) - else : - assert score == 0 - - - def test_assistant_trust_score_no_blackout_2_attack_diff_time_no_alert(self) -> None : - """ When we raise 2 alerts for 2 attacks at the same time (step 2) - but no blackout occur, we expect a maximum score at the end of the episode, - a cumulated reward equal to 2*reward_max_no_blackout + end of episode bonus. - score is otherwise 0 at other time steps - """ - - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=[1, 1], - steps_attack=[1, 2]) - with make(self.env_nm, - test=True, - difficulty="1", - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponentMultiLines, - kwargs_opponent=kwargs_opponent, - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), - _add_to_name="_tatsnb2dtna" - ) as env : - env.seed(0) - env.reset() - step = 0 - for i in range(env.max_episode_duration()): - act = env.action_space() - obs, score, done, info = env.step(act) - step += 1 - - if step in _get_steps_attack(kwargs_opponent, multi=True) : + + if step in _get_steps_attack(kwargs_opponent, multi=True) : assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" else: assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" @@ -809,10 +819,7 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac else : assert score == 0, f"error for step {step}: {score} vs 0" - - -class TestAlertTrustScoreBlackout(unittest.TestCase): - """test the basic bahavior of the assistant alert feature when a blackout occur""" +class TestAlertTrustScoreBlackout_NoAttackCause(unittest.TestCase): def setUp(self) -> None: """ WARNING: Parameter ALERT_TIME_WINDOW should be set to 2 in these test for the environment used @@ -821,7 +828,6 @@ def setUp(self) -> None: PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" ) - def get_dn(self, env): return env.action_space({}) @@ -830,30 +836,92 @@ def get_blackout(self, env): blackout_action.gen_set_bus = [(0, -1)] return blackout_action -# Cas avec blackout 1 ligne attaquée -# return -10 - def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : + # this is the test case a blackout occur but not because of an attack and you get a maximum score + def test_assistant_trust_score_blackout_attack_nocause_blackout_no_alert(self) -> None: + """When 1 line is attacked at step 3 and you don't raise an alert + and a blackout occur at step 7 (not considered as because of the attack because outside of the alert time window) + we expect a minimum score, + a cumulated reward equal to reward_max_no_blackout + score is otherwise 0 at other time steps """ - When 1 line is attacked at step 3 and we don't raise any alert - and a blackout occur at step 4 - we expect a score of -10 + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), + _add_to_name="_tatsbarga" + ) as env: + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 7: + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == env._reward_helper.template_reward.max_score + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 1 + + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_no_blackout'] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] + break + else: + assert score == 0 + + # this is the test case a blackout occur but not because of an attack and you get a minimum score + def test_assistant_trust_score_blackout_attack_nocause_blackout_raise_alert(self) -> None: + """When 1 line is attacked at step 3 and we raise an alert + and a blackout occur at step 7 (not considered as because of the attack because outside of the alert time window) + we expect a minimum score, + a cumulated reward equal to reward_min_no_blackout + score is otherwise 0 at other time steps """ - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], - duration=3, + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, steps_attack=[3]) with make(self.env_nm, test=True, - difficulty="1", - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponent, - kwargs_opponent=kwargs_opponent, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), - _add_to_name="_tatsbana" - ) as env : + _add_to_name="_tatsbarga" + ) as env: new_param = Parameters() new_param.MAX_LINE_STATUS_CHANGED = 10 @@ -864,32 +932,246 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None : for i in range(env.max_episode_duration()): attackable_line_id = 0 act = self.get_dn(env) - if step == 3 : + if i == 7: act = self.get_blackout(env) + elif i == 2: + # I raise the alert (on the right line) just before the opponent attack + # opp attack at step = 3, so i = 2 + act = env.action_space({"raise_alert": [attackable_line_id]}) obs, score, done, info = env.step(act) step += 1 - - if step in _get_steps_attack(kwargs_opponent): + if step in _get_steps_attack(kwargs_opponent): assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + if done: assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 + assert nb_last_attacks == 0 assert total_nb_attacks == 1 - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout']# -10 + + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_no_blackout'] + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] + total_nb_attacks, nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_no_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_no_blackout'] break - else : + else: assert score == 0 -# return 2 + + + + # this is the test case a blackout occur but not because of an attack and you get a score of 0 (in the middle) + def test_assistant_trust_score_blackout_no_attack_alert(self) -> None: + + """Even if there is a blackout, an we raise an alert + we expect a score of 0 because there is no attack and we don't finish the scenario""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3: + act = self.get_blackout(env) + elif i == 1: + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + if info["opponent_attack_line"] is None: + if done: # info["opponent_attack_line"] is None : + assert score == 0. + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 + else: + raise Grid2OpException('No attack expected') + + if done: + break + + assert done + + # return 0 + def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None: + """Even if there is a blackout, an we don't raise an alert + we expect a score of 0 because there is no attack and we don't finish the scenario""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3: + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + if info["opponent_attack_line"] is None: + if done: + assert score == 0. + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 + else: + raise Grid2OpException('No attack expected') + + if done: + break + + assert done + + # return 0 + def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> None: + """Even if there is a blackout, an we raise an alert too early + we expect a score of 0 because there is no attack and we don't finish the scenario""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3: + act = self.get_blackout(env) + elif i in [0, 1, 2]: + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + if info["opponent_attack_line"] is None: + assert score == 0. + if done: + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 + else: + raise Grid2OpException('No attack expected') + + if done: + break + + assert done + + # return 0 + def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) -> None: + """Even if there is a blackout, an we raise an alert too late + we expect a score of 0 because there is no attack and we don't finish the scenario""" + with make( + self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) + ) as env: + env.seed(0) + env.reset() + + done = False + for i in range(env.max_episode_duration()): + act = self.get_dn(env) + if i == 3: + act = self.get_blackout(env) + elif i == 4: + # we never go here ... + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + + if info["opponent_attack_line"] is None: + assert score == 0. + if done: + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 0 + assert total_nb_attacks == 0 + + assert env._reward_helper.template_reward.total_nb_attacks == 0. + assert env._reward_helper.template_reward.cumulated_reward == 0. + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + + assert cm_reward_min_ep == 0.0 + assert cm_reward_max_ep == 0.0 + else: + raise Grid2OpException('No attack expected') + + if done: + break + + assert done + + +class TestAlertTrustScoreBlackout_CauseAttack(unittest.TestCase): + """test the basic bahavior of the assistant alert feature when a blackout occur""" + + def setUp(self) -> None: + """ WARNING: Parameter ALERT_TIME_WINDOW should be set to 2 in these test for the environment used + Max Iter should be set to 10""" + self.env_nm = os.path.join( + PATH_DATA_TEST, "l2rpn_idf_2023_with_alert" + ) + + + def get_dn(self, env): + return env.action_space({}) + + def get_blackout(self, env): + blackout_action = env.action_space({}) + blackout_action.gen_set_bus = [(0, -1)] + return blackout_action + + # this is the test case blakcout with attack where it reaches maximum score def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : """When 1 line is attacked at step 3 and we raise a good alert and a blackout occur at step 4, we expect a maximum score, @@ -953,7 +1235,7 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : else : assert score == 0 -# return -10 + # this is the test case blakcout with attack where it reaches minimum score def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout(self) -> None : """ When 1 line is attacked at step 3 and we raise 1 alert too late @@ -998,26 +1280,159 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( if step in _get_steps_attack(kwargs_opponent): assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - - if done: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 + + assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks,nb_last_attacks) + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] + break + else : + assert score == 0 + + # this is the test case blakcout with attack where it reaches a mean score (in the middle) + def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_alert(self) -> None: + """ + When 2 lines are attacked simultaneously (considered as a single attack event) at step 2 and we raise only 1 alert + and a blackout occur at step 4, we expect a mean score, + a cumulated reward equal to (reward_max_blackout + reward_min_blackout)/2 + score is otherwise 0 at other time steps + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE] + ['48_53_141'], + duration=3, + steps_attack=[3, 3]) + with make(self.env_nm, + test=True, + difficulty="1", + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + _add_to_name="_tatsb2laso1a" + ) as env: + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if i == 3: + act = self.get_blackout(env) + elif i == 2: + # attack at step 3, so i = 2, which is the + # right time to send an alert + act = env.action_space({"raise_alert": [0]}) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: + total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks + nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks + + assert nb_last_attacks == 1 + assert total_nb_attacks == 1 # 1 because to simultaneaous attacks is considered as a signgle attack event + + cm_reward = env._reward_helper.template_reward.cumulated_reward + assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_max_blackout'] + DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout']) / 2 # 2 here because there are two attacks at the same time, so we take the mean of the individual alert scores + + cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( + total_nb_attacks, nb_last_attacks) + # attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... + assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] + assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] + + max_score = env._reward_helper.template_reward.max_score + mean_score = (DEFAULT_PARAMS_TRUSTSCORE['min_score'] + max_score) / 2 + assert score == mean_score + break + else: + assert score == 0 + + def test_assistant_trust_score_blackout_attack_no_alert(self) -> None: + """ + When 1 line is attacked at step 3 and we don't raise any alert + and a blackout occur at step 4, we expect a minimum score, + a cumulated reward equal to reward_min_blackout + score is otherwise 0 at other time steps + """ + kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE], + duration=3, + steps_attack=[3]) + with make(self.env_nm, + test=True, + difficulty="1", + opponent_attack_cooldown=0, + opponent_attack_duration=99999, + opponent_budget_per_ts=1000, + opponent_init_budget=10000., + opponent_action_class=PlayableAction, + opponent_class=TestOpponent, + kwargs_opponent=kwargs_opponent, + reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), + _add_to_name="_tatsbana" + ) as env: + new_param = Parameters() + new_param.MAX_LINE_STATUS_CHANGED = 10 + + env.change_parameters(new_param) + env.seed(0) + env.reset() + step = 0 + for i in range(env.max_episode_duration()): + attackable_line_id = 0 + act = self.get_dn(env) + if step == 3: + act = self.get_blackout(env) + obs, score, done, info = env.step(act) + step += 1 + + if step in _get_steps_attack(kwargs_opponent): + assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" + else: + assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" + + if done: assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks assert nb_last_attacks == 1 assert total_nb_attacks == 1 - - assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] - + assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ + 'reward_min_blackout'] # -10 cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) + total_nb_attacks, nb_last_attacks) assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] break - else : + else: assert score == 0 - + def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> None : """ When 1 line is attacked at step 3 and we raise 1 alert too early @@ -1152,80 +1567,6 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts else : assert score == 0 -# return -4 - def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_alert(self) -> None: - """ - When 2 lines are attacked simustaneously (considered as a single attack event) at step 2 and we raise only 1 alert - and a blackout occur at step 4, we expect a mean score, - a cumulated reward equal to (reward_max_blackout + reward_min_blackout)/2 - score is otherwise 0 at other time steps - """ - kwargs_opponent = dict(lines_attacked=[ATTACKED_LINE]+['48_53_141'], - duration=3, - steps_attack=[3, 3]) - with make(self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE), - opponent_attack_cooldown=0, - opponent_attack_duration=99999, - opponent_budget_per_ts=1000, - opponent_init_budget=10000., - opponent_action_class=PlayableAction, - opponent_class=TestOpponent, - kwargs_opponent=kwargs_opponent, - _add_to_name="_tatsb2laso1a" - ) as env : - new_param = Parameters() - new_param.MAX_LINE_STATUS_CHANGED = 10 - - env.change_parameters(new_param) - env.seed(0) - env.reset() - step = 0 - for i in range(env.max_episode_duration()): - attackable_line_id = 0 - act = self.get_dn(env) - if i == 3 : - act = self.get_blackout(env) - elif i == 2: - # attack at step 3, so i = 2, which is the - # right time to send an alert - act = env.action_space({"raise_alert": [0]}) - obs, score, done, info = env.step(act) - step += 1 - - if step in _get_steps_attack(kwargs_opponent): - assert info["opponent_attack_line"] is not None, f"no attack is detected at step {step}" - else: - assert info["opponent_attack_line"] is None, f"an attack is detected at step {step}" - - if done: - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 1 - assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event - - cm_reward=env._reward_helper.template_reward.cumulated_reward - assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ - 'reward_min_blackout'])/2 #2 here because there are two attacks at the same time, so we take the mean of the individual alert scores - - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - #attention, attaque dans une même fenêtre avant blackout ne compte que pour une seule attaque pondérée... - assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] - assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] - - max_score=env._reward_helper.template_reward.max_score - mean_score=(DEFAULT_PARAMS_TRUSTSCORE['min_score']+max_score)/2 - assert score == mean_score - break - else : - assert score == 0 - -# return 2 def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_alerts(self) -> None : """ When 2 lines are attacked at different steps 3 and 4 and we raise 2 alert @@ -1426,7 +1767,6 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo else : assert score == 0, f"error for step {step}: {score} vs 0" -# return 2 def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1_good_alert(self) -> None: """ When 2 lines are attacked at different steps 3 and 6 and we raise 1 alert at step 5 on the second attack @@ -1491,191 +1831,6 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 else : assert score == 0, f"error for step {step}: {score} vs 0" -# return 0 - def test_assistant_trust_score_blackout_no_attack_alert(self) -> None : - - """Even if there is a blackout, an we raise an alert - we expect a score of 0 because there is no attack and we don't finish the scenario""" - with make( - self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) - ) as env: - env.seed(0) - env.reset() - - done = False - for i in range(env.max_episode_duration()): - act = self.get_dn(env) - if i == 3 : - act = self.get_blackout(env) - elif i == 1: - act = env.action_space({"raise_alert": [0]}) - obs, score, done, info = env.step(act) - if info["opponent_attack_line"] is None: - if done : #info["opponent_attack_line"] is None : - assert score == 0. - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 0 - assert total_nb_attacks == 0 - - assert env._reward_helper.template_reward.total_nb_attacks==0. - assert env._reward_helper.template_reward.cumulated_reward==0. - - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - - assert cm_reward_min_ep == 0.0 - assert cm_reward_max_ep == 0.0 - else : - raise Grid2OpException('No attack expected') - - if done : - break - - assert done - -# return 0 - def test_assistant_trust_score_blackout_no_attack_no_alert(self) -> None : - """Even if there is a blackout, an we don't raise an alert - we expect a score of 0 because there is no attack and we don't finish the scenario""" - with make( - self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) - ) as env: - env.seed(0) - env.reset() - - done = False - for i in range(env.max_episode_duration()): - act = self.get_dn(env) - if i == 3 : - act = self.get_blackout(env) - obs, score, done, info = env.step(act) - if info["opponent_attack_line"] is None : - if done: - assert score == 0. - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 0 - assert total_nb_attacks == 0 - - assert env._reward_helper.template_reward.total_nb_attacks == 0. - assert env._reward_helper.template_reward.cumulated_reward == 0. - - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - - assert cm_reward_min_ep == 0.0 - assert cm_reward_max_ep == 0.0 - else : - raise Grid2OpException('No attack expected') - - if done : - break - - assert done - -# return 0 - def test_assistant_trust_score_blackout_no_attack_before_window_alert(self) -> None : - """Even if there is a blackout, an we raise an alert too early - we expect a score of 0 because there is no attack and we don't finish the scenario""" - with make( - self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) - ) as env: - env.seed(0) - env.reset() - - done = False - for i in range(env.max_episode_duration()): - act = self.get_dn(env) - if i == 3 : - act = self.get_blackout(env) - elif i in [0, 1, 2]: - act = env.action_space({"raise_alert": [0]}) - obs, score, done, info = env.step(act) - if info["opponent_attack_line"] is None : - assert score == 0. - if done: - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 0 - assert total_nb_attacks == 0 - - assert env._reward_helper.template_reward.total_nb_attacks == 0. - assert env._reward_helper.template_reward.cumulated_reward == 0. - - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - - assert cm_reward_min_ep == 0.0 - assert cm_reward_max_ep == 0.0 - else : - raise Grid2OpException('No attack expected') - - if done : - break - - assert done - -# return 0 - def test_assistant_trust_score_blackout_no_attack_before_window_no_alert(self) -> None : - """Even if there is a blackout, an we raise an alert too late - we expect a score of 0 because there is no attack and we don't finish the scenario""" - with make( - self.env_nm, - test=True, - difficulty="1", - reward_class=_AlertTrustScore(**DEFAULT_PARAMS_TRUSTSCORE) - ) as env: - env.seed(0) - env.reset() - - done = False - for i in range(env.max_episode_duration()): - act = self.get_dn(env) - if i == 3 : - act = self.get_blackout(env) - elif i == 4: - # we never go here ... - act = env.action_space({"raise_alert": [0]}) - obs, score, done, info = env.step(act) - - if info["opponent_attack_line"] is None : - assert score == 0. - if done: - - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks - nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - - assert nb_last_attacks == 0 - assert total_nb_attacks == 0 - - assert env._reward_helper.template_reward.total_nb_attacks == 0. - assert env._reward_helper.template_reward.cumulated_reward == 0. - - cm_reward_min_ep, cm_reward_max_ep = env._reward_helper.template_reward._compute_min_max_reward( - total_nb_attacks,nb_last_attacks) - - assert cm_reward_min_ep == 0.0 - assert cm_reward_max_ep == 0.0 - else : - raise Grid2OpException('No attack expected') - - if done : - break - - assert done class TestRunnerAlertTrust(unittest.TestCase): From 00b9d8dc04a0ccc8ed3587d2b517fd103a9d4ad4 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 17:08:13 +0200 Subject: [PATCH 099/103] removing if for asserts in test_alert_trust_score.py --- grid2op/tests/test_alert_trust_score.py | 56 ++++++++++++------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 112895b0f..0b5a2b3ab 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -153,11 +153,10 @@ def test_assistant_trust_score_no_blackout_attack_alert(self) -> None : assert cm_reward_min_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_min_no_blackout"] assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]+DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] - if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] - else: - assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] # because reward_end_episode_bonus == 0 + # Can Be used if reward_end_episode_bonus!=0 + # assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + # assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 @@ -223,11 +222,10 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_1_alert(self) -> N max_score = env._reward_helper.template_reward.max_score mean_score = (max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 - if (DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] == 0): - assert score == mean_score - else: - assert score > mean_score # assuming reward_end_episode_bonus is always positive of course - assert score == manual_score(cm_reward, cm_reward_min_ep, cm_reward_max_ep, max_score) + assert score == mean_score # because reward_end_episode_bonus == 0 + # Can Be used if reward_end_episode_bonus!=0 + # assert score > mean_score + # assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else: assert score == 0 @@ -558,11 +556,10 @@ def test_assistant_trust_score_no_blackout_2_attack_same_time_2_alert(self) -> N assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks - if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] - else: - assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] # because reward_end_episode_bonus == 0 + # Can Be used if reward_end_episode_bonus!=0 + # assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + # assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 @@ -678,11 +675,10 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_2_alert(self) -> N assert cm_reward_max_ep == DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"] + \ DEFAULT_PARAMS_TRUSTSCORE["reward_max_no_blackout"] * total_nb_attacks - if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] - else: - assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) + assert score == DEFAULT_PARAMS_TRUSTSCORE["min_score"] # because reward_end_episode_bonus == 0 + # Can Be used if reward_end_episode_bonus!=0 + # assert score > DEFAULT_PARAMS_TRUSTSCORE["min_score"] + # assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0 @@ -744,11 +740,12 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_first_attack max_score=env._reward_helper.template_reward.max_score mean_score=(max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 - if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == mean_score - else: - assert score > mean_score #assuming reward_end_episode_bonus is always positive of course - assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) + + assert score == mean_score # because reward_end_episode_bonus == 0 + # Can Be used if reward_end_episode_bonus!=0 + # assert score > mean_score + # assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) + else : assert score == 0 @@ -811,11 +808,10 @@ def test_assistant_trust_score_no_blackout_2_attack_diff_time_alert_second_attac max_score=env._reward_helper.template_reward.max_score mean_score=(max_score + DEFAULT_PARAMS_TRUSTSCORE["min_score"]) / 2 - if(DEFAULT_PARAMS_TRUSTSCORE["reward_end_episode_bonus"]==0): - assert score == mean_score - else: - assert score > mean_score - assert score == manual_score(cm_reward,cm_reward_min_ep,cm_reward_max_ep,max_score) + assert score == mean_score # because reward_end_episode_bonus == 0 + # Can Be used if reward_end_episode_bonus!=0 + # assert score > mean_score + # assert score == manual_score (cm_reward,cm_reward_min_ep,cm_reward_max_ep,env._reward_helper.template_reward.max_score) else : assert score == 0, f"error for step {step}: {score} vs 0" From ae4942f02fdd5cccc4c1f392ffa6f8008cd0e302 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 17:17:04 +0200 Subject: [PATCH 100/103] adding requested typo change on any weights positive --- grid2op/utils/l2rpn_idf_2023_scores.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/grid2op/utils/l2rpn_idf_2023_scores.py b/grid2op/utils/l2rpn_idf_2023_scores.py index b456738c9..307cf3881 100644 --- a/grid2op/utils/l2rpn_idf_2023_scores.py +++ b/grid2op/utils/l2rpn_idf_2023_scores.py @@ -115,12 +115,12 @@ def __init__( add_nb_highres_sim=add_nb_highres_sim, ) weights=np.array([weight_op_score,weight_assistant_score,weight_nres_score]) - test_weights = weights.sum() - if test_weights != 1.0: + total_weights = weights.sum() + if total_weights != 1.0: raise Grid2OpException( 'The weights of each component of the score shall sum to 1' ) - if np.any(test_weights <0): + if np.any(weights <0): raise Grid2OpException( 'All weights should be positive' ) From 10845e3dd03b1b7a14306353b91af0081860a909 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 17:21:05 +0200 Subject: [PATCH 101/103] making requested changes 1) commenting nb_last_attacks 2)reusing _get_blackout --- grid2op/tests/test_alert_trust_score.py | 39 ++++++++++++------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 0b5a2b3ab..1e41ceab1 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -25,7 +25,8 @@ from _aux_opponent_for_test_alerts import (_get_steps_attack, TestOpponent, - TestOpponentMultiLines) + TestOpponentMultiLines, + _get_blackout) ATTACKED_LINE = "48_50_136" @@ -828,9 +829,7 @@ def get_dn(self, env): return env.action_space({}) def get_blackout(self, env): - blackout_action = env.action_space({}) - blackout_action.gen_set_bus = [(0, -1)] - return blackout_action + return _get_blackout(env) # this is the test case a blackout occur but not because of an attack and you get a maximum score def test_assistant_trust_score_blackout_attack_nocause_blackout_no_alert(self) -> None: @@ -880,7 +879,7 @@ def test_assistant_trust_score_blackout_attack_nocause_blackout_no_alert(self) - total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 0 + assert nb_last_attacks == 0 # because no attack caused the blackout assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ @@ -946,7 +945,7 @@ def test_assistant_trust_score_blackout_attack_nocause_blackout_raise_alert(self total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 0 + assert nb_last_attacks == 0 # because no attack caused the blackout assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ @@ -1163,9 +1162,7 @@ def get_dn(self, env): return env.action_space({}) def get_blackout(self, env): - blackout_action = env.action_space({}) - blackout_action.gen_set_bus = [(0, -1)] - return blackout_action + return _get_blackout(env) # this is the test case blakcout with attack where it reaches maximum score def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : @@ -1218,7 +1215,7 @@ def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 + assert nb_last_attacks == 1 # because blackout caused by attack assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_max_blackout'] @@ -1283,7 +1280,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_just_before_blackout( total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 + assert nb_last_attacks == 1 # because blackout caused by attack assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward==DEFAULT_PARAMS_TRUSTSCORE['reward_min_blackout'] @@ -1348,8 +1345,8 @@ def test_assistant_trust_score_blackout_2_lines_attacked_simulaneous_only_1_aler total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 - assert total_nb_attacks == 1 # 1 because to simultaneaous attacks is considered as a signgle attack event + assert nb_last_attacks == 1 # because blackout caused by attack + assert total_nb_attacks == 1 # 1 because two simultaneaous attacks is considered as a signgle attack event cm_reward = env._reward_helper.template_reward.cumulated_reward assert cm_reward == (DEFAULT_PARAMS_TRUSTSCORE[ @@ -1417,7 +1414,7 @@ def test_assistant_trust_score_blackout_attack_no_alert(self) -> None: total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 + assert nb_last_attacks == 1 # because blackout caused by attack assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ 'reward_min_blackout'] # -10 @@ -1480,7 +1477,7 @@ def test_assistant_trust_score_blackout_attack_raise_alert_too_early(self) -> No total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 + assert nb_last_attacks == 1 # because blackout caused by attack assert total_nb_attacks == 1 assert env._reward_helper.template_reward.cumulated_reward == DEFAULT_PARAMS_TRUSTSCORE[ @@ -1546,8 +1543,8 @@ def test_assistant_trust_score_blackout_2_lines_same_step_in_window_good_alerts total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 - assert total_nb_attacks == 1 #1 because to simultaneaous attacks is considered as a signgle attack event + assert nb_last_attacks == 1 # because blackout caused by attack + assert total_nb_attacks == 1 #1 because two simultaneaous attacks is considered as a signgle attack event assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ 'reward_max_blackout']+DEFAULT_PARAMS_TRUSTSCORE[ @@ -1613,7 +1610,7 @@ def test_assistant_trust_score_blackout_2_lines_different_step_in_window_good_a total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 2 + assert nb_last_attacks == 2 # because blackout caused by attacks assert total_nb_attacks == 2 cm_reward = env._reward_helper.template_reward.cumulated_reward @@ -1678,7 +1675,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 2 + assert nb_last_attacks == 2 # because blackout caused by attacks assert total_nb_attacks == 2 cm_reward = env._reward_helper.template_reward.cumulated_reward @@ -1743,7 +1740,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_step_in_windo total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 2 + assert nb_last_attacks == 2 # because blackout caused by attacks assert total_nb_attacks == 2 cm_reward = env._reward_helper.template_reward.cumulated_reward @@ -1811,7 +1808,7 @@ def test_assistant_trust_score_blackout_2_lines_attacked_different_1_in_window_1 total_nb_attacks = env._reward_helper.template_reward.total_nb_attacks nb_last_attacks = env._reward_helper.template_reward.nb_last_attacks - assert nb_last_attacks == 1 + assert nb_last_attacks == 1 # because blackout caused by attack assert total_nb_attacks == 2 assert env._reward_helper.template_reward.cumulated_reward == (DEFAULT_PARAMS_TRUSTSCORE[ From 825f478a2f7b2144f9b6ec88634c6d82f77ac8b2 Mon Sep 17 00:00:00 2001 From: marota Date: Tue, 25 Jul 2023 17:45:50 +0200 Subject: [PATCH 102/103] correcting get_blackout using env.action_space, not env --- grid2op/tests/test_alert_trust_score.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/grid2op/tests/test_alert_trust_score.py b/grid2op/tests/test_alert_trust_score.py index 1e41ceab1..58a18e48d 100644 --- a/grid2op/tests/test_alert_trust_score.py +++ b/grid2op/tests/test_alert_trust_score.py @@ -829,7 +829,7 @@ def get_dn(self, env): return env.action_space({}) def get_blackout(self, env): - return _get_blackout(env) + return _get_blackout(env.action_space) # this is the test case a blackout occur but not because of an attack and you get a maximum score def test_assistant_trust_score_blackout_attack_nocause_blackout_no_alert(self) -> None: @@ -1162,7 +1162,7 @@ def get_dn(self, env): return env.action_space({}) def get_blackout(self, env): - return _get_blackout(env) + return _get_blackout(env.action_space) # this is the test case blakcout with attack where it reaches maximum score def test_assistant_trust_score_blackout_attack_raise_good_alert(self) -> None : From bed96096c7d22a3651151fc5bae5262ad1cbd2cd Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Wed, 26 Jul 2023 11:19:33 +0200 Subject: [PATCH 103/103] update changelog, ready for version 1.9.2 [skip ci] --- CHANGELOG.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index bc2a3f11d..7d9cd2a4a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -31,7 +31,7 @@ Change Log - [???] "asynch" multienv - [???] properly model interconnecting powerlines -[1.9.2] - 2023-07-xx +[1.9.2] - 2023-07-26 --------------------- - [BREAKING] rename with filename starting with lowercase all the files in the "`Backend`", "`Action`" and "`Environment`" modules. This is both consistent with python practice but allows also to make the @@ -50,6 +50,7 @@ Change Log an action disconnect an element, it will not change its sepoint at the same time). - [FIXED] a bug in `AlertReward` due to `reset` not being called. - [FIXED] issue https://github.com/rte-france/Grid2Op/issues/494 +- [ADDED] the score function used for the L2RPN 2023 competition (Paris Area) - [IMPROVED] overall performances by calling `arr.sum()` or `arr.any()` instead of `np.sum(arr)` or `np.any(arr)` see https://numpy.org/neps/nep-0018-array-function-protocol.html#performance - [IMPROVED] overall performance of `obs.simulate` function by improving speed of copy of `_BackendAction`