Time Series (doc in progress)

The documentation of this section is in progress. It is rather incomplete for the moment, and only expose the most basic features.

If you are interested in collaborating to improve this section, let us know.

Goal

This class aims to make faster (and easier) the computations of the current flows (measured in Amps) at a certain side of a powerline / transformer when the topology is not modified.

It can be used as:

from lightsim2grid import TimeSerie
import grid2op
from lightsim2grid.lightSimBackend import LightSimBackend

env_name = ...
env = grid2op.make(env_name, backend=LightSimBackend())

time_series = TimeSerie(env)
res_p, res_a, res_v = time_series.get_flows(scenario_id=..., seed=...)

# we have:
# res_p[row_id] will be the active power flows (origin side), on all powerlines corresponding to step "row_id"
# res_a[row_id] will be the current flows, on all powerlines corresponding to step "row_id"
# res_v[row_id] will be the complex voltage, on all bus of the grid at step "row_id"

For now this relies on grid2op, but we could imagine a version of this class that can read to / from other data sources (for now please use the more basic lightsim2grid.timeSerie.Computers for such purpose)

Importantly, this method is around 13x faster than simulating “do nothing” (or “one change then nothing”) with grid2op (see section Benchmarks )

Note

A more detailed example is given in the examples\time_serie.py file from the lightsim2grid package.

Warning

Topology and injections

The topology is taken from the initial provided grid and cannot be changed when evaluating a given “time serie”.

Then, the call to time_series.compute_V(scenario_id=…, seed=…) will only read the injections (productions and loads) from grid2op to compute the voltages.

Note

As this class calls a long c++ function, it is possible to use the python Threading module to achieve high efficient parrallelism. An example is provided in the examples\computers_with_grid2op_multithreading.py file.

Benchmarks

Here are some benchmarks made with:

  • system: Linux 5.11.0-40-generic

  • OS: ubuntu 20.04

  • processor: Intel(R) Core(TM) i7-4790K CPU @ 4.00GHz

  • python version: 3.8.10.final.0 (64 bit)

  • numpy version: 1.18.5

  • pandas version: 1.1.4

  • pandapower version: 2.7.0

  • lightsim2grid version: 0.6.0

  • grid2op version: 1.6.4

Where lightsim2grid has been installed from source with all optimization enabled.

This benchmark is available by running, from the root of the lightsim2grid repository:

cd examples
python3 time_serie.py

For this setting the outputs are:

For environment: l2rpn_neurips_2020_track2
Total time spent in "computer" to solve everything: 0.05s (12277 pf / s), 0.08 ms / pf)
    - time to pre process the injections: 0.00s
    - time to perform powerflows: 0.05s (12697 pf / s, 0.08 ms / pf)
In addition, it took 0.00 s to retrieve the current from the complex voltages (in total 11681.3 pf /s, 0.09 ms / pf)

Comparison with raw grid2op timings
It took grid2op (with lightsim2grid): 0.66s to perform the same computation
    This is a 13.4 speed up from TimeSerie over raw grid2op (lightsim2grid)
It took grid2op (with pandapower): 14.94s to perform the same computation
    This is a 302.9 speed up from TimeSerie over raw grid2op (pandapower)
All results match !

In this case then, the TimeSerie module is more than 15 times faster than raw grid2op.

Detailed usage

Classes:

Computers

alias of TimeSeriesCPP

TimeSerie(grid2op_env)

This helper class, that only works with grid2op when using a LightSimBackend allows to compute the flows (at the origin side of the powerline / transformers).

lightsim2grid.timeSerie.Computers

alias of TimeSeriesCPP Methods:

amps_computation_time(self)

Time spent in computing the flows (in amps) after the voltages have been computed at each nodes

available_solvers(self)

Return the list of solver available on the current lightsim2grid installation.

change_solver(self, arg0)

This function allows to control which solver is used during the powerflow.

clear(self)

Clear the solver and to as if the class never performed any powerflow.

close(self)

Clear the solver and to as if the class never performed any powerflow.

compute_Vs(self, arg0, arg1, arg2, arg3, ...)

Compute the voltages (at each bus of the grid model) for some time series of injections (productions, loads, storage units, etc.)

compute_flows(self)

Retrieve the flows (in amps, at the origin of each powerlines / high voltage size of each transformers.

compute_power_flows(self)

Retrieve the active flows (in MW, at the origin of each powerlines / high voltage size of each transformers.

get_flows(self)

Get the current flows (in kA) at the origin side / high voltage side of each transformers / powerlines.

get_power_flows(self)

Get the active flows (in MW) at the origin side / high voltage side of each transformers / powerlines.

get_sbuses(self)

Get the complex power injected at each (solver id) bus of the powergrid.

get_solver_type(self)

Return the type of the solver currently used.

get_status(self)

Status of the solvers (1: success, 0: failure).

get_voltages(self)

Get the complex voltage angles at each bus of the powergrid.

nb_solved(self)

Total number of powerflows solved.

preprocessing_time(self)

Time spent in pre processing the data (this involves, but is not limited to the computation of the Sbus)

solver_time(self)

Total time spent only in solving the powerflows (excluding pre processing the data, post processing them, initializing everything etc.)

total_time(self)

Total time spent in solving the powerflows, pre processing the data, post processing them, initializing everything etc.

class lightsim2grid.timeSerie.TimeSerie(grid2op_env)[source]

This helper class, that only works with grid2op when using a LightSimBackend allows to compute the flows (at the origin side of the powerline / transformers). It is roughly equivalent to the grid2op code:

import grid2op
import numpy as np
from grid2op.Parameters import Parameters
from lightsim2grid.LightSimBackend import LightSimBackend

env_name = ...
param = Parameters()
param.NO_OVERFLOW_DISCONNECTION = True

env = grid2op.make(env_name, param=param, backend=LightSimBackend())

done = False
obs = env.reset()
nb_step = obs.max_step
Vs = np.zeros((nb_step, 2 * env.n_sub), dtype=complex)
As = np.zeros((nb_step, env.n_line), dtype=float)
while not done:
    obs, reward, done, info = env.step(env.action_space())
    Vs[i, :env.n_sub] = env.backend.V
    As[i] = obs.a_or

Compare to the previous code, it avoid all grid2op code and can be more than 15 times faster (on the case 118).

It also allows to use python threading module, as the c++ computation can be done in different python threads (the GIL is not locked during the c++ computation).

Examples

It can be used as:

from lightsim2grid import TimeSerie
import grid2op
from lightsim2grid.LightSimBackend import LightSimBackend

env_name = ...
env = grid2op.make(env_name, param=param, backend=LightSimBackend())

time_series = TimeSerie(env)
res_p, res_a, res_v = time_series.get_flows(scenario_id=..., seed=...)

Methods:

clear()

Clear everything, as if nothing has been computed

close()

permanently close the object

compute_A()

This function returns the current flows (in Amps, A) at the origin (for powerline) / high voltage (for transformer) side

compute_P()

This function returns the active power flows (in MW) at the origin (for powerline) / high voltage (for transformer) side

compute_V([scenario_id, seed, v_init, ...])

This function allows to retrieve the complex voltage at each bus of the grid for each step.

compute_V_from_inj(prod_p, load_p, load_q[, ...])

This function allows to compute the voltages, at each bus given a list of productions and loads.

get_flows([scenario_id, seed, v_init, ...])

Retrieve the flows for each step simulated.

get_injections([scenario_id, seed])

This function allows to retrieve the injection of the given scenario, for the given seed from the grid2op internal environment.

clear()[source]

Clear everything, as if nothing has been computed

close()[source]

permanently close the object

compute_A()[source]

This function returns the current flows (in Amps, A) at the origin (for powerline) / high voltage (for transformer) side

It does not recompute the voltages at each buses, it uses the information get from compute_V and This is why you must call compute_V(…) first !

compute_P()[source]

This function returns the active power flows (in MW) at the origin (for powerline) / high voltage (for transformer) side

It does not recompute the voltages at each buses, it uses the information get from compute_V and This is why you must call compute_V(…) first !

compute_V(scenario_id=None, seed=None, v_init=None, ignore_errors=False)[source]

This function allows to retrieve the complex voltage at each bus of the grid for each step.

Warning

Topology fixed = no maintenance, no attacks, etc.

As the topology is fixed, this class does not allow to simulate the effect of maintenance or attacks !

compute_V_from_inj(prod_p, load_p, load_q, v_init=None, ignore_errors=False)[source]

This function allows to compute the voltages, at each bus given a list of productions and loads.

We do not recommend to use it directly, as the order of the load or generators might vary !

get_flows(scenario_id=None, seed=None, v_init=None, ignore_errors=False)[source]

Retrieve the flows for each step simulated.

Each row of the resulting flow matrix will correspond to a step.

Examples

import grid2op
from lightsim2grid import TimeSerie
from lightsim2grid import LightSimBackend
env_name = ...
env = grid2op.make(env_name, backend=LightSimBackend())

timeserie = TimeSerie(env)
res_p, res_a, res_v = timeserie.get_flows(scenario_id, seed, v_init, ignore_errors)

# in this results, then
# res_a[row_id] will be the flows, on all powerline corresponding to the `row_id` contingency.
# you can retrieve it with `security_analysis.contingency_order[row_id]`
get_injections(scenario_id=None, seed=None)[source]

This function allows to retrieve the injection of the given scenario, for the given seed from the grid2op internal environment.