Skip to content

Commit

Permalink
Merge pull request #189 from BDonnot/bd_dev
Browse files Browse the repository at this point in the history
Bd dev
  • Loading branch information
BDonnot authored Mar 6, 2024
2 parents 3a36498 + a9ffd3c commit d44196c
Show file tree
Hide file tree
Showing 27 changed files with 946 additions and 231 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Change Log
- [???] properly model interconnecting powerlines


[1.9.9] - 2024-xx-yy
[1.10.0] - 2024-03-06
----------------------
- [BREAKING] the order of the actions in `env.action_space.get_all_unitary_line_set` and
`env.action_space.get_all_unitary_topologies_set` might have changed (this is caused
Expand Down Expand Up @@ -75,6 +75,7 @@ Change Log
- [IMPROVED] type hints for the `gym_compat` module (more work still required in this area)
- [IMPROVED] the `MultiDiscreteActSpace` to have one "dimension" controling all powerlines
(see "one_line_set" and "one_line_change")
- [IMPROVED] doc at different places, including the addition of the MDP implemented by grid2op.

[1.9.8] - 2024-01-26
----------------------
Expand Down
14 changes: 9 additions & 5 deletions docs/action.rst
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@ As we explained in the previous paragraph, some action on one end of a powerline
powerline or disconnect it. This means they modify the bus of **both** the extremity of the powerline.

Here is a table summarizing how the buses are impacted. We denoted by "`PREVIOUS_OR`" the last bus at which
the origin end of the powerline was connected and "`PREVIOUS_EX`" the last bus at which the extremity end of the
the origin side of the powerline was connected and "`PREVIOUS_EX`" the last bus at which the extremity side of the
powerline was connected. Note that for clarity when something is not modified by the action we decided to write on
the table "not modified" (this entails that after this action, if the powerline is connected then "new origin bus" is
"`PREVIOUS_OR`" and "new extremity bus" is "`PREVIOUS_EX`"). We remind the reader that "-1" encode for a
Expand Down Expand Up @@ -459,14 +459,18 @@ package that was formerly "openAI gym").

This includes:

- :class:`grid2op.gym_compat.GymActionSpace` which "represents" actions as a gymnasium `Dict`
- :class:`grid2op.gym_compat.BoxGymActSpace` which represents actions as gymnasium `Box`
- :class:`grid2op.gym_compat.GymActionSpace` which "represents" actions as a gymnasium
`Dict <https://gymnasium.farama.org/api/spaces/composite/#dict>`_
- :class:`grid2op.gym_compat.BoxGymActSpace` which represents actions as gymnasium
`Box <https://gymnasium.farama.org/api/spaces/fundamental/#box>`_
(actions are numpy arrays). This is especially suited for continuous attributes
such as redispatching, storage or curtailment.
- :class:`grid2op.gym_compat.DiscreteActSpace` which represents actions as gymnasium `Discrete`
- :class:`grid2op.gym_compat.DiscreteActSpace` which represents actions as gymnasium
`Discrete <https://gymnasium.farama.org/api/spaces/fundamental/#discrete>`_
(actions are integer). This is especially suited for discrete actions such as
setting line status or topologies at substation.
- :class:`grid2op.gym_compat.MultiDiscreteActSpace` which represents actions as gymnasium `Discrete`
- :class:`grid2op.gym_compat.MultiDiscreteActSpace` which represents actions as gymnasium
`MultiDiscrete <https://gymnasium.farama.org/api/spaces/fundamental/#multidiscrete>`_
(actions are integer). This is also especially suited for discrete actions such as
setting line status or topologies at substation.

Expand Down
76 changes: 39 additions & 37 deletions docs/createbackend.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,12 @@ stored in the attribute `self._grid` that can be anything.
grid2op will only use the information given in the `*_infos()` methods
(*eg* :func:`grid2op.Backend.Backend.loads_info`) and never by directly accessing `self._grid`

In other words, `self._grid` can be anything: a PandaPower `Network`, a GridCal `MultiCircuit`,
a lightsim2grid `GridModel`, a pypowsybl `Network` (or `SortedNetwork`),
a powerfactory `Project` etc. Grid2op will never attempt to access `self._grid`
In other words, `self._grid` can be anything: a `PandaPower <https://pandapower.readthedocs.io/en/latest/>`_ `Network`, a
`GridCal <https://gridcal.readthedocs.io/en/latest/>`_ `MultiCircuit`,
a `lightsim2grid <lightsim2grid.readthedocs.io/>`_ `GridModel`, a
`pypowsybl <pypowsybl.readthedocs.io/>`_ `Network` (or `SortedNetwork`),
a `powerfactory <https://www.digsilent.de/en/scripting-and-automation.html>` `Project` etc.
Grid2op will never attempt to access `self._grid`

(Though, to be perfectly honest, some agents might rely on some type `_grid`, if that's the case, too
bad for these agents they will need to implement special methods to be compatible with your backend.
Expand Down Expand Up @@ -195,8 +198,9 @@ There are 4 **__main__** types of method you need to implement if you want to us

.. _grid-description:

Grid description
------------------
load_grid: Grid description
----------------------------

In this section we explicit what attributes need to be implemented to have a valid backend instance. We focus on
the attribute of the `Backend` you have to set. But don't forget you also need to load a powergrid and store
it in the `_grid` attribute.
Expand All @@ -207,18 +211,16 @@ Basically the `load_grid` function would look something like:
def load_grid(self, path=None, filename=None):
# simply handles different way of inputing the data
if path is None and filename is None:
raise RuntimeError("You must provide at least one of path or file to load a powergrid.")
if path is None:
full_path = filename
elif filename is None:
full_path = path
else:
full_path = os.path.join(path, filename)
if not os.path.exists(full_path):
raise RuntimeError("There is no powergrid at \"{}\"".format(full_path))
# load the grid in your favorite format:
full_path = self.make_complete_path(path, filename)
# from grid2op 1.10.0 you need to call one of
self.can_handle_more_than_2_busbar() # see doc for more information
OR
self.cannot_handle_more_than_2_busbar() # see doc for more information
# It is important you include it at the top of this method, otherwise you
# will not have access to self.n_busbar_per_sub
# load the grid in your favorite format, located at `full_path`:
self._grid = ... # the way you do that depends on the "solver" you use
# and now initialize the attributes (see list bellow)
Expand Down Expand Up @@ -256,7 +258,7 @@ Name See paragraph Type Size Description
`line_ex_to_subid`_ :ref:`subid` vect, int `n_line`_ For each powerline, it gives the substation id to which its **extremity** end is connected
`name_load`_ vect, str `n_load`_ (optional) name of each load on the grid [if not set, by default it will be "load_$LoadSubID_$LoadID" for example "load_1_10" if the load with id 10 is connected to substation with id 1]
`name_gen`_ vect, str `n_gen`_ (optional) name of each generator on the grid [if not set, by default it will be "gen_$GenSubID_$GenID" for example "gen_2_42" if the generator with id 42 is connected to substation with id 2]
`name_line`_ vect, str `n_line`_ (optional) name of each powerline (and transformers !) on the grid [if not set, by default it will be "$SubOrID_SubExID_LineID" for example "1_4_57" if the powerline with id 57 has its origin end connected to substation with id 1 and its extremity end connected to substation with id 4]
`name_line`_ vect, str `n_line`_ (optional) name of each powerline (and transformers !) on the grid [if not set, by default it will be "$SubOrID_SubExID_LineID" for example "1_4_57" if the powerline with id 57 has its origin side connected to substation with id 1 and its extremity side connected to substation with id 4]
`name_sub`_ vect, str `n_sub`_ (optional) name of each substation on the grid [if not set, by default it will be "sub_$SubID" for example "sub_41" for the substation with id 41]
`sub_info`_ :ref:`sub-i` vect, int `n_sub`_ (can be automatically set if you don't initialize it) For each substation, it gives the number of elements connected to it ("elements" here denotes: powerline - and transformer- ends, load or generator)
`dim_topo`_ :ref:`sub-i` int NA (can be automatically set if you don't initialize it) Total number of elements on the grid ("elements" here denotes: powerline - and transformer- ends, load or generator)
Expand Down Expand Up @@ -321,7 +323,7 @@ extremely complex way to say you have to do this:
Note the number for each element in the substation.

In this example, for substaion with id 0 (bottom left) you decided
that the powerline with id 0 (connected at this substation at its origin end) will be the "first object of this
that the powerline with id 0 (connected at this substation at its origin side) will be the "first object of this
substation". Then the "Load 0" is the second object [remember index a 0 based, so the second object has id 1],
generator 0 is the third object of this substation (you can know it with the "3" near it) etc.

Expand Down Expand Up @@ -445,12 +447,12 @@ First, have a look at substation 0:

You know that, at this substation 0 there are `6` elements connected. In this example, these are:

- origin end of Line 0
- origin side of Line 0
- Load 0
- gen 0
- origin end of line 1
- origin end of line 2
- origin end of line 3
- origin side of line 1
- origin side of line 2
- origin side of line 3

Given that, you can fill:

Expand All @@ -475,12 +477,12 @@ You defined (in a purely arbitrary manner):

So you get:

- first component of `line_or_to_sub_pos` is 0 [because "origin end of line 0" is "element 0" of this substation]
- first component of `line_or_to_sub_pos` is 0 [because "origin side of line 0" is "element 0" of this substation]
- first component of `load_to_sub_pos` is 1 [because "load 0" is "element 1" of this substation]
- first component of `gen_to_sub_pos` is 2 [because "gen 0" is "element 2" of this substation]
- fourth component of `line_or_to_sub_pos` is 3 [because "origin end of line 3" is "element 3" of this substation]
- third component of `line_or_to_sub_pos` is 4 [because "origin end of line 2" is "element 4" of this substation]
- second component of `line_or_to_sub_pos` is 5 [because "origin end of line 1" is "element 5" of this substation]
- fourth component of `line_or_to_sub_pos` is 3 [because "origin side of line 3" is "element 3" of this substation]
- third component of `line_or_to_sub_pos` is 4 [because "origin side of line 2" is "element 4" of this substation]
- second component of `line_or_to_sub_pos` is 5 [because "origin side of line 1" is "element 5" of this substation]

This is showed in the figure below:

Expand Down Expand Up @@ -513,7 +515,7 @@ of your implementation of `load_grid` function)

.. _backend-action-create-backend:

BackendAction: modification
apply_action: underlying grid modification
----------------------------------------------
In this section we detail step by step how to understand the specific format used by grid2op to "inform" the backend
on how to modify its internal state before computing a powerflow.
Expand Down Expand Up @@ -580,22 +582,22 @@ At the end, the `apply_action` function of the backend should look something lik
... # the way you do that depends on the `internal representation of the grid`
lines_or_bus = backendAction.get_lines_or_bus()
for line_id, new_bus in lines_or_bus:
# modify the "busbar" of the origin end of powerline line_id
# modify the "busbar" of the origin side of powerline line_id
if new_bus == -1:
# the origin end of powerline is disconnected in the action, disconnect it on your internal representation of the grid
# the origin side of powerline is disconnected in the action, disconnect it on your internal representation of the grid
... # the way you do that depends on the `internal representation of the grid`
else:
# the origin end of powerline is moved to either busbar 1 (in this case `new_bus` will be `1`)
# the origin side of powerline is moved to either busbar 1 (in this case `new_bus` will be `1`)
# or to busbar 2 (in this case `new_bus` will be `2`)
... # the way you do that depends on the `internal representation of the grid`
lines_ex_bus = backendAction.get_lines_ex_bus()
for line_id, new_bus in lines_ex_bus:
# modify the "busbar" of the extremity end of powerline line_id
# modify the "busbar" of the extremity side of powerline line_id
if new_bus == -1:
# the extremity end of powerline is disconnected in the action, disconnect it on your internal representation of the grid
# the extremity side of powerline is disconnected in the action, disconnect it on your internal representation of the grid
... # the way you do that depends on the `internal representation of the grid`
else:
# the extremity end of powerline is moved to either busbar 1 (in this case `new_bus` will be `1`)
# the extremity side of powerline is moved to either busbar 1 (in this case `new_bus` will be `1`)
# or to busbar 2 (in this case `new_bus` will be `2`)
... # the way you do that depends on the `internal representation of the grid`
Expand Down Expand Up @@ -695,8 +697,8 @@ And of course you do the same for generators and both ends of each powerline.

.. _vector-orders-create-backend:

Read back the results (flows, voltages etc.)
-----------------------------------------------
***_infos() : Read back the results (flows, voltages etc.)
--------------------------------------------------------------
This last "technical" part concerns what can be refer to as "getters" from the backend. These functions allow to
read back the state of the grid and expose its results to grid2op in a standardize manner.
Expand Down Expand Up @@ -797,7 +799,7 @@ And you do chat for all substations, giving:

So in this simple example, the first element of the topology vector will represent the origin of powerline 0,
the second element will represent the load 0, the 7th element (id 6, remember python index are 0 based) represent
first element of substation 1, so in this case extremity end of powerline 3, the 8th element the generator 1, etc.
first element of substation 1, so in this case extremity side of powerline 3, the 8th element the generator 1, etc.
up to element with id 20 whith is the last element of the last substation, in this case extremity of powerline 7.

Once you know the order, the encoding is pretty straightforward:
Expand Down
6 changes: 3 additions & 3 deletions docs/grid_graph.rst
Original file line number Diff line number Diff line change
Expand Up @@ -326,11 +326,11 @@ To know what element of the grid is the "42nd", you can:
case the extremity side of powerline `line_id`.
2) look at the table :attr:`grid2op.Space.GridObjects.grid_objects_types` and especially the line 42 so
`env.grid_objects_types[42,:]` which contains this information as well. Each column of this table encodes
for one type of element (first column is substation, second is load, then generator, then origin end of
powerline then extremity end of powerline and finally storage unit. Each will have "-1" if the element
for one type of element (first column is substation, second is load, then generator, then origin side of
powerline then extremity side of powerline and finally storage unit. Each will have "-1" if the element
is not of that type, and otherwise and id > 0. Taking the same example as for the above bullet point!
`env.grid_objects_types[42,:] = [sub_id, -1, -1, -1, line_id, -1]` meaning the "42nd" element of the grid
if the extremity end (because it's the 5th column) of id `line_id` (the other element being marked as "-1").
if the extremity side (because it's the 5th column) of id `line_id` (the other element being marked as "-1").
3) refer to the :func:`grid2op.Space.GridObject.topo_vect_element` for an "easier" way to retrieve information
about this element.

Expand Down
Loading

0 comments on commit d44196c

Please sign in to comment.