Action
This page is organized as follow:
Objectives
The “Action” module lets you define some actions on the underlying power _grid. These actions are either made by an agent, or by the environment.
For now, the actions can act on:
the “injections” and allows you to change:
the generators active power production setpoint
the generators voltage magnitude setpoint
the loads active power consumption
the loads reactive power consumption
the status of the powerlines (connected/disconnected)
the configuration at substations eg setting different objects to different buses for example
The BaseAction class is abstract. You can implement it the way you want. If you decide to extend it, make sure
that the grid2op.Backend
class will be able to understand it. If you don’t, your extension will
not affect the
underlying powergrid. Indeed a grid2op.Backend
will call the BaseAction.__call__()
method
and should
understands its return type.
The BaseAction
and all its derivatives also offer some useful inspection utilities:
BaseAction.__str__()
prints the action in a format that gives useful information on how it will affect the powergrid
BaseAction.effect_on()
returns a dictionary that gives information about its effect.
From BaseAction
inherit in particular the PlayableAction
, the base class of all action that
players are allowed to play.
Finally, BaseAction
class define some strict behavior to follow if reimplementing them.
The correctness of each
instances of BaseAction is assessed both when calling BaseAction.update()
or with a call to
BaseAction._check_for_ambiguity()
performed for example by the Backend when it must implement
its effect on the
powergrid through a call to BaseAction.__call__()
Constructing an action in grid2op is made in the following manner:
import grid2op
env = grid2op.make("l2rpn_case14_sandbox")
dictionary_describing_the_action = {...} # se bellow
my_action = env.action_space(dictionary_describing_the_action)
print(my_action)
On the above code, dictionary_describing_the_action should be a dictionary that describe what action
you want to perform on the grid. For more information you can consult the help of the BaseAction.update()
.
To avoid extremely verbose things, as of grid2op 1.5.0, we introduced some convenience functions to allow easier action construction. You can now do act.load_set_bus = … instead of the previously way more verbose act.update({“set_bus”: {“loads_id”: …}})
Main action “properties”
In the table below, we present the main properties that you can use to code, using the grid2op framework, the action that you want to perform on the grid.
Name(s) |
Type |
Size (each) |
---|---|---|
int |
||
int |
||
int |
||
int |
||
int |
||
int |
||
bool |
||
bool |
||
bool |
||
bool |
||
bool |
||
bool |
||
int |
||
bool |
||
float |
||
float |
||
float |
All the attributes above are “properties”, you don’t have to use parenthesis to access them:
# valid code
gen_buses = act.gen_change_bus
# do not run
# invalid code, it will "crash", do not run
gen_buses = act.gen_change_bus()
# end do not run
And neither should you uses parenthesis to modify them:
# valid code
act.load_set_bus = [(1, 2) , (2, 1), (3, 1)]
# invalid code, it will crash, do not run
act.load_set_bus([(1, 2) , (2, 1), (3, 1)])
# end do not run
Property cannot be set “directly”, you have to use the act.XXX = .. syntax. For example:
# valid code
act.line_change_status = [1, 3, 4]
# invalid code, it will raise an error, and even if it did not it would have not effect
# do not run
act.line_change_status[1] = True
# end do not run
Usage Examples
In this section, we describe how to implement some action types. For further information about the impact of the action implemented, please consult the appropriate getting_started notebook.
Set bus
The “properties” concerned by this sections are: set_bus, gen_set_bus, load_set_bus, line_or_set_bus, line_ex_set_bus and storage_set_bus. They all work in the same fashion, a detailed explanation is provided in the gen_set_bus help page.
Concretely, to perform a “set_bus” action you need to provide 2 elements: the id of the object you want to modify, and where you want to place it.
For example, if you want to change the element (regardless of its type) 5, and set it to busbar 2:
act = env.action_space() # create an action
act.set_bus = [(5, 2)] # perform the desired modification
You can modify as many elements as you want:
act = env.action_space() # create an action
act.set_bus = [(5, 2), (6, 1)]
# equivalent to:
act2 = env.action_space() # create an action
act2.set_bus = [(5, 2)]
act2.set_bus = [(6, 1)]
And if you want to modify everything on the same action, you can do:
act = env.action_space() # create an action
act_vect = ... # for example `act_vect = np.random.choice([-1, 1, 2], size=act.dim_topo)`
act.set_bus = act_vect
In the example above, act_vect can, for example, come from a neural network that is able to predict a “good” state of the grid, the one that it “wants”.
Note
In the example above, act_vect should be a vector of integer.
Change bus
The “properties” concerned by this sections are: change_bus, gen_change_bus, load_change_bus, line_or_change_bus, line_ex_change_bus and storage_change_bus. They all work in the same fashion, a detailed explanation is provided in the gen_change_bus help page.
Concretely, to perform a “change_bus” action you need to provide 1 element: the id of the element you want to change.
For example, if you want to change the element (regardless of its type) 5, and change the busbar on which it is connected:
act = env.action_space() # create an action
act.set_bus = [5] # perform the desired modification
You can modify as many elements as you want:
act = env.action_space() # create an action
act.change_bus = [5, 6]
# equivalent to:
act2 = env.action_space() # create an action
act2.change_bus = [5]
act2.change_bus = [6]
And if you want to modify everything on the same action, you can do:
act = env.action_space() # create an action
act_vect = ... # for example `act_vect = np.random.choice([0, 1], size=act.dim_topo).astype(bool)`
act.change_bus = act_vect
In the example above, act_vect can, for example, come from a neural network that is able to predict a “good” state of the grid, the one that it “wants”.
Note
In the example above, act_vect should be a vector of boolean.
Note
If an element is disconnected, performing a “change_bus” action on this element will have not effect.
Note
Aside from reconnecting elements, which can be done only using the “set_bus” actions, the “change_bus” and “set_bus” leads to equivalent grid states. For each state obs_t, for each “change_bus” action a_change, there exists a “set_bus” action a_set such that env.step(a_change) has exactly the same impact as env.step(a_set) (note that the a_set equivalent to a_change depends on the current state of the environment, of course).
We introduced in grid2op the two (equivalent) representation not to limit agent. If we make the parallel with oter RL environment, “change_bus” can be thought as “turn left” or “turn right” whereas “set_bus” is more “go at position (x,y)”.
Set status
TODO
Change status
TODO
Redispatching
TODO
Storage power setpoint
TODO
Getting the resulting topology after an action
Unfortunately, it is sometimes relatively difficult to understand what will be the exact effect of a given action on a powergrid.
This mainly caused by the fact that the modeled environment embed some complexity of a real powergrid.
To ease the process of estimating the impact of an action on a environment, tow main functions have been developed and are available:
obs.simulate(act, time_step=0) which will “apply” the action on the known state and do “as if” a step has been made. This is called “simulate”, it is rather accurate (up to the “we don’t know the future” part) in the sense that is does check for illegal actions, ambiguous actions, reconnect properly the powerlines if needed etc. and performs simulation of “cascading failures” and other things. Of course it takes a lot of time to carry out all these computation.
impact = obs + act (since grid2op 1.5.0). On the other hand, the “+” operator of the observation is much faster. It can be use to rapidly estimate the state of the grid (especially the topology) after the application of an action for example. This is to ease the process of studying what does an action exactly.
The difference in computation time, for an action of type “topology set” is shown in the table below:
method |
env name |
backend used |
time to perform (ms) |
---|---|---|---|
obs + act |
l2rpn_case14_sandbox |
pandapower |
0.21 |
obs.simulate(act, time_step=0) |
l2rpn_case14_sandbox |
pandapower |
17.3 |
obs + act |
l2rpn_case14_sandbox |
lightsim2grid |
0.21 |
obs.simulate(act, time_step=0) |
l2rpn_case14_sandbox |
lightsim2grid |
1.56 |
obs + act |
l2rpn_neurips_2020_track2_small |
pandapower |
0.22 |
obs.simulate(act, time_step=0) |
l2rpn_neurips_2020_track2_small |
pandapower |
33.4 |
obs + act |
l2rpn_neurips_2020_track2_small |
lightsim2grid |
0.22 |
obs.simulate(act, time_step=0) |
l2rpn_neurips_2020_track2_small |
lightsim2grid |
2.03 |
(results were obtained with grid2op version 1.5.0 on a “Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz” using “Python 3.8.5 (default, Jul 28 2020, 12:59:40) [GCC 9.3.0] on linux” on ubuntu 20.04.1 “20.04.1-Ubuntu SMP Tue Jan 12 16:39:47 UTC 2021” using linux kernel “5.8.0-38-generic”)
As you can see, the obs + act method is always approximately 10 times faster than the obs.simulate(act, time_step=0) [of course providing much less information] and can be up to 150 faster on larger grid (IEEE 118) using the default pandapower backend.
We can also note that, as it doesn’t require the use of any simulation, the time to do the obs + act is more or less independent of the grid size (0.21 ms for a grid counting 14 substations and 0.22ms for a grid with 118 substations) while the obs.simulate is not.
Now to retrieve a “graph like” object, you can :
# method 1
sim_obs, *_ = obs.simulate(act)
# method 2
obs_add = obs + add
And refer to the page A grid, a graph: grid2op representation of the powergrid or the section But where is the graph ? to retrieve a graph structure from these observations.
For example:
bus_bus_mat = obs_add.bus_connectivity_matrix() # alternatively `sim_obs.bus_connectivity_matrix()`
# or
connect_mat = obs_add.connectivity_matrix() # alternatively `sim_obs.connectivity_matrix()`
Illegal vs Ambiguous
Manipulating a powergrid is more complex than asking “pacman” to move “left” / “down” / “right” or “up”. Computing a correct action can be a tedious process.
An action can be incorrect because of two main factors:
ambiguous
: this will be the case when an action is performed on 17 objects whereas the given substations counts only 16 of them, this will be the case when you ask to reconnect powerline 999 while there are only 20 powerlines on the grid etc. This is raised when the action cannot be understood as a correct action. Grid2op does not know how to interpret your action. If we take the “PacMan” game an ambiguous action would translate in moving “up” and “down” at the same time.illegal
: (seegrid2op.Rules.BaseRules
andgrid2op.Parameters.Parameters
for more information). An action can be legal or illegal depending on the rules of the game. For example, we could forbid to reconnect powerline 7 between time steps 123 and 159 (this would corresponds to a “maintenance” of the powerline, you can imagine people painting the tower for example). But that does not mean reconnecting powerline 7 is forbidden at other times steps. In this case we say the action is “illegal”. Still my overall favorite game, in PacMan this would be the equivalent to moving left while there are a wall on the left.
Ambiguous or Illegal, the action will be replaced by a “do nothing” without any other incidents on the game.
Note on powerline status
As of grid2op version 1.2.0, we attempted to clean and rationalize the API concerning the change of powerline status (see explanatory notebook getting_started/3_Action_GridManipulation for more detailed explanation.
The powerline status (connected / disconnected) can now be affected in two different ways:
by setting / changing its status directly (using the “set_line_status” or “change_line_status” keyword).
[NEW] by modifying the bus on any of the end (origin or extremity) of a powerline
In that later case, the behavior is:
if the bus of a powerline end (origin or extremity) is “set” to -1 and not modified at the other and if the powerline was connected, it will disconnect this powerline
if the bus of a powerline end (origin or extremity) is “set” to 1 or 2 at one end and not modified at the other and if the powerline was connected, it will reconnect the powerline
if the bus of a powerline end (origin or extremity) is “set” to -1 at one end and set to 1 or 2 at its other end the action is ambiguous.
The way to compute the impact of the action has also been adjusted to reflect these changes.
In the table below we try to summarize all the possible actions and their impact on the powerline. This table is made considering that “LINE_ID” is an id of a powerline and “SUB_OR” is the id of the origin of the substation. If a status is 0 it means the powerlines is disconnected, if the status is 1 it means it is connected.
action |
original status |
final status |
substations affected |
line status affected |
---|---|---|---|---|
{“set_line_status”: [(LINE_ID, -1)]} |
1 |
0 |
None |
LINE_ID |
{“set_line_status”: [(LINE_ID, +1)]} |
1 |
1 |
None |
LINE_ID |
{“set_line_status”: [(LINE_ID, -1)]} |
0 |
0 |
None |
LINE_ID |
{“set_line_status”: [(LINE_ID, +1)]} |
0 |
1 |
None |
LINE_ID |
{“change_line_status”: [LINE_ID]} |
1 |
0 |
None |
LINE_ID |
{“change_line_status”: [LINE_ID]} |
0 |
1 |
None |
LINE_ID |
{“set_bus”: {“lines_or_id”: [(LINE_ID, -1)]}} |
1 |
0 |
None |
INE_ID |
{“set_bus”: {“lines_or_id”: [(LINE_ID, -1)]}} |
0 |
0 |
SUB_OR |
None |
{“set_bus”: {“lines_or_id”: [(LINE_ID, 2)]}} |
1 |
1 |
SUB_OR |
None |
{“set_bus”: {“lines_or_id”: [(LINE_ID, 2)]}} |
0 |
1 |
None |
LINE_ID |
{“change_bus”: {“lines_or_id”: [LINE_ID]}} |
1 |
1 |
SUB_OR |
None |
{“change_bus”: {“lines_or_id”: [LINE_ID]}} |
0 |
0 |
SUB_OR |
None |
This has other impacts. In grid2op there is a convention that if an object is disconnected, then it is assigned to bus “-1”. For a powerline this entails that a status changed affects the bus of
As we explained in the previous paragraph, some action on one end of a powerline can reconnect a 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 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 disconnected object.
action |
original status |
final status |
new origin bus |
new extremity bus |
---|---|---|---|---|
{“set_line_status”: [(LINE_ID, -1)]} |
1 |
0 |
-1 |
-1 |
{“set_line_status”: [(LINE_ID, +1)]} |
1 |
1 |
Not modified |
Not modified |
{“set_line_status”: [(LINE_ID, -1)]} |
0 |
0 |
Not modified |
Not modified |
{“set_line_status”: [(LINE_ID, +1)]} |
0 |
1 |
PREVIOUS_OR |
PREVIOUS_EX |
{“change_line_status”: [LINE_ID]} |
1 |
0 |
-1 |
-1 |
{“change_line_status”: [LINE_ID]} |
0 |
1 |
PREVIOUS_OR |
PREVIOUS_EX |
{“set_bus”: {“lines_or_id”: [(LINE_ID, -1)]}} |
1 |
0 |
-1 |
-1 |
{“set_bus”: {“lines_or_id”: [(LINE_ID, -1)]}} |
0 |
0 |
Not modified |
Not modified |
{“set_bus”: {“lines_or_id”: [(LINE_ID, 2)]}} |
1 |
1 |
2 |
Not modified |
{“set_bus”: {“lines_or_id”: [(LINE_ID, 2)]}} |
0 |
1 |
2 |
PREVIOUS_EX |
{“change_bus”: {“lines_or_id”: [LINE_ID]}} |
1 |
1 |
* |
Not modified |
{“change_bus”: {“lines_or_id”: [LINE_ID]}} |
0 |
0 |
Not modified |
Not modified |
* means that this bus is affected: if it was on bus 1 it moves on bus 2 and vice versa.
Note on random actions
Sampling a “non ambiguous” legal action is a difficult task.
TODO
Easier actions manipulation
The action class presented here can be quite complex to apprehend, especially for a machine learning algorithm.
Grid2op offers some more “convient” manipulation of the powergrid by transforming this rather “descriptive” action formulation to “action_space” that are compatible with Farama Fundation Gymnasium package ( package that was formerly “openAI gym”).
This includes:
grid2op.gym_compat.GymActionSpace
which “represents” actions as a gymnasium Dictgrid2op.gym_compat.BoxGymActSpace
which represents actions as gymnasium Box (actions are numpy arrays). This is especially suited for continuous attributes such as redispatching, storage or curtailment.grid2op.gym_compat.DiscreteActSpace
which represents actions as gymnasium Discrete (actions are integer). This is especially suited for discrete actions such as setting line status or topologies at substation.grid2op.gym_compat.MultiDiscreteActSpace
which represents actions as gymnasium MultiDiscrete (actions are integer). This is also especially suited for discrete actions such as setting line status or topologies at substation.
Note
The main difference between grid2op.gym_compat.DiscreteActSpace
and
grid2op.gym_compat.MultiDiscreteActSpace
is that Discrete actions will
allow the agent to perform only one type of action at each step (either it performs
redispatching on one generator OR on another generator OR it set the status of a powerline
OR it set the substation at one substation etc. but it cannot “peform redispatching on
2 or more generators” nor can it “perform redispatching on one generator AND disconnect a powerline”)
which can be rather limited for some applications.
Detailed Documentation by class
Classes:
|
|
|
This is a base class for each |
|
Class representing the possibility to play everything. |
|
This type of |
|
INTERNAL |
|
From this class inherit all actions that the player will be allowed to do. |
|
This type of |
This type of |
|
TODO storage doc |
|
|
This type of |
This type of |
|
|
This class allows serializing/ deserializing the action space. |
|
This type of |
|
This type of |
|
This type of |
This type of |
|
|
This type of |
|
This type of |
|
INTERNAL |
- class grid2op.Action.ActionSpace(gridobj, legal_action, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>, _local_dir_cls=None)[source]
ActionSpace
should be created by angrid2op.Environment.Environment
with its parameters coming from a properly set upgrid2op.Backend.Backend
(ie a Backend instance with a loaded powergrid. Seegrid2op.Backend.Backend.load_grid()
for more information).It will allow, thanks to its
ActionSpace.__call__()
method to create validBaseAction
. It is the the preferred way to create an object of classBaseAction
in this package.On the contrary to the
BaseAction
, it is NOT recommended to overload this helper. If more flexibility is needed on the type ofBaseAction
created, it is recommended to pass a different “actionClass” argument when it’s built. Note that it’s mandatory that the class used in the “actionClass” argument derived from theBaseAction
.- legal_action
Class specifying the rules of the game used to check the legality of the actions.
- Type:
grid2op.RulesChecker.BaseRules
Methods:
__call__
([dict_, check_legal, env, ...])This utility allows you to build a valid action, with the proper sizes if you provide it with a valid dictionary.
__init__
(gridobj, legal_action[, ...])INTERNAL USE ONLY
_custom_deepcopy_for_copy
(new_obj)implements a faster "res = copy.deepcopy(self)" to use in "self.copy" Do not use it anywhere else...
_is_legal
(action, env)INTERNAL USE ONLY
close
()INTERNAL
copy
()INTERNAL
- __call__(dict_: Dict[Literal['set_line_status', 'change_line_status', 'set_bus', 'change_bus', 'redispatch', 'set_storage', 'curtail', 'raise_alarm', 'raise_alert', 'injection', 'hazards', 'maintenance', 'shunt'], Any] | None = None, check_legal: bool = False, env: BaseEnv | None = None, _names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None) BaseAction [source]
This utility allows you to build a valid action, with the proper sizes if you provide it with a valid dictionary.
More information about this dictionary can be found in the
Action.update()
help. This dictionary is not changed in this method.NB This is the only recommended way to make a valid, with proper dimension
Action
object:Examples
Here is a short example on how to make a action. For more detailed examples see
Action.update()
import grid2op # create a simple environment env = grid2op.make("l2rpn_case14_sandbox") act = env.action_space({}) # act is now the "do nothing" action, that doesn't modify the grid.
- Parameters:
dict (
dict
) – seeAction.__call__()
documentation for an extensive help about this parametercheck_legal (
bool
) – is there a test performed on the legality of the action. NB When an object of classAction
is used, it is automatically tested for ambiguity. If this parameter is set toTrue
then a legality test is performed. An action can be illegal if the environment doesn’t allow it, for example if an agent tries to reconnect a powerline during a maintenance.env (
grid2op.Environment.Environment
, optional) – An environment used to perform a legality check.
- Returns:
res – An action that is valid and corresponds to what the agent want to do with the formalism defined in see
Action.udpate()
.- Return type:
Notes
This function is not in the “SerializableActionSpace” because the “legal_action” is not serialized. TODO ?
- __init__(gridobj, legal_action, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>, _local_dir_cls=None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
The actions space is created by the environment. Do not attempt to create one yourself.
All parameters (name_gen, name_load, name_line, sub_info, etc.) are used to fill the attributes having the same name. See
ActionSpace
for more information.- Parameters:
gridobj (
grid2op.Space.GridObjects
) – The representation of the powergrid.actionClass (
type
) – Note that this parameter expected a class and not an object of the class. It is used to return the appropriate action type.legal_action (
grid2op.RulesChecker.BaseRules
) – Class specifying the rules of the game used to check the legality of the actions.
- _custom_deepcopy_for_copy(new_obj)[source]
implements a faster “res = copy.deepcopy(self)” to use in “self.copy” Do not use it anywhere else…
- _is_legal(action, env)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Whether an action is legal or not is checked by the environment at each call to env.step
- Parameters:
action (
BaseAction
) – The action to testenv (
grid2op.Environment.Environment
) – The current environment
- Returns:
res –
True
if the action is legal, ie is allowed to be performed by the rules of the game.False
otherwise.- Return type:
bool
- class grid2op.Action.BaseAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This is a base class for each
BaseAction
objects. As stated above, an action represents conveniently the modifications that will affect a powergrid.It is not recommended to instantiate an action from scratch. The recommended way to get an action is either by modifying an existing one using the method
BaseAction.update()
or to call andActionSpace
object that has been properly set up by angrid2op.Environment
.BaseAction can be fully converted to and back from a numpy array with a fixed size.
An action can modify the grid in multiple ways. It can change :
the production and voltage setpoint of the generator units
the amount of power consumed (for both active and reactive part) for load
disconnect powerlines
change the topology of the _grid.
To be valid, an action should be convertible to a tuple of 5 elements:
the first element is the “injections” vector: representing the way generator units and loads are modified
It is, in turn, a dictionary with the following keys (optional)
“load_p” a vector of the same size of the load, giving the modification of the loads active consumption
“load_q” a vector of the same size of the load, giving the modification of the loads reactive consumption
“prod_p” a vector of the same size of the generators, giving the modification of the productions active setpoint production
“prod_v” a vector of the same size of the generators, giving the modification of the productions voltage setpoint
the second element is made of force line status. It is made of a vector of size
BaseAction._n_lines
(the number of lines in the powergrid) and is interpreted as:-1 force line disconnection
+1 force line reconnection
0 do nothing to this line
the third element is the switch line status vector. It is made of a vector of size
BaseAction.n_line
and is interpreted as:True
: change the line statusFalse
: don’t do anything
the fourth element set the buses to which the object is connected. It’s a vector of integers with the following interpretation:
0 -> don’t change
-1 -> disconnect the object.
1 -> connect to bus 1
2 -> connect to bus 2
3 -> connect to bus 3 (added in version 1.10.0)
etc. (added in version 1.10.0)
the fifth element changes the buses to which the object is connected. It’s a boolean vector interpreted as:
False
: nothing is doneTrue
: change the bus eg connect it to bus 1 if it was connected to bus 2 or connect it to bus 2 if it was connected to bus 1. NB this is only active if the system has only 2 buses per substation (that’s the case for the L2RPN challenge).
the sixth element is a vector, representing the redispatching. Component of this vector is added to the generators active setpoint value (if set) of the first elements.
NB the difference between
BaseAction._set_topo_vect
andBaseAction._change_bus_vect
is the following:If a component of
BaseAction._set_topo_vect
is 1, then the object (load, generator or powerline) will be moved to bus 1 of the substation to which it is connected. If it is already to bus 1 nothing will be done. If it’s on another bus it will connect it to bus 1. It’s disconnected, it will reconnect it and connect it to bus 1.If a component of
BaseAction._change_bus_vect
is True, then the object will be moved from one bus to another. If the object were on bus 1 it will be moved on bus 2, and if it were on bus 2, it will be moved on bus 1. If the object were disconnected, then this does nothing.
The conversion to the action into an understandable format by the backend is performed by the “update” method, that takes into account a dictionary and is responsible to convert it into this format. It is possible to overload this class as long as the overloaded
BaseAction.__call__()
operator returns the specified format, and theBaseAction.__init__()
method has the same signature.This format is then digested by the backend and the powergrid is modified accordingly.
- _set_line_status
For each powerline, it gives the effect of the action on the status of it. It should be understood as:
-1: disconnect the powerline
0: don’t affect the powerline
+1: reconnect the powerline
- Type:
numpy.ndarray
, dtype:int
- _switch_line_status
For each powerline, it informs whether the action will switch the status of a powerline of not. It should be understood as followed:
False
: the action doesn’t affect the powerlineTrue
: the action affects the powerline. If it was connected, it will disconnect it. If it was disconnected, it will reconnect it.
- Type:
numpy.ndarray
, dtype:bool
- _dict_inj
Represents the modification of the injection (productions and loads) of the power _grid. This dictionary can have the optional keys:
“load_p” to set the active load values (this is a numpy array with the same size as the number of load in the power _grid with Nan: don’t change anything, else set the value
“load_q”: same as above but for the load reactive values
“prod_p”: same as above but for the generator active setpoint values. It has the size corresponding to the number of generators in the test case.
“prod_v”: same as above but set the voltage setpoint of generator units.
- Type:
dict
- _set_topo_vect
Similar to
BaseAction._set_line_status
but instead of affecting the status of powerlines, it affects the bus connectivity at a substation. It has the same size as the full topological vector (BaseAction._dim_topo
) and for each element it should be understood as:0 -> don’t change
1 -> connect to bus 1
2 -> connect to bus 2
-1 -> disconnect the object.
- Type:
numpy.ndarray
, dtype:int
- _change_bus_vect
Similar to
BaseAction._switch_line_status
but it affects the topology at substations instead of the status of the powerline. It has the same size as the full topological vector (BaseAction._dim_topo
) and each component should mean:False
: the object is not affectedTrue
: the object will be moved to another bus. If it was on bus 1 it will be moved on bus 2, and if it was on bus 2 it will be moved on bus 1.
- Type:
numpy.ndarray
, dtype:bool
- authorized_keys
The set indicating which keys the actions can understand when calling
BaseAction.update()
- Type:
set
- _subs_impacted
This attributes is either not initialized (set to
None
) or it tells, for each substation, if it is impacted by the action (in this caseBaseAction._subs_impacted
[sub_id] isTrue
) or not (in this caseBaseAction._subs_impacted
[sub_id] isFalse
)- Type:
numpy.ndarray
, dtype:bool
- _lines_impacted
This attributes is either not initialized (set to
None
) or it tells, for each powerline, if it is impacted by the action (in this caseBaseAction._lines_impacted
[line_id] isTrue
) or not (in this caseBaseAction._subs_impacted
[line_id] isFalse
)- Type:
numpy.ndarray
, dtype:bool
- attr_list_vect
The authorized key that are processed by
BaseAction.__call__()
to modify the injections- Type:
list
, static
- attr_list_vect_set
The authorized key that is processed by
BaseAction.__call__()
to modify the injections- Type:
set
, static
- _redispatch
Amount of redispatching that this action will perform. Redispatching will increase the generator’s active setpoint value. This will be added to the value of the generators. The Environment will make sure that every physical constraint is met. This means that the agent provides a setpoint, but there is no guarantee that the setpoint will be achievable. Redispatching action is cumulative, this means that if at a given timestep you ask +10 MW on a generator, and on another you ask +10 MW then the total setpoint for this generator that the environment will try to implement is +20MW.
- Type:
numpy.ndarray
, dtype:float
- _storage_power
Amount of power you want each storage units to produce / absorbs. Storage units are in “loads” convention. This means that if you ask for a positive number, the storage unit will absorb power from the grid (=it will charge) and if you ask for a negative number, the storage unit will inject power on the grid (storage unit will discharge).
- Type:
numpy.ndarray
, dtype:float
- _curtail
For each renewable generator, allows you to give a maximum value (as ratio of Pmax, eg 0.5 => you limit the production of this generator to 50% of its Pmax) to renewable generators.
Warning
In grid2op we decided that the “curtailment” type of actions consists in directly providing the upper bound you the agent allowed for a given generator. It does not reflect the amount of MW that will be “curtailed” but will rather provide a limit on the number of MW a given generator can produce.
- Type:
numpy.ndarray
, dtype:float
Examples
Here are example on how to use the action, for more information on what will be the effect of each, please refer to the explanatory notebooks.
You have two main methods to build actions, as showed here:
import grid2op env_name = "l2rpn_case14_sandbox" # or any other name env = grid2op.make(env_name) # first method: action_description = {...} # see below act = env.action_space(action_description) # second method act = env.action_space() act.PROPERTY = MODIF
The description of action as a dictionary is the “historical” method. The method using the properties has been added to simplify the API.
To connect / disconnect powerline, using the “set” action, you can:
# method 1 act = env.action_space({"set_line_status": [(line_id, new_status), (line_id, new_status), ...]}) # method 2 act = env.action_space() act.line_set_status = [(line_id, new_status), (line_id, new_status), ...]
typically: 0 <= line_id <= env.n_line and new_status = 1 or -1
To connect / disconnect powerline using the “change” action type, you can:
# method 1 act = env.action_space({"change_line_status": [line_id, line_id, ...]}) # method 2 act = env.action_space() act.line_change_status = [line_id, line_id, ...]
typically: 0 <= line_id <= env.n_line
To modify the busbar at which an element is connected you can (if using set, to use “change” instead replace “set_bus” in the text below by “change_bus” eg nv.action_space({“change_bus”: …}) or act.load_change_bus = … ):
# method 1 act = env.action_space({"set_bus": {"lines_or_id": [(line_id, new_bus), (line_id, new_bus), ...], "lines_ex_id": [(line_id, new_bus), (line_id, new_bus), ...], "loads_id": [(load_id, new_bus), (load_id, new_bus), ...], "generators_id": [(gen_id, new_bus), (gen_id, new_bus), ...], "storages_id": [(storage_id, new_bus), (storage_id, new_bus), ...] } }) # method 2 act = env.action_space() act.line_or_set_bus = [(line_id, new_bus), (line_id, new_bus), ...] act.line_ex_set_bus = [(line_id, new_bus), (line_id, new_bus), ...] act.load_set_bus = [(load_id, new_bus), (load_id, new_bus), ...] act.gen_set_bus = [(gen_id, new_bus), (gen_id, new_bus), ...] act.storage_set_bus = [(storage_id, new_bus), (storage_id, new_bus), ...]
Of course you can modify one type of object at a time (you don’t have to specify all “lines_or_id”, “lines_ex_id”, “loads_id”, “generators_id”, “storages_id”
You can also give the topologies you want at each substations with:
# method 1 act = env.action_space({"set_bus":{ "substations_id": [(sub_id, topo_sub), (sub_id, topo_sub), ...] }}) # method 2 act = env.action_space() act.sub_set_bus = [(sub_id, topo_sub), (sub_id, topo_sub), ...]
In the above typically 0 <= sub_id < env.n_sub and topo_sub is a vector having the right dimension ( so if a substation has 4 elements, then topo_sub should have 4 elements)
It has to be noted that act.sub_set_bus will return a 1d vector representing the topology of the grid as “set” by the action, with the convention, -1 => disconnect, 0 => don’t change, 1=> set to bus 1 and 2 => set object to bus 2.
In order to perform redispatching you can do as follow:
# method 1 act = env.action_space({"redispatch": [(gen_id, amount), (gen_id, amount), ...]}) # method 2 act = env.action_space() act.redispatch = [(gen_id, amount), (gen_id, amount), ...]
Typically 0<= gen_id < env.n_gen and amount is a floating point between gen_max_ramp_down and gen_min_ramp_down for the generator modified.
In order to perform action on storage units, you can:
# method 1 act = env.action_space({"set_storage": [(storage_id, amount), (storage_id, amount), ...]}) # method 2 act = env.action_space() act.set_storage = [(storage_id, amount), (storage_id, amount), ...]
Typically 0 <= storage_id < env.n_storage and amount is a floating point between the maximum power and minimum power the storage unit can absorb / produce.
Finally, in order to perform curtailment action on renewable generators, you can:
# method 1 act = env.action_space({"curtail": [(gen_id, amount), (gen_id, amount), ...]}) # method 2 act = env.action_space() act.curtail = [(gen_id, amount), (gen_id, amount), ...]
Typically 0 <= gen_id < env.n_gen and amount is a floating point between the 0. and 1. giving the limit of power you allow each renewable generator to produce (expressed in ratio of Pmax). For example if gen_id=1 and amount=0.7 it means you limit the production of generator 1 to 70% of its Pmax.
Methods:
__add__
(other)Implements the + operator for the action using the += definition.
__call__
()INTERNAL USE ONLY
__eq__
(other)Test the equality of two actions.
__iadd__
(other)Add an action to this one.
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
__str__
()This utility allows printing in a human-readable format what objects will be impacted by the action.
INTERNAL
_assign_attr_from_name
(attr_nm, vect)INTERNAL
_aux_affect_object_bool
(values, name_el, ...)NB : this do not set the _modif_set_bus attribute.
_aux_affect_object_float
(values, name_el, ...)INTERNAL USE ONLY
_aux_affect_object_int
(values, name_el, ...)NB : this do not set the _modif_set_bus attribute.
This method checks if an action is ambiguous or not.
_digest_alarm
(dict_)_get_array_from_attr_name
(attr_name)INTERNAL
check if curtailment action is ambiguous
check if storage actions are ambiguous
called at the end of "from_vect" if the function requires post processing
INTERNAL USE ONLY
INTERNAL
INTERNAL
as_dict
()Represent an action "as a" dictionary.
This method returns an action as a dictionnary, that can be serialized using the "json" module.
This functions returns True if the current action has any chance to change the grid.
This method allows to check if this method is ambiguous per se (defined more formally as: whatever the observation at time t, and the changes that can occur between t and t+1, this action will be ambiguous).
curtailment_mw_to_ratio
(curtailment_mw)Transform a "curtailment" given as maximum MW to the grid2op formalism (in ratio of gen_pmax)
decompose_as_unary_actions
([group_topo, ...])This function allows to split a possibly "complex" action into its "unary" counterpart.
effect_on
([_sentinel, load_id, gen_id, ...])Return the effect of this action on a unique given load, generator unit, powerline or substation.
Computes and returns a vector that can be used in the
BaseAction.__call__()
with the keyword "set_status" if building anBaseAction
.Retrieve the modification that will be performed on all the generators
Retrieve the modification that will be performed on all the loads
Computes and returns a vector that can be used in the
BaseAction.__call__()
with the keyword "set_status" if building anBaseAction
.Retrieve the modification that will be performed on all the storage unit
get_topological_impact
([powerline_status])Gives information about the element being impacted by this action.
Shorthand to get the type of an action.
This will return a dictionary which contains details on objects that will be impacted by the action.
Says if the action, as defined is ambiguous per se or not.
limit_curtail_storage
(obs[, margin, ...])This function tries to limit the possibility to end up with a "game over" because actions on curtailment or storage units (see the "Notes" section for more information).
INTERNAL
remove possible shunts data from the classes, if shunts are deactivated
This function will modify 'self' and remove all "change" action type.
remove_line_status_from_topo
([obs, ...])New in version 1.8.0.
reset
()INTERNAL USE ONLY
update
(dict_)Update the action with a comprehensible format specified by a dictionary.
Attributes:
Allows to retrieve (and affect) the busbars at which any element is change.
another name for
BaseAction.change_line_status()
Allows to perfom some curtailment on some generators
Allows to perfom some curtailment on some generators in MW (by default in grid2Op it should be expressed in ratio of gen_pmax)
Allows to retrieve (and affect) the busbars at which the action change the generator units.
Allows to retrieve (and affect) the busbars at which the action set the generator units.
Property to set the status of the powerline.
Allows to retrieve (and affect) the busbars at which the extremity side of powerlines are changed.
Allows to retrieve (and affect) the busbars at which the extremity side of each powerline is set.
Allows to retrieve (and affect) the busbars at which the origin side of powerlines are changed.
Allows to retrieve (and affect) the busbars at which the action set the lines (origin side).
Property to set the status of the powerline.
Allows to retrieve (and affect) the busbars at which the loads is changed.
Allows to retrieve (and affect) the busbars at which the action set the loads.
Property to raise alert.
Allows to retrieve (and affect) the redispatching setpoint of the generators.
Allows to retrieve (and affect) the busbars at which any element is set.
another name for
BaseAction.line_set_status()
Another name for the property
BaseAction.storage_p()
Allows to retrieve (and affect) the busbars at which the storage units are changed.
Allows to modify the setpoint of the storage units.
Allows to retrieve (and affect) the busbars at which the action set the storage units.
- __add__(other) BaseAction [source]
Implements the + operator for the action using the += definition.
This function is not commutative !
Notes
Be careful if two actions do not share the same type (for example you want to add act1 of type
TopologyAction
to act2 of typeDispatchAction
) the results of act1 + act2 might differ from what you expect.The result will always of the same type as act1. In the above case, it means that the dispatch part of act2`will be ignored (because it is ignored in :class:`TopologyAction).
This is why we recommend to using this class directly with the
PlayableAction
or from action directly generated with env.action_space()
- __call__() Tuple[dict, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, dict] [source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
This method is used to return the effect of the current action in a format understandable by the backend. This format is detailed below.
This function must also integrate the redispatching strategy for the BaseAction.
It also performs a check of whether or not an action is “Ambiguous”, eg an action that reconnect a powerline but doesn’t specify on which bus to reconnect it is said to be ambiguous.
If this
BaseAction.__call__()
is overloaded, the call ofBaseAction._check_for_ambiguity()
must be ensured by this the derived class.- Returns:
dict_injection (
dict
) – This dictionnary isBaseAction._dict_inj
set_line_status (
numpy.ndarray
, dtype:int) – This array isBaseAction._set_line_status
switch_line_status (
numpy.ndarray
, dtype:bool) – This array isBaseAction._switch_line_status
set_topo_vect (
numpy.ndarray
, dtype:int) – This array isBaseAction._set_topo_vect
change_bus_vect (
numpy.ndarray
, dtype:bool) – This array isBaseAction._change_bus_vect
redispatch (
numpy.ndarray
, dtype:float) – This array, that has the same size as the number of generators indicates for each generator the amount of redispatching performed by the action.storage_power (
numpy.ndarray
, dtype:float) – Indicates, for all storage units, what is the production / absorbtion setpointcurtailment (
numpy.ndarray
, dtype:float) – Indicates, for all generators, which curtailment is applied (if any)shunts (
dict
) – A dictionary containing the shunts data, with keys: “shunt_p”, “shunt_q” and “shunt_bus” and the convention, for “shun_p” and “shunt_q” that Nan means “don’t change” and for shunt_bus: -1 => disconnect 0 don’t change, and 1 / 2 connect to bus 1 / 2
- Raises:
grid2op.Exceptions.AmbiguousAction – Or one of its derivate class.
- __eq__(other) bool [source]
Test the equality of two actions.
2 actions are said to be identical if they have the same impact on the powergrid. This is unrelated to their respective class. For example, if an Action is of class
Action
and doesn’t act on the injection, it can be equal to an Action of the derived classTopologyAction
(if the topological modifications are the same of course).This implies that the attributes
Action.authorized_keys
is not checked in this method.Note that if 2 actions don’t act on the same powergrid, or on the same backend (eg number of loads, or generators are not the same in self and other, or they are not in the same order) then action will be declared as different.
Known issue if two backends are different, but the description of the _grid are identical (ie all n_gen, n_load, n_line, sub_info, dim_topo, all vectors *_to_subid, and *_pos_topo_vect are identical) then this method will not detect the backend are different, and the action could be declared as identical. For now, this is only a theoretical behavior: if everything is the same, then probably, up to the naming convention, then the power grids are identical too.
- Parameters:
other (
BaseAction
) – An instance of class Action to which “self” will be compared.- Returns:
res – Whether the actions are equal or not.
- Return type:
bool
- __hash__ = None
- __iadd__(other: Self)[source]
Add an action to this one.
Adding an action to myself is equivalent to perform myself, and then perform other (but at the same step)
- Parameters:
other (
BaseAction
) –
Examples
import grid2op env_name = "l2rpn_case14_sandbox" # or any other name env = grid2op.make(env_name) act1 = env.action_space() act1.set_bus = ... # for example print("before += :") print(act1) act2 = env.action_space() act2.redispatch = ... # for example print(act2) act1 += act 2 print("after += ") print(act1)
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- __str__() str [source]
This utility allows printing in a human-readable format what objects will be impacted by the action.
- Returns:
str – The string representation of an
BaseAction
in a human-readable format.- Return type:
str
Examples
It is simply the “print” function:
action = env.action_space(...) print(action)
- _add_act_and_remove_line_status_only_set(other: BaseAction) BaseAction [source]
INTERNAL
This is used by the environment when combining action in the “set state” in env.reset.
It supposes both self and other are only “set” actions
New in version 1.10.2.
- _assign_attr_from_name(attr_nm, vect)[source]
INTERNAL
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Assign the proper attributes with name ‘attr_nm’ with the value of the vector vect
If this function is overloaded, then the _get_array_from_attr_name must be too.
- Parameters:
attr_nm –
vect –
doc (TODO) –
- _aux_affect_object_bool(values, name_el, nb_els, name_els, inner_vect, outer_vect, _nm_ch_bk_key=None)[source]
NB : this do not set the _modif_set_bus attribute. It is expected to be set in the property setter. This is not set here, because it’s recursive and if it fails at a point, it would be set for nothing
values: the new values to set name_el: “load” nb_els: self.n_load inner_vect: self.load_pos_topo_vect name_els: self.name_load outer_vect: self._change_bus_vect
will modify outer_vect[inner_vect]
- _aux_affect_object_float(values, name_el, nb_els, name_els, inner_vect, outer_vect, _nm_ch_bk_key=None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
NB : this do not set the _modif_set_bus attribute. It is expected to be set in the property setter. This is not set here, because it’s recursive and if it fails at a point, it would be set for nothing
values: the new values to set name_el: “load” nb_els: self.n_load inner_vect: self.load_pos_topo_vect name_els: self.name_load outer_vect: self._set_topo_vect
will modify outer_vect[inner_vect]
- _aux_affect_object_int(values, name_el, nb_els, name_els, inner_vect, outer_vect, min_val=-1, max_val=2, _nm_ch_bk_key: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
NB : this do not set the _modif_set_bus attribute. It is expected to be set in the property setter. This is not set here, because it’s recursive and if it fails at a point, it would be set for nothing
values: the new values to set name_el: “load” nb_els: self.n_load inner_vect: self.load_pos_topo_vect name_els: self.name_load outer_vect: self._set_topo_vect
will modify outer_vect[inner_vect]
- _check_for_ambiguity()[source]
This method checks if an action is ambiguous or not. If the instance is ambiguous, an
grid2op.Exceptions.AmbiguousAction
is raised.An action can be ambiguous in the following context:
It incorrectly affects the injections:
self._dict_inj["load_p"]
doesn’t have the same size as the number of loads on the _grid.self._dict_inj["load_q"]
doesn’t have the same size as the number of loads on the _grid.self._dict_inj["prod_p"]
doesn’t have the same size as the number of loads on the _grid.self._dict_inj["prod_v"]
doesn’t have the same size as the number of loads on the _grid.
It affects the powerline in an incorrect manner:
self._switch_line_status
has not the same size as the number of powerlinesself._set_line_status
has not the same size as the number of powerlinesthe status of some powerline is both changed (
self._switch_line_status[i] == True
for some i) and set (self._set_line_status[i]
for the same i is not 0)a powerline is both connected at one end (ex. its origin is set to bus 1) and disconnected at another (its extremity is set to bus -1)
It has an ambiguous behavior concerning the topology of some substations
the state of some bus for some element is both changed (
self._change_bus_vect[i] = True
for some i) and set (self._set_topo_vect[i]
for the same i is not 0)self._set_topo_vect
has not the same dimension as the number of elements on the powergridself._change_bus_vect
has not the same dimension as the number of elements on the powergrid
For redispatching, Ambiguous actions can come from:
Some redispatching action is active, yet
grid2op.Space.GridObjects.redispatching_unit_commitment_availble
is set toFalse
the length of the redispatching vector
BaseAction._redispatching
is not compatible with the number of generators.some redispatching are above the maximum ramp up
grid2op.Space.GridObjects.gen_max_ramp_up
some redispatching are below the maximum ramp down
grid2op.Space.GridObjects.gen_max_ramp_down
the redispatching action affect non dispatchable generators
the redispatching and the production setpoint, if added, are above pmax for at least a generator
the redispatching and the production setpoint, if added, are below pmin for at least a generator
In case of need to overload this method, it is advise to still call this one from the base
BaseAction
with “super()._check_for_ambiguity()
” or “BaseAction._check_for_ambiguity(self)
”.- Raises:
grid2op.Exceptions.AmbiguousAction – Or any of its more precise subclasses, depending on which assumption is not met.
- _get_array_from_attr_name(attr_name)[source]
INTERNAL
Warning
/!\ Internal, do not use unless you know what you are doing /!\
This function returns the proper attribute vector that can be inspected in the
GridObject.shape()
,GridObject.size()
,GridObject.dtype()
,GridObject.from_vect()
andGridObject.to_vect()
method.If this function is overloaded, then the _assign_attr_from_name must be too.
- Parameters:
attr_name (
str
) – Name of the attribute to inspect or set- Returns:
res – The attribute corresponding the name, flatten as a 1d vector.
- Return type:
numpy.ndarray
- _post_process_from_vect()[source]
called at the end of “from_vect” if the function requires post processing
- _reset_vect()[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Need to be called when update is called !
- alarm_raised() ndarray [source]
INTERNAL
Warning
/!\ Only valid with “l2rpn_icaps_2021” environment /!\
This function is used to know if the given action aimed at raising an alarm or not.
- Returns:
res – The indexes of the areas where the agent has raised an alarm.
- Return type:
numpy array
- alert_raised() ndarray [source]
INTERNAL
This function is used to know if the given action aimed at raising an alert or not.
- Returns:
res – The indexes of the lines where the agent has raised an alert.
- Return type:
numpy array
- as_dict() Dict[Literal['load_p', 'load_q', 'prod_p', 'prod_v', 'change_line_status', 'set_line_status', 'change_bus_vect', 'set_bus_vect', 'redispatch', 'storage_power', 'curtailment'], Any] [source]
Represent an action “as a” dictionary. This dictionary is useful to further inspect on which elements the actions had an impact. It is not recommended to use it as a way to serialize actions. The “do nothing” action should always be represented by an empty dictionary.
The following keys (all optional) are present in the results:
load_p: if the action modifies the active loads.
load_q: if the action modifies the reactive loads.
prod_p: if the action modifies the active productions of generators.
prod_v: if the action modifies the voltage setpoint of generators.
set_line_status if the action tries to set the status of some powerlines. If present, this is a a dictionary with keys:
nb_connected: number of powerlines that are reconnected
nb_disconnected: number of powerlines that are disconnected
connected_id: the id of the powerlines reconnected
disconnected_id: the ids of the powerlines disconnected
change_line_status: if the action tries to change the status of some powerlines. If present, this is a dictionary with keys:
nb_changed: number of powerlines having their status changed
changed_id: the ids of the powerlines that are changed
change_bus_vect: if the action tries to change the topology of some substations. If present, this is a dictionary with keys:
nb_modif_subs: number of substations impacted by the action
modif_subs_id: ids of the substations impacted by the action
change_bus_vect: details the objects that are modified. It is itself a dictionary that represents for each impacted substations (keys) the modification of the objects connected to it.
set_bus_vect: if the action tries to set the topology of some substations. If present, this is a dictionary with keys:
nb_modif_subs: number of substations impacted by the action
modif_subs_id: the ids of the substations impacted by the action
set_bus_vect: details the objects that are modified. It is also a dictionary that represents for each impacted substations (keys) how the elements connected to it are impacted (their “new” bus)
hazards if the action is composed of some hazards. In this case, it’s simply the index of the powerlines that are disconnected because of them.
nb_hazards the number of hazards the “action” implemented (eg number of powerlines disconnected because of hazards.
maintenance if the action is composed of some maintenance. In this case, it’s simply the index of the powerlines that are affected by maintenance operation at this time step. that are disconnected because of them.
nb_maintenance the number of maintenance the “action” implemented eg the number of powerlines disconnected because of maintenance operations.
redispatch the redispatching action (if any). It gives, for each generator (all generator, not just the dispatchable one) the amount of power redispatched in this action.
storage_power: the setpoint for production / consumption for all storage units
curtailment: the curtailment performed on all generator
shunt :
- Returns:
res – The action represented as a dictionary. See above for a description of it.
- Return type:
dict
- as_serializable_dict() dict [source]
This method returns an action as a dictionnary, that can be serialized using the “json” module.
It can be used to store the action into a grid2op indepependant format (the default action serialization, for speed, writes actions to numpy array. The size of these arrays can change depending on grid2op versions, especially if some different types of actions are implemented).
Once you have these dictionnary, you can use them to build back the action from the action space.
Warning
This function does not work correctly with version of grid2op lower (or equal to) 1.9.5
Examples
It can be used like:
import grid2op env_name = "l2rpn_case14_sandbox" # or anything else env = grid2op.make(env_name) act = env.action_space(...) dict_ = act.as_serializable_dict() # you can save this dict with the json library act2 = env.action_space(dict_) act == act2
- can_affect_something() bool [source]
This functions returns True if the current action has any chance to change the grid.
Notes
This does not say however if the action will indeed modify something somewhere !
- property change_bus: ndarray
Allows to retrieve (and affect) the busbars at which any element is change.
It behaves similarly as
BaseAction.gen_change_bus
and can be use to modify any elements type as opposed to the more specificBaseAction.gen_change_bus
,BaseAction.load_change_bus
,BaseAction.line_or_change_bus
,BaseAction.line_ex_change_bus
orBaseAction.storage_change_bus
that are specific to a certain type of objects.Notes
For performance reasons, it do not allow to modify the elements by there names.
The order of each elements are given in the
grid2op.Space.GridObjects.gen_pos_topo_vect
,grid2op.Space.GridObjects.load_pos_topo_vect
,grid2op.Space.GridObjects.line_or_pos_topo_vect
,grid2op.Space.GridObjects.line_ex_pos_topo_vect
orgrid2op.Space.GridObjects.storage_pos_topo_vect
For example:
act.set_bus [0, 1, 3]
Will:
change the bus of the (unique) element for which *_pos_topo_vect is 1
change the bus of (unique) element for which *_pos_topo_vect is 2
change the bus of (unique) element for which *_pos_topo_vect is 3
You can use the documentation page Elements modeled in this environment and their main properties for more information about which element correspond to what component of this “vector”.
- property change_line_status: ndarray
another name for
BaseAction.change_line_status()
- check_space_legit()[source]
This method allows to check if this method is ambiguous per se (defined more formally as: whatever the observation at time t, and the changes that can occur between t and t+1, this action will be ambiguous).
For example, an action that try to assign something to busbar 3 will be ambiguous per se. An action that tries to dispatch a non dispatchable generator will be also ambiguous per se.
However, an action that “switch” (change) the status (connected / disconnected) of a powerline can be ambiguous and it will not be detected here. This is because the ambiguity depends on the current state of the powerline:
if the powerline is disconnected, changing its status means reconnecting it. And we cannot reconnect a powerline without specifying on which bus.
on the contrary if the powerline is connected, changing its status means disconnecting it, which is always feasible.
In case of “switch” as we see here, the action can be ambiguous, but not ambiguous per se. This method will never throw any error in this case.
- Raises:
grid2op.Exceptions.AmbiguousAction – Or any of its more precise subclasses, depending on which assumption is not met.
- property curtail: ndarray
Allows to perfom some curtailment on some generators
It behaves similarly as
BaseAction.redispatch
. See the help there for more information.For more information, feel free to consult the documentation Generators where more details are given about the modeling ot these storage units.
- property curtail_mw: ndarray
Allows to perfom some curtailment on some generators in MW (by default in grid2Op it should be expressed in ratio of gen_pmax)
It behaves similarly as
BaseAction.redispatch
. See the help there for more information.For more information, feel free to consult the documentation Generators where more details are given about the modeling ot these storage units.
- curtailment_mw_to_ratio(curtailment_mw) ndarray [source]
Transform a “curtailment” given as maximum MW to the grid2op formalism (in ratio of gen_pmax)
- Parameters:
curtailment_mw – Same type of inputs you can use in act.curtail = …
- Return type:
A proper input to act.curtail with the converted input expressed in ratio of gen_pmax
Examples
If you want to limit the production of generator 1 (suppose its renewable) at 1.5MW then you can do:
gen_id = 1 amount_max = 1.5 act.curtail = act.curtailment_mw_to_ratio([(gen_id, amount_max)])
- decompose_as_unary_actions(group_topo=False, group_line_status=False, group_redispatch=True, group_storage=True, group_curtail=True) Dict[Literal['change_bus', 'set_bus', 'change_line_status', 'set_line_status', 'redispatch', 'set_storage', 'curtail'], List[BaseAction]] [source]
This function allows to split a possibly “complex” action into its “unary” counterpart.
By “unary” action here we mean “action that acts on only one type”. For example an action that only set_line_status is unary but an action that acts on set_line_status AND set_bus is not. Also, note that an action that acts on set_line_status and change_line_status is not considered as “unary” by this method.
This functions output a dictionnary with up to 7 keys:
“change_bus” if the action affects the grid with change_bus. In this case the value associated with this key is a list containing only action that performs change_bus
“set_bus” if the action affects the grid with`set_bus`. In this case the value associated with this key is a list containing only action that performs set_bus
“change_line_status” if the action affects the grid with change_line_status In this case the value associated with this key is a list containing only action that performs change_line_status
“set_line_status” if the action affects the grid with set_line_status In this case the value associated with this key is a list containing only action that performs set_line_status
“redispatch” if the action affects the grid with redispatch In this case the value associated with this key is a list containing only action that performs redispatch
“set_storage” if the action affects the grid with set_storage In this case the value associated with this key is a list containing only action that performs set_storage
“curtail” if the action affects the grid with curtail In this case the value associated with this key is a list containing only action that performs curtail
NB if the action is a “do nothing” action type, then this function will return an empty dictionary.
New in version 1.9.1.
Notes
If the action is not ambiguous (ie it is valid and can be correctly understood by grid2op) and if you sum all the actions in all the lists of all the keys of the dictionnary returned by this function, you will retrieve exactly the current action.
For example:
import grid2op env_name = "l2rpn_case14_sandbox" env = grid2op.make(env_name, ...) act = env.action_space({"curtail": [(4, 0.8), (5, 0.7)], "set_storage": [(0, +1.), (1, -1.)], "redispatch": [(0, +1.), (1, -1.)], "change_line_status": [2, 3], "set_line_status": [(0, -1), (1, -1)], "set_bus": {"loads_id": [(0, 2), (1, 2)], "generators_id": [(0, 2)]}, "change_bus": {"loads_id": [2, 3], "generators_id": [1]} }) res = act.decompose_as_unary_actions() tmp = env.action_space() for k, v in res.items(): for a in v: tmp += a assert tmp == act
- Parameters:
group_topo (bool, optional) – This flag allows you to control the size of the change_bus and set_bus values. If it’s
True
then the values associated with this keys will be unique (made of one single element) that will affect all the elements affected by this action (grouping them all together) Otherwise, it will counts as many elements as the number of substations affected by a change_bus or a set_bus. Each action returned by this will then act on only one substation. By default False (meaning there will be as many element in change_bus as the number of substations affected by a change_bus action [same for set_bus])group_line_status (bool, optional) – Whether to group the line status in one single action (so the values associated with the keys set_line_status and change_line_status will count exactly one element - if present) or not. By default False (meaning there will be as many element in change_line_status as the number of lines affected by a change_line_status action [same for set_line_status] : if the original action set the status of two powerlines, then the value associated with set_line_status will count 2 elements: the first action will set the status of the first line affected by the action, the second will… set the status of the second line affected by the action)
group_redispatch (bool, optional) – same behaviour as group_line_status but for “generators” and “redispatching” instead of “powerline” and set_line_status, by default True (meaning the value associated with the key redispatch will be a list of one element performing a redispatching action on all generators modified by the current action)
group_storage (bool, optional) – same behaviour as group_line_status but for “storage units” and “set setpoint” instead of “powerline” and set_line_status, by default True (meaning the value associated with the key set_storage will be a list of one element performing a set point action on all storage units modified by the current action)
group_curtail (bool, optional) – same behaviour as group_line_status but for “generators” and “curtailment” instead of “powerline” and set_line_status, , by default True (meaning the value associated with the key curtail will be a list of one element performing a curtailment on all storage generators modified by the current action)
- Returns:
See description for further information.
- Return type:
dict
- effect_on(_sentinel=None, load_id=None, gen_id=None, line_id=None, substation_id=None, storage_id=None) dict [source]
Return the effect of this action on a unique given load, generator unit, powerline or substation. Only one of load, gen, line or substation should be filled.
The query of these objects can only be done by id here (ie by giving the integer of the object in the backed). The
ActionSpace
has some utilities to access them by name too.- Parameters:
_sentinel (
None
) – Used to prevent positional parameters. Internal, do not use.load_id (
int
) – The ID of the load we want to inspectgen_id (
int
) – The ID of the generator we want to inspectline_id (
int
) – The ID of the powerline we want to inspectsubstation_id (
int
) – The ID of the substation we want to inspectstorage_id (
int
) – The ID of the storage unit we want to inspect
- Returns:
res (
dict
) – A dictionary with keys and value depending on which object needs to be inspected:if a load is inspected, then the keys are:
”new_p” the new load active value (or NaN if it doesn’t change),
”new_q” the new load reactive value (or Nan if nothing has changed from this point of view)
”set_bus” the new bus where the load will be moved (int: id of the bus, 0 no change, -1 disconnected)
”change_bus” whether or not this load will be moved from one bus to another (for example is an action asked it to go from bus 1 to bus 2)
if a generator is inspected, then the keys are:
”new_p” the new generator active setpoint value (or NaN if it doesn’t change),
”new_v” the new generator voltage setpoint value (or Nan if nothing has changed from this point of view)
”set_bus” the new bus where the load will be moved (int: id of the bus, 0 no change, -1 disconnected)
”change_bus” whether or not this load will be moved from one bus to another (for example is an action asked it to go from bus 1 to bus 2)
”redispatch” the amount of power redispatched for this generator.
”curtailment”: the amount of curtailment on this generator
if a powerline is inspected then the keys are:
”change_bus_or”: whether or not the origin side will be moved from one bus to another
”change_bus_ex”: whether or not the extremity side will be moved from one bus to another
”set_bus_or”: the new bus where the origin will be moved
”set_bus_ex”: the new bus where the extremity will be moved
”set_line_status”: the new status of the power line
”change_line_status”: whether or not to switch the status of the powerline
if a substation is inspected, it returns the topology to this substation in a dictionary with keys:
”change_bus”
”set_bus”
if a storage unit is inspected, it returns a dictionary with:
”change_bus”
”set_bus”
”power” : the power you want to produce / absorb with the storage unit ( if < 0 the power is produced, if > 0 then power is absorbed)
NB the difference between “set_bus” and “change_bus” is the following –
If “set_bus” is 1, then the object (load, generator or powerline) will be moved to bus 1 of the substation to which it is connected. If it is already to bus 1 nothing will be done. If it’s on another bus it will connect it to bus 1. It’s disconnected, it will reconnect it and connect it to bus 1.
If “change_bus” is True, then the object will be moved from one bus to another. If the object were on bus 1 then it will be moved on bus 2, and if it were on bus 2, it will be moved on bus 1. If the object were disconnected, then it will be connected to the affected bus.
- Raises:
grid2op.Exception.Grid2OpException – If _sentinel is modified, or if none of the arguments are set or alternatively if 2 or more of the parameters are being set.
- property gen_change_bus: ndarray
Allows to retrieve (and affect) the busbars at which the action change the generator units.
- Returns:
A vector of bool, of size act.n_gen indicating what type of action is performed for each generator units with the convention :
False
this generator is not affected by any “change” actionTrue
this generator bus is not affected by any “change” action. If it was on bus 1, it will be moved to bus 2, if it was on bus 2 it will be moved to bus 1 ( and if it was disconnected it will stay disconnected)
- Return type:
res
Examples
To retrieve the impact of the action on the storage unit, you can do:
gen_buses = act.gen_change_bus
To modify these buses you can do:
# create an environment where i can modify everything import numpy as np import grid2op from grid2op.Action import CompleteAction env = grid2op.make("educ_case14_storage", test=True, action_class=CompleteAction) # create an action act = env.action_space() # method 1 : provide the full vector act.gen_change_bus = np.ones(act.n_gen, dtype=bool) # method 2: provide the index of the unit you want to modify act.gen_change_bus = 1 # method 3: provide a list of the units you want to modify act.gen_change_bus = [1, 2] # method 4: change the storage unit by their name with a set act.gen_change_bus = {"gen_1_0"}
Note
The “rule of thumb” to modify an object using “change” method it to provide always the ID of an object. The ID should be an integer (or a name in some cases). It does not make any sense to provide a “value” associated to an ID: either you change it, or not.
Notes
It is a “property”, you don’t have to use parenthesis to access it:
# valid code gen_buses = act.gen_change_bus # invalid code, it will crash, do not run gen_buses = act.gen_change_bus() # end do not run
And neither should you uses parenthesis to modify it:
# valid code act.gen_change_bus = [1, 2, 3] # invalid code, it will crash, do not run act.gen_change_bus([1, 2, 3]) # end do not run
Property cannot be set “directly”, you have to use the act.XXX = .. syntax. For example:
# valid code act.gen_change_bus = [1, 3, 4] # invalid code, it will raise an error, and even if it did not it would have not effect # do not run act.gen_change_bus[1] = True # end do not run
Note
Be careful not to mix “change” and “set”. For “change” you only need to provide the ID of the elements you want to change, for “set” you need to provide the ID AND where you want to set them.
- property gen_set_bus: ndarray
Allows to retrieve (and affect) the busbars at which the action set the generator units.
Changed in version 1.10.0: From grid2op version 1.10.0 it is possible (under some cirumstances, depending on how the environment is created) to set the busbar to a number >= 3, depending on the value of type(act).n_busbar_per_sub.
- Returns:
A vector of integer, of size act.n_gen indicating what type of action is performed for each generator units with the convention :
0 the action do not action on this generator
-1 the action disconnect the generator
1 the action set the generator to busbar 1
2 the action set the generator to busbar 2
3 the action set the generator to busbar 3 (grid2op >= 1.10.0)
etc. (grid2op >= 1.10.0)
- Return type:
res
Examples
To retrieve the impact of the action on the generator, you can do:
gen_buses = act.gen_set_bus
To modify these buses with set you can do:
# create an environment where i can modify everything import numpy as np import grid2op from grid2op.Action import CompleteAction env = grid2op.make("educ_case14_storage", test=True, action_class=CompleteAction) # create an action act = env.action_space() # method 1 : provide the full vector act.gen_set_bus = np.ones(act.n_gen, dtype=int) # method 2: provide the index of the unit you want to modify act.gen_set_bus = (1, 2) # method 3: provide a list of the units you want to modify act.gen_set_bus = [(1, 2), (0, -1)] # method 4: change the storage unit by their name with a dictionary act.gen_set_bus = {"gen_1_0": 2}
Note
The “rule of thumb” to modify an object using “set” method it to provide always the ID of an object AND its value. The ID should be an integer (or a name in some cases) and the value an integer representing on which busbar to put the new element.
Notes
It is a “property”, you don’t have to use parenthesis to access it:
# valid code gen_buses = act.gen_set_bus # invalid code, it will crash, do not run gen_buses = act.gen_set_bus() # end do not run
And neither should you uses parenthesis to modify it:
# valid code act.gen_set_bus = [(1, 2), (0, -1)] # invalid code, it will crash, do not run act.gen_set_bus([(1, 2), (0, -1)]) # end do not run
Property cannot be set “directly”, you have to use the act.XXX = … syntax. For example:
# valid code act.gen_set_bus = [(1, 2), (0, -1)] # invalid code, it will raise an error, and even if it did not it would have not effect # do not run act.gen_set_bus[1] = 2 # end do not run
Note
Be careful not to mix “change” and “set”. For “change” you only need to provide the ID of the elements you want to change, for “set” you need to provide the ID AND where you want to set them.
- get_change_line_status_vect() ndarray [source]
Computes and returns a vector that can be used in the
BaseAction.__call__()
with the keyword “set_status” if building anBaseAction
.NB this vector is not the internal vector of this action but corresponds to “do nothing” action.
- Returns:
res – A vector that doesn’t affect the grid, but can be used in
BaseAction.__call__()
with the keyword “set_status” if building anBaseAction
.- Return type:
numpy.array
, dtype:dt_bool
- get_gen_modif() Tuple[ndarray, ndarray, ndarray, ndarray] [source]
Retrieve the modification that will be performed on all the generators
TODO add curtailment and redispatching
- Returns:
gen_p (
np.ndarray
) – New gen p (Nan = not modified) [in MW]gen_v (
np.ndarray
) – New gen v setpoint (Nan = not modified) [in kV]gen_set_bus (
np.ndarray
) – New bus of the generators, affected with “set_bus” commandgen_change_bus (
np.ndarray
) – New bus of the generators, affected with “change_bus” command
- get_load_modif() Tuple[ndarray, ndarray, ndarray, ndarray] [source]
Retrieve the modification that will be performed on all the loads
- Returns:
load_p (
np.ndarray
) – New load p (Nan = not modified) [in MW]load_q (
np.ndarray
) – New load q (Nan = not modified) [in MVaR]load_set_bus (
np.ndarray
) – New bus of the loads, affected with “set_bus” commandload_change_bus (
np.ndarray
) – New bus of the loads, affected with “change_bus” command
- get_set_line_status_vect() ndarray [source]
Computes and returns a vector that can be used in the
BaseAction.__call__()
with the keyword “set_status” if building anBaseAction
.NB this vector is not the internal vector of this action but corresponds to “do nothing” action.
- Returns:
res – A vector that doesn’t affect the grid, but can be used in
BaseAction.__call__()
with the keyword “set_status” if building anBaseAction
.- Return type:
numpy.array
, dtype:dt_int
- get_storage_modif() Tuple[ndarray, ndarray, ndarray] [source]
Retrieve the modification that will be performed on all the storage unit
- Returns:
storage_power (
np.ndarray
) – New storage power target (Nan = not modified, otherwise the setpoint given) [in MW]storage_set_bus (
np.ndarray
) – New bus of the storage units, affected with “set_bus” command (0 = not affected, -1 = disconnected)storage_change_bus (
np.ndarray
) – New bus of the storage units, affected with “change_bus” command
- get_topological_impact(powerline_status=None) Tuple[ndarray, ndarray] [source]
Gives information about the element being impacted by this action. NB The impacted elements can be used by
grid2op.BaseRules
to determine whether or not an action is legal or not. NB The impacted are the elements that can potentially be impacted by the action. This does not mean they will be impacted. For examples:If an action from an
grid2op.BaseAgent
reconnect a powerline, but this powerline is being disconnected by a hazard at the same time step, then this action will not be implemented on the grid.
However, it this powerline couldn’t be reconnected for some reason (for example it was already out of order) the action will still be declared illegal, even if it has NOT impacted the powergrid.
If an action tries to disconnect a powerline already disconnected, it will “impact” this powergrid. This means that even if the action will do nothing, it disconnecting this powerline is against the rules, then the action will be illegal.
If an action tries to change the topology of a substation, but this substation is already at the target topology, the same mechanism applies. The action will “impact” the substation, even if, in the end, it consists of doing nothing.
Any such “change” that would be illegal is declared as “illegal” regardless of the real impact of this action on the powergrid.
- Returns:
lines_impacted (
numpy.ndarray
, dtype:dt_bool) – A vector with the same size as the number of powerlines in the grid (BaseAction.n_line
) with for each componentTrue
if the line STATUS is impacted by the action, andFalse
otherwise. SeeBaseAction._lines_impacted
for more information.subs_impacted (
numpy.ndarray
, dtype:dt_bool) – A vector with the same size as the number of substations in the grid with for each componentTrue
if the substation is impacted by the action, andFalse
otherwise. SeeBaseAction._subs_impacted
for more information.
Examples
You can use this function like;
import grid2op env_name = "l2rpn_case14_sandbox" # or any other name env = grid2op.make(env_name) # get an action action = env.action_space.sample() # inspect its impact lines_impacted, subs_impacted = action.get_topological_impact() for line_id in np.where(lines_impacted)[0]: print(f"The line {env.name_line[line_id]} with id {line_id} is impacted by this action") print(action)
- get_types() Tuple[bool, bool, bool, bool, bool, bool, bool] [source]
Shorthand to get the type of an action. The type of an action is among:
“injection”: does this action modifies load or generator active values
“voltage”: does this action modifies the generator voltage setpoint or the shunts
“topology”: does this action modifies the topology of the grid (ie set or switch some buses)
“line”: does this action modifies the line status
“redispatching” does this action modifies the redispatching
“storage” does this action impact the production / consumption of storage units
“curtailment” does this action impact the non renewable generators through curtailment
Notes
A single action can be of multiple types.
The do nothing has no type at all (all flags are
False
)If a line only set / change the status of a powerline then it does not count as a topological modification.
If the bus to which a storage unit is connected is modified, but there is no setpoint for the production / consumption of any storage units, then the action is NOT taged as an action on the storage units.
- Returns:
injection (
bool
) – Does it affect load or generator active valuevoltage (
bool
) – Does it affect the voltagetopology (
bool
) – Does it affect the topology (line status change / switch are NOT counted as topology)line (
bool
) – Does it affect the line status (line status change / switch are NOT counted as topology)redispatching (
bool
) – Does it performs (explicitly) any redispatchingstorage (
bool
) – Does it performs (explicitly) any action on the storage production / consumptioncurtailment (
bool
) – Does it performs (explicitly) any action on renewable generator
- impact_on_objects() dict [source]
This will return a dictionary which contains details on objects that will be impacted by the action.
- Returns:
dict – The dictionary representation of an action impact on objects with keys, “has_impact”, “injection”, “force_line”, “switch_line”, “topology”, “redispatch”, “storage”, “curtailment”.
- Return type:
dict
- is_ambiguous() Tuple[bool, AmbiguousAction] [source]
Says if the action, as defined is ambiguous per se or not.
See definition of
BaseAction.check_space_legit()
for more details about ambiguity per se.- Returns:
res (
True
if the action is ambiguous,False
otherwise.)info (
dict
or not) – More information about the error. If the action is not ambiguous, it values toNone
- limit_curtail_storage(obs: BaseObservation, margin: float = 10.0, do_copy: bool = False, _tol_equal: float = 0.01) Tuple[BaseAction, ndarray, ndarray] [source]
This function tries to limit the possibility to end up with a “game over” because actions on curtailment or storage units (see the “Notes” section for more information).
It will modify the action (unless do_copy is True) from a given observation obs. It limits the curtailment / storage unit to ensure that the amount of MW curtailed / taken to-from the storage units are within -sum(obs.gen_margin_down) and sum(obs.gen_margin_up)
The margin parameter is here to allows to “take into account” the uncertainties. Indeed, if you limit only to -sum(obs.gen_margin_down) and sum(obs.gen_margin_up), because you don’t know how much the production will vary (due to loads, or intrisinc variability of renewable energy sources). The higher margin the less likely you will end up with a “game over” but the more your action will possibly be affected. The lower this parameter, the more likely you will end up with a game over but the less your action will be impacted. It represents a certain amount of MW.
Notes
At each time, the environment ensures that the following equations are met:
for each controlable generators $p^{(c)}_{min} <= p^{(c)}_t <= p^{(c)}_{max}$
for each controlable generators $-ramp_{min}^{(c)} <= p^{(c)}_t - p^{(c)}_{t-1} <= ramp_{max}^{(c)}$
at each step the sum of MW curtailed and the total contribution of storage units is absorbed by the controlable generators so that the total amount of power injected at this step does not change: $sum_{ ext{all generators } g} p^{(g, scenario)}_t = sum_{ ext{controlable generators } c} p^{(c)}_t + sum_{ ext{storage unit } s} p^{s}_t + sum_{ ext{renewable generator} r} p^{(r)}_t$ where $p^{(g)}_t$ denotes the productions of generator $g$ in the input data “scenario” (ie “in the current episode”, “before any modification”, “decided by the market / central authority”).
In the above equations, sum_{ ext{storage unit } s} p^{s}_t are controled by the action (thanks to the storage units) and sum_{ ext{renewable generator} r} p^{(r)}_t are controlled by the curtailment.
sum_{ ext{all generators } g} p^{(g, scenario)}_t are input data from the environment (that cannot be modify).
The exact value of each p^{(c)}_t (for each controlable generator) is computed by an internal routine of the environment.
The constraint comes from the fact that sum_{ ext{controlable generators } c} p^{(c)}_t is determined by the last equation above but at the same time the values of each p^{(c)}_t (for each controllable generator) is heavily constrained by equations 1) and 2).
Note
This argument and the
grid2op.Parameters.Parameters.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION()
have the same objective: prevent an agent to do some curtailment too strong for the grid.When using
grid2op.Parameters.Parameters.LIMIT_INFEASIBLE_CURTAILMENT_STORAGE_ACTION()
, the environment will do it knowing exactly what will happen next (its a bit “cheating”) and limit exactly the action to exactly right amount.Using
grid2op.Aciton.BaseAction.limit_curtail_storage()
is always feasible, but less precise and subject to uncertainties.Warning
If the action has no effect (for example you give a limit of the curtailment above the actual production of renewable generators) then regardless of the “margin” parameter your action will be declared “legal” which may cause unfeasibility in the future.
- Parameters:
obs (
Observation
) – The current observation. The main attributes used for the observation are obs.gen_margin_down and obs.gen_margin_up.margin (
float
, optional) – The “margin” taken from the controlable generators “margin” to “take into account” when limiting the action (see description for more information), by default 10.do_copy (
bool
, optional) – Whether to make a copy of the current action (if set toTrue
) or to modify the action “in-place” (default, whenFalse
)
- Returns:
act: the action after the storage unit / curtailment are modified (by default it’s also self)
res_add_curtailed: the modification made to the curtailment
res_add_storage: the modification made to the storage units
- Return type:
Action, np.ndarray, np.ndarray
- property line_change_status: ndarray
Property to set the status of the powerline.
It behave similarly than
BaseAction.gen_change_bus
but with the following convention:False
will not affect the powerlineTrue
will change the status of the powerline. If it was connected, it will attempt to disconnect it, if it was disconnected, it will attempt to reconnect it.
- property line_ex_change_bus: ndarray
Allows to retrieve (and affect) the busbars at which the extremity side of powerlines are changed.
It behaves similarly as
BaseAction.gen_change_bus
. See the help there for more information.
- property line_ex_set_bus: ndarray
Allows to retrieve (and affect) the busbars at which the extremity side of each powerline is set.
It behaves similarly as
BaseAction.gen_set_bus
. See the help there for more information.
- property line_or_change_bus: ndarray
Allows to retrieve (and affect) the busbars at which the origin side of powerlines are changed.
It behaves similarly as
BaseAction.gen_change_bus
. See the help there for more information.
- property line_or_set_bus: ndarray
Allows to retrieve (and affect) the busbars at which the action set the lines (origin side).
Changed in version 1.10.0: From grid2op version 1.10.0 it is possible (under some cirumstances, depending on how the environment is created) to set the busbar to a number >= 3, depending on the value of type(act).n_busbar_per_sub.
- Returns:
A vector of integer, of size act.n_gen indicating what type of action is performed for each lines (origin side) with the convention :
0 the action do not action on this line (origin side)
-1 the action disconnect the line (origin side)
1 the action set the line (origin side) to busbar 1
2 the action set the line (origin side) to busbar 2
3 the action set the line (origin side) to busbar 3 (grid2op >= 1.10.0)
etc.
- Return type:
res
Examples
Please refer to the documentation of
BaseAction.gen_set_bus
for more information.Note
Be careful not to mix “change” and “set”. For “change” you only need to provide the ID of the elements you want to change, for “set” you need to provide the ID AND where you want to set them.
- property line_set_status: ndarray
Property to set the status of the powerline.
It behave similarly than
BaseAction.gen_set_bus
but with the following convention:0 still means it is not affected
+1 means that we force the connection on a powerline
-1 means we force the disconnection of a powerline
Notes
Setting a status of a powerline to +2 will raise an error.
Examples
For example:
act.line_set_status = [(0,1), (1, -1), (3, 1)]
Will force the reconnection of line id 0 and 1 and force disconnection of line id 1.
- property load_change_bus: ndarray
Allows to retrieve (and affect) the busbars at which the loads is changed.
It behaves similarly as
BaseAction.gen_change_bus
. See the help there for more information.
- property load_set_bus: ndarray
Allows to retrieve (and affect) the busbars at which the action set the loads.
Changed in version 1.10.0: From grid2op version 1.10.0 it is possible (under some cirumstances, depending on how the environment is created) to set the busbar to a number >= 3, depending on the value of type(act).n_busbar_per_sub.
- Returns:
A vector of integer, of size act.n_gen indicating what type of action is performed for each load units with the convention :
0 the action do not action on this load
-1 the action disconnect the load
1 the action set the load to busbar 1
2 the action set the load to busbar 2
3 the action set the load to busbar 3 (grid2op >= 1.10.0)
etc. (grid2op >= 1.10.0)
- Return type:
res
Examples
Please refer to the documentation of
BaseAction.gen_set_bus
for more information.Note
Be careful not to mix “change” and “set”. For “change” you only need to provide the ID of the elements you want to change, for “set” you need to provide the ID AND where you want to set them.
- classmethod process_grid2op_compat()[source]
INTERNAL
Warning
/!\ Internal, do not use unless you know what you are doing /!\ This is done at the creation of the environment. Use of this class outside of this particular use is really dangerous and will lead to undefined behaviours. Do not use this function.
This is called when the class is initialized, with init_grid to broadcast grid2op compatibility feature.
This function can be overloaded, but in this case it’s best to call this original method too.
- classmethod process_shunt_satic_data()[source]
remove possible shunts data from the classes, if shunts are deactivated
- property raise_alarm: ndarray
Warning
/!\ Only valid with “l2rpn_icaps_2021” environment /!\
Property to raise alarm.
If you set it to
True
an alarm is raised for the given area, otherwise None are raised.Notes
In order to be able to “cancel” an alarm properly, if you set “two consecutive alarm” on the same area it will behave as if you had set none:
import grid2op env_name = "l2rpn_icaps_2021" # chose an environment that supports the alarm feature env = grid2op.make(env_name) act = env.action_space() act.raise_alarm = [0] # this act will raise an alarm on the area 0 act.raise_alarm = [0] # this second call will "cancel" the alarm for convenience
This might be counter intuitive
- property raise_alert: ndarray
Property to raise alert.
If you set it to
True
an alert is raised for the given line, otherwise no alert is raised.Notes
import grid2op env_name = "l2rpn_idf_2023" # chose an environment that supports the alert feature env = grid2op.make(env_name) act = env.action_space() act.raise_alert = [0] # this act will raise an alert on the powerline attackable 0 (powerline concerned will be action.alertable_line_ids[0])
- property redispatch: ndarray
Allows to retrieve (and affect) the redispatching setpoint of the generators.
- Returns:
A vector of integer, of size act.n_gen indicating what type of action is performed for each generator units. Note that these are the setpoint. The actual redispatching that will be available might be different. See Generators for more information.
- Return type:
res
Examples
To retrieve the impact of the action on the generator unit, you can do:
redisp = act.redispatch
For each generator it will give the amount of redispatch this action wants to perform.
To change the setpoint of the redispatching, you can do:
# create an environment where i can modify everything import numpy as np import grid2op from grid2op.Action import CompleteAction env = grid2op.make("educ_case14_storage", test=True, action_class=CompleteAction) # create an action act = env.action_space() # method 1 : provide the full vector act.redispatch = np.ones(act.n_gen, dtype=float) # only floats are accepted ! # method 2: provide the index of the unit you want to modify act.redispatch = (1, 2.5) # method 3: provide a list of the units you want to modify act.redispatch = [(1, 2.5), (0, -1.3)] # method 4: change the generators by their name with a dictionary act.redispatch = {"gen_1_0": 2.0}
Note
The “rule of thumb” to perform redispatching is to provide always the ID of an object AND its value. The ID should be an integer (or a name in some cases) and the value a float representing what amount of redispatching you want to perform on the unit with the associated ID.
Notes
It is a “property”, you don’t have to use parenthesis to access it:
# valid code redisp = act.redispatch # invalid code, it will crash, do not run redisp = act.redispatch() # end do not run
And neither should you uses parenthesis to modify it:
# valid code act.redispatch = [(1, 2.5), (0, -1.3)] # invalid code, it will crash, do not run act.redispatch([(1, 2.5), (0, -1.3)]) # end do not run
Property cannot be set “directly”, you have to use the act.XXX = .. syntax. For example:
# valid code act.redispatch = [(1, 2.5), (0, -1.3)] # invalid code, it will raise an error, and even if it did not it would have not effect # do not run act.redispatch[1] = 2.5 # end do not run
Note
Be careful not to mix action to set something on a bus bar (where the values are integer, like “set_bus” or “set_status”) and continuous action (where the values are float, like “redispatch” or “storage_p”)
- remove_change() BaseAction [source]
This function will modify ‘self’ and remove all “change” action type.
It is mainly used in the environment, when removing the “change” type for setting the original state of the grid.
New in version 1.10.2.
- remove_line_status_from_topo(obs: BaseObservation | None = None, check_cooldown: bool = True)[source]
New in version 1.8.0.
This function prevent an action to act on a powerline status if through the “set_bus” and “change_bus” part if a cooldown applies ( see Note on powerline status for cases where this can apply)
For example:
import grid2op import numpy as np env_name = "l2rpn_icaps_2021_small" env = grid2op.make(env_name) env.set_id(0) env.seed(0) obs = env.reset() act = env.action_space({"set_bus": {"substations_id": [(27, [1, -1, 2, 2, 1])]}}) obs, reward, done, info = env.step(act) act_sub28 = env.action_space({"set_bus": {"substations_id": [(28, [1, 2, 2, 1, 1])]}}) obs, reward, done, info = env.step(act_sub28) # >>> info["exception"] : IllegalAction('Powerline with ids [42] have been modified illegally (cooldown)')
This is because in the second action, the powerline 42 is assigned to bus 2, so it would be reconnected, which is not possible due to the cooldown.
The behaviour is (for all powerlines where a cooldown applies ie obs.time_before_cooldown_sub > 0):
if this line is disconnected and is assigned to a bus 1 or 2 at a substation for one of its end, then this part of the action is ignored (it has not effect: bus will NOT be set)
if this line is connected and it is assigned to bus “-1” at one of its side (extremity or origin side) then this part of the action is ignored (bus will NOT be “set”)
if this line is disconnected and the bus to one of its side is “changed”, then this part is ignored: bus will NOT be changed
And regardless of cooldowns it also:
if a powerline is affected to a certain bus at one of its end with set_bus (for example set_bus to 1 or 2) and at the same time disconnected (set_line_status is -1) then the set_bus part is ignored to avoid AmbiguousAction
if a powerline is disconnect from its bus at one of its end with set_bus (for example set_bus to -1) and at the same time reconnected (set_line_status is 1) then the set_bus part is ignored to avoid AmbiguousAction
if a powerline is affected to a certain bus at one of its end with change_bus (change_bus is
True
) and at the same time disconnected (set_line_status is -1) then the change_bus part is ignore to avoid AmbiguousAction
Warning
This modifies the action in-place, especially the “set_bus” and “change_bus” attributes.
Note
This function does not check the cooldowns if you specify check_cooldown=False
Note
As from version 1.9.0 you are no longer forced to provide an observation if check_cooldown=False
Warning
For grid2op equal or lower to 1.9.5 this function was bugged in some corner cases. We highly recommend upgrading if you use this function with these grid2op versions.
Examples
To avoid the issue explained above, you can now do:
import grid2op import numpy as np env_name = "l2rpn_icaps_2021_small" env = grid2op.make(env_name) env.set_id(0) env.seed(0) obs = env.reset() act = env.action_space({"set_bus": {"substations_id": [(27, [1, -1, 2, 2, 1])]}}) obs, reward, done, info = env.step(act) act_sub28_clean = env.action_space({"set_bus": {"substations_id": [(28, [1, 2, 2, 1, 1])]}}) act_sub28_clean.remove_line_status_from_topo(obs) print(act_sub28_clean) # This action will: # - NOT change anything to the injections # - NOT perform any redispatching action # - NOT modify any storage capacity # - NOT perform any curtailment # - NOT force any line status # - NOT switch any line status # - NOT switch anything in the topology # - Set the bus of the following element(s): # - Assign bus 1 to line (extremity) id 41 [on substation 28] # - Assign bus 2 to line (origin) id 44 [on substation 28] # - Assign bus 1 to line (extremity) id 57 [on substation 28] # - Assign bus 1 to generator id 16 [on substation 28] # - NOT raise any alarm # - NOT raise any alert obs, reward, done, info = env.step(act_sub28_clean) # >>> info["exception"] : []
Note
The part of the action act_sub28_clean that would “- Assign bus 2 to line (extremity) id 42 [on substation 28]” has been removed because powerline 42 is disconnected in the observation and under a cooldown.
- Parameters:
obs (
grid2op.Observation.BaseObservation
) – The current observationcheck_cooldown (bool, optional) – If True (default) will modify the action only for the powerline impacted by a cooldown. Otherwise will modify all the powerlines.
- reset()[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Reset the action to the “do nothing” state.
- property set_bus: ndarray
Allows to retrieve (and affect) the busbars at which any element is set.
It behaves similarly as
BaseAction.gen_set_bus
and can be use to modify any elements type as opposed to the more specificBaseAction.gen_set_bus
,BaseAction.load_set_bus
,BaseAction.line_or_set_bus
,BaseAction.line_ex_set_bus
orBaseAction.storage_set_bus
that are specific to a certain type of objects.Notes
For performance reasons, it do not allow to modify the elements by there names.
The order of each elements are given in the
grid2op.Space.GridObjects.gen_pos_topo_vect
,grid2op.Space.GridObjects.load_pos_topo_vect
,grid2op.Space.GridObjects.line_or_pos_topo_vect
,grid2op.Space.GridObjects.line_ex_pos_topo_vect
orgrid2op.Space.GridObjects.storage_pos_topo_vect
For example:
act.set_bus = [(0,1), (1, -1), (3, 2)]
Will:
set to bus 1 the (unique) element for which *_pos_topo_vect is 1
disconnect the (unique) element for which *_pos_topo_vect is 2
set to bus 2 the (unique) element for which *_pos_topo_vect is 3
You can use the documentation page Elements modeled in this environment and their main properties for more information about which element correspond to what component of this vector.
- property set_line_status: ndarray
another name for
BaseAction.line_set_status()
- property set_storage: ndarray
Another name for the property
BaseAction.storage_p()
- property storage_change_bus: ndarray
Allows to retrieve (and affect) the busbars at which the storage units are changed.
It behaves similarly as
BaseAction.gen_change_bus
. See the help there for more information.
- property storage_p: ndarray
Allows to modify the setpoint of the storage units.
It behaves similarly as
BaseAction.redispatch
. See the help there for more information.Notes
The “load convention” is used for storage units. This means that:
if you ask a positive value, the storage unit will charge, power will be “taken” from the grid to the unit. The unit in this case will behave like a load
if you ask a negative value, the storage unit will discharge, power will be injected from the unit to the grid. The unit, in this case, will behave like a generator.
For more information, feel free to consult the documentation Storage units (optional) where more details are given about the modeling ot these storage units.
- property storage_set_bus: ndarray
Allows to retrieve (and affect) the busbars at which the action set the storage units.
Changed in version 1.10.0: From grid2op version 1.10.0 it is possible (under some cirumstances, depending on how the environment is created) to set the busbar to a number >= 3, depending on the value of type(act).n_busbar_per_sub.
- Returns:
A vector of integer, of size act.n_gen indicating what type of action is performed for each storage unit with the convention :
0 the action do not action on this storage unit
-1 the action disconnect the storage unit
1 the action set the storage unit to busbar 1
2 the action set the storage unit to busbar 2
3 the action set the storage unit to busbar 3 (grid2op >= 1.10.0)
etc. (grid2op >= 1.10.0)
- Return type:
res
Examples
Please refer to the documentation of
BaseAction.gen_set_bus
for more information.Note
Be careful not to mix “change” and “set”. For “change” you only need to provide the ID of the elements you want to change, for “set” you need to provide the ID AND where you want to set them.
- update(dict_: Dict[Literal['set_line_status', 'change_line_status', 'set_bus', 'change_bus', 'redispatch', 'set_storage', 'curtail', 'raise_alarm', 'raise_alert', 'injection', 'hazards', 'maintenance', 'shunt'], Any])[source]
Update the action with a comprehensible format specified by a dictionary.
Preferably, if a key of the argument dict_ is not found in
Action.authorized_keys
it should throw a warning. This argument will be completely ignored.This method also reset the attributes
Action._vectorized
Action._lines_impacted
andAction._subs_impacted
toNone
regardless of the argument in input.If an action consists of “reconnecting” a powerline, and this same powerline is affected by maintenance or a hazard, it will be erased without any warning. “hazards” and “maintenance” have the priority. This is a requirement for all proper
Action
subclass.- Parameters:
dict (
dict
) –If it’s
None
or empty it does nothing. Otherwise, it can contain the following (optional) keys:”injection” if the action will modify the injections (generator setpoint/load value - active or reactive) of the powergrid. It has optionally one of the following keys:
”load_p”: to set the active load values (this is a numpy array with the same size as the number of load in the power _grid with Nan: don’t change anything, else set the value
”load_q”: same as above but for the load reactive values
”prod_p”: same as above but for the generator active setpoint values. It has the size corresponding to the number of generators in the test case.
”prod_v”: same as above but set the voltage setpoint of generator units.
”hazards”: represents the hazards that the line might suffer (boolean vector) False: no hazard, nothing is done, True: a hazard, the powerline is disconnected
”maintenance”: represents the maintenance operation performed on each powerline (boolean vector) False: no maintenance, nothing is done, True: a maintenance is scheduled, the powerline is disconnected
”set_line_status”: a vector (int or float) to set the status of the powerline status (connected / disconnected) with the following interpretation:
0: nothing is changed,
-1: disconnect the powerline,
+1: reconnect the powerline. If an action consists in “reconnecting” a powerline, and this same powerline is affected by a maintenance or a hazard, it will be erased without any warning. “hazards” and “maintenance” have the priority.
”change_line_status”: a vector (bool) to change the status of the powerline. This vector should be interpreted as:
False
: do nothingTrue
: change the status of the powerline: disconnect it if it was connected, connect it if it was disconnected
”set_bus”: (numpy int vector or dictionary) will set the buses to which the objects are connected. It follows a similar interpretation than the line status vector:
0 -> don’t change anything
+1 -> set to bus 1,
+2 -> set to bus 2
+3 -> set to bus 3 (grid2op >= 1.10.0)
etc.
-1: You can use this method to disconnect an object by setting the value to -1.
”change_bus”: (numpy bool vector or dictionary) will change the bus to which the object is connected.
True
will change it (eg switch it from bus 1 to bus 2 or from bus 2 to bus 1). NB this is only active if the system has only 2 buses per substation.Note
Change in version: 1.10.0 This feature is deactivated if act.n_busbar_per_sub >= 3 or act.n_busbar_per_sub == 1
”redispatch”: the best use of this is to specify either the numpy array of the redispatch vector you want to apply (that should have the size of the number of generators on the grid) or to specify a list of tuple, each tuple being 2 elements: first the generator ID, second the amount of redispatching, for example [(1, -23), (12, +17)]
”set_storage”: the best use of this is to specify either the numpy array of the storage units vector you want to apply (that should have the size of the number of storage units on the grid) or to specify a list of tuple, each tuple being 2 elements: first the storage ID, second the amount of power you want to produce / absorb, for example [(1, -23), (12, +17)]
NB the difference between “set_bus” and “change_bus” is the following:
If “set_bus” is 1, then the object (load, generator or powerline) will be moved to bus 1 of the substation to which it is connected. If it is already to bus 1 nothing will be done. If it’s on another bus it will connect it to bus 1. It’s disconnected, it will reconnect it and connect it to bus 1.
If “change_bus” is True, then objects will be moved from one bus to another. If the object were on bus 1 then it will be moved on bus 2, and if it were on bus 2, it will be moved on bus 1. If the object is disconnected then the action is ambiguous, and calling it will throw an AmbiguousAction exception.
”curtail” : TODO
”raise_alarm” : TODO
”raise_alert”: TODO
NB: CHANGES: you can reconnect a powerline without specifying on each bus you reconnect it at both its ends. In that case the last known bus id for each its end is used.
NB: if for a given powerline, both switch_line_status and set_line_status is set, the action will not be usable. This will lead to an
grid2op.Exceptions.AmbiguousAction
exception.NB: The length of vectors provided here is NOT check in this function. This method can be “chained” and only on the final action, when used, eg. in the Backend, is checked.
NB: If a powerline is disconnected, on maintenance, or suffer an outage, the associated “set_bus” will be ignored. Disconnection has the priority on anything. This priority is given because, in case of hazard, the hazard has the priority over the possible actions.
Examples
Here are short examples on how to update an action eg. how to create a valid
Action
object that be used to modify agrid2op.Backend.Backend
.In all the following examples, we suppose that a valid grid2op environment is created, for example with:
import grid2op from grid2op.Action import BaseAction env_name = "l2rpn_case14_sandbox" # create a simple environment # and make sure every type of action can be used. env = grid2op.make(env_name, action_class=BaseAction)
Example 1: modify the load active values to set them all to 1. You can replace “load_p” by “load_q”, “prod_p” or “prod_v” to change the load reactive value, the generator active setpoint or the generator voltage magnitude setpoint.
new_load = np.ones(env.action_space.n_load) modify_load_active_value = env.action_space({"injection": {"load_p": new_load}}) print(modify_load_active_value)
Example 2: disconnect the powerline of id 1:
disconnect_powerline = env.action_space({"set_line_status": [(1, -1)]}) print(disconnect_powerline) # there is a shortcut to do that: disconnect_powerline2 = env.disconnect_powerline(line_id=1)
Example 3: force the reconnection of the powerline of id 5 by connected it to bus 1 on its origin side and bus 2 on its extremity side.
reconnect_powerline = env.action_space({"set_line_status": [(5, 1)], "set_bus": {"lines_or_id": [(5, 1)]}, "set_bus": {"lines_ex_id": [(5, 2)]} }) print(reconnect_powerline) # and the shorter method: reconnect_powerline = env.action.space.reconnect_powerline(line_id=5, bus_or=1, bus_ex=2)
Example 4: change the bus to which load 4 is connected:
change_load_bus = env.action_space({"set_bus": {"loads_id": [(4, 1)]} }) print(change_load_bus)
Example 5: reconfigure completely substation 5, and connect the first 3 elements to bus 1 and the last 3 elements to bus 2
sub_id = 5 target_topology = np.ones(env.sub_info[sub_id], dtype=dt_int) target_topology[3:] = 2 reconfig_sub = env.action_space({"set_bus": {"substations_id": [(sub_id, target_topology)] } }) print(reconfig_sub)
Example 6: apply redispatching of +17.42 MW at generator with id 23 and -27.8 at generator with id 1
redisp_act = env.action_space({"redispatch": [(23, +17.42), (23, -27.8)]}) print(redisp_act)
Example 7: apply an action on a storage unit: have the storage unit of id 0 produce 1.5MW
storage_act = env.action_space({"set_storage": [(0, -1.5)]}) print(storage_act)
Example 8: apply a action of type curtailment: limit the production to a renewable energy unit (in the example the generator with id 2) at 80% of its maximum capacity
renewable_energy_source = 2 storage_act = env.action_space({"curtail": [(renewable_energy_source, 0.8)]}) print(storage_act)
- Returns:
self – Return the modified instance. This is handy to chain modifications if needed.
- Return type:
- class grid2op.Action.CompleteAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
Class representing the possibility to play everything.
It cannot (and should not) be used by an Agent. Indeed, Agent actions are limited to
PlayableAction
. This class is used by the chronics, the environment the opponent or the voltage controler for example.Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.DispatchAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
only implements the modifications of the grid through “redispatch” keyword.Nothing else is supported and any attempt to use something else will have not impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.DontAct(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL
Warning
/!\ Internal, do not use unless you know what you are doing /!\
This type of action is only compatible with “do nothing”…
This class is model the action where you force someone to do absolutely nothing. It is not the “do nothing” action.
This is not the “do nothing” action. This class will not implement any way to modify the grid. Any attempt to modify it will fail.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL
update
(dict_)It has the particularity to not use dict_
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL
Warning
/!\ Internal, do not use unless you know what you are doing /!\
See the definition of
BaseAction.__init__()
and ofBaseAction
for more information. Nothing more is done in this constructor.
- class grid2op.Action.PlayableAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
From this class inherit all actions that the player will be allowed to do. This includes for example
TopologyAndDispatchAction
orTopologyAction
Methods:
__call__
()Warning
/!\ Internal, do not use unless you know what you are doing /!\
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
update
(dict_)Warning
/!\ Internal, do not use unless you know what you are doing /!\
- __call__()[source]
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Compare to the ancestor
BaseAction.__call__()
this type of BaseAction doesn’t allow internal actions The returned tuple is same, but with empty dictionaries for internal actions- Returns:
dict_injection (
dict
) – This dictionary is always emptyset_line_status (
numpy.ndarray
, dtype:int) – This array isBaseAction._set_line_status
switch_line_status (
numpy.ndarray
, dtype:bool) – This array isBaseAction._switch_line_status
set_topo_vect (
numpy.ndarray
, dtype:int) – This array isBaseAction._set_topo_vect
change_bus_vect (
numpy.ndarray
, dtype:bool) – This array isBaseAction._change_bus_vect
redispatch (
numpy.ndarray
, dtype:float) – The array isBaseAction._redispatch
curtail (
numpy.ndarray
, dtype:float) – The array isBaseAction._curtail
shunts (
dict
) – Always empty for this class
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- update(dict_)[source]
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Similar to
BaseAction
, except that the allowed entries are limited to the playable action set- Parameters:
dict (
dict
) – See the help ofBaseAction.update()
for a detailed explanation. If an entry is not in the playable action set, this will raise- Returns:
self – Return object itself thus allowing multiple calls to “update” to be chained.
- Return type:
- class grid2op.Action.PowerlineChangeAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
only implements the modifications of the grid through “change_line_status”.Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.PowerlineChangeAndDispatchAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
only implements the modifications of the grid with powerlines switch and dispatch actions.It accepts the key words: “change_line_status” and “redispatch”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.PowerlineChangeDispatchAndStorageAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
TODO storage doc
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.PowerlineSetAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
only implements the modifications of the grid through “set_line_status” keyword.Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.PowerlineSetAndDispatchAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
only implements the modifications of the grid with set topological and dispatch actions.It accepts the key words: “set_line_status” and “redispatch”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.SerializableActionSpace(gridobj, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>, _init_grid=True, _local_dir_cls=None)[source]
This class allows serializing/ deserializing the action space.
It should not be used inside an
grid2op.Environment.Environment
, as some functions of the action might not be compatible with the serialization, especially the checking of whether or not an action is legal or not.- actionClass
Type used to build the
SerializableActionSpace.template_act
- Type:
type
- _template_act
An instance of the “actionClass” provided used to provide higher level utilities, such as the size of the action (see
Action.size()
) or to sample a new Action (seegrid2op.Action.Action.sample()
)- Type:
Methods:
__init__
(gridobj[, actionClass, _init_grid, ...])INTERNAL USE ONLY
_is_ok_2
(n_busbar_per_sub, tup)check there are at least 2 elements per busbars
_is_ok_line
(n_busbar_per_sub, tup, lines_id)check there are at least a line connected to each buses
_sample_raise_alarm
([rnd_update])_sample_raise_alert
([rnd_update])change_bus
(name_element[, extremity, ...])Utilities to change the bus of a single element if you give its name.
disconnect_powerline
([line_id, line_name, ...])Utilities to disconnect a powerline more easily.
from_dict
(dict_)INTERNAL USE ONLY
get_all_unitary_alarm
(action_space)get_all_unitary_alert
(action_space)Return all unitary actions that raise an alert on powerlines.
get_all_unitary_curtail
(action_space[, ...])Curtailment action are continuous action.
get_all_unitary_line_change
(action_space)Return all unitary actions that "change" powerline status.
get_all_unitary_line_set
(action_space)Return all unitary actions that "set" powerline status.
get_all_unitary_line_set_simple
(action_space)Return all unitary actions that "set" powerline status but in a more simple way than
SerializableActionSpace.get_all_unitary_line_set()
get_all_unitary_redispatch
(action_space[, ...])Redispatching action are continuous action.
get_all_unitary_storage
(action_space[, ...])Storage action are continuous action.
get_all_unitary_topologies_change
(action_space)This methods allows to compute and return all the unitary topological changes that can be performed on a powergrid.
get_all_unitary_topologies_set
(action_space)This methods allows to compute and return all the unitary topological changes that can be performed on a powergrid.
get_back_to_ref_state
(obs[, ...])This function returns the list of unary actions that you can perform in order to get back to the "fully meshed" / "initial" topology.
Computes and return a vector that can be used in the "change_line_status" keyword if building an
BaseAction
Computes and returns a vector that can be used in the "set_status" keyword if building an
BaseAction
reconnect_powerline
(bus_or, bus_ex[, ...])Utilities to reconnect a powerline more easily.
sample
()A utility used to sample a new random
BaseAction
.set_bus
(name_element, new_bus[, extremity, ...])Utilities to set the bus of a single element if you give its name.
supports_type
(action_type)Returns if the current action_space supports the current action type.
- __init__(gridobj, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>, _init_grid=True, _local_dir_cls=None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
The
grid2op.Environment.Environment
is responsible for the creation of the action space. Do not attempt to make one yourself.- Parameters:
gridobj (
grid2op.Space.GridObjects
) – Representation of the underlying powergrid.actionClass (
type
) – Type of action used to buildSpace.SerializableSpace._template_obj
. It should derived fromBaseAction
.
- classmethod _is_ok_2(n_busbar_per_sub: int, tup) bool [source]
check there are at least 2 elements per busbars
- classmethod _is_ok_line(n_busbar_per_sub: int, tup: ndarray, lines_id: ndarray) bool [source]
check there are at least a line connected to each buses
- _sample_raise_alarm(rnd_update=None)[source]
Warning
/!\ Only valid with “l2rpn_icaps_2021” environment /!\
- change_bus(name_element: str, extremity: Literal['or', 'ex'] | None = None, substation: int | None = None, type_element: str | None = None, previous_action: BaseAction | None = None) BaseAction [source]
Utilities to change the bus of a single element if you give its name. NB Changing a bus has the effect to assign the object to bus 1 if it was before that connected to bus 2, and to assign it to bus 2 if it was connected to bus 1. It should not be mixed up with
ActionSpace.set_bus()
.If the parameter “previous_action” is not
None
, then the action given to it is updated (in place) and returned.- Parameters:
name_element (
str
) – The name of the element you want to change the busextremity (
str
) – “or” or “ex” for origin or extremity, ignored if an element is not a powerline.substation (
int
, optional) – Its substation ID, if you know it will increase the performance. Otherwise, the method will search for it.type_element (
str
, optional) – Type of the element to look for. It is here to speed up the computation. One of “line”, “gen” or “load”previous_action (
BaseAction
, optional) – The (optional) action to update. It should be of the same type asActionSpace.actionClass
Notes
If you use previous_action it will modify the action in place which means that previous_action will be modified by this method.
- Returns:
res – The action with the modification implemented
- Return type:
:raises res
grid2op.Exception.AmbiguousAction
: If previous_action has not the same type asActionSpace.actionClass
.Examples
You can use it this way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # change bus of element named 'gen_1_0' change_gen_0 = env.action_space.change_bus('gen_1_0', type_element="gen") # you are not forced to specify the element types change_load_1 = env.action_space.change_bus('load_2_1') # dealing with powerline, you can affect one of its extremity # (handy when you don't know on which substation it is located) change_line_8_or = env.action_space.change_bus('5_11_8', extremity="or") # and you can combine the action with change_line_14_ex = env.action_space.change_bus('12_13_14', extremity="ex") change_line_14_ex_load_2 = env.action_space.change_bus("load_3_2", previous_action=change_line_14_ex) print(change_line_14_ex_load_2) # be careful, "change_line_14_ex" is affected and is in fact equal to # "change_line_14_ex_load_2" # after the last call!
- disconnect_powerline(line_id: int | None = None, line_name: str | None = None, previous_action: BaseAction | None = None) BaseAction [source]
Utilities to disconnect a powerline more easily.
- Parameters:
line_id (
int
) – The powerline to be disconnected.line_name (
str
) – Name of the powerline. Note that either line_id or line_name should be provided. If both are provided, it is an error, if none are provided it is an error.previous_action (
BaseAction
) – If you want to stack up multiple actions.
- Returns:
res – The action that will disconnect the powerline.
- Return type:
Notes
If you use previous_action it will modify the action in place which means that previous_action will be modified by this method.
Examples
You can use it this way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # and now you can disconnect line 0 disco_line_0 = env.action_space.disconnect_powerline(line_id=0) # or line with name "0_4_1" disco_line_1 = env.action_space.disconnect_powerline(line_name="0_4_1") # and you can disconnect both line 2 and 3 with: disco_line_2 = env.action_space.disconnect_powerline(line_id=2) disco_line_2_and_3 = env.action_space.disconnect_powerline(line_id=3, previous_action=disco_line_2) print(disco_line_2_and_3) # be careful, "disco_line_2" is affected and is in fact equal to "disco_line_2_and_3" # after the last call!
- staticmethod from_dict(dict_)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Allows the de-serialization of an object stored as a dictionary (for example in the case of JSON saving).
- Parameters:
dict (
dict
) – Representation of an BaseAction Space (aka SerializableActionSpace) as a dictionary.- Returns:
res – An instance of an action space matching the dictionary.
- Return type:
:class:
SerializableActionSpace
- staticmethod get_all_unitary_alarm(action_space: Self) List[BaseAction] [source]
Warning
/!\ Only valid with “l2rpn_icaps_2021” environment /!\
- staticmethod get_all_unitary_alert(action_space: Self) List[BaseAction] [source]
Return all unitary actions that raise an alert on powerlines.
Warning
There will be one action per combination of attackable lines, so basically, if you can raise alerts on 10 powerline, you will end up with 2**10 actions.
If you got 22 attackable lines, then you got 2**22 actions… probably a TERRIBLE IDEA !
- staticmethod get_all_unitary_curtail(action_space: Self, num_bin: int = 10, min_value: float = 0.5) List[BaseAction] [source]
Curtailment action are continuous action. This method is an helper to convert the continuous action into discrete action (by rounding).
The number of actions is equal to num_bin (by default 10) per renewable generator (remember that only renewable generator can be curtailed in grid2op).
This method acts as followed:
it will divide the interval [0, 1] into num_bin, each will make a distinct action (then counting num_bin different action, because 0.0 is removed)
Note
With this “helper” only one generator is affected by one action. For example there are no action acting on both generator 1 and generator 2 at the same time.
- Parameters:
action_space (
ActionSpace
) – The action space used.num_bin (
int
) – Number of actions for each renewable generatormin_value (
float
) – Between 0. and 1.: minimum value allow for the curtailment. For example if you set this value to be 0.2 then no curtailment will be done to limit the generator below 20% of its maximum capacity
- Returns:
res – The list of all discretized curtailment actions.
- Return type:
list
- staticmethod get_all_unitary_line_change(action_space: Self) List[BaseAction] [source]
Return all unitary actions that “change” powerline status.
For each powerline, there is only one such action that consist in change its status.
- Parameters:
action_space (
ActionSpace
) – The action space used.- Returns:
res – The list of all “change” action acting on powerline status
- Return type:
list
- staticmethod get_all_unitary_line_set(action_space: Self) List[BaseAction] [source]
Return all unitary actions that “set” powerline status.
For each powerline, if there are 2 busbars per substation, there are 5 such actions:
disconnect it
connected it origin at bus 1 and extremity at bus 1
connected it origin at bus 1 and extremity at bus 2
connected it origin at bus 2 and extremity at bus 1
connected it origin at bus 2 and extremity at bus 2
This number increases quite rapidly if there are more busbars allowed per substation of course. For example if you allow for 3 busbars per substations, it goes from (1 + 2*2) [=5] to (1 + 3 * 3) [=10] and if you allow for 4 busbars per substations you end up with (1 + 4 * 4) [=17] possible actions per powerline.
- Parameters:
action_space (
ActionSpace
) – The action space used.- Returns:
res – The list of all “set” action acting on powerline status
- Return type:
list
- staticmethod get_all_unitary_line_set_simple(action_space: Self) List[BaseAction] [source]
Return all unitary actions that “set” powerline status but in a more simple way than
SerializableActionSpace.get_all_unitary_line_set()
For each powerline, there are 2 such actions:
disconnect it
connected it (implicitly to the last known busbar where each side used to be connected)
It has the main advantages to “only” add 2 actions per powerline instead of 5 (if the number of busbars per substation is 2).
Using this method, powerlines will always be reconnected to their previous busbars (the last known one) and you will always get exactly 2 actions per powerlines.
- Parameters:
action_space (
ActionSpace
) – The action space used.- Returns:
res – The list of all “set” action acting on powerline status
- Return type:
list
- staticmethod get_all_unitary_redispatch(action_space, num_down=5, num_up=5, max_ratio_value=1.0) List[BaseAction] [source]
Redispatching action are continuous action. This method is an helper to convert the continuous action into “discrete actions” (by rounding).
The number of actions is equal to num_down + num_up (by default 10) per dispatchable generator.
This method acts as followed:
it will divide the interval [-gen_max_ramp_down, 0] into num_down, each will make a distinct action (then counting num_down different action, because 0.0 is removed)
it will do the same for [0, gen_maw_ramp_up]
Note
With this “helper” only one generator is affected by one action. For example there are no action acting on both generator 1 and generator 2 at the same time.
- Parameters:
action_space (
ActionSpace
) – The action space used.num_down (
int
) – In how many intervals the “redispatch down” will be splitnum_up (
int
) – In how many intervals the “redispatch up” will be splitmax_ratio_value (
float
) – Expressed in terms of ratio of gen_max_ramp_up / gen_max_ramp_down, it gives the maximum value that will be used to generate the actions. For example, if max_ratio_value=0.5, then it will not generate actions that attempts to redispatch more than 0.5 * gen_max_ramp_up (or less than - 0.5 * gen_max_ramp_down). This helps reducing the instability that can be caused by redispatching.
- Returns:
res – The list of all discretized redispatching actions.
- Return type:
list
- staticmethod get_all_unitary_storage(action_space: Self, num_down: int = 5, num_up: int = 5) List[BaseAction] [source]
Storage action are continuous action. This method is an helper to convert the continuous action into discrete action (by rounding).
The number of actions is equal to num_down + num_up (by default 10) per storage unit.
This method acts as followed:
it will divide the interval [-storage_max_p_prod, 0] into num_down, each will make a distinct action (then counting num_down different action, because 0.0 is removed)
it will do the same for [0, storage_max_p_absorb]
Note
With this “helper” only one storage unit is affected by one action. For example there are no action acting on both storage unit 1 and storage unit 2 at the same time.
- Parameters:
action_space (
ActionSpace
) – The action space used.- Returns:
res – The list of all discretized actions on storage units.
- Return type:
list
- staticmethod get_all_unitary_topologies_change(action_space: Self, sub_id: int | None = None) List[BaseAction] [source]
This methods allows to compute and return all the unitary topological changes that can be performed on a powergrid.
The changes will be performed using the “change_bus” method. It excludes the “do nothing” action
- Parameters:
action_space (
ActionSpace
) – The action space used.sub_id (
int
, optional) – The substation ID. IfNone
it is done for all substations.
Notes
This might take a long time on large grid (possibly 10-15 mins for the IEEE 118 for example)
- Returns:
res – The list of all the topological actions that can be performed.
- Return type:
list
Examples
You can use it this way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # all "change bus" action for all the substations all_change_actions = env.action_space.get_all_unitary_topologies_change(env.action_space) # you can only study "change_bus" action for a given substation (can dramatically improve the computation time) all_change_actions_sub4 = env.action_space.get_all_unitary_topologies_change(env.action_space, sub_id=4)
- staticmethod get_all_unitary_topologies_set(action_space: Self, sub_id: int | None = None, add_alone_line=True, _count_only=False) List[BaseAction] [source]
This methods allows to compute and return all the unitary topological changes that can be performed on a powergrid.
The changes will be performed using the “set_bus” method. The “do nothing” action will be counted once per substation in the grid.
It returns all the “valid” topologies available at any substation (if sub_id is
None
-default) or at the requested substation.To be valid a topology must satisfy:
there are at least one side of the powerline connected to each busbar (there cannot be a load alone on a bus or a generator alone on a bus for example)
if add_alone_line=False (not the default) then there must be at least two elements in a substation
Note
We try to make the result of this function as small as possible. This means that if at any substation the number of “valid” topology is only 1, it is ignored and will not be added in the result.
This imply that when env.n_busbar_per_sub=1 then this function returns the empty list.
Note
If add_alone_line is True (again NOT the default) then if any substation counts less than 3 elements or less then no action will be added for this substation.
If there are 4 or 5 elements at a substation (and add_alone_line=False), then only topologies using 2 busbar will be used.
Warning
This generates only topologies were all elements are connected. It does not generate topologies with disconnected lines.
Warning
As far as we know, there are no bugs in this implementation. However we did not spend lots of time finding a “closed form” formula to count exactly the number of possible topologies. This means that we might have missed some topologies or counted the same “results” multiple times if there has been an error in the symmetries.
If you are interested in this topic, let us know with a discussion, for example here https://github.com/rte-france/Grid2Op/discussions
- Parameters:
action_space (
ActionSpace
) – The action space used.sub_id (
int
, optional) – The substation ID. IfNone
it is done for all substations.add_alone_line (
bool
, optional) – IfTrue
(default) then topologiees where 1 line side is “alone” on a bus are valid and put in the output (more topologies are considered). If not then only topologies with at least one line AND 2 elements per buses are returned._count_only (
bool
, optional) – Does not return the list but rather only the number of elements there would be
Notes
This might take a long time on large grid (possibly 10-15 mins for the IEEE 118 for example)
- Returns:
res – The list of all the topological actions that can be performed.
- Return type:
list
Examples
You can use it this way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # all "set_bus" actions all_change_actions = env.action_space.get_all_unitary_topologies_set(env.action_space) # you can only study "set_bus" action for a given substation (can dramatically improve the computation time) all_change_actions_sub4 = env.action_space.get_all_unitary_topologies_set(env.action_space, sub_id=4)
- get_back_to_ref_state(obs: BaseObservation, storage_setpoint: float = 0.5, precision: int = 5) Dict[Literal['powerline', 'substation', 'redispatching', 'storage', 'curtailment'], List[BaseAction]] [source]
This function returns the list of unary actions that you can perform in order to get back to the “fully meshed” / “initial” topology.
- Parameters:
observation – The current observation (the one you want to know actions to set it back ot)
Notes
In this context a “unary” action, is (exclusive or):
an action that acts on a single powerline
an action on a single substation
a redispatching action (acting possibly on all generators)
a storage action (acting possibly on all generators)
The list might be relatively long, in the case where lots of actions are needed. Depending on the rules of the game (for example limiting the action on one single substation), in order to get back to this topology, multiple consecutive actions will need to be implemented.
It is returned as a dictionnary of list. This dictionnary has 4 keys:
“powerline” for the list of actions needed to set back the powerlines in a proper state (connected). They can be of type “change_line” or “set_line”.
“substation” for the list of actions needed to set back each substation in its initial state (everything connected to bus 1). They can be implemented as “set_bus” or “change_bus”
“redispatching”: for the redispatching actions (there can be multiple redispatching actions needed because of the ramps of the generator)
“storage”: for action on storage units (you might need to perform multiple storage actions because of the maximum power these units can absorb / produce )
“curtailment”: for curtailment action (usually at most one such action is needed)
After receiving these lists, the agent has the choice for the order in which to apply these actions as well as how to best combine them (you can most of the time combine action of different types in grid2op.)
Warning
It does not presume anything on the availability of the objects. For examples, this funciton ignores completely the cooldowns on lines and substations.
Warning
For the storage units, it tries to set their current setpoint to storage_setpoint % of their storage total capacity. Applying these actions at different times might not fully set back the storage to this capacity in case of storage losses !
Warning
See section Note on powerline status for note on the powerline status. It might happen that you modify a powerline status using a “set_bus” (ie tagged as “susbtation” by this function).
Warning
It can raise warnings in case it’s not possible, with your action space, to get back to the original / fully meshed topology
Examples
You can use it like this:
import grid2op env_name = "l2rpn_case14_sandbox" env = grid2op.make(env_name) obs = env.reset(seed=1) # perform a random action obs, reward, done, info = env.step(env.action_space.sample()) assert not done # you might end up in a "done" state depending on the random action acts = obs.get_back_to_ref_state() print(acts)
- get_change_line_status_vect() ndarray [source]
Computes and return a vector that can be used in the “change_line_status” keyword if building an
BaseAction
- Returns:
res – A vector that doesn’t affect the grid, but can be used in “change_line_status”
- Return type:
numpy.array
, dtype:dt_bool
- get_set_line_status_vect() ndarray [source]
Computes and returns a vector that can be used in the “set_status” keyword if building an
BaseAction
- Returns:
res – A vector that doesn’t affect the grid, but can be used in “set_line_status”
- Return type:
numpy.array
, dtype:dt_int
- reconnect_powerline(bus_or: int, bus_ex: int, line_id: int | None = None, line_name: str | None = None, previous_action: BaseAction | None = None) BaseAction [source]
Utilities to reconnect a powerline more easily.
Note that in case “bus_or” or “bus_ex” are not the current bus to which the powerline is connected, they will be affected by this action.
Notes
This utility requires you to specify on which bus you want to connect each end (”origin” or “extremity”) of the powerline you want to reconnect.
If you don’t want to specify them, you can set them to
0
and it will reconnect them to the last known buses to which they were connected (this is automatically done by the Environment since version 0.8.0).If you use previous_action it will modify the action in place which means that previous_action will be modified by this method.
- Parameters:
line_id (
int
) – The powerline to be disconnected.bus_or (
int
) – On which bus to reconnect the powerline at its origin sidebus_ex (
int
) – On which bus to reconnect the powerline at its extremity sideprevious_action –
- Returns:
res – The action that will reconnect the powerline.
- Return type:
Examples
You can use it this way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # and now you can reconnect line 0 reco_line_0 = env.action_space.reconnect_powerline(line_id=0, bus_or=1, bus_ex=0) # or line with name "0_4_1" to bus 1 on its "origin" end and bus 2 on its "extremity" end reco_line_1 = env.action_space.reconnect_powerline(line_name="0_4_1", bus_or=1, bus_ex=2) # and you can reconnect both line 2 and 3 with: reco_line_2 = env.action_space.reconnect_powerline(line_id=2, bus_or=1, bus_ex=2) reco_line_2_and_3 = env.action_space.reconnect_powerline(line_id=3, bus_or=0, bus_ex=1, previous_action=reco_line_2) print(reco_line_2_and_3) # be careful, "reco_line_2" is affected and is in fact equal to "reco_line_2_and_3" # after the last call!
- sample() BaseAction [source]
A utility used to sample a new random
BaseAction
.The sampled action is unitary: It has an impact on a single line/substation/generator.
There is no guarantee concerning the “legality” of the action (see the description of the Action module for more information about illegal action).
It will only act by doing action supported by the action space. For example, if the action space does not support “redispatching” then this method will NOT sample any redispatching action.
- Returns:
res – A random action sampled from the
ActionSpace.actionClass
- Return type:
Examples
The first usage is to sample uniform unary actions, you can do this with the following:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # and now you can sample from the action space random_action = env.action_space.sample()
Note that the random action can be illegal depending on the game rules defined in the rules
grid2op.Rules
If for some reason you want to sample more complex actions, you can do this the following way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # and now you can sample from the action space random_action = env.action_space() # this action is not random at all, it starts by "do nothing" for i in range(5): # my resulting action will be a complex action # that will be the results of applying 5 random actions random_action += env.action_space.sample() print(random_action)
- set_bus(name_element: str, new_bus: int, extremity: Literal['or', 'ex'] | None = None, substation: int | None = None, type_element: int | None = None, previous_action: BaseAction | None = None) BaseAction [source]
Utilities to set the bus of a single element if you give its name. NB Setting a bus has the effect to assign the object to this bus. If it was before that connected to bus 1, and you assign it to bus 1 (new_bus = 1) it will stay on bus 1. If it was on bus 2 (and you still assign it to bus 1) it will be moved to bus 2. 1. It should not be mixed up with
ActionSpace.change_bus()
.If the parameter “previous_action” is not
None
, then the action given to it is updated (in place) and returned.- Parameters:
name_element (
str
) – The name of the element you want to change the busnew_bus (
int
) – Id of the new bus to connect the object to.extremity (
str
) – “or” or “ext” for origin or extremity, ignored if the element is not a powerline.substation (
int
, optional) – Its substation ID, if you know it will increase the performance. Otherwise, the method will search for it.type_element (
str
, optional) – Type of the element to look for. It is here to speed up the computation. One of “line”, “gen” or “load”previous_action (
BaseAction
, optional) – The (optional) action to update. It should be of the same type asActionSpace.actionClass
- Returns:
res – The action with the modification implemented
- Return type:
- Raises:
AmbiguousAction – If previous_action has not the same type as
ActionSpace.actionClass
.
Examples
You can use it this way:
import grid2op env = grid2op.make("l2rpn_case14_sandbox") # set bus of element named 'gen_1_0' to bus 2 setbus_gen_0 = env.action_space.set_bus('gen_1_0', new_bus=2, type_element="gen") # are not forced to specify the element types (example with load set to bus 1) setbus_load_1 = env.action_space.set_bus('load_2_1', new_bus=1) # dealing with powerline, you can affect one of its extremity # (handy when you don't know on which substation it is located) setbus_line_8_or = env.action_space.set_bus('5_11_8', new_bus=1, extremity="or") # and you can combine the actions with: setbus_line_14_ex = env.action_space.set_bus('12_13_14', new_bus=2, extremity="ex") setbus_line_14_ex_load_2 = env.action_space.set_bus("load_3_2", new_bus=1, previous_action=setbus_line_14_ex) print(setbus_line_14_ex_load_2) # be careful, "setbus_line_14_ex" is affected and is in fact equal to # "setbus_line_14_ex_load_2" # after the last call!
- supports_type(action_type: Literal['set_line_status', 'change_line_status', 'set_bus', 'change_bus', 'redispatch', 'storage_power', 'set_storage', 'curtail', 'curtail_mw', 'raise_alarm', 'raise_alert'])[source]
Returns if the current action_space supports the current action type.
- Parameters:
action_type (
str
) – One of “set_line_status”, “change_line_status”, “set_bus”, “change_bus”, “redispatch”, “storage_power”, “set_storage”, “curtail”, “curtail_mw”, “raise_alarm” or “raise_alert” A string representing the action types you want to inspect.- Return type:
True
if you can use the action_type to create an action,False
otherwise.
Examples
To know if you can use the act.set_bus property to change the bus of an element, you can use:
import grid2op from grid2op.Converter import ConnectivityConverter env = grid2op.make("l2rpn_case14_sandbox", test=True) can_i_use_set_bus = env.action_space.supports_type("set_bus") # this is True env2 = grid2op.make("educ_case14_storage", test=True) can_i_use_set_bus = env2.action_space.supports_type("set_bus") # this is False # this environment do not allow for topological changes but only action on storage units and redispatching
- class grid2op.Action.TopologyAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
only implements the modifications of the grid with topological actions.It accepts the key words: “set_line_status”, “change_line_status”, “set_bus” and “change_bus”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.TopologyAndDispatchAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
implements the modifications of the grid with topological and redispatching actions.It accepts the key words: “set_line_status”, “change_line_status”, “set_bus”, “change_bus” and “redispatch”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.TopologyChangeAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
implements the modifications of the grid with “change” topological actions.It accepts the key words: “change_line_status” and “change_bus”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.TopologyChangeAndDispatchAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
implements the modifications of the grid with “change” topological actions and allows for redispatching.It accepts the key words: “change_line_status”, “change_bus” and “redispatch”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.TopologySetAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
implements the modifications of the grid with “set” topological actions.It accepts the key words: “set_line_status” and “set_bus”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.TopologySetAndDispatchAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
This type of
PlayableAction
implements the modifications of the grid with “set” topological actions and allows for redispatching.It accepts the key words: “set_line_status”, “set_bus” and “redispatch”. Nothing else is supported and any attempt to use something else will have no impact.
Methods:
__init__
([_names_chronics_to_backend])INTERNAL USE ONLY
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL USE ONLY
Warning
/!\ Internal, do not use unless you know what you are doing /!\
It is NOT recommended to create an action with this method, use the action space of the environment
grid2op.Environment.Environment.action_space
instead.This is used to create an BaseAction instance. Preferably,
BaseAction
should be created withActionSpace
.IMPORTANT: Use
ActionSpace.__call__()
orActionSpace.sample()
to generate a valid action.
- class grid2op.Action.VoltageOnlyAction(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
INTERNAL
Warning
/!\ Internal, do not use unless you know what you are doing /!\
This is the main class used by the voltage controller.
This class is here to serve as a base class for the controller of the voltages (if any). It allows to perform only modification of the generator voltage set point.
Only action of type “injection” are supported, and only setting “prod_v” keyword.
Methods:
__init__
([_names_chronics_to_backend])See the definition of
BaseAction.__init__()
and ofBaseAction
for more information.Warning
/!\ Internal, do not use unless you know what you are doing /!\
update
(dict_)Warning
/!\ Internal, do not use unless you know what you are doing /!\
- __init__(_names_chronics_to_backend: Dict[Literal['loads', 'prods', 'lines'], Dict[str, str]] | None = None)[source]
See the definition of
BaseAction.__init__()
and ofBaseAction
for more information. Nothing more is done in this constructor.
- _check_dict()[source]
Warning
/!\ Internal, do not use unless you know what you are doing /!\
Check that nothing, beside prod_v has been updated with this action.
- update(dict_)[source]
Warning
/!\ Internal, do not use unless you know what you are doing /!\
As its original implementation, this method allows modifying the way a dictionary can be mapped to a valid
BaseAction
.It has only minor modifications compared to the original
BaseAction.update()
implementation, most notably, it doesn’t update theBaseAction._dict_inj
. It raises a warning if attempting to change them.- Parameters:
dict (
dict
) – See the help ofBaseAction.update()
for a detailed explanation. NB all the explanations concerning the “injection”, “change bus”, “set bus”, or “change line status” are irrelevant for this subclass.- Returns:
self – Return object itself thus allowing multiple calls to “update” to be chained.
- Return type:
PowerLineSet
If you still can’t find what you’re looking for, try in one of the following pages:
Still trouble finding the information ? Do not hesitate to send a github issue about the documentation at this link: Documentation issue template