Skip to content

Commit 04293b3

Browse files
committed
fix some bugs introduced when no detachment was allowed
Signed-off-by: DONNOT Benjamin <[email protected]>
1 parent 6c6bcef commit 04293b3

File tree

8 files changed

+86
-15
lines changed

8 files changed

+86
-15
lines changed

CHANGELOG.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ Native multi agents support:
135135
`can_handle_XXX` functions (*eg* `can_handle_more_than_2_busbar()` or `can_handle_detachment()`)
136136
- [FIXED] an issue with `obs.get_forecast_env` with changeNothing and DoNothingHandler time series
137137
- [FIXED] a bug in updating the shunt in PandaPowerBackend (depdending on pandas version)
138+
- [FIXED] a bug when action that reconnect loads, storage units or shunts are done
139+
in the "obs.simulate" (results could depend from previous "obs.simulate" calls)
138140
- [ADDED] possibility to set the "thermal limits" when calling `env.reset(..., options={"thermal limit": xxx})`
139141
- [ADDED] possibility to retrieve some structural information about elements with
140142
with `gridobj.get_line_info(...)`, `gridobj.get_load_info(...)`, `gridobj.get_gen_info(...)`

grid2op/Action/_backendAction.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,9 @@ def _assign_0_to_disco_el(self) -> None:
881881
Do not consider disconnected elements are modified for there active / reactive / voltage values
882882
"""
883883
cls = type(self)
884+
if not cls.detachment_is_allowed:
885+
# is detachment is not allowed, this should not happen
886+
return
884887
gen_changed = self.current_topo.changed[cls.gen_pos_topo_vect]
885888
gen_bus = self.current_topo.values[cls.gen_pos_topo_vect]
886889
self.prod_p.force_unchanged(gen_changed, gen_bus)

grid2op/Backend/pandaPowerBackend.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -867,7 +867,7 @@ def apply_action(self, backendAction: Union["grid2op.Action._backendAction._Back
867867
topo__,
868868
shunts__,
869869
) = backendAction()
870-
870+
871871
# handle bus status
872872
self._grid.bus["in_service"] = pd.Series(data=active_bus.T.reshape(-1),
873873
index=np.arange(cls.n_sub * cls.n_busbar_per_sub),
@@ -1543,7 +1543,7 @@ def storages_info(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
15431543
)
15441544

15451545
def _storages_info(self):
1546-
if self.n_storage:
1546+
if self.n_storage > 0:
15471547
# this is because we support "backward comaptibility" feature. So the storage can be
15481548
# deactivated from the Environment...
15491549
# p_storage = self._grid.res_storage["p_mw"].values.astype(dt_float)

grid2op/Environment/baseEnv.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4132,7 +4132,7 @@ def fast_forward_chronics(self, nb_timestep, init_dt=None):
41324132
raise EnvError("This environment is not intialized. "
41334133
"Have you called `env.reset()` after last game over ?")
41344134
nb_timestep = int(nb_timestep)
4135-
4135+
41364136
# Go to the timestep requested minus one
41374137
nb_timestep = max(1, nb_timestep - 1)
41384138
self.chronics_handler.fast_forward(nb_timestep)

grid2op/Environment/environment.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def __init__(
9494
rewardClass=FlatReward,
9595
legalActClass=AlwaysLegal,
9696
voltagecontrolerClass=ControlVoltageFromFile,
97-
other_rewards={},
97+
other_rewards=None,
9898
thermal_limit_a=None,
9999
with_forecast=True,
100100
epsilon_poly=1e-4, # precision of the redispatching algorithm we don't recommend to go above 1e-4
@@ -107,9 +107,9 @@ def __init__(
107107
opponent_budget_class=NeverAttackBudget,
108108
opponent_attack_duration=0,
109109
opponent_attack_cooldown=99999,
110-
kwargs_opponent={},
110+
kwargs_opponent=None,
111111
attention_budget_cls=LinearAttentionBudget,
112-
kwargs_attention_budget={},
112+
kwargs_attention_budget=None,
113113
has_attention_budget=False,
114114
logger=None,
115115
kwargs_observation=None,
@@ -126,6 +126,15 @@ def __init__(
126126
_local_dir_cls=None, # only set at the first call to `make(...)` after should be false
127127
_overload_name_multimix=None,
128128
):
129+
if other_rewards is None:
130+
other_rewards = {}
131+
132+
if kwargs_opponent is None:
133+
kwargs_opponent = {}
134+
135+
if kwargs_attention_budget is None:
136+
kwargs_attention_budget = {}
137+
129138
BaseEnv.__init__(
130139
self,
131140
init_env_path=init_env_path,

grid2op/Observation/baseObservation.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,9 @@ def __init__(self,
653653
self.gen_p_delta = np.empty(shape=cls.n_gen, dtype=dt_float)
654654

655655
# detachment (>= 1.11.0)
656-
self.load_detached = np.ones(shape=cls.n_load, dtype=dt_bool)
657-
self.gen_detached = np.ones(shape=cls.n_gen, dtype=dt_bool)
658-
self.storage_detached = np.ones(shape=cls.n_storage, dtype=dt_bool)
656+
self.load_detached = np.zeros(shape=cls.n_load, dtype=dt_bool)
657+
self.gen_detached = np.zeros(shape=cls.n_gen, dtype=dt_bool)
658+
self.storage_detached = np.zeros(shape=cls.n_storage, dtype=dt_bool)
659659
self.load_p_detached = np.zeros(shape=cls.n_load, dtype=dt_float)
660660
self.load_q_detached = np.zeros(shape=cls.n_load, dtype=dt_float)
661661
self.gen_p_detached = np.zeros(shape=cls.n_gen, dtype=dt_float)
@@ -677,6 +677,7 @@ def _aux_copy(self, other : Self) -> None:
677677
"year",
678678
"delta_time",
679679
"_is_done",
680+
"_prev_conn"
680681
]
681682

682683
attr_vect = [

grid2op/tests/test_shedding.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,63 @@ def test_shedding_load_step(self):
432432
assert np.abs(self.env._delta_gen_p.sum() / self.env._gen_activeprod_t.sum()) <= 0.02 # less than 2% losses
433433

434434

435+
class TestSheddingActionsNoShedding(unittest.TestCase):
436+
def setUp(self) -> None:
437+
super().setUp()
438+
p = Parameters()
439+
p.MAX_SUB_CHANGED = 999999
440+
with warnings.catch_warnings():
441+
warnings.filterwarnings("ignore")
442+
self.env = grid2op.make("educ_case14_storage",
443+
param=p,
444+
action_class=CompleteAction,
445+
allow_detachment=False,
446+
test=True,
447+
_add_to_name=type(self).__name__)
448+
obs = self.env.reset(seed=0, options={"time serie id": 0}) # Reproducibility
449+
450+
def tearDown(self) -> None:
451+
self.env.close()
452+
super().tearDown()
453+
454+
def test_load(self):
455+
obs = self.env.reset()
456+
assert not type(self.env).detachment_is_allowed
457+
assert (~obs.load_detached).all()
458+
459+
with self.assertRaises(UserWarning):
460+
with warnings.catch_warnings():
461+
warnings.filterwarnings("error")
462+
self.env.action_space({"detach_load": 0})
463+
464+
obs, reward, done, info = self.env.step(self.env.action_space({"set_bus": {"loads_id": [(0, -1)]}}))
465+
assert done
466+
467+
def test_gen(self):
468+
obs = self.env.reset()
469+
assert not type(self.env).detachment_is_allowed
470+
assert (~obs.gen_detached).all()
471+
472+
with self.assertRaises(UserWarning):
473+
with warnings.catch_warnings():
474+
warnings.filterwarnings("error")
475+
self.env.action_space({"detach_gen": 0})
476+
477+
obs, reward, done, info = self.env.step(self.env.action_space({"set_bus": {"generators_id": [(0, -1)]}}))
478+
assert done
479+
480+
def test_storage(self):
481+
obs = self.env.reset()
482+
assert not type(self.env).detachment_is_allowed
483+
assert (~obs.storage_detached).all()
484+
485+
with self.assertRaises(UserWarning):
486+
with warnings.catch_warnings():
487+
warnings.filterwarnings("error")
488+
self.env.action_space({"detach_storage": 0})
435489

490+
obs, reward, done, info = self.env.step(self.env.action_space({"set_bus": {"storages_id": [(0, -1)]}, "set_storage": [(0, 1.)]}))
491+
assert done
436492

437493

438494
# TODO with the env parameters STOP_EP_IF_GEN_BREAK_CONSTRAINTS and ENV_DOES_REDISPATCHING

grid2op/tests/test_ts_handlers.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -511,18 +511,18 @@ def tearDown(self) -> None:
511511
self.env.close()
512512
return super().tearDown()
513513

514-
def _aux_test_obs(self, obs, max_it=12):
515-
assert len(obs._forecasted_inj) == 13 # 12 + 1
514+
def _aux_test_obs(self, obs, max_it=12, tol=1e-5):
515+
assert len(obs._forecasted_inj) == max_it + 1 # 12 + 1
516516
init_obj = obs._forecasted_inj[0]
517-
for el in obs._forecasted_inj:
517+
for for_h, el in enumerate(obs._forecasted_inj):
518518
for k_ in ["load_p", "load_q"]:
519-
assert np.all(el[1]["injection"][k_] == init_obj[1]["injection"][k_])
519+
assert np.abs(el[1]["injection"][k_] - init_obj[1]["injection"][k_]).max() <= tol, f'iter {for_h} : {el[1]["injection"][k_]} vs {init_obj[1]["injection"][k_]}'
520520
k_ = "prod_p" # because of slack...
521521
assert np.all(el[1]["injection"][k_][:-1] == init_obj[1]["injection"][k_][:-1])
522522

523-
obs.simulate(self.env.action_space(), 12)
523+
obs.simulate(self.env.action_space(), max_it)
524524
with self.assertRaises(NoForecastAvailable):
525-
obs.simulate(self.env.action_space(), 13)
525+
obs.simulate(self.env.action_space(), max_it + 1)
526526

527527
def test_step(self):
528528
obs = self.env.reset()

0 commit comments

Comments
 (0)