Skip to content

Commit c30f1ce

Browse files
authored
Merge pull request #562 from BDonnot/bd_dev
Bd dev
2 parents f4cd921 + f932d7c commit c30f1ce

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+453
-208
lines changed

CHANGELOG.rst

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,26 @@ Change Log
3232
- [???] properly model interconnecting powerlines
3333

3434

35-
[1.9.7] - 20xx-yy-zz
35+
[1.9.7] - 2023-12-0z
3636
----------------------
37+
- [BREAKING] removal of the `grid2op/Exceptions/PowerflowExceptions.py` file and move the
38+
`DivergingPowerflow` as part of the BackendException. If you imported (to be avoided)
39+
with `from grid2op.Exceptions.PowerflowExceptions import PowerflowExceptions`
40+
simply do `from grid2op.Exceptions import PowerflowExceptions` and nothing
41+
will change.
42+
- [BREAKING] rename with filename starting with lowercase all the files in the "`Exceptions`",
43+
module. This is both consistent with python practice but allows also to make the
44+
difference between the files in the
45+
module and the class imported. This should have little to no impact on all codes but to "upgrade"
46+
instead of `from grid2op.Exceptions.XXX import PowerflowExceptions` (which you should not have done in the first place)
47+
just do `from grid2op.Exceptions import PowerflowExceptions`. Expect other changes like this for other grid2op modules
48+
in the near future.
49+
- [BREAKING] change the `gridobj_cls.shape()` and `gridobj_cls.dtype()` to `gridobj_cls.shapes()` and `gridobj_cls.dtypes()`
50+
to be more clear when dealing with action_space and observation_space (where `shape` and `dtype` are attribute and not functions)
51+
This change means you can still use `act.shape()` and `act.dtype()` but that `act_space.shape` and `act_space.dtype` are now
52+
clearly properties (and NOT attribute). For the old function `gridobj_cls.dtype()` you can now use `gridobj_cls.dtypes()`
53+
- [FIXED] issue https://github.com/rte-france/Grid2Op/issues/561 (indent issue)
54+
- [FIXED] issue https://github.com/rte-france/Grid2Op/issues/550 : issue with `shunts_data_available` now better handled
3755
- [IMPROVED] the function to check the backend interface now also check that
3856
the `topo_vect` returns value between 1 and 2.
3957
- [IMPROVED] the function to check backend now also check the `topo_vect`

grid2op/Action/_backendAction.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,8 @@ def __init__(self):
236236
)
237237

238238
# shunts
239-
if self.shunts_data_available:
239+
cls = type(self)
240+
if cls.shunts_data_available:
240241
self.shunt_p = ValueStore(self.n_shunt, dtype=dt_float)
241242
self.shunt_q = ValueStore(self.n_shunt, dtype=dt_float)
242243
self.shunt_bus = ValueStore(self.n_shunt, dtype=dt_int)
@@ -266,7 +267,8 @@ def __deepcopy__(self, memodict={}):
266267
res.storage_power.copy(self.storage_power)
267268
res.activated_bus[:, :] = self.activated_bus
268269
# res.big_topo_to_subid[:] = self.big_topo_to_subid # cste
269-
if self.shunts_data_available:
270+
cls = type(self)
271+
if cls.shunts_data_available:
270272
res.shunt_p.copy(self.shunt_p)
271273
res.shunt_q.copy(self.shunt_q)
272274
res.shunt_bus.copy(self.shunt_bus)
@@ -307,7 +309,8 @@ def reorder(self, no_load, no_gen, no_topo, no_storage, no_shunt):
307309

308310
self.storage_power.reorder(no_storage)
309311

310-
if self.shunts_data_available:
312+
cls = type(self)
313+
if cls.shunts_data_available:
311314
self.shunt_p.reorder(no_shunt)
312315
self.shunt_q.reorder(no_shunt)
313316
self.shunt_bus.reorder(no_shunt)
@@ -331,7 +334,8 @@ def reset(self):
331334
self.storage_power.values[:] = 0.0
332335

333336
# shunts
334-
if self.shunts_data_available:
337+
cls = type(self)
338+
if cls.shunts_data_available:
335339
self.shunt_p.reset()
336340
self.shunt_q.reset()
337341
self.shunt_bus.reset()
@@ -411,7 +415,7 @@ def __iadd__(self, other):
411415
# II shunts
412416
if type(self).shunts_data_available:
413417
shunts = {}
414-
if other.shunts_data_available:
418+
if type(other).shunts_data_available:
415419
shunts["shunt_p"] = other.shunt_p
416420
shunts["shunt_q"] = other.shunt_q
417421
shunts["shunt_bus"] = other.shunt_bus
@@ -515,7 +519,7 @@ def __call__(self):
515519
)
516520
topo = self.current_topo
517521
shunts = None
518-
if self.shunts_data_available:
522+
if type(self).shunts_data_available:
519523
shunts = self.shunt_p, self.shunt_q, self.shunt_bus
520524
self._get_active_bus()
521525
return self.activated_bus, injections, topo, shunts

grid2op/Action/baseAction.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ def __init__(self):
440440
self._subs_impacted = None
441441

442442
# shunts
443-
if self.shunts_data_available:
443+
if type(self).shunts_data_available:
444444
self.shunt_p = np.full(
445445
shape=self.n_shunt, fill_value=np.NaN, dtype=dt_float
446446
)
@@ -495,6 +495,12 @@ def copy(self) -> "BaseAction":
495495
# sometimes this method is used...
496496
return self.__deepcopy__()
497497

498+
def shape(self):
499+
return type(self).shapes()
500+
501+
def dtype(self):
502+
return type(self).dtypes()
503+
498504
def _aux_copy(self, other):
499505
attr_simple = [
500506
"_modif_inj",
@@ -524,7 +530,7 @@ def _aux_copy(self, other):
524530
"_raise_alert",
525531
]
526532

527-
if self.shunts_data_available:
533+
if type(self).shunts_data_available:
528534
attr_vect += ["shunt_p", "shunt_q", "shunt_bus"]
529535

530536
for attr_nm in attr_simple:
@@ -1050,7 +1056,7 @@ def __eq__(self, other) -> bool:
10501056
return False
10511057

10521058
# shunts are the same
1053-
if self.shunts_data_available:
1059+
if type(self).shunts_data_available:
10541060
if self.n_shunt != other.n_shunt:
10551061
return False
10561062
is_ok_me = np.isfinite(self.shunt_p)
@@ -1455,7 +1461,7 @@ def reset(self):
14551461
self._subs_impacted = None
14561462

14571463
# shunts
1458-
if self.shunts_data_available:
1464+
if type(self).shunts_data_available:
14591465
self.shunt_p[:] = np.NaN
14601466
self.shunt_q[:] = np.NaN
14611467
self.shunt_bus[:] = 0
@@ -1631,7 +1637,7 @@ def __iadd__(self, other):
16311637
self._assign_iadd_or_warn("_change_bus_vect", me_change)
16321638

16331639
# shunts
1634-
if self.shunts_data_available:
1640+
if type(self).shunts_data_available:
16351641
val = other.shunt_p
16361642
ok_ind = np.isfinite(val)
16371643
shunt_p = 1.0 * self.shunt_p
@@ -1763,7 +1769,7 @@ def __call__(self) -> Tuple[dict, np.ndarray, np.ndarray, np.ndarray, np.ndarray
17631769
storage_power = self._storage_power
17641770
# remark: curtailment is handled by an algorithm in the environment, so don't need to be returned here
17651771
shunts = {}
1766-
if self.shunts_data_available:
1772+
if type(self).shunts_data_available:
17671773
shunts["shunt_p"] = self.shunt_p
17681774
shunts["shunt_q"] = self.shunt_q
17691775
shunts["shunt_bus"] = self.shunt_bus
@@ -1780,7 +1786,7 @@ def __call__(self) -> Tuple[dict, np.ndarray, np.ndarray, np.ndarray, np.ndarray
17801786
)
17811787

17821788
def _digest_shunt(self, dict_):
1783-
if not self.shunts_data_available:
1789+
if not type(self).shunts_data_available:
17841790
return
17851791

17861792
if "shunt" in dict_:
@@ -2664,7 +2670,7 @@ def _check_for_ambiguity(self):
26642670
"which it is connected. This is ambiguous. You must *set* this bus instead."
26652671
)
26662672

2667-
if self.shunts_data_available:
2673+
if type(self).shunts_data_available:
26682674
if self.shunt_p.shape[0] != self.n_shunt:
26692675
raise IncorrectNumberOfElements(
26702676
"Incorrect number of shunt (for shunt_p) in your action."
@@ -3396,7 +3402,7 @@ def get_types(self) -> Tuple[bool, bool, bool, bool, bool, bool, bool]:
33963402
"""
33973403
injection = "load_p" in self._dict_inj or "prod_p" in self._dict_inj
33983404
voltage = "prod_v" in self._dict_inj
3399-
if self.shunts_data_available:
3405+
if type(self).shunts_data_available:
34003406
voltage = voltage or np.isfinite(self.shunt_p).any()
34013407
voltage = voltage or np.isfinite(self.shunt_q).any()
34023408
voltage = voltage or (self.shunt_bus != 0).any()

grid2op/Action/voltageOnlyAction.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def __init__(self):
4040
"""
4141
BaseAction.__init__(self)
4242

43-
if VoltageOnlyAction._shunt_added is False and self.shunts_data_available:
43+
if VoltageOnlyAction._shunt_added is False and type(self).shunts_data_available:
4444
VoltageOnlyAction.attr_list_vect += ["shunt_p", "shunt_q", "shunt_bus"]
4545
VoltageOnlyAction.authorized_keys.add("shunt")
4646
VoltageOnlyAction._shunt_added = True
@@ -61,7 +61,7 @@ def _check_dict(self):
6161
"""
6262
if self._dict_inj:
6363
for el in self._dict_inj:
64-
if el not in self.attr_list_vect:
64+
if el not in type(self).attr_list_vect:
6565
raise AmbiguousAction(
6666
'Impossible to modify something different than "prod_v" using '
6767
'"VoltageOnlyAction" action.'

grid2op/Backend/backend.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,15 @@
2525
from grid2op.dtypes import dt_int, dt_float, dt_bool
2626
from grid2op.Exceptions import (
2727
EnvError,
28-
DivergingPowerFlow,
2928
IncorrectNumberOfElements,
3029
IncorrectNumberOfLoads,
31-
)
32-
from grid2op.Exceptions import (
3330
IncorrectNumberOfGenerators,
3431
BackendError,
3532
IncorrectNumberOfLines,
33+
DivergingPowerflow,
34+
Grid2OpException,
3635
)
3736
from grid2op.Space import GridObjects
38-
from grid2op.Exceptions import Grid2OpException
3937

4038

4139
# TODO method to get V and theta at each bus, could be in the same shape as check_kirchoff
@@ -941,7 +939,7 @@ def _runpf_with_diverging_exception(self, is_dc : bool) -> Optional[Exception]:
941939
942940
Raises
943941
------
944-
exc_: :class:`grid2op.Exceptions.DivergingPowerFlow`
942+
exc_: :class:`grid2op.Exceptions.DivergingPowerflow`
945943
In case of divergence of the powerflow
946944
947945
"""
@@ -952,13 +950,13 @@ def _runpf_with_diverging_exception(self, is_dc : bool) -> Optional[Exception]:
952950
except Grid2OpException as exc_:
953951
exc_me = exc_
954952
except Exception as exc_:
955-
exc_me = DivergingPowerFlow(
953+
exc_me = DivergingPowerflow(
956954
f" An unexpected error occurred during the computation of the powerflow."
957955
f"The error is: \n {exc_} \n. This is game over"
958956
)
959957

960958
if not conv and exc_me is None:
961-
exc_me = DivergingPowerFlow(
959+
exc_me = DivergingPowerflow(
962960
"GAME OVER: Powerflow has diverged during computation "
963961
"or a load has been disconnected or a generator has been disconnected."
964962
)
@@ -1820,7 +1818,9 @@ def update_from_obs(self,
18201818
sh_q[~shunt_co] = np.NaN
18211819
dict_["shunt"]["shunt_p"] = sh_p
18221820
dict_["shunt"]["shunt_q"] = sh_q
1823-
act.update(dict_)
1821+
elif type(self).shunts_data_available and not type(obs).shunts_data_available:
1822+
warnings.warn("Backend supports shunt but not the observation. This behaviour is non standard.")
1823+
act.update(dict_)
18241824
backend_action += act
18251825
self.apply_action(backend_action)
18261826

@@ -1854,8 +1854,9 @@ def assert_grid_correct(self) -> None:
18541854
)
18551855
# reset the attribute of the grid2op.Backend.Backend class
18561856
# that can be messed up with depending on the initialization of the backend
1857-
Backend._clear_class_attribute()
1858-
orig_type._clear_class_attribute()
1857+
Backend._clear_class_attribute() # reset totally the grid2op Backend type
1858+
# orig_type._clear_class_attribute()
1859+
orig_type._clear_grid_dependant_class_attributes() # only reset the attributes that could be modified by user
18591860

18601861
my_cls = type(self)
18611862
my_cls.my_bk_act_class = _BackendAction.init_grid(my_cls)

grid2op/Backend/pandaPowerBackend.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ class PandaPowerBackend(Backend):
107107
# and use "env" as "any open ai gym" environment.
108108
109109
"""
110-
110+
shunts_data_available = True
111+
111112
def __init__(
112113
self,
113114
detailed_infos_for_cascading_failures : bool=False,
@@ -713,7 +714,7 @@ def _init_private_attrs(self) -> None:
713714
self._sh_vnkv = self._grid.bus["vn_kv"][self.shunt_to_subid].values.astype(
714715
dt_float
715716
)
716-
self.shunts_data_available = True
717+
# self.shunts_data_available = True # TODO shunts_data_available
717718

718719
# store the topoid -> objid
719720
self._big_topo_to_obj = [(None, None) for _ in range(self.dim_topo)]

grid2op/Chronics/fromOneEpisodeData.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,10 @@ class FromOneEpisodeData(GridValue):
137137
138138
env = grid2op.make(env_name,
139139
chronics_class=FromOneEpisodeData,
140-
data_feeding_kwargs={"ep_data": ep_data},
140+
data_feeding_kwargs={"ep_data": ep_data,
141+
"list_perfect_forecasts": (5, 10, 15)},
141142
opponent_class=FromEpisodeDataOpponent,
142143
opponent_attack_cooldown=1,
143-
list_perfect_forecasts=(5, 10, 15)
144144
)
145145
# it creates an environment with perfect forecasts available for the next step (5),
146146
# the step afterwards (10) and again the following one (15)
@@ -327,7 +327,6 @@ def forecasts(self):
327327
"""
328328
if not self.list_perfect_forecasts:
329329
return []
330-
331330
res = []
332331
for h_id, h in enumerate(self.list_perfect_forecasts):
333332
res_d = {}
@@ -342,6 +341,7 @@ def forecasts(self):
342341

343342
def get_kwargs(self, dict_):
344343
dict_["ep_data"] = copy.deepcopy(self._episode_data)
344+
# dict_["list_perfect_forecasts"] = copy.deepcopy(self.list_perfect_forecasts)
345345
return dict_
346346

347347
def get_id(self) -> str:

grid2op/Converter/BackendConverter.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,18 @@ def _init_myself(self):
268268
nm="storage",
269269
)
270270

271+
if type(self.source_backend).shunts_data_available and not type(self.target_backend).shunts_data_available:
272+
raise Grid2OpException("Source backend supports shunts and not target backend. This is not handled")
273+
elif type(self.target_backend).shunts_data_available and not type(self.source_backend).shunts_data_available:
274+
raise Grid2OpException("Target backend supports shunts and not source backend. This is not handled")
275+
276+
# TODO shunts data available
271277
# shunt are available if both source and target provide it
272-
self.shunts_data_available = (
273-
self.source_backend.shunts_data_available
274-
and self.target_backend.shunts_data_available
278+
type(self).shunts_data_available = (
279+
type(self.source_backend).shunts_data_available
280+
and type(self.target_backend).shunts_data_available
275281
)
276-
if self.shunts_data_available:
282+
if type(self).shunts_data_available:
277283
self._shunt_tg2sr = np.full(self.n_shunt, fill_value=-1, dtype=dt_int)
278284
self._shunt_sr2tg = np.full(self.n_shunt, fill_value=-1, dtype=dt_int)
279285
# automatic mode
@@ -408,11 +414,17 @@ def assert_grid_correct(self):
408414
sr_cls.set_env_name(env_name)
409415

410416
# handle specifc case of shunt data:
411-
if not self.target_backend.shunts_data_available:
417+
if not type(self.target_backend).shunts_data_available:
418+
if type(self.source_backend).shunts_data_available:
419+
raise Grid2OpException("Impossible to use a converter when one of the backend "
420+
"supports shunt and the other not at the moment.")
421+
# TODO shunts_data_available: you need ideally to create a different class
422+
# for the backend that does not support it.
423+
412424
# disable the shunt data in grid2op.
413-
self.source_backend.shunts_data_available = False
414-
self.source_backend.n_shunt = None
415-
self.source_backend.name_shunt = np.empty(0, dtype=str)
425+
# type(self.source_backend).shunts_data_available = False
426+
# type(self.source_backend).n_shunt = None
427+
# type(self.source_backend).name_shunt = np.empty(0, dtype=str)
416428

417429
self._init_class_attr(obj=self.source_backend)
418430
if self.path_redisp is not None:
@@ -494,7 +506,7 @@ def assert_grid_correct(self):
494506
assert np.all(sorted(self._topo_tg2sr[topo_sr2tg_without_storage]) == target_without_storage)
495507
self._topo_sr2tg = topo_sr2tg_without_storage
496508

497-
if self.shunts_data_available:
509+
if type(self).shunts_data_available:
498510
self._check_both_consistent(self._shunt_tg2sr, self._shunt_sr2tg)
499511

500512
# finally check that powergrids are identical (up to the env name)
@@ -716,7 +728,7 @@ def get_action_to_set(self):
716728
act._set_line_status[:] = act._set_line_status[line_vect]
717729
act._switch_line_status[:] = act._switch_line_status[line_vect]
718730

719-
if act.shunt_added and act.shunts_data_available:
731+
if act.shunt_added and type(act).shunts_data_available:
720732
shunt_vect = self._shunt_sr2tg
721733
act.shunt_p[:] = act.shunt_p[shunt_vect]
722734
act.shunt_q[:] = act.shunt_q[shunt_vect]

0 commit comments

Comments
 (0)