Skip to content

Commit 9476dfd

Browse files
committed
improve test for shedding, for redispatch and generator
Signed-off-by: DONNOT Benjamin <[email protected]>
1 parent b7ddc8b commit 9476dfd

File tree

6 files changed

+141
-50
lines changed

6 files changed

+141
-50
lines changed

.circleci/config.yml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ jobs:
4747
export _GRID2OP_FORCE_TEST=1
4848
cd grid2op/tests/
4949
python3 helper_list_test.py > li_test
50-
head -n 40 li_test | circleci tests split > /tmp/tests_run
50+
cat li_test | circleci tests split > /tmp/tests_run
5151
- run:
5252
command: |
5353
source venv_test/bin/activate
@@ -58,15 +58,15 @@ jobs:
5858
source venv_test/bin/activate
5959
cd grid2op/tests/
6060
export _GRID2OP_FORCE_TEST=1
61-
coverage run --parallel-mode -m unittest -v $(cat /tmp/tests_run)
62-
ls -lah | grep .coverage
63-
- run:
64-
command: |
65-
ls -lah /Grid2Op/grid2op/tests/.coverage.*
61+
coverage run -m unittest -v $(cat /tmp/tests_run)
62+
# ls -lah | grep .coverage
63+
# - run:
64+
# command: |
65+
# ls -lah /Grid2Op/grid2op/tests/.coverage.*
6666

67-
- store_artifacts:
68-
path: "/Grid2Op/grid2op/tests/test_Action*.py"
69-
destination: coverage_artifacts/
67+
# - store_artifacts:
68+
# path: "/Grid2Op/grid2op/tests/test_Action.py"
69+
# destination: coverage_artifacts/
7070

7171
gen_coverage:
7272
executor: grid2op-executor

grid2op/Backend/backend.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,6 @@ def cannot_handle_more_than_2_busbar(self):
261261
"upgrade it to a newer version.")
262262
self.n_busbar_per_sub = DEFAULT_N_BUSBAR_PER_SUB
263263

264-
265264
def can_handle_detachment(self):
266265
"""
267266
.. versionadded:: 1.11.0
@@ -280,7 +279,8 @@ def can_handle_detachment(self):
280279
:func:`Backend.cannot_handle_detachment`.
281280
282281
If not, then the environments created with your backend will not be able to
283-
"operate" grid with load and generator detachment.
282+
"operate" the grid with load and generator detached (episode will be terminated
283+
if this happens).
284284
285285
.. danger::
286286
We highly recommend you do not try to override this function.

grid2op/Backend/pandaPowerBackend.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ def _init_private_attrs(self) -> None:
730730

731731
self._compute_pos_big_topo()
732732

733-
self._topo_vect = np.full(self.dim_topo, fill_value=-1, dtype=dt_int)
733+
self._topo_vect : np.ndarray = np.full(self.dim_topo, fill_value=-1, dtype=dt_int)
734734

735735
# utilities for imeplementing apply_action
736736
self._corresp_name_fun = {}
@@ -841,7 +841,7 @@ def storage_deact_for_backward_comaptibility(self) -> None:
841841
self.storage_q = np.full(cls.n_storage, dtype=dt_float, fill_value=np.nan)
842842
self.storage_v = np.full(cls.n_storage, dtype=dt_float, fill_value=np.nan)
843843
self._topo_vect.flags.writeable = True
844-
self._topo_vect.resize(cls.dim_topo)
844+
self._topo_vect.resize(cls.dim_topo, refcheck=False)
845845
self._topo_vect.flags.writeable = False
846846
self._get_topo_vect()
847847

grid2op/Environment/baseEnv.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3196,11 +3196,9 @@ def _aux_update_backend_action(self,
31963196
# the environment must make sure it's a zero-sum action.
31973197
# same kind of limit for the storage
31983198
res_exc_ = None
3199-
# cancel the tags
3199+
# cancel the redisp tag (storage should be kept for topology)
32003200
tag_redisp = action._modif_redispatch
3201-
tag_storage = action._modif_storage
32023201
action._modif_redispatch = False
3203-
action._modif_storage = False
32043202
# cancel the values
32053203
action._redispatch[:] = 0.0 # redispatch is added in _aux_apply_redisp a bit later in the code
32063204
action._storage_power[:] = self._storage_power
@@ -3211,7 +3209,6 @@ def _aux_update_backend_action(self,
32113209
action._redispatch[:] = init_disp
32123210
# put back the tags
32133211
action._modif_redispatch = tag_redisp
3214-
action._modif_storage = tag_storage
32153212
return res_exc_
32163213

32173214
def _update_alert_properties(self, action, lines_attacked, subs_attacked):
@@ -3395,7 +3392,11 @@ def _aux_update_detachment_info(self):
33953392
self._storage_power[self._storages_detached] = 0.
33963393

33973394
def _aux_run_pf_after_state_properly_set(
3398-
self, action, init_line_status, new_p, except_
3395+
self,
3396+
action: BaseAction,
3397+
init_line_status,
3398+
new_p,
3399+
except_ : List[Exception]
33993400
):
34003401
has_error = True
34013402
detailed_info = None
@@ -3429,11 +3430,18 @@ def _aux_run_pf_after_state_properly_set(
34293430
def _aux_apply_detachment(self, new_p, new_p_th):
34303431
gen_detached_user = self._backend_action.get_gen_detached()
34313432
load_detached_user = self._backend_action.get_load_detached()
3433+
34323434
# handle gen
3433-
mw_gen_lost_this = new_p[gen_detached_user].sum() # + self._actual_dispatch[gen_detached_user].sum()
3435+
mw_gen_lost_this = new_p[gen_detached_user].sum()
3436+
34343437
# handle loads
3435-
self._detached_elements_mw = -mw_gen_lost_this - self._detached_elements_mw_prev
3436-
self._detached_elements_mw_prev = self._detached_elements_mw
3438+
3439+
# put everything together
3440+
total_power_lost = -mw_gen_lost_this
3441+
self._detached_elements_mw = (-total_power_lost +
3442+
self._actual_dispatch[gen_detached_user].sum() -
3443+
self._detached_elements_mw_prev)
3444+
self._detached_elements_mw_prev = -total_power_lost
34373445

34383446
# and now modifies the vectors
34393447
new_p[gen_detached_user] = 0.

grid2op/tests/BaseBackendTest.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2636,8 +2636,8 @@ def test_storage_action_topo(self):
26362636
not done
26372637
), f"i should be able to do a step with some storage units error is {exc_}"
26382638
storage_p, storage_q, storage_v = self.env.backend.storages_info()
2639-
assert np.all(np.abs(storage_p - 0.0) <= self.tol_one)
2640-
assert np.all(np.abs(storage_q - 0.0) <= self.tol_one)
2639+
assert np.all(np.abs(storage_p - 0.0) <= self.tol_one), f"{storage_p} vs 0."
2640+
assert np.all(np.abs(storage_q - 0.0) <= self.tol_one), f"{storage_q} vs 0."
26412641

26422642
# first case, standard modification
26432643
array_modif = np.array([-1.5, -10.0], dtype=dt_float)
@@ -2654,8 +2654,8 @@ def test_storage_action_topo(self):
26542654
obs, reward, done, info = self.env.step(act)
26552655
assert not info["exception"]
26562656
storage_p, storage_q, storage_v = self.env.backend.storages_info()
2657-
assert np.all(np.abs(storage_p - array_modif) <= self.tol_one)
2658-
assert np.all(np.abs(storage_q - 0.0) <= self.tol_one)
2657+
assert np.all(np.abs(storage_p - array_modif) <= self.tol_one), f"{storage_p} vs {array_modif}"
2658+
assert np.all(np.abs(storage_q - 0.0) <= self.tol_one), f"{storage_q} vs {0.}"
26592659
assert obs.storage_bus[0] == 2
26602660
assert obs.line_or_bus[8] == 2
26612661
assert obs.gen_bus[3] == 2

grid2op/tests/test_shedding.py

Lines changed: 108 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,21 @@
1717
from grid2op.Action.baseAction import BaseAction
1818
from grid2op.Exceptions import AmbiguousAction
1919
from grid2op.Action import CompleteAction
20+
from grid2op.Backend import PandaPowerBackend
2021
from grid2op.Parameters import Parameters
2122
from grid2op.Action._backendAction import _BackendAction
2223

2324

25+
class _BackendNoDetach(PandaPowerBackend):
26+
@classmethod
27+
def set_detachment_is_allowed(cls, detachment_is_allowed: bool) -> None:
28+
cls.detachment_is_allowed = False
29+
30+
def load_grid(self, path, filename = None):
31+
self.cannot_handle_detachment()
32+
return super().load_grid(path, filename)
33+
34+
2435
class TestShedding(unittest.TestCase):
2536

2637
def setUp(self) -> None:
@@ -494,44 +505,52 @@ def test_storage(self):
494505
class TestDetachmentRedisp(unittest.TestCase):
495506
def setUp(self):
496507
super().setUp()
497-
p = Parameters()
498-
p.MAX_SUB_CHANGED = 999999
508+
param = Parameters()
509+
param.MAX_SUB_CHANGED = 999999
499510
with warnings.catch_warnings():
500511
warnings.filterwarnings("ignore")
501512
self.env = grid2op.make("educ_case14_storage",
502-
param=p,
513+
param=param,
503514
action_class=CompleteAction,
504515
allow_detachment=True,
505516
test=True,
506517
_add_to_name=type(self).__name__)
507-
type(self.env).gen_pmax = 3. * np.array([140., 120., 70., 70., 40., 100.])
508-
type(self.env).gen_max_ramp_down = type(self.env).gen_pmax
509-
type(self.env).gen_max_ramp_up = type(self.env).gen_pmax
518+
# assign new limits not to get limited by it
519+
new_vals = 3. * np.array([140., 120., 70., 70., 40., 100.])
520+
li_all_cls = [type(self.env),
521+
type(self.env.action_space),
522+
self.env.action_space.actionClass]
523+
for this_cls in li_all_cls:
524+
this_cls.gen_pmax = new_vals
525+
this_cls.gen_max_ramp_down = new_vals
526+
this_cls.gen_max_ramp_up = new_vals
527+
self.tol_redisp = max(self.env._epsilon_poly, 1e-5)
510528
obs = self.env.reset(seed=0, options={"time serie id": 0}) # Reproducibility
511529
return super().setUp()
512530

513531
def tearDown(self):
514532
self.env.close()
515533
return super().tearDown()
516534

517-
def test_no_redisp_no_detach(self):
535+
def test_no_redisp_no_detach(self, tol=1e-5):
518536
# just a basic test to get the values not modified
519537
obs, reward, done, info = self.env.step(self.env.action_space())
520-
assert abs(obs.gen_p[0] - 83.6) <= 1e-6, f'{obs.gen_p[0]} vs 83.6'
538+
assert abs(obs.gen_p[0] - 83.6) <= tol, f'{obs.gen_p[0]} vs 83.6'
521539
obs, reward, done, info = self.env.step(self.env.action_space())
522-
assert abs(obs.gen_p[0] - 83.4) <= 1e-6, f'{obs.gen_p[0]} vs 83.4'
540+
assert abs(obs.gen_p[0] - 83.4) <= tol, f'{obs.gen_p[0]} vs 83.4'
523541
obs, reward, done, info = self.env.step(self.env.action_space())
524-
assert abs(obs.gen_p[0] - 83.9) <= 1e-6, f'{obs.gen_p[0]} vs 83.9'
542+
assert abs(obs.gen_p[0] - 83.9) <= tol, f'{obs.gen_p[0]} vs 83.9'
525543

526544
def test_detached_no_redisp_0(self):
527-
gen_id = 1
545+
amount_redisp = 10.
528546
# first test: apply redispatch, then disco
529-
act = self.env.action_space({"redispatch": [(0, 1.)]})
547+
act = self.env.action_space({"redispatch": [(0, amount_redisp)]})
530548
# act = self.env.action_space()
531549
obs, reward, done, info = self.env.step(act)
532550
assert not done
533-
assert np.abs(obs.actual_dispatch[0] - 1.) <= 1e-8, f"{obs.actual_dispatch[0]} vs 1."
534-
assert np.abs(obs.actual_dispatch.sum() - 0.) <= 1e-5, f"{obs.actual_dispatch.sum()} vs 0."
551+
assert not info["exception"], info["exception"]
552+
assert np.abs(obs.actual_dispatch[0] - amount_redisp) <= 1e-8, f"{obs.actual_dispatch[0]} vs {amount_redisp}"
553+
assert np.abs(obs.actual_dispatch.sum() - 0.) <= self.tol_redisp, f"{obs.actual_dispatch.sum()} vs 0."
535554
# does not work, env chronics are not precise (even without redisp it's 2.9 MW or something)
536555
# assert abs(obs.gen_p_delta.sum() - 0.) <= 1., f"{obs.gen_p_delta.sum()}" # gen_p delta should be bellow 1 MW
537556

@@ -540,8 +559,8 @@ def test_detached_no_redisp_0(self):
540559
assert not done2, info2["exception"]
541560
assert np.abs(obs2.gen_p[0] - 0.) <= 1e-8, f"{obs2.gen_p[0]} vs 0."
542561
assert np.abs(obs2.actual_dispatch[0]) <= 1e-8, f"{obs2.actual_dispatch[0]} vs 0."
543-
# dispatch should compensate the 83.4 MW (base) and the +1 (of the dispatch)
544-
assert np.abs(obs2.actual_dispatch.sum() + (83.4 + 1)) <= 1e-5, f"{obs2.actual_dispatch.sum()} vs {(83.4 + 1)}"
562+
# dispatch should compensate the 83.4 MW (base)
563+
assert np.abs(obs2.actual_dispatch.sum() - (83.4)) <= self.tol_redisp, f"{obs2.actual_dispatch.sum()} vs {(83.4)}"
545564
# does not work, env chronics are not precise (even without redisp it's 2.9 MW or something)
546565
# assert abs(obs2.gen_p_delta.sum() - 0.) <= 1., f"{obs2.gen_p_delta.sum()}" # gen_p delta should be bellow 1 MW
547566

@@ -551,36 +570,100 @@ def test_detached_no_redisp_0(self):
551570
assert np.abs(obs3.gen_p[0] - 0.) <= 1e-8, f"{obs3.gen_p[0]} vs 0."
552571
assert np.abs(obs3.actual_dispatch[0]) <= 1e-8, f"{obs3.actual_dispatch[0]} vs 0."
553572
# dispatch should compensate the 83.4 MW (base) and the +1 (of the dispatch)
554-
assert np.abs(obs3.actual_dispatch.sum() + (83.9 + 1)) <= 1e-5, f"{obs3.actual_dispatch.sum()} vs {(83.9 + 1)}"
573+
assert np.abs(obs3.actual_dispatch.sum() - (83.9 )) <= self.tol_redisp, f"{obs3.actual_dispatch.sum()} vs {(83.9)}"
555574
# does not work, env chronics are not precise (even without redisp it's 2.9 MW or something)
556575

557576
def test_detached_no_redisp_1(self):
558577
# second test: apply disconnect, then redispatch
559578
act_redisp = self.env.action_space({"redispatch": [(0, 1.)]})
560579
act_disc = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}})
561-
562580
obs, reward, done, info = self.env.step(act_disc)
563581
assert not done
564582
assert np.abs(obs.actual_dispatch[0] - 0.) <= 1e-8, f"{obs.actual_dispatch[0]} vs 0."
565-
assert np.abs(obs.actual_dispatch.sum() - 0.) <= 1e-5, f"{obs.actual_dispatch.sum()} vs 0."
583+
assert np.abs(obs.actual_dispatch.sum() - 83.6) <= self.tol_redisp, f"{obs.actual_dispatch.sum()} vs 83.6"
566584
assert np.abs(obs.gen_p[0] - 0.) <= 1e-8, f"{obs.gen_p[0]} vs 0."
567585

568586
obs2, r2, done2, info2 = self.env.step(act_redisp)
569587
assert not done2, info2["exception"]
570588
assert np.abs(obs2.actual_dispatch[0]) <= 1e-8, f"{obs2.actual_dispatch[0]} vs 0."
571-
assert np.abs(obs2.actual_dispatch.sum() - 0.) <= 1e-5, f"{obs2.actual_dispatch.sum()} vs 0."
589+
assert np.abs(obs2.actual_dispatch.sum() - 83.4) <= self.tol_redisp, f"{obs2.actual_dispatch.sum()} vs 83.4"
572590

591+
obs3, r3, done3, info3 = self.env.step(self.env.action_space())
592+
assert not done3, info3["exception"]
593+
assert np.abs(obs3.actual_dispatch[0]) <= 1e-8, f"{obs3.actual_dispatch[0]} vs 0."
594+
assert abs(obs3.gen_p[0]) <= 1e-8, f"{obs3.gen_p[0]} vs 0."
595+
assert np.abs(obs3.actual_dispatch.sum() - 83.9) <= self.tol_redisp, f"{obs3.actual_dispatch.sum()} vs 83.9"
596+
597+
def test_detached_reattached(self):
598+
# second test: apply redisp, then disco, then reco
599+
act_redisp = self.env.action_space({"redispatch": [(0, 1.)]})
600+
act_disc = self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}})
601+
act_reco = self.env.action_space({"set_bus": {"generators_id": [(0, 1)]}})
602+
obs, reward, done, info = self.env.step(act_redisp)
603+
assert not done
604+
assert np.abs(obs.actual_dispatch[0] - 1.) <= 1e-8, f"{obs.actual_dispatch[0]} vs 0."
605+
assert np.abs(obs.actual_dispatch.sum() - 0.) <= self.tol_redisp, f"{obs.actual_dispatch.sum()} vs 0."
606+
607+
obs2, r2, done2, info2 = self.env.step(act_disc)
608+
assert not done2, info2["exception"]
609+
assert np.abs(obs2.actual_dispatch[0]) <= 1e-8, f"{obs2.actual_dispatch[0]} vs 0."
610+
assert np.abs(obs2.actual_dispatch.sum() - 83.4) <= self.tol_redisp, f"{obs2.actual_dispatch.sum()} vs 83.4"
611+
612+
obs3, r3, done3, info3 = self.env.step(act_reco)
613+
assert not done3, info3["exception"]
614+
assert np.abs(obs3.actual_dispatch[0] - 1.) <= self.tol_redisp, f"{obs3.actual_dispatch[0]} vs 1."
615+
assert abs(obs3.gen_p[0] - (83.9 + 1.) ) <= self.tol_redisp, f"{obs3.gen_p[0]} vs 84.9"
616+
assert np.abs(obs3.actual_dispatch.sum() - 0.) <= self.tol_redisp, f"{obs3.actual_dispatch.sum()} vs 83.9"
617+
618+
619+
class TestSheddingcorrectlySet(unittest.TestCase):
620+
def test_shedding_env1_bk1(self):
621+
with warnings.catch_warnings():
622+
warnings.filterwarnings("ignore")
623+
env = grid2op.make("educ_case14_storage",
624+
action_class=CompleteAction,
625+
allow_detachment=True,
626+
test=True,
627+
_add_to_name=type(self).__name__+"test_shedding_env1_bk1")
628+
assert type(env).detachment_is_allowed
629+
630+
def test_shedding_env0_bk1(self):
631+
with warnings.catch_warnings():
632+
warnings.filterwarnings("ignore")
633+
env = grid2op.make("educ_case14_storage",
634+
action_class=CompleteAction,
635+
allow_detachment=False,
636+
test=True,
637+
_add_to_name=type(self).__name__+"test_shedding_env0_bk1")
638+
assert not type(env).detachment_is_allowed
639+
640+
def test_shedding_env1_bk0(self):
641+
with warnings.catch_warnings():
642+
warnings.filterwarnings("ignore")
643+
env = grid2op.make("educ_case14_storage",
644+
action_class=CompleteAction,
645+
allow_detachment=True,
646+
test=True,
647+
backend=_BackendNoDetach(),
648+
_add_to_name=type(self).__name__+"test_shedding_env1_bk1")
649+
assert not type(env).detachment_is_allowed
650+
651+
def test_shedding_env0_bk0(self):
652+
with warnings.catch_warnings():
653+
warnings.filterwarnings("ignore")
654+
env = grid2op.make("educ_case14_storage",
655+
action_class=CompleteAction,
656+
allow_detachment=False,
657+
test=True,
658+
backend=_BackendNoDetach(),
659+
_add_to_name=type(self).__name__+"test_shedding_env0_bk1")
660+
assert not type(env).detachment_is_allowed
573661

574662
# TODO with the env parameters STOP_EP_IF_GEN_BREAK_CONSTRAINTS and ENV_DOES_REDISPATCHING
575-
# TODO when something is "re attached" on the grid
576-
# TODO check gen detached does not participate in redisp
577663

578664
# TODO shedding in simulate
579665
# TODO shedding in Simulator !
580666

581-
# TODO Shedding: test when backend does not support it is not set
582-
# TODO shedding: test when user deactivates it it is not set
583-
584667
# TODO Shedding: Runner
585668

586669
# TODO Shedding: environment copied

0 commit comments

Comments
 (0)