From f456d49933beb0b025f43d7d5c8191f67fc473c6 Mon Sep 17 00:00:00 2001 From: DONNOT Benjamin Date: Tue, 8 Jun 2021 11:08:14 +0200 Subject: [PATCH] fixing issue rte-france#223 --- CHANGELOG.rst | 2 + grid2op/PlotGrid/LayoutUtil.py | 15 ++++-- grid2op/Space/GridObjects.py | 11 +++-- grid2op/Space/space_utils.py | 4 ++ .../5bus_modif_grid/grid_layout.json | 30 ++++++++++++ grid2op/tests/test_issue_223.py | 46 +++++++++++++++++++ 6 files changed, 99 insertions(+), 9 deletions(-) create mode 100644 grid2op/data_test/5bus_modif_grid/grid_layout.json create mode 100644 grid2op/tests/test_issue_223.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 1bd1a61f0..6305fac11 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -37,6 +37,8 @@ Change Log - [FIXED]: some bugs in the `GreedyAgent` and `TopologyGreedy` - [FIXED]: `Issue#220 `_ `flow_bus_matrix` did not took into account disconnected powerlines, leading to impossibility to compute this matrix in some cases. +- [FIXED]: `Issue#223 `_ : now able to plot a grid even + if there is nothing controllable in grid2op present in it. - [ADDED] support for the "alarm operator" / "attention budget" feature - [ADDED] retrieval of the `max_step` (ie the maximum number of step that can be performed for the current episode) in the observation diff --git a/grid2op/PlotGrid/LayoutUtil.py b/grid2op/PlotGrid/LayoutUtil.py index 909b762eb..1731afdf5 100644 --- a/grid2op/PlotGrid/LayoutUtil.py +++ b/grid2op/PlotGrid/LayoutUtil.py @@ -60,6 +60,10 @@ def layout_obs_sub_load_and_gen(obs, scale=1000.0, use_initial=False): gen_w = 25 stor_w = 25 + # add the nodes + for sub_id in range(obs.n_sub): + G.add_node(sub_id) + # Set lines edges for line_idx in range(obs.n_line): lor_sub = obs.line_or_to_subid[line_idx] @@ -107,9 +111,8 @@ def layout_obs_sub_load_and_gen(obs, scale=1000.0, use_initial=False): initial_layout = {} for sub_idx, sub_name in enumerate(layout_keys): sub_pos = copy.deepcopy(obs.grid_layout[sub_name]) - #sub_pos[0] *= scale - #sub_pos[1] *= scale initial_layout[sub_idx] = sub_pos + for load_idx, load_subid in enumerate(obs.load_to_subid): sub_name = layout_keys[load_subid] load_sub_pos = obs.load_to_sub_pos[load_idx] @@ -119,6 +122,7 @@ def layout_obs_sub_load_and_gen(obs, scale=1000.0, use_initial=False): load_pos[0] += math.cos(load_sub_pos) * load_w load_pos[1] += math.sin(load_sub_pos) * load_w initial_layout[load_offset + load_idx] = load_pos + for gen_idx, gen_subid in enumerate(obs.gen_to_subid): sub_name = layout_keys[gen_subid] gen_sub_pos = obs.gen_to_sub_pos[gen_idx] @@ -145,8 +149,11 @@ def layout_obs_sub_load_and_gen(obs, scale=1000.0, use_initial=False): fix = list(range(obs.n_sub)) seed = np.random.RandomState(0) # Use Fruchterman-Reingold algorithm - kkl = nx.spring_layout(G, scale=scale, fixed=fix, - pos=initial_layout, seed=seed, + kkl = nx.spring_layout(G, + scale=scale, + fixed=fix, + pos=initial_layout, + seed=seed, iterations=1000) else: # Use kamada_kawai algorithm diff --git a/grid2op/Space/GridObjects.py b/grid2op/Space/GridObjects.py index 848addc73..65d549ae9 100644 --- a/grid2op/Space/GridObjects.py +++ b/grid2op/Space/GridObjects.py @@ -26,9 +26,9 @@ from grid2op.Exceptions import * from grid2op.Space.space_utils import extract_from_dict, save_to_dict - # TODO tests of these methods and this class in general + class GridObjects: """ INTERNAL @@ -1745,10 +1745,11 @@ 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): - # raise BackendError("There are {} bus with 0 element connected to it.".format(np.sum(cls.sub_info < 1))) - warnings.warn(f"There are {np.sum(cls.sub_info < 1)} substations where no 'controlable' elements " - f"are connected. These substations will be used in the computation of the powerflow " - f"(by the backend) but you will NOT be able to control anything on them.") + 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 " + f"are connected. These substations will be used in the computation of the powerflow " + f"(by the backend) but you will NOT be able to control anything on them.") + grid2op.Space.space_utils._WARNING_ISSUED_FOR_SUB_NO_ELEM = True # redispatching / unit commitment if cls.redispatching_unit_commitment_availble: diff --git a/grid2op/Space/space_utils.py b/grid2op/Space/space_utils.py index ebaa43edc..14677a12a 100644 --- a/grid2op/Space/space_utils.py +++ b/grid2op/Space/space_utils.py @@ -9,6 +9,10 @@ import copy from grid2op.Exceptions import Grid2OpException +# i already issued the warning for the "some substations have no controllable elements" +_WARNING_ISSUED_FOR_SUB_NO_ELEM = False +# this global variable is not const ! It is modified in GridObjects.py + def extract_from_dict(dict_, key, converter): if key not in dict_: diff --git a/grid2op/data_test/5bus_modif_grid/grid_layout.json b/grid2op/data_test/5bus_modif_grid/grid_layout.json new file mode 100644 index 000000000..1107ee55a --- /dev/null +++ b/grid2op/data_test/5bus_modif_grid/grid_layout.json @@ -0,0 +1,30 @@ +{ + "sub_0": [ + 0.0, + 0.0 + ], + "sub_1": [ + 0.0, + 400.0 + ], + "sub_2": [ + 200.0, + 400.0 + ], + "sub_3": [ + 400.0, + 400.0 + ], + "sub_4": [ + 400.0, + 0.0 + ], + "sub_5": [ + 500.0, + 0.0 + ], + "sub_6": [ + 400.0, + -100.0 + ] +} diff --git a/grid2op/tests/test_issue_223.py b/grid2op/tests/test_issue_223.py new file mode 100644 index 000000000..120a78c9a --- /dev/null +++ b/grid2op/tests/test_issue_223.py @@ -0,0 +1,46 @@ +# 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 warnings + +import grid2op +from grid2op.Chronics import ChangeNothing +from grid2op.tests.helper_path_test import * +try: + from grid2op.PlotGrid import PlotMatplot + CAN_PLOT = True +except ImportError as exc_: + CAN_PLOT = False + + +class Issue223Tester(unittest.TestCase): + def _skip_if_not_installed(self): + if not CAN_PLOT: + self.skipTest("matplotlib is not installed") + + def setUp(self) -> None: + if CAN_PLOT: + with warnings.catch_warnings(): + warnings.filterwarnings("ignore") + env_nm = os.path.join(PATH_DATA_TEST, "5bus_modif_grid") + self.env = grid2op.make(env_nm, + test=True, + chronics_class=ChangeNothing) + self.env.seed(0) + self.env.reset() + + def test_env_working(self): + self._skip_if_not_installed() + with warnings.catch_warnings(): + warnings.filterwarnings("error") # there should be no warning there + # in the issue, it crashes there + plot_helper = PlotMatplot(self.env.observation_space) + assert "sub_5" in plot_helper._grid_layout + assert "sub_6" in plot_helper._grid_layout + # now test i can plot an observation + fig = plot_helper.plot_obs(self.env.reset())