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:

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)

set_bus

int

dim_topo

gen_set_bus

int

n_gen

load_set_bus

int

n_load

line_or_set_bus

int

n_line

line_ex_set_bus

int

n_line

storage_set_bus

int

n_storage

change_bus

bool

dim_topo

gen_change_bus

bool

n_gen

load_change_bus

bool

n_load

line_or_change_bus

bool

n_line

line_ex_change_bus

bool

n_line

storage_change_bus

bool

n_storage

line_set_status

int

n_line

line_change_status

bool

n_line

redispatch

float

n_gen

storage_p

float

n_storage

curtail

float

n_gen

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: (see grid2op.Rules.BaseRules and grid2op.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:

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:

ActionSpace(gridobj, legal_action[, actionClass])

ActionSpace should be created by an grid2op.Environment.Environment with its parameters coming from a properly set up grid2op.Backend.Backend (ie a Backend instance with a loaded powergrid.

BaseAction()

This is a base class for each BaseAction objects.

CompleteAction()

Class representing the possibility to play everything.

DispatchAction()

This type of PlayableAction only implements the modifications of the grid through "redispatch" keyword.

DontAct()

INTERNAL

PlayableAction()

From this class inherit all actions that the player will be allowed to do.

PowerlineChangeAction()

This type of PlayableAction only implements the modifications of the grid through "change_line_status".

PowerlineChangeAndDispatchAction()

This type of PlayableAction only implements the modifications of the grid with powerlines switch and dispatch actions.

PowerlineChangeDispatchAndStorageAction()

TODO storage doc

PowerlineSetAction()

This type of PlayableAction only implements the modifications of the grid through "set_line_status" keyword.

PowerlineSetAndDispatchAction()

This type of PlayableAction only implements the modifications of the grid with set topological and dispatch actions.

SerializableActionSpace(gridobj[, ...])

This class allows serializing/ deserializing the action space.

TopologyAction()

This type of PlayableAction only implements the modifications of the grid with topological actions.

TopologyAndDispatchAction()

This type of PlayableAction implements the modifications of the grid with topological and redispatching actions.

TopologyChangeAction()

This type of PlayableAction implements the modifications of the grid with "change" topological actions.

TopologyChangeAndDispatchAction()

This type of PlayableAction implements the modifications of the grid with "change" topological actions and allows for redispatching.

TopologySetAction()

This type of PlayableAction implements the modifications of the grid with "set" topological actions.

TopologySetAndDispatchAction()

This type of PlayableAction implements the modifications of the grid with "set" topological actions and allows for redispatching.

VoltageOnlyAction()

INTERNAL

class grid2op.Action.ActionSpace(gridobj, legal_action, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>)[source]

ActionSpace should be created by an grid2op.Environment.Environment with its parameters coming from a properly set up grid2op.Backend.Backend (ie a Backend instance with a loaded powergrid. See grid2op.Backend.Backend.load_grid() for more information).

It will allow, thanks to its ActionSpace.__call__() method to create valid BaseAction. It is the the preferred way to create an object of class BaseAction 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 of BaseAction 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 the BaseAction.

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, injection])

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[, actionClass])

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['injection', 'hazards', 'maintenance', 'set_line_status', 'change_line_status', 'set_bus', 'change_bus', 'redispatch', 'set_storage', 'curtail', 'raise_alarm', 'raise_alert'], Any] = None, check_legal: bool = False, env: grid2op.Environment.BaseEnv = None, *, injection=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) – see Action.__call__() documentation for an extensive help about this parameter

  • check_legal (bool) – is there a test performed on the legality of the action. NB When an object of class Action is used, it is automatically tested for ambiguity. If this parameter is set to True 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:

BaseAction

__init__(gridobj, legal_action, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>)[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…

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:
Returns:

resTrue if the action is legal, ie is allowed to be performed by the rules of the game. False otherwise.

Return type:

bool

close()[source]

INTERNAL

Warning

/!\ Internal, do not use unless you know what you are doing /!\

Make sure all references to possible backends are closed. This is not used here in general but might be for some specific cases.

copy()[source]

INTERNAL

Warning

/!\ Internal, do not use unless you know what you are doing /!\

Perform a deep copy of the Observation space.

class grid2op.Action.BaseAction[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 and ActionSpace object that has been properly set up by an grid2op.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 status

    • False: 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 done

    • True: 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 and BaseAction._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 the BaseAction.__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 powerline

  • True: 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 affected

  • True: 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 case BaseAction._subs_impacted[sub_id] is True) or not (in this case BaseAction._subs_impacted[sub_id] is False)

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 case BaseAction._lines_impacted[line_id] is True) or not (in this case BaseAction._subs_impacted[line_id] is False)

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__()

INTERNAL USE ONLY

__str__()

This utility allows printing in a human-readable format what objects will be impacted by the action.

_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.

_check_for_ambiguity()

This method checks if an action is ambiguous or not.

_digest_alarm(dict_)

_get_array_from_attr_name(attr_name)

INTERNAL

_is_curtailment_ambiguous()

check if curtailment action is ambiguous

_is_storage_ambiguous()

check if storage actions are ambiguous

_post_process_from_vect()

called at the end of "from_vect" if the function requires post processing

_reset_vect()

INTERNAL USE ONLY

alarm_raised()

INTERNAL

alert_raised()

INTERNAL

as_dict()

Represent an action "as a" dictionary.

as_serializable_dict()

This method returns an action as a dictionnary, that can be serialized using the "json" module.

can_affect_something()

This functions returns True if the current action has any chance to change the grid.

check_space_legit()

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.

get_change_line_status_vect()

Computes and returns a vector that can be used in the BaseAction.__call__() with the keyword "set_status" if building an BaseAction.

get_gen_modif()

Retrieve the modification that will be performed on all the generators

get_load_modif()

Retrieve the modification that will be performed on all the loads

get_set_line_status_vect()

Computes and returns a vector that can be used in the BaseAction.__call__() with the keyword "set_status" if building an BaseAction.

get_storage_modif()

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.

get_types()

Shorthand to get the type of an action.

impact_on_objects()

This will return a dictionary which contains details on objects that will be impacted by the action.

is_ambiguous()

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).

process_grid2op_compat()

INTERNAL

process_shunt_satic_data()

remove possible shunts data from the classes, if shunts are deactivated

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:

__hash__

change_bus

Allows to retrieve (and affect) the busbars at which any element is change.

change_line_status

another name for BaseAction.change_line_status()

curtail

Allows to perfom some curtailment on some generators

curtail_mw

Allows to perfom some curtailment on some generators in MW (by default in grid2Op it should be expressed in ratio of gen_pmax)

gen_change_bus

Allows to retrieve (and affect) the busbars at which the action change the generator units.

gen_set_bus

Allows to retrieve (and affect) the busbars at which the action set the generator units.

line_change_status

Property to set the status of the powerline.

line_ex_change_bus

Allows to retrieve (and affect) the busbars at which the extremity side of powerlines are changed.

line_ex_set_bus

Allows to retrieve (and affect) the busbars at which the extremity side of each powerline is set.

line_or_change_bus

Allows to retrieve (and affect) the busbars at which the origin side of powerlines are changed.

line_or_set_bus

Allows to retrieve (and affect) the busbars at which the action set the lines (origin side).

line_set_status

Property to set the status of the powerline.

load_change_bus

Allows to retrieve (and affect) the busbars at which the loads is changed.

load_set_bus

Allows to retrieve (and affect) the busbars at which the action set the loads.

raise_alarm

raise_alert

Property to raise alert.

redispatch

Allows to retrieve (and affect) the redispatching setpoint of the generators.

set_bus

Allows to retrieve (and affect) the busbars at which any element is set.

set_line_status

another name for BaseAction.line_set_status()

set_storage

Another name for the property BaseAction.storage_p()

storage_change_bus

Allows to retrieve (and affect) the busbars at which the storage units are changed.

storage_p

Allows to modify the setpoint of the storage units.

storage_set_bus

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 type DispatchAction) 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 of BaseAction._check_for_ambiguity() must be ensured by this the derived class.

Returns:

  • dict_injection (dict) – This dictionnary is BaseAction._dict_inj

  • set_line_status (numpy.ndarray, dtype:int) – This array is BaseAction._set_line_status

  • switch_line_status (numpy.ndarray, dtype:bool) – This array is BaseAction._switch_line_status

  • set_topo_vect (numpy.ndarray, dtype:int) – This array is BaseAction._set_topo_vect

  • change_bus_vect (numpy.ndarray, dtype:bool) – This array is BaseAction._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 setpoint

  • curtailment (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 class TopologyAction (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__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.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)
_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)[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)[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)[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 powerlines

    • self._set_line_status has not the same size as the number of powerlines

    • the 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 powergrid

    • self._change_bus_vect has not the same dimension as the number of elements on the powergrid

  • For redispatching, Ambiguous actions can come from:

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.

_digest_alarm(dict_)[source]

Warning

/!\ Only valid with “l2rpn_icaps_2021” environment /!\

_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() and GridObject.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

_is_curtailment_ambiguous()[source]

check if curtailment action is ambiguous

_is_storage_ambiguous()[source]

check if storage actions are ambiguous

_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 specific BaseAction.gen_change_bus, BaseAction.load_change_bus, BaseAction.line_or_change_bus, BaseAction.line_ex_change_bus or BaseAction.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 or grid2op.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 inspect

  • gen_id (int) – The ID of the generator we want to inspect

  • line_id (int) – The ID of the powerline we want to inspect

  • substation_id (int) – The ID of the substation we want to inspect

  • storage_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” action

  • True 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 an BaseAction.

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 an BaseAction.

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” command

  • gen_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” command

  • load_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 an BaseAction.

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 an BaseAction.

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 component True if the line STATUS is impacted by the action, and False otherwise. See BaseAction._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 component True if the substation is impacted by the action, and False otherwise. See BaseAction._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 value

  • voltage (bool) – Does it affect the voltage

  • topology (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 redispatching

  • storage (bool) – Does it performs (explicitly) any action on the storage production / consumption

  • curtailment (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 to None

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:

  1. for each controlable generators $p^{(c)}_{min} <= p^{(c)}_t <= p^{(c)}_{max}$

  2. for each controlable generators $-ramp_{min}^{(c)} <= p^{(c)}_t - p^{(c)}_{t-1} <= ramp_{max}^{(c)}$

  3. 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 to True) or to modify the action “in-place” (default, when False)

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 powerline

  • True 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_line_status_from_topo(obs: grid2op.Observation.BaseObservation = 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 observation

  • check_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 specific BaseAction.gen_set_bus, BaseAction.load_set_bus, BaseAction.line_or_set_bus, BaseAction.line_ex_set_bus or BaseAction.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 or grid2op.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_)[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 and Action._subs_impacted to None 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 nothing

    • True: 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. .. versionchanged:: 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.Exception.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 a grid2op.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:

BaseAction

class grid2op.Action.CompleteAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.DispatchAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.DontAct[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__()

INTERNAL

update(dict_)

It has the particularity to not use dict_

__init__()[source]

INTERNAL

Warning

/!\ Internal, do not use unless you know what you are doing /!\

See the definition of BaseAction.__init__() and of BaseAction for more information. Nothing more is done in this constructor.

update(dict_)[source]

It has the particularity to not use dict_

Parameters:

dict (dict) – A dictionnary, not taken into account for this specific class.

class grid2op.Action.PlayableAction[source]

From this class inherit all actions that the player will be allowed to do. This includes for example TopologyAndDispatchAction or TopologyAction

Methods:

__call__()

Warning

/!\ Internal, do not use unless you know what you are doing /!\

__init__()

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:

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.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 of BaseAction.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:

PlayableAction

class grid2op.Action.PowerlineChangeAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.PowerlineChangeAndDispatchAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.PowerlineChangeDispatchAndStorageAction[source]

TODO storage doc

Methods:

__init__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.PowerlineSetAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.PowerlineSetAndDispatchAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.SerializableActionSpace(gridobj, actionClass=<class 'grid2op.Action.baseAction.BaseAction'>, _init_grid=True)[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 (see grid2op.Action.Action.sample())

Type:

BaseAction

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.

get_change_line_status_vect()

Computes and return a vector that can be used in the "change_line_status" keyword if building an BaseAction

get_set_line_status_vect()

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)[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 build Space.SerializableSpace._template_obj. It should derived from BaseAction.

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 /!\

_sample_raise_alert(rnd_update=None)[source]

Warning

Not available in all environments.

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 bus

  • extremity (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 as ActionSpace.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:

BaseAction

:raises res grid2op.Exception.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")

# 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:

BaseAction

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 generator

  • min_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 split

  • num_up (int) – In how many intervals the “redispatch up” will be split

  • max_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. If None 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. If None it is done for all substations.

  • add_alone_line (bool, optional) – If True (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 side

  • bus_ex (int) – On which bus to reconnect the powerline at its extremity side

  • previous_action

Returns:

res – The action that will reconnect the powerline.

Return type:

BaseAction

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:

BaseAction

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 bus

  • new_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 as ActionSpace.actionClass

Returns:

res – The action with the modification implemented

Return type:

BaseAction

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)[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” or “curtail_mw” 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[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.TopologyAndDispatchAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.TopologyChangeAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.TopologyChangeAndDispatchAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.TopologySetAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.TopologySetAndDispatchAction[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__()

INTERNAL USE ONLY

__init__()[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 with ActionSpace.

IMPORTANT: Use ActionSpace.__call__() or ActionSpace.sample() to generate a valid action.

class grid2op.Action.VoltageOnlyAction[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__()

See the definition of BaseAction.__init__() and of BaseAction for more information.

_check_dict()

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__()[source]

See the definition of BaseAction.__init__() and of BaseAction 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 the BaseAction._dict_inj. It raises a warning if attempting to change them.

Parameters:

dict (dict) – See the help of BaseAction.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