Skip to content

Commit ad85fa4

Browse files
authored
Merge pull request #704 from BDonnot/bd_dev
Small fixes (mainly doc) from review
2 parents 4bed5f6 + 0817063 commit ad85fa4

15 files changed

+271
-139
lines changed

CHANGELOG.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ Native multi agents support:
100100
- add detachment
101101
- add change_bus / set_bus
102102

103-
[1.11.0] - 202x-yy-zz
103+
[1.11.0] - 2025-04-14
104104
-----------------------
105105
- [BREAKING] Change for `FromMultiEpisodeData` that disables the caching by default
106106
when creating the data.

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,9 @@ interesting part of this framework:
202202
* [11_IntegrationWithExistingRLFrameworks](getting_started/11_IntegrationWithExistingRLFrameworks.ipynb)
203203
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Grid2Op/grid2op/blob/master/getting_started/11_IntegrationWithExistingRLFrameworks.ipynb)
204204
explains how to use grid2op with other reinforcement learning framework. TODO: this needs to be redone
205+
* [12_DetachmentOfLoadsAndGenerators.ipynb](getting_started/12_DetachmentOfLoadsAndGenerators.ipynb.ipynb)
206+
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/Grid2Op/grid2op/blob/master/getting_started/12_DetachmentOfLoadsAndGenerators.ipynb.ipynb)
207+
explains briefly what is detachment.
205208

206209
Try them out in your own browser without installing
207210
anything with the help of mybinder:

binder/environment.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ dependencies:
88
- pip
99
- pip:
1010
- grid2op
11-
- jyquickhelper
1211
- numpy
1312
- numba
1413
- seaborn

getting_started/13_DetachmentOfLoadsAndGenerators.ipynb renamed to getting_started/12_DetachmentOfLoadsAndGenerators.ipynb

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,13 @@
2323
"from pathlib import Path\n",
2424
"\n",
2525
"# Setup Environment\n",
26-
"data_path = Path.cwd() / \"grid2op\" / \"data\"\n",
27-
"p = Parameters()\n",
28-
"p.MAX_SUB_CHANGED = 5\n",
29-
"env = grid2op.make(data_path / \"rte_case5_example\", param=p, allow_detachment=True)\n",
26+
"env_standard = grid2op.make(\"rte_case5_example\", test=True, allow_detachment=False)\n",
27+
"env_with_detach = grid2op.make(\"rte_case5_example\", test=True, allow_detachment=True)\n",
3028
"\n",
3129
"# Setup Plotter Utility\n",
32-
"plotter = PlotMatplot(env.observation_space, load_name=True, gen_name=True, dpi=150)\n",
33-
"print(f\"Loads: {env.n_load}, Generators: {env.n_gen}, Storage: {env.n_storage}, Allow Detachment: {env._allow_detachment}\")"
30+
"plotter = PlotMatplot(env_standard.observation_space, load_name=True, gen_name=True, dpi=150)\n",
31+
"for env, env_name in zip([env_standard, env_with_detach], [\"env_standard\", \"env_with_detach\"]):\n",
32+
" print(f\"For {env_name}: Loads: {env.n_load}, Generators: {env.n_gen}, Storage: {env.n_storage}, Detachment is allowed: {env.detachment_is_allowed}\")"
3433
]
3534
},
3635
{
@@ -46,22 +45,33 @@
4645
"metadata": {},
4746
"outputs": [],
4847
"source": [
49-
"load_lookup = {name:i for i,name in enumerate(env.name_load)}\n",
50-
"gen_lookup = {name:i for i,name in enumerate(env.name_gen)}\n",
51-
"act = env.action_space({\"set_bus\":[(env.load_pos_topo_vect[load_lookup[\"load_3_1\"]], -1),\n",
52-
" (env.load_pos_topo_vect[load_lookup[\"load_4_2\"]], -1)]})\n",
48+
"act = env_standard.action_space({\"set_bus\":{\"loads_id\": [(\"load_3_1\", -1)]}})\n",
5349
"print(act)\n",
54-
"env.set_id(\"00\")\n",
55-
"init_obs = env.reset()\n",
56-
"obs, reward, done, info = env.step(act)\n",
50+
"init_obs = env_standard.reset(seed=0, options={\"time serie id\": \"00\"})\n",
51+
"obs, reward, done, info = env_standard.step(act)\n",
5752
"plotter.plot_obs(obs, figure=plt.figure(figsize=(8,5)))\n",
53+
"plt.title(\"Without providing 'allow_detachment=True' grid2op fails if a load is disconnected\")\n",
54+
"plt.show()"
55+
]
56+
},
57+
{
58+
"cell_type": "code",
59+
"execution_count": null,
60+
"metadata": {},
61+
"outputs": [],
62+
"source": [
63+
"init_obs = env_with_detach.reset(seed=0, options={\"time serie id\": \"00\"})\n",
64+
"obs, reward, done, info = env_with_detach.step(act)\n",
65+
"plotter.plot_obs(obs, figure=plt.figure(figsize=(8,5)))\n",
66+
"plt.title(\"Providing 'allow_detachment=True' grid2op continues if a load is disconnected\")\n",
67+
"plt.tight_layout()\n",
5868
"plt.show()"
5969
]
6070
}
6171
],
6272
"metadata": {
6373
"kernelspec": {
64-
"display_name": "venv_test",
74+
"display_name": "Python 3 (ipykernel)",
6575
"language": "python",
6676
"name": "python3"
6777
},
@@ -75,9 +85,9 @@
7585
"name": "python",
7686
"nbconvert_exporter": "python",
7787
"pygments_lexer": "ipython3",
78-
"version": "3.12.7"
88+
"version": "3.10.12"
7989
}
8090
},
8191
"nbformat": 4,
82-
"nbformat_minor": 2
92+
"nbformat_minor": 4
8393
}

grid2op/Action/baseAction.py

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ class BaseAction(GridObjects):
339339
Typically `0 <= storage_id < env.n_storage` and `amount` is a floating point between the maximum
340340
power and minimum power the storage unit can absorb / produce.
341341
342-
Finally, in order to perform curtailment action on renewable generators, you can:
342+
In order to perform curtailment action on renewable generators, you can:
343343
344344
.. code-block:: python
345345
@@ -354,7 +354,40 @@ class BaseAction(GridObjects):
354354
giving the limit of power you allow each renewable generator to produce (expressed in ratio of
355355
Pmax). For example if `gen_id=1` and `amount=0.7` it means you limit the production of
356356
generator 1 to 70% of its Pmax.
357+
358+
Finally, provided that the environment is loaded with `allow_detachment=True`, you can also
359+
perform "detachment" action on the grid with:
360+
361+
.. code-block:: python
362+
363+
import grid2op
364+
from grid2op.Action import BaseAction
365+
env_name = "l2rpn_case14_sandbox" # or any other name
366+
env = grid2op.make(env_name, allow_detachment=True)
367+
368+
# method 1
369+
act = env.action_space({"detach_load": [load1_id, load2_id, ...]})
370+
371+
# method 2
372+
act = env.action_space()
373+
act.detach_load = [load1_id, load2_id, ...]
357374
375+
You can do similar action for storage and generator, for example
376+
377+
.. code-block:: python
378+
379+
import grid2op
380+
from grid2op.Action import BaseAction
381+
env_name = "educ_case14_storage" # or any other name
382+
env = grid2op.make(env_name, test=True, allow_detachment=True)
383+
384+
# for generators (method 1 showed here, but method 2 works, of course)
385+
act = env.action_space({"detach_gen": [gen1_id, gen2_id, ...]})
386+
387+
# for storage units (method 2 showed here, but method 1 works too, of course)
388+
act = env.action_space()
389+
act.detach_storage = [storage1_id, storage2_id, ...]
390+
358391
"""
359392

360393
authorized_keys = {
@@ -550,19 +583,6 @@ def process_detachment(cls):
550583
if el in cls.authorized_keys:
551584
cls.authorized_keys.remove(el)
552585
cls._update_value_set()
553-
# else:
554-
# # I support detachment, I need to make sure this is registered
555-
# cls.attr_list_vect = copy.deepcopy(cls.attr_list_vect)
556-
# cls.attr_list_set = copy.deepcopy(cls.attr_list_set)
557-
# # add the detachment from the list to vector
558-
# for el in ["_detach_load", "_detach_gen", "_detach_storage"]:
559-
# if el not in cls.attr_list_vect:
560-
# cls.attr_list_vect.append(el)
561-
# # add the detachment from the allowed action
562-
# for el in ["detach_load", "detach_gen", "detach_storage"]:
563-
# if el not in cls.authorized_keys:
564-
# cls.authorized_keys.add(el)
565-
# cls._update_value_set()
566586
return super().process_detachment()
567587

568588
def copy(self) -> "BaseAction":
@@ -3569,6 +3589,16 @@ def __str__(self) -> str:
35693589
res.append(f"\t - Raise alert(s) {line_str}")
35703590
else:
35713591
res.append("\t - Not raise any alert")
3592+
3593+
if my_cls.detachment_is_allowed:
3594+
for el in my_cls.OBJ_SUPPORT_DETACH:
3595+
_modif_detach_xxx = getattr(self, f"_modif_detach_{el}")
3596+
_detach_xxx = getattr(self, f"_detach_{el}")
3597+
if _modif_detach_xxx:
3598+
res.append(f"\t - Detach {el}: {_detach_xxx.nonzero()[0]}")
3599+
else:
3600+
res.append(f"\t - Not detach any {el}")
3601+
35723602
return "\n".join(res)
35733603

35743604
def impact_on_objects(self) -> dict:

grid2op/Action/playableAction.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ class PlayableAction(BaseAction):
2828
"set_storage",
2929
"curtail",
3030
"raise_alarm",
31-
"raise_alert"
31+
"raise_alert",
32+
"detach_load", # new in 1.11.0
33+
"detach_gen", # new in 1.11.0
34+
"detach_storage", # new in 1.11.0
3235
}
3336

3437
attr_list_vect = [
@@ -40,7 +43,10 @@ class PlayableAction(BaseAction):
4043
"_storage_power",
4144
"_curtail",
4245
"_raise_alarm",
43-
"_raise_alert"
46+
"_raise_alert",
47+
"_detach_load", # new in 1.11.0
48+
"_detach_gen", # new in 1.11.0
49+
"_detach_storage", # new in 1.11.0
4450
]
4551
attr_list_set = set(attr_list_vect)
4652
shunt_added = True # no shunt here

grid2op/Observation/baseObservation.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,20 +432,65 @@ class BaseObservation(GridObjects):
432432
`env.parameters.ALERT_TIME_WINDOW` steps)
433433
434434
gen_p_delta: :class:`numpy.ndarray`, dtype:float
435+
.. versionadded:: 1.11.0
436+
437+
Difference between the generator setpoint (asked by the environment)
438+
and the generator real active value at the given steps.
439+
440+
For example, if the "asked generator value" is such that
441+
"sum asked_generator_value = sum load" then the
442+
gen_p_delta attribute will corresponds exactly to how the
443+
power losses are compensated by the backend.
435444
436445
load_detached: :class:`numpy.ndarray`, dtype:bool
446+
.. versionadded:: 1.11.0
447+
448+
Whether or not each load has been detached (only
449+
available for env supporting detachement feature)
437450
438451
gen_detached: :class:`numpy.ndarray`, dtype:bool
452+
.. versionadded:: 1.11.0
453+
454+
Whether or not each generator has been detached (only
455+
available for env supporting detachement feature)
439456
440457
storage_detached: :class:`numpy.ndarray`, dtype:bool
458+
.. versionadded:: 1.11.0
459+
460+
Whether or not each storage unit has been detached (only
461+
available for env supporting detachement feature)
441462
442463
load_p_detached: :class:`numpy.ndarray`, dtype:float
464+
.. versionadded:: 1.11.0
465+
466+
Amount (in MW) given how many MW have beeen "detached"
467+
for each load on the grid. It is 0 for
468+
load still connected to the grid and only available for
469+
environment supporting detachment.
443470
444471
load_q_detached: :class:`numpy.ndarray`, dtype:float
472+
.. versionadded:: 1.11.0
473+
474+
Amount (in MVAr) given how many MVAr have beeen "detached"
475+
for each load on the grid. It is 0 for
476+
load still connected to the grid and only available for
477+
environment supporting detachment.
445478
446479
gen_p_detached: :class:`numpy.ndarray`, dtype:float
480+
.. versionadded:: 1.11.0
481+
482+
Amount (in MW) given how many MW have beeen "detached"
483+
for each generator on the grid. It is 0 for
484+
generator still connected to the grid and only available for
485+
environment supporting detachment.
447486
448487
storage_p_detached: :class:`numpy.ndarray`, dtype:float
488+
.. versionadded:: 1.11.0
489+
490+
Amount (in MW) given how many MW have beeen "detached"
491+
for each storage unit on the grid. It is 0 for
492+
storage unit still connected to the grid and only available for
493+
environment supporting detachment.
449494
450495
_shunt_p: :class:`numpy.ndarray`, dtype:float
451496
Shunt active value (only available if shunts are available) (in MW)
@@ -1294,6 +1339,8 @@ def _aux_process_grid2op_compat_1_11_0(cls):
12941339
"load_q_detached",
12951340
"gen_p_detached",
12961341
"storage_p_detached",
1342+
# protection (>= 1.11.0)
1343+
"timestep_protection_engaged"
12971344
]:
12981345
try:
12991346
cls.attr_list_vect.remove(el)

0 commit comments

Comments
 (0)