LightSimBackend

This is an implementation of a grid2op Backend that uses lightsim2grid simulator coded in c++.

The integration with grid2op is rather easy. You simply need to provide the key-word argument backend=LightSimBackend() when building your environment using the grid2op.make function and you can use it transparently.

Example

See the section Use with grid2op for more information and more examples.

For standard grid2op environment, you can use it like:

import grid2op
from lightsim2grid.LightSimBackend import LightSimBackend
from grid2op.Agent import RandomAgent

# create an environment
env_name = "rte_case14_realistic"  # for example, other environments might be usable
env = grid2op.make(env_name,
                   backend=LightSimBackend()  # this is the only change you have to make!
                   )

# create an agent
my_agent = RandomAgent(env.action_space)

# proceed as you would any open ai gym loop
nb_episode = 10
for _ in range(nb_episde):
    # you perform in this case 10 different episodes
    obs = env.reset()
    reward = env.reward_range[0]
    done = False
    while not done:
        # here you loop on the time steps: at each step your agent receive an observation
        # takes an action
        # and the environment computes the next observation that will be used at the next step.
        act = agent.act(obs, reward, done)
        obs, reward, done, info = env.step(act)
        # the `LightSimBackend` will be used to carry out the powerflow computation instead
        # of the default grid2op `PandaPowerBackend`

Detailed documentation

Classes:

LightSimBackend([...])

This is a specialization of the grid2op Backend class to use the lightsim2grid solver, coded in c++, aiming at speeding up the computations.

class lightsim2grid.lightSimBackend.LightSimBackend(detailed_infos_for_cascading_failures=False)[source]

This is a specialization of the grid2op Backend class to use the lightsim2grid solver, coded in c++, aiming at speeding up the computations.

Methods:

apply_action(backendAction)

Specific implementation of the method to apply an action modifying a powergrid in the pandapower format.

assert_grid_correct_after_powerflow()

This method is called by the environment.

close()

INTERNAL

copy()

INTERNAL

generators_info()

INTERNAL

get_line_flow()

INTERNAL

get_line_status()

INTERNAL

get_theta()

returns
  • line_or_theta (numpy.ndarray) -- For each orgin side of powerline, gives the voltage angle

get_topo_vect()

INTERNAL

lines_ex_info()

INTERNAL

lines_or_info()

INTERNAL

load_grid([path, filename])

INTERNAL

loads_info()

INTERNAL

reset(grid_path[, grid_filename])

INTERNAL

runpf([is_dc])

INTERNAL

set_solver_max_iter(max_iter)

Set the maximum number of iteration the solver is allowed to perform.

set_solver_type(solver_type)

Change the type of solver you want to use.

set_tol(new_tol)

Set the tolerance of the powerflow.

shunt_info()

INTERNAL

storages_info()

INTERNAL

apply_action(backendAction)[source]

Specific implementation of the method to apply an action modifying a powergrid in the pandapower format.

assert_grid_correct_after_powerflow()[source]

This method is called by the environment. It ensure that the backend remains consistent even after a powerflow has be run with Backend.runpf() method.

Returns

None

Raise

grid2op.Exceptions.EnvError and possibly all of its derived class.

close()[source]

INTERNAL

Warning

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

This is called by env.close() do not attempt to use it otherwise.

This function is called when the environment is over. After calling this function, the backend might not behave properly, and in any case should not be used before another call to Backend.load_grid() is performed

copy()[source]

INTERNAL

Warning

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

Performs a deep copy of the backend.

In the default implementation we explicitly called the deepcopy operator on self._grid to make the error message more explicit in case there is a problem with this part.

The implementation is equivalent to:

return copy.deepcopy(self)
Returns

An instance of Backend equal to self, but deep copied.

Return type

Backend

generators_info()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.prod_p, grid2op.Observation.BaseObservation.prod_q and grid2op.Observation.BaseObservation.prod_v instead.

This method is used to retrieve information about the generators (active, reactive production and voltage magnitude of the bus to which it is connected).

Returns

  • prod_p numpy.ndarray – The active power production for each generator (in MW)

  • prod_q numpy.ndarray – The reactive power production for each generator (in MVAr)

  • prod_v numpy.ndarray – The voltage magnitude of the bus to which each generators is connected (in kV)

get_line_flow()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.a_or or grid2op.Observation.BaseObservation.a_ex for example

Return the current flow in each lines of the powergrid. Only one value per powerline is returned.

If the AC mod is used, this shall return the current flow on the end of the powerline where there is a protection. For example, if there is a protection on “origin end” of powerline “l2” then this method shall return the current flow of at the “origin end” of powerline l2.

Note that in general, there is no loss of generality in supposing all protections are set on the “origin end” of the powerline. So this method will return all origin line flows. It is also possible, for a specific application, to return the maximum current flow between both ends of a power _grid for more complex scenario.

For assumption about the order of the powerline flows return in this vector, see the help of the Backend.get_line_status() method.

Returns

an array with the line flows of each powerline

Return type

np.array, dtype:float

get_line_status()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.line_status instead

Return the status of each lines (connected : True / disconnected: False )

It is assume that the order of the powerline is fixed: if the status of powerline “l1” is put at the 42nd element of the return vector, then it should always be set at the 42nd element.

It is also assumed that all the other methods of the backend that allows to retrieve informations on the powerlines also respect the same convention, and consistent with one another. For example, if powerline “l1” is the 42nd second of the vector returned by Backend.get_line_status() then information about it’s flow will be at position 42 of the vector returned by Backend.get_line_flow() for example.

Returns

an array with the line status of each powerline

Return type

np.array, dtype:bool

get_theta()[source]
Returns

  • line_or_theta (numpy.ndarray) – For each orgin side of powerline, gives the voltage angle

  • line_ex_theta (numpy.ndarray) – For each extremity side of powerline, gives the voltage angle

  • load_theta (numpy.ndarray) – Gives the voltage angle to the bus at which each load is connected

  • gen_theta (numpy.ndarray) – Gives the voltage angle to the bus at which each generator is connected

  • storage_theta (numpy.ndarray) – Gives the voltage angle to the bus at which each storage unit is connected

get_topo_vect()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.topo_vect

Get the topology vector from the Backend._grid. The topology vector defines, for each object, on which bus it is connected. It returns -1 if the object is not connected.

It is a vector with as much elements (productions, loads and lines extremity) as there are in the powergrid.

For each elements, it gives on which bus it is connected in its substation.

For example, if the first element of this vector is the load of id 1, then if res[0] = 2 it means that the load of id 1 is connected to the second bus of its substation.

You can check which object of the powerlines is represented by each component of this vector by looking at the *_pos_topo_vect (eg. grid2op.Space.GridObjects.load_pos_topo_vect) vectors. For each elements it gives its position in this vector.

As any function of the backend, it is not advised to use it directly. You can get this information in the grid2op.Observation.Observation.topo_vect instead.

Returns

res – An array saying to which bus the object is connected.

Return type

numpy.ndarray dtype: int

lines_ex_info()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.p_ex, grid2op.Observation.BaseObservation.q_ex, grid2op.Observation.BaseObservation.a_ex and, grid2op.Observation.BaseObservation.v_ex instead

It returns the information extracted from the _grid at the extremity end of each powerline.

For assumption about the order of the powerline flows return in this vector, see the help of the Backend.get_line_status() method.

Returns

  • p_ex numpy.ndarray – the extremity active power flowing on the lines (in MW)

  • q_ex numpy.ndarray – the extremity reactive power flowing on the lines (in MVAr)

  • v_ex numpy.ndarray – the voltage magnitude at the extremity of each powerlines (in kV)

  • a_ex numpy.ndarray – the current flow at the extremity of each powerlines (in A)

lines_or_info()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.p_or, grid2op.Observation.BaseObservation.q_or, grid2op.Observation.BaseObservation.a_or and, grid2op.Observation.BaseObservation.v_or instead

It returns the information extracted from the _grid at the origin end of each powerline.

For assumption about the order of the powerline flows return in this vector, see the help of the Backend.get_line_status() method.

Returns

  • p_or numpy.ndarray – the origin active power flowing on the lines (in MW)

  • q_or numpy.ndarray – the origin reactive power flowing on the lines (in MVAr)

  • v_or numpy.ndarray – the voltage magnitude at the origin of each powerlines (in kV)

  • a_or numpy.ndarray – the current flow at the origin of each powerlines (in A)

load_grid(path=None, filename=None)[source]

INTERNAL

Warning

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

This is called once at the loading of the powergrid.

Load the powergrid. It should first define self._grid.

And then fill all the helpers used by the backend eg. all the attributes of Space.GridObjects.

After a the call to Backend.load_grid() has been performed, the backend should be in such a state where the grid2op.Space.GridObjects is properly set up. See the description of grid2op.Space.GridObjects to know which attributes should be set here and which should not.

Parameters
  • path (string) – the path to find the powergrid

  • filename (string, optional) – the filename of the powergrid

Returns

None

loads_info()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.load_p, grid2op.Observation.BaseObservation.load_q and grid2op.Observation.BaseObservation.load_v instead.

This method is used to retrieve information about the loads (active, reactive consumption and voltage magnitude of the bus to which it is connected).

Returns

  • load_p numpy.ndarray – The active power consumption for each load (in MW)

  • load_q numpy.ndarray – The reactive power consumption for each load (in MVAr)

  • load_v numpy.ndarray – The voltage magnitude of the bus to which each load is connected (in kV)

reset(grid_path, grid_filename=None)[source]

INTERNAL

Warning

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

This is done in the env.reset() method and should be performed otherwise.

Reload the power grid. For backwards compatibility this method calls Backend.load_grid. But it is encouraged to overload it in the subclasses.

runpf(is_dc=False)[source]

INTERNAL

Warning

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

This is called by Backend.next_grid_state() (that computes some kind of cascading failures).

This is one of the core function if you want to code a backend. It will carry out a powerflow.

Run a power flow on the underlying _grid. Powerflow can be AC (is_dc = False) or DC (is_dc = True)

Parameters

is_dc (bool) – is the powerflow run in DC or in AC

Returns

True if it has converged, or false otherwise. In case of non convergence, no flows can be inspected on the _grid.

Return type

bool

Returns

an exception in case of divergence (or none if no particular info are available)

Return type

Exception

set_solver_max_iter(max_iter)[source]

Set the maximum number of iteration the solver is allowed to perform.

We do not recommend to modify the default value (10), unless you are using the GaussSeidel powerflow. This powerflow being slower, we do not recommend to use it.

Recommendation:

  • for SolverType.SparseLU: 10

  • for SolverType.GaussSeidel: 10000

  • for SolverType.DC: this has no effect

  • for SolverType.SparseKLU: 10

Parameters

max_iter (int) – Maximum number of iteration the powerflow can run. It should be number >= 1

Notes

This has to be set for every backend that you want to use. For example, you have to set it in the backend of the _obs_env of the observation and if you are using “grid2op.MultMixEnv` you have to set it in all mixes!

set_solver_type(solver_type)[source]

Change the type of solver you want to use.

Note that a powergrid should have been loaded for this function to work.

This function does not modify LightSimBackend.max_iter nor LightSimBackend.tol. You might want to modify these values depending on the solver you are using.

Notes

By default, the fastest AC solver is used for your platform. This means that if KLU is available, then it is used otherwise it’s SparseLU.

This has to be set for every backend that you want to use. For example, you have to set it in the backend of the _obs_env of the observation and if you are using “grid2op.MultMixEnv` you have to set it in all mixes!

Parameters

solver_type (lightsim2grid.SolverType) – The new type of solver you want to use. See backend.available_solvers for a list of available solver on your machine.

set_tol(new_tol)[source]

Set the tolerance of the powerflow. This means that the powerflow will stop when the Kirchhoff’s Circuit Laws are met up to a tolerance of “new_tol”.

Decrease the tolerance might speed up the computation of the powerflow but will decrease the accuracy. We do not recommend to modify the default value of 1e-8.

Parameters

new_tol (float) – The new tolerance to use (should be a float > 0)

Notes

This has to be set for every backend that you want to use. For example, you have to set it in the backend of the _obs_env of the observation and if you are using “grid2op.MultMixEnv` you have to set it in all mixes!

shunt_info()[source]

INTERNAL

Warning

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

This method is optional. If implemented, it should return the proper information about the shunt in the powergrid.

If not implemented it returns empty list.

Note that if there are shunt on the powergrid, it is recommended that this method should be implemented before calling Backend.check_kirchoff().

If this method is implemented AND Backend.check_kirchoff() is called, the method Backend.sub_from_bus_id() should also be implemented preferably.

Returns

  • shunt_p (numpy.ndarray) – For each shunt, the active power it withdraw at the bus to which it is connected.

  • shunt_q (numpy.ndarray) – For each shunt, the reactive power it withdraw at the bus to which it is connected.

  • shunt_v (numpy.ndarray) – For each shunt, the voltage magnitude of the bus to which it is connected.

  • shunt_bus (numpy.ndarray) – For each shunt, the bus id to which it is connected.

storages_info()[source]

INTERNAL

Warning

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

Prefer using grid2op.Observation.BaseObservation.storage_power instead.

This method is used to retrieve information about the storage units (active, reactive consumption and voltage magnitude of the bus to which it is connected).

Returns

  • storage_p numpy.ndarray – The active power consumption for each load (in MW)

  • storage_q numpy.ndarray – The reactive power consumption for each load (in MVAr)

  • storage_v numpy.ndarray – The voltage magnitude of the bus to which each load is connected (in kV)