Skip to content

Commit

Permalink
Merge pull request #612 from BDonnot/master
Browse files Browse the repository at this point in the history
fix example notebook (how to make a backend)
  • Loading branch information
BDonnot authored Jun 3, 2024
2 parents 181383a + d615fa2 commit 74c6948
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 61 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ Change Log
- [???] "asynch" multienv
- [???] properly model interconnecting powerlines

[1.10.3] - 2024-xx-yy
-------------------------
- TODO A number of max buses per sub
- TODO Automatic "experimental_read_from_local_dir"
- TODO Notebook for stable baselines
- TODO in the reset options: datetime start and max number of steps

[1.10.2] - 2024-05-27
-------------------------
- [BREAKING] the `runner.run_one_episode` now returns an extra first argument:
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'Benjamin Donnot'

# The full version, including alpha/beta/rc tags
release = '1.10.2'
release = '1.10.3.dev0'
version = '1.10'


Expand Down
25 changes: 24 additions & 1 deletion examples/backend_integration/Step0_make_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,28 @@
from grid2op.Opponent import BaseOpponent


class PandaPowerBackendNoShunt(PandaPowerBackend):
shunts_data_available = False


def create_action(env, backend, action):
"""this is done internally by grid2op.
The idea is to generate a "backend action" (which again is provided by grid2op)
easily
"""
# bk_act = env._backend_action_class()
# bk_act += action # action for pandapower backend
# bk_act.reorder(env.backend._load_sr2tg,
# env.backend._gen_sr2tg,
# env.backend._topo_sr2tg,
# env.backend._storage_sr2tg,
# env.backend._shunt_sr2tg)
bk_act = type(backend).my_bk_act_class()
bk_act += action
return bk_act


def make_env_for_backend(env_name, backend_class):
# env_name: one of:
# - rte_case5_example: the grid in the documentation (completely fake grid)
Expand All @@ -65,8 +87,9 @@ def make_env_for_backend(env_name, backend_class):
action_class=CompleteAction, # we tell grid2op we will manipulate all type of actions
reward_class=ConstantReward, # we don't have yet redispatching data, that might be use by the reward
opponent_class=BaseOpponent, # we deactivate the opponents
# backend=backend_class()
backend=BackendConverter(source_backend_class=backend_class,
target_backend_class=PandaPowerBackend,
target_backend_class=PandaPowerBackendNoShunt,
use_target_backend_name=True)
)
obs = env.reset()
Expand Down
9 changes: 5 additions & 4 deletions examples/backend_integration/Step1_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@


class CustomBackend_Step1(Backend):
shunts_data_available = False
def load_grid(self,
path : Union[os.PathLike, str],
filename : Optional[Union[os.PathLike, str]]=None) -> None:
Expand Down Expand Up @@ -170,8 +171,8 @@ def lines_ex_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
# storage_pos_topo_vect

# for example
print(type(backend).name_load)
print(type(backend).load_to_subid)
print(type(backend).load_to_sub_pos)
print(type(backend).load_pos_topo_vect)
print(f"Name of the loads, seen in grid2op: {type(backend).name_load}")
print(f"Id of substation, for each load: {type(backend).load_to_subid}")
print(f"Position in the substation topology vector, for each load: {type(backend).load_to_sub_pos}")
print(f"Position in the global topology vector, for each load: {type(backend).load_pos_topo_vect}")

5 changes: 2 additions & 3 deletions examples/backend_integration/Step2_modify_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def loads_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray]:
if __name__ == "__main__":
import grid2op
import os
from Step0_make_env import make_env_for_backend
from Step0_make_env import make_env_for_backend, create_action

path_grid2op = grid2op.__file__
path_data_test = os.path.join(os.path.split(path_grid2op)[0], "data")
Expand Down Expand Up @@ -105,8 +105,7 @@ def loads_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray]:
# have the proper size)

# this is technical to grid2op (done internally)
bk_act = env._backend_action_class()
bk_act += action
bk_act = create_action(env, backend, action)
#############

# this is what the backend receive:
Expand Down
5 changes: 2 additions & 3 deletions examples/backend_integration/Step3_modify_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def generators_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray]:
if __name__ == "__main__":
import grid2op
import os
from Step0_make_env import make_env_for_backend
from Step0_make_env import make_env_for_backend, create_action

path_grid2op = grid2op.__file__
path_data_test = os.path.join(os.path.split(path_grid2op)[0], "data")
Expand Down Expand Up @@ -103,8 +103,7 @@ def generators_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray]:
# have the proper size)

# this is technical to grid2op (done internally)
bk_act = env._backend_action_class()
bk_act += action
bk_act = create_action(env, backend, action)
#############

# this is what the backend receive:
Expand Down
5 changes: 2 additions & 3 deletions examples/backend_integration/Step4_modify_line_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def lines_ex_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
if __name__ == "__main__":
import grid2op
import os
from Step0_make_env import make_env_for_backend
from Step0_make_env import make_env_for_backend, create_action

path_grid2op = grid2op.__file__
path_data_test = os.path.join(os.path.split(path_grid2op)[0], "data")
Expand All @@ -205,8 +205,7 @@ def lines_ex_info(self)-> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
action = env.action_space({"set_line_status": [(0, -1)]})

# this is technical to grid2op
bk_act = env._backend_action_class()
bk_act += action
bk_act = create_action(env, backend, action)
#############

# this is what the backend receive:
Expand Down
10 changes: 5 additions & 5 deletions examples/backend_integration/Step5_modify_topology.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def _aux_change_bus_or_disconnect(self, new_bus, dt, key, el_id):
# are either 1 or 2)
def apply_action(self, backendAction: Union["grid2op.Action._backendAction._BackendAction", None]) -> None:
# the following few lines are highly recommended
if action is None:
if backendAction is None:
return

# loads and generators are modified in the previous script
Expand Down Expand Up @@ -173,12 +173,12 @@ def get_topo_vect(self) -> np.ndarray:
if __name__ == "__main__":
import grid2op
import os
from Step0_make_env import make_env_for_backend
from Step0_make_env import make_env_for_backend, create_action

path_grid2op = grid2op.__file__
path_data_test = os.path.join(os.path.split(path_grid2op)[0], "data")

env_name = "l2rpn_wcci_2022_dev"
env_name = "rte_case5_example"
# one of:
# - rte_case5_example: the grid in the documentation (completely fake grid)
# - l2rpn_case14_sandbox: inspired from IEEE 14
Expand Down Expand Up @@ -206,6 +206,7 @@ def get_topo_vect(self) -> np.ndarray:
sub_id = 1
local_topo = (1, 2, 1, 2, 1, 2)
elif env_name == "l2rpn_wcci_2022_dev":
raise RuntimeError("Storage units are not handled by the example backend, and there are some on the grid.")
sub_id = 3
local_topo = (1, 2, 1, 2, 1)
else:
Expand All @@ -214,8 +215,7 @@ def get_topo_vect(self) -> np.ndarray:
#############################

# this is technical to grid2op
bk_act = env._backend_action_class()
bk_act += action
bk_act = create_action(env, backend, action)
####################################

# this is what the backend receive:
Expand Down
54 changes: 30 additions & 24 deletions examples/backend_integration/Step6_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
interacts with it.
"""

from tqdm import tqdm
from Step5_modify_topology import CustomBackend_Minimal


Expand Down Expand Up @@ -60,42 +60,48 @@
########### First "test" perform nothing and see what it gives
done = False
nb_step = 0
while True:
obs, reward, done, info = env.step(env.action_space())
if done:
break
nb_step += 1
with tqdm() as pbar:
while True:
obs, reward, done, info = env.step(env.action_space())
if done:
break
nb_step += 1
pbar.update()
print(f"{nb_step} steps have been made with your backend with do nothing")

########## Second "test" perform random actions every now and then
env.seed(0)
obs = env.reset()
done = False
nb_step = 0
while True:
if nb_step % 10 == 9:
# do a randome action sometime
act = env.action_space.sample()
else:
# do nothing most of the time
act = env.action_space()
obs, reward, done, info = env.step(act)
if done:
break
nb_step += 1
print(f"{nb_step} steps have been made with your backend with random actions")
with tqdm() as pbar:
while True:
if nb_step % 10 == 9:
# do a randome action sometime
act = env.action_space.sample()
else:
# do nothing most of the time
act = env.action_space()
obs, reward, done, info = env.step(act)
if done:
break
nb_step += 1
pbar.update()
print(f"{nb_step} steps have been made with your backend with some random actions")

########### Third "test" using an "agent" that "does smart actions" (greedy agent)
done = False
nb_step = 0
obs = env.reset()
reward = 0.
agent = RecoPowerlineAgent(env.action_space)
while True:
act = agent.act(obs, reward)
obs, reward, done, info = env.step(act)
if done:
break
nb_step += 1
with tqdm() as pbar:
while True:
act = agent.act(obs, reward)
obs, reward, done, info = env.step(act)
if done:
break
nb_step += 1
pbar.update()
print(f"{nb_step} steps have been made with the greedy agent")

87 changes: 87 additions & 0 deletions examples/backend_integration/Step7_optional_make_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# 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 script provides a way to run the tests performed by grid2Op for the backend.
These tests are not 100% complete (some things might not be tested and are tested somewhere else)
but they cover a big part of what the backend is expected to do.
YOU NEED TO INSTALL GRID2OP FROM THE GITHUB REPO FOR THIS TO WORK !
To do that, simply:
1) clone grid2op repo
2) cd there
3) run `pip install -e .`
(do this in a venv preferably)
"""

import unittest
import warnings

# first the backend class (for the example here)
from Step5_modify_topology import CustomBackend_Minimal

# then some required things
from grid2op.tests.helper_path_test import PATH_DATA_TEST_PP, PATH_DATA_TEST
from grid2op.tests.helper_path_test import HelperTests
PATH_DATA_TEST_INIT = PATH_DATA_TEST
PATH_DATA_TEST = PATH_DATA_TEST_PP

# then all the tests that can be automatically performed
from grid2op.tests.BaseBackendTest import BaseTestNames, BaseTestLoadingCase, BaseTestLoadingBackendFunc
from grid2op.tests.BaseBackendTest import BaseTestTopoAction, BaseTestEnvPerformsCorrectCascadingFailures
from grid2op.tests.BaseBackendTest import BaseTestChangeBusAffectRightBus, BaseTestShuntAction
from grid2op.tests.BaseBackendTest import BaseTestResetEqualsLoadGrid, BaseTestVoltageOWhenDisco, BaseTestChangeBusSlack
from grid2op.tests.BaseBackendTest import BaseIssuesTest, BaseStatusActions
from grid2op.tests.test_Environment import (TestLoadingBackendPandaPower as BaseTestLoadingBackendPandaPower,
TestResetOk as BaseTestResetOk)
from grid2op.tests.test_Environment import (TestResetAfterCascadingFailure as TestResetAfterCascadingFailure,
TestCascadingFailure as BaseTestCascadingFailure)
from grid2op.tests.BaseRedispTest import BaseTestRedispatch, BaseTestRedispatchChangeNothingEnvironment
from grid2op.tests.BaseRedispTest import BaseTestRedispTooLowHigh, BaseTestDispatchRampingIllegalETC
from grid2op.tests.BaseRedispTest import BaseTestLoadingAcceptAlmostZeroSumRedisp

# then still some glue code, mainly for the names of the time series
from grid2op.Converter import BackendConverter
from grid2op.Backend import PandaPowerBackend

# our backend does not read the names from the grid, so this test is not relevant
# class TestNames(HelperTests, BaseTestNames):
# def make_backend(self, detailed_infos_for_cascading_failures=False):
# with warnings.catch_warnings():
# warnings.filterwarnings("ignore")
# bk = BackendConverter(source_backend_class=CustomBackend_Minimal,
# target_backend_class=PandaPowerBackend,
# use_target_backend_name=True,
# detailed_infos_for_cascading_failures=detailed_infos_for_cascading_failures)
# return bk

# def get_path(self):
# return PATH_DATA_TEST_INIT

class TestLoadingCase(HelperTests, BaseTestLoadingCase):
def make_backend(self, detailed_infos_for_cascading_failures=False):
with warnings.catch_warnings():
warnings.filterwarnings("ignore")
bk = BackendConverter(source_backend_class=CustomBackend_Minimal,
target_backend_class=PandaPowerBackend,
use_target_backend_name=True,
detailed_infos_for_cascading_failures=detailed_infos_for_cascading_failures)
return bk

def get_path(self):
return PATH_DATA_TEST

def get_casefile(self):
return "test_case14.json"


if __name__ == "__main__":
unittest.main()
Loading

0 comments on commit 74c6948

Please sign in to comment.