Time Series
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.TimeSeriesCPP for such purpose)
Importantly, this method is around 11x faster than simulating “do nothing” (or “one change then nothing”) with grid2op (and lightsim2grid, see section Benchmarks (Time Series) )
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\timeseries_with_grid2op_multithreading.py file.
Note
Set time_series.init_from_n_powerflow = True before calling compute_V (setting it
afterwards has no effect) to initialize the first step of the batch with the voltage
solution of the grid’s current (“n”) state instead of a flat start – this is usually
faster. See lightsim2grid.timeSerie.TimeSerie.init_from_n_powerflow().
Independent scenarios: InjectionSweep
TimeSerie initializes each step with the solution of the step before it. That is the right thing to do for a time series – two consecutive instants are close to one another, so the previous solution is an excellent starting point – but it makes the steps a chain: step i cannot be computed before step i-1, and its result depends on it.
If your “steps” are unrelated scenarios rather than consecutive instants (a sample of load /
generation patterns, a set of “what if” injections, a Monte-Carlo draw…), use
lightsim2grid.injectionSweep.InjectionSweep instead. It computes exactly the same
thing, with exactly the same interface, but starts every step from the same voltage – the
one you provide, or the “n” powerflow result if init_from_n_powerflow is set – just like
lightsim2grid.contingencyAnalysis.ContingencyAnalysis does for each contingency.
Two things follow:
the results do not depend on the order the steps are given in;
the batch can be spread over several OS threads, in c++, with sweep.nb_thread = … (the results do not depend on that either). TimeSerie cannot: splitting a chain into per-thread ranges would break it, so setting nb_thread to anything but 1 raises there.
import grid2op
from lightsim2grid import InjectionSweep, LightSimBackend
env_name = ...
env = grid2op.make(env_name, backend=LightSimBackend())
sweep = InjectionSweep(env)
sweep.nb_thread = 4
res_p, res_a, res_v = sweep.get_flows(scenario_id=..., seed=...)
Note
On a genuine time series TimeSerie usually needs fewer solver iterations, precisely because each step starts from its neighbour’s solution. InjectionSweep trades that away for independence – and buys back much more than it costs as soon as you use several threads.
Note
TimeSerie / InjectionSweep also expose a newer, setter-based API (modify_gen_p / modify_sgen_p / modify_load_p / modify_load_q / modify_gen_v + compute()) as an alternative to the single bundled compute_V_from_inj call – see Scenario Sweep (which uses that same API, plus a per-step contingency) for details on how it behaves when an axis is never set. modify_gen_v (per-step generator target voltage magnitude, in pu – vm_pu, NOT kV) is different from the other four: it does not feed the injection (Sbus) at all, it only re-seeds |V| at each voltage-regulating generator’s regulated bus before that step’s solve.
Benchmarks (Time Series)
Here are some benchmarks made with:
date: 2026-08-28 16:57 CEST
system: Linux 6.8.0-60-generic
OS: ubuntu 22.04
processor: 13th Gen Intel(R) Core(TM) i7-13700H
python version: 3.12.8.final.0 (64 bit)
numpy version: 2.3.5
pandas version: 2.3.3
pandapower version: 3.4.0
grid2op version: 1.12.5.dev0
lightsim2grid version: 1.0.0
lightsim2grid extra information:
klu_solver_available: True
nicslu_solver_available: True
cktso_solver_available: True
compiled_march_native: True
compiled_o3_optim: True
This benchmark is available by running, from the root of the lightsim2grid repository:
cd benchmarks
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.03s (20834 pf / s), 0.05 ms / pf)
- time to pre process the injections: 0.00s
- time to perform powerflows: 0.03s (22437 pf / s, 0.04 ms / pf)
In addition, it took 0.00 s to retrieve the current from the complex voltages (in total 19934.2 pf /s, 0.05 ms / pf)
Comparison with raw grid2op timings
It took grid2op (with lightsim2grid): 0.32s to perform the same computation
This is a 11.0 speed up from TimeSerie over raw grid2op (lightsim2grid)
It took grid2op (with pandapower): 6.56s to perform the same computation
This is a 227.1 speed up from TimeSerie over raw grid2op (pandapower)
In this case then, the `TimeSerie` module is 11 times faster than raw grid2op (lightsim2grid) and 227 times faster than raw grid2op (pandapower)
All results match !
Detailed usage
Classes:
alias of |
|
|
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). |
Allows the computation of time series, that is, the same grid topology is used while the active / reactive power injected at each buse vary. |
- lightsim2grid.timeSerie.Computers
alias of
TimeSeriesCPP
- 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 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 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([v_init, max_iter, tol, ignore_errors])Run the batch using whatever was set by
modify_gen_p()/modify_sgen_p()/modify_load_p()/modify_load_q()(the new setter-based API -- an alternative to the single bundledcompute_V_from_inj()call).This function returns the current flows (in Amps, A) at the origin (for powerline) / high voltage (for transformer) side
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.
modify_gen_p(gen_p)Per-step active generator setpoints, shape
(n_simul, n_gen).modify_gen_v(gen_v)Per-step generator target voltage magnitude, shape
(n_simul, n_gen), in pu (vm_pu), NOT kV.modify_load_p(load_p)Per-step active load setpoints, shape
(n_simul, n_load).modify_load_q(load_q)Per-step reactive load setpoints, shape
(n_simul, n_load).modify_sgen_p(sgen_p)Per-step active static generator setpoints, shape
(n_simul, n_sgen).Attributes:
Whether to initialize the complex voltages of the first step of the batch with the results of a "n" powerflow (a powerflow at the current state of the grid) instead of a flat start.
- compute(v_init=None, max_iter=None, tol=None, ignore_errors=False)[source]
Run the batch using whatever was set by
modify_gen_p()/modify_sgen_p()/modify_load_p()/modify_load_q()(the new setter-based API – an alternative to the single bundledcompute_V_from_inj()call).max_iter/toldefault to the backend’s own values when not given.
- 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.
- property init_from_n_powerflow
Whether to initialize the complex voltages of the first step of the batch with the results of a “n” powerflow (a powerflow at the current state of the grid) instead of a flat start. Default:
False. Must be set before the computation actually runs (eg beforecompute_Vis called); it has no effect on a powerflow that has already been solved.
- modify_gen_p(gen_p)[source]
Per-step active generator setpoints, shape
(n_simul, n_gen). Part of the new setter-based API (seecompute()); an alternative tocompute_V_from_inj(), not required if you use that call instead.
- modify_gen_v(gen_v)[source]
Per-step generator target voltage magnitude, shape
(n_simul, n_gen), in pu (vm_pu), NOT kV. Unlikemodify_gen_p()/modify_load_p()/modify_load_q(), this does NOT feed the injection (Sbus) – it only re-seeds|V|at each voltage-regulating generator’s regulated bus before that step’s solve. Seemodify_gen_p().
- modify_load_p(load_p)[source]
Per-step active load setpoints, shape
(n_simul, n_load). Seemodify_gen_p().
- modify_load_q(load_q)[source]
Per-step reactive load setpoints, shape
(n_simul, n_load). Seemodify_gen_p().
- modify_sgen_p(sgen_p)[source]
Per-step active static generator setpoints, shape
(n_simul, n_sgen). Seemodify_gen_p().
- class lightsim2grid.timeSerie.TimeSeriesCPP
Allows the computation of time series, that is, the same grid topology is used while the active / reactive power injected at each buse vary. The grid topology is fixed, the injections vary.
This is a “raw” c++ class, for an easier to use interface, please refer to the python documentation of the
lightsim2grid.timeSerie.TimeSerieclass.Methods:
amps_computation_time(self)Time spent in computing the flows (in amps) after the voltages have been computed at each nodes
Returns the names of all registered algorithms, including any loaded plugins, as a list of string.
Return the list of the names of the algorithm available on the current lightsim2grid installation.
change_algorithm(*args, **kwargs)Overloaded function.
change_solver(*args, **kwargs)Overloaded function.
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(self, Vinit, max_iter, tol)Run the batch: one powerflow per simulation, using whatever was set by modify_* (and, on ScenarioSweep, set_contingency_lines / set_contingency_trafos).
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.
converged_mask(self)Per-row convergence, as a list[bool] of length nb_steps() (row order matches the row order of whatever was solved: my_defaults() for ContingencyAnalysis, the injection / contingency matrices otherwise).
get_algo_config(self)Config (eg ScalingPolicyType / damping parameters) of the internal solver used for every step.
get_algo_name(self)Registry name of the currently selected algorithm.
get_algo_type(self)Return the type of the solver currently used.
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_status(self)Status of the solvers (1: success, 0: failure).
get_voltages(self)Get the complex voltage angles at each bus of the powergrid.
modify_gen_p(self, gen_p)Per-step active generator setpoints, shape (n_simul, n_gen).
modify_gen_v(self, gen_v)Per-step generator target voltage magnitude, shape (n_simul, n_gen), in pu (vm_pu), NOT kV.
modify_load_p(self, load_p)Per-step active load setpoints, shape (n_simul, n_load).
modify_load_q(self, load_q)Per-step reactive load setpoints, shape (n_simul, n_load).
modify_sgen_p(self, sgen_p)Per-step active static generator setpoints, shape (n_simul, n_sgen).
nb_converged(self)Number of powerflows, among those nb_solved() attempted, that actually converged.
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)
set_algo_config(self, config)See get_algo_config().
solver_time(self)Total time spent only in solving the powerflows (excluding pre processing the data, post processing them, initializing everything etc.)
thread_init_time(self)Time (in seconds,
float) spent building the per thread solvers.total_time(self)Total time spent in solving the powerflows, pre processing the data, post processing them, initializing everything etc.
Attributes:
Whether to initialize the complex voltages of the first step with the results of a "n" powerflow (ie a powerflow run at the start of the computation, on the injections of the grid model) or not.
Number of OS threads used to compute the steps (default
1).- amps_computation_time(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) float
Time spent in computing the flows (in amps) after the voltages have been computed at each nodes
It is given in seconds (
float).
- available_algorithm_names(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) list[str]
Returns the names of all registered algorithms, including any loaded plugins, as a list of string.
- available_default_algorithms(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) list[lightsim2grid.lightsim2grid_cpp.AlgorithmType]
Return the list of the names of the algorithm available on the current lightsim2grid installation.
This is a list of
lightsim2grid.algorithm.AlgorithmType.
- change_algorithm(*args, **kwargs)
Overloaded function.
change_algorithm(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, arg0: lightsim2grid.lightsim2grid_cpp.AlgorithmType) -> None
This function allows to control which solver is used during the powerflow. See the section Available powerflow algorithms for more information about them.
See also
lightsim2grid.algorithm.AlgorithmTypefor a list of the available algorithms (NB: some algorithms might not be available on all platform)Note
If the algorithm type entered is a DC algorithm (eg from
lightsim2grid.algorithm.AlgorithmType, DC_SparseLU, DC_KLU or DC_NICSLU), it will change the _dc_solver otherwise the regular _solver is modified.Examples
from lightsim2grid.algorithm import AlgorithmType # init the grid model from lightsim2grid.network import init_from_pandapower pp_net = ... # any pandapower grid lightsim_grid_model = init_from_pandapower(pp_net) # some warnings might be issued as well as some warnings # change the algorithm used for the powerflow # to use internally a Newton Raphson algorithm with the Eigen sparse LU linear solver lightsim_grid_model.change_algorithm(AlgorithmType.NR_SparseLU)
change_algorithm(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, arg0: str) -> None
Change the AC (or DC) algorithm by registry name. Accepts built-in names and plugin names registered via
load_solver_plugin().See also
change_algorithm()to change it bylightsim2grid.algorithm.AlgorithmTypeinstead.
- change_solver(*args, **kwargs)
Overloaded function.
change_solver(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, arg0: lightsim2grid.lightsim2grid_cpp.AlgorithmType) -> None
DEPRECATED: use ‘change_algorithm’ instead
change_solver(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, arg0: str) -> None
DEPRECATED: use ‘change_algorithm’ instead
- clear(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) None
Clear the solver and to as if the class never performed any powerflow.
- close(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) None
Clear the solver and to as if the class never performed any powerflow.
- compute(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, Vinit: Annotated[numpy.typing.NDArray[numpy.complex128], '[m, 1]'], max_iter: SupportsInt | SupportsIndex, tol: SupportsFloat | SupportsIndex) None
Run the batch: one powerflow per simulation, using whatever was set by modify_* (and, on ScenarioSweep, set_contingency_lines / set_contingency_trafos). Raises if nothing was ever set.
- compute_Vs(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, arg0: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg1: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg2: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg3: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg4: Annotated[numpy.typing.NDArray[numpy.complex128], '[m, 1]'], arg5: SupportsInt | SupportsIndex, arg6: SupportsFloat | SupportsIndex) int
Compute the voltages (at each bus of the grid model) for some time series of injections (productions, loads, storage units, etc.)
Note
This function must be called before
lightsim2grid.timeSerie.TimeSeriesCPP.compute_flows()andlightsim2grid.timeSerie.TimeSeriesCPP.get_flows(),lightsim2grid.timeSerie.TimeSeriesCPP.get_voltages()orlightsim2grid.timeSerie.TimeSeriesCPP.get_sbuses().Note
During this computation, the GIL is released, allowing easier parrallel computation
- gen_p:
numy.ndarray, float Active generation for each generators. Its counts as many column as the number of generators on the grid and as many rows as the number of steps to compute.
- sgen_p:
numy.ndarray, float Active generation for each static generator. Its counts as many column as the number of static generators on the grid and as many rows as the number of steps to compute.
- load_p:
numy.ndarray, float Active consumption for each loads. Its counts as many column as the number of loads on the grid and as many rows as the number of steps to compute.
- load_q:
numy.ndarray, float Reactive consumption for each loads. Its counts as many column as the number of loads on the grid and as many rows as the number of steps to compute.
- Vinit:
numy.ndarray, complex First voltage at each bus of the grid model (including the disconnected buses)
- max_iter:
int Total number of iteration (>0 integer)
- tol:
float Solver tolerance (> 0. float)
- status:
int The status of the computation. 1 means “success”: all powerflows were computed sucessfully, 0 means there were some errors and that the computation stopped after a certain number of steps.
DEPRECATED: prefer modify_gen_p / modify_sgen_p / modify_load_p / modify_load_q + compute() instead.
- gen_p:
- compute_flows(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.writeable', 'flags.c_contiguous']
Retrieve the flows (in amps, at the origin of each powerlines / high voltage size of each transformers.
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been called.Note
This function must be called before
lightsim2grid.timeSerie.TimeSeriesCPP.get_flows()Note
During this computation, the GIL is released, allowing easier parrallel computation
- compute_power_flows(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.writeable', 'flags.c_contiguous']
Retrieve the active flows (in MW, at the origin of each powerlines / high voltage size of each transformers.
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been called.Note
This function must be called before
lightsim2grid.timeSerie.TimeSeriesCPP.get_flows()Note
During this computation, the GIL is released, allowing easier parrallel computation
- converged_mask(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) list[bool]
Per-row convergence, as a list[bool] of length nb_steps() (row order matches the row order of whatever was solved: my_defaults() for ContingencyAnalysis, the injection / contingency matrices otherwise). Unlike converged() (ContingencyAnalysis-only, and only usable if compute_limit_violations=True was set), this is available on every batch class – TimeSeries, InjectionSweep, ContingencyAnalysis and ScenarioSweep alike – unconditionally, no setup required.
Row i is True iff that row was both invertible and reported convergence by the solver. A row that was never attempted at all (eg every row after the first failure in a TimeSeries, whose steps are chained and so stop there) is False too – indistinguishable from an outright divergence, the same “never attempted” == “did not converge” convention nb_solved() / nb_converged() already use.
- get_algo_config(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) lightsim2grid.lightsim2grid_cpp.AlgoConfig
Config (eg ScalingPolicyType / damping parameters) of the internal solver used for every step. Copied once from the grid model’s own get_ac_algo_config() at construction time, then independent of it; re-apply with set_algo_config() if you change the grid model’s config afterwards, or after change_algorithm().
- get_algo_name(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) str
Registry name of the currently selected algorithm. Unlike get_algo_type(), stays meaningful for plugin solvers (and built-ins with no dedicated AlgorithmType member).
- get_algo_type(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) lightsim2grid.lightsim2grid_cpp.AlgorithmType
Return the type of the solver currently used.
This is equivalent to the get_type of the
lightsim2grid.algorithm.AlgorithmSelector.get_type()of the solver used.
- get_flows(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]']
Get the current flows (in kA) at the origin side / high voltage side of each transformers / powerlines.
Each rows correspond to a time step, each column to a powerline / transformer
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_flows()has been called. (compute_flows also requires thatlightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been caleed)- Returns:
As – The flows (in kA) at the origin side / high voltage side of each transformers / powerlines.
- Return type:
numpy.ndarry(matrix)
- get_power_flows(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]']
Get the active flows (in MW) at the origin side / high voltage side of each transformers / powerlines.
Each rows correspond to a time step, each column to a powerline / transformer
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_power_flows()has been called. (compute_power_flows also requires thatlightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been caleed)- Returns:
Ps – The active flows (in MW) at the origin side / high voltage side of each transformers / powerlines.
- Return type:
numpy.ndarry(matrix)
- get_sbuses(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) Annotated[numpy.typing.NDArray[numpy.complex128], '[m, n]', 'flags.c_contiguous']
Get the complex power injected at each (solver id) bus of the powergrid. Results are given in pair unit. We do not recommend to use it as it uses the solver id and NOT the powergrid bus id (you can refer to
lightsim2grid.network.LSGrid.id_me_to_ac_solver()andlightsim2grid.network.LSGrid.id_ac_solver_to_me()for more information)Each rows correspond to a time step, each column to a bus (bus are identified by their solver id !)
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs().- Returns:
Sbuses – The complex power injected at each bus (pair unit, load sign convention)
- Return type:
numpy.ndarry(matrix)
- get_status(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) int
Status of the solvers (1: success, 0: failure).
Note
Even if the solver failed at some point, some results might still be available (but not totally).
- get_voltages(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) Annotated[numpy.typing.NDArray[numpy.complex128], '[m, n]']
Get the complex voltage angles at each bus of the powergrid.
Each rows correspond to a time step, each column to a bus.
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs().- Returns:
Vs – The complex voltage angles at each bus of the powergrid.
- Return type:
numpy.ndarry(matrix)
- property init_from_n_powerflow
Whether to initialize the complex voltages of the first step with the results of a “n” powerflow (ie a powerflow run at the start of the computation, on the injections of the grid model) or not.
Default:
False, meaning the first step is initialized with the input vector given tolightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs(). Every other step is initialized with the result of the step before it either way.
- modify_gen_p(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, gen_p: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step active generator setpoints, shape (n_simul, n_gen). See the class docstring: locks / checks the number of simulations against any other modify_* / set_contingency_* call already made on this object.
- modify_gen_v(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, gen_v: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step generator target voltage magnitude, shape (n_simul, n_gen), in pu (vm_pu), NOT kV. Unlike modify_gen_p/modify_sgen_p/modify_load_p/modify_load_q, this does NOT feed the injection (Sbus) – it only re-seeds |V| at each voltage-regulating generator’s regulated bus before that step’s solve. See modify_gen_p() for the shared row-count-lock behavior.
- modify_load_p(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, load_p: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step active load setpoints, shape (n_simul, n_load). See modify_gen_p().
- modify_load_q(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, load_q: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step reactive load setpoints, shape (n_simul, n_load). See modify_gen_p().
- modify_sgen_p(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, sgen_p: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step active static generator setpoints, shape (n_simul, n_sgen). See modify_gen_p().
- nb_converged(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) int
Number of powerflows, among those nb_solved() attempted, that actually converged. Always <= nb_solved(): a row skipped outright (eg a non-invertible / islanding admittance matrix, on ContingencyAnalysis / ScenarioSweep) never reaches the solver at all, so it counts towards neither.
- nb_solved(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) int
Total number of powerflows solved.
- property nb_thread
Number of OS threads used to compute the steps (default
1).With
nb_thread == 1the behaviour is the legacy sequential one. Withnb_thread > 1the steps are split into contiguous ranges, each solved by its own thread (each with its own solver), writing to disjoint rows of the result matrix: the results do NOT depend on the number of threads. Values< 1are clamped to1.Warning
This is only available on
lightsim2grid.injectionSweep.InjectionSweepCPP(and onlightsim2grid.contingencyAnalysis.ContingencyAnalysisCPP), whose computations are independent of one another.On
lightsim2grid.timeSerie.TimeSeriesCPPeach step is initialized with the result of the previous one, so the steps cannot be split over threads without making the results depend on how they were split: setting it to anything but 1 raises aRuntimeError. UseInjectionSweepCPPif you want the very same injections computed in parallel.
- preprocessing_time(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) float
Time spent in pre processing the data (this involves, but is not limited to the computation of the Sbus)
It is given in seconds (
float).
- set_algo_config(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP, config: lightsim2grid.lightsim2grid_cpp.AlgoConfig) None
See get_algo_config().
- solver_time(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) float
Total time spent only in solving the powerflows (excluding pre processing the data, post processing them, initializing everything etc.)
It is given in seconds (
float).
- thread_init_time(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) float
Time (in seconds,
float) spent building the per thread solvers. It is 0. whennb_threadis 1, in which case the (already initialized) internal solver is reused.
- total_time(self: lightsim2grid.lightsim2grid_cpp.TimeSeriesCPP) float
Total time spent in solving the powerflows, pre processing the data, post processing them, initializing everything etc.
It is given in seconds (
float).
Classes:
|
Same computation as |
Allows the computation of many powerflows on the same grid topology while the active / reactive power injected at each bus vary: exactly the same inputs, the same results and the same interface as |
- class lightsim2grid.injectionSweep.InjectionSweep(grid2op_env)[source]
Same computation as
lightsim2grid.timeSerie.TimeSerie– a fixed grid topology, one powerflow per set of injections – but every powerflow starts from the same voltage instead of from the result of the previous one.That makes the steps independent of one another: the result of a step does not depend on the steps computed before it, nor on the order in which they were given. Use this class when the “steps” are unrelated scenarios rather than consecutive instants of a time series. Two practical consequences:
the computation can be spread over several OS threads, see
nb_threadbelow (lightsim2grid.timeSerie.TimeSeriecannot: splitting a chained computation would make its results depend on how it was split);a step that is far from its neighbours does not inherit a bad starting point from them – but a step that IS close to its neighbours no longer benefits from their solution, so a genuine time series usually converges in fewer iterations with
lightsim2grid.timeSerie.TimeSerie.
Examples
It is used exactly like
lightsim2grid.timeSerie.TimeSerie:import grid2op from lightsim2grid import InjectionSweep from lightsim2grid import LightSimBackend env_name = ... env = grid2op.make(env_name, backend=LightSimBackend()) sweep = InjectionSweep(env) sweep.nb_thread = 4 # optional, the results do not depend on it res_p, res_a, res_v = sweep.get_flows(scenario_id=..., seed=...)
Attributes:
Whether to initialize the complex voltages of each step of the batch with the results of a "n" powerflow (a powerflow at the current state of the grid) instead of the vector given to
compute_V.1).- property init_from_n_powerflow
Whether to initialize the complex voltages of each step of the batch with the results of a “n” powerflow (a powerflow at the current state of the grid) instead of the vector given to
compute_V. Default:False.Unlike
lightsim2grid.timeSerie.TimeSerie.init_from_n_powerflow, this applies to every step and not only the first one – here every step starts from that same voltage. Must be set before the computation actually runs.
- property nb_thread
1).The steps are split into contiguous ranges, each solved by its own thread with its own solver, writing to disjoint rows of the result matrix: the results do not depend on the number of threads. Values
< 1are clamped to1.Must be set before the computation actually runs (eg before
compute_Vis called); it has no effect on a batch that has already been computed.- Type:
Number of OS threads used to compute the steps (default
- class lightsim2grid.injectionSweep.InjectionSweepCPP
Allows the computation of many powerflows on the same grid topology while the active / reactive power injected at each bus vary: exactly the same inputs, the same results and the same interface as
lightsim2grid.timeSerie.TimeSeriesCPP.The difference is how each computation is initialized.
TimeSeriesCPPinitializes a step with the solution of the step before it (they are consecutive instants of a time series, so they are expected to be close to one another).InjectionSweepCPPinitializes every step with the very same voltage - the one you provide, or the result of the “n” powerflow ifinit_from_n_powerflowis set - exactly likelightsim2grid.contingencyAnalysis.ContingencyAnalysisCPPdoes for each of its contingencies.Use it when the “steps” are independent scenarios rather than consecutive instants. The result of a step then does not depend on the steps computed before it, nor on the order in which they are given, and the computation can be spread over several threads (see
nb_thread, whichTimeSeriesCPPcannot support).This is a “raw” c++ class, for an easier to use interface, please refer to the python documentation of the
lightsim2grid.injectionSweep.InjectionSweepclass.Methods:
amps_computation_time(self)Time spent in computing the flows (in amps) after the voltages have been computed at each nodes
Returns the names of all registered algorithms, including any loaded plugins, as a list of string.
Return the list of the names of the algorithm available on the current lightsim2grid installation.
change_algorithm(*args, **kwargs)Overloaded function.
change_solver(*args, **kwargs)Overloaded function.
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(self, Vinit, max_iter, tol)Run the batch: one powerflow per simulation, using whatever was set by modify_* (and, on ScenarioSweep, set_contingency_lines / set_contingency_trafos).
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.
converged_mask(self)Per-row convergence, as a list[bool] of length nb_steps() (row order matches the row order of whatever was solved: my_defaults() for ContingencyAnalysis, the injection / contingency matrices otherwise).
get_algo_config(self)Config (eg ScalingPolicyType / damping parameters) of the internal solver used for every step.
get_algo_name(self)Registry name of the currently selected algorithm.
get_algo_type(self)Return the type of the solver currently used.
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_status(self)Status of the solvers (1: success, 0: failure).
get_voltages(self)Get the complex voltage angles at each bus of the powergrid.
modify_gen_p(self, gen_p)Per-step active generator setpoints, shape (n_simul, n_gen).
modify_gen_v(self, gen_v)Per-step generator target voltage magnitude, shape (n_simul, n_gen), in pu (vm_pu), NOT kV.
modify_load_p(self, load_p)Per-step active load setpoints, shape (n_simul, n_load).
modify_load_q(self, load_q)Per-step reactive load setpoints, shape (n_simul, n_load).
modify_sgen_p(self, sgen_p)Per-step active static generator setpoints, shape (n_simul, n_sgen).
nb_converged(self)Number of powerflows, among those nb_solved() attempted, that actually converged.
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)
set_algo_config(self, config)See get_algo_config().
solver_time(self)Total time spent only in solving the powerflows (excluding pre processing the data, post processing them, initializing everything etc.)
thread_init_time(self)Time (in seconds,
float) spent building the per thread solvers.total_time(self)Total time spent in solving the powerflows, pre processing the data, post processing them, initializing everything etc.
Attributes:
Whether to initialize the complex voltages of each step with the results of a "n" powerflow (ie a powerflow run at the start of the computation, on the injections of the grid model) or not.
Number of OS threads used to compute the steps (default
1).- amps_computation_time(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) float
Time spent in computing the flows (in amps) after the voltages have been computed at each nodes
It is given in seconds (
float).
- available_algorithm_names(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) list[str]
Returns the names of all registered algorithms, including any loaded plugins, as a list of string.
- available_default_algorithms(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) list[lightsim2grid.lightsim2grid_cpp.AlgorithmType]
Return the list of the names of the algorithm available on the current lightsim2grid installation.
This is a list of
lightsim2grid.algorithm.AlgorithmType.
- change_algorithm(*args, **kwargs)
Overloaded function.
change_algorithm(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, arg0: lightsim2grid.lightsim2grid_cpp.AlgorithmType) -> None
This function allows to control which solver is used during the powerflow. See the section Available powerflow algorithms for more information about them.
See also
lightsim2grid.algorithm.AlgorithmTypefor a list of the available algorithms (NB: some algorithms might not be available on all platform)Note
If the algorithm type entered is a DC algorithm (eg from
lightsim2grid.algorithm.AlgorithmType, DC_SparseLU, DC_KLU or DC_NICSLU), it will change the _dc_solver otherwise the regular _solver is modified.Examples
from lightsim2grid.algorithm import AlgorithmType # init the grid model from lightsim2grid.network import init_from_pandapower pp_net = ... # any pandapower grid lightsim_grid_model = init_from_pandapower(pp_net) # some warnings might be issued as well as some warnings # change the algorithm used for the powerflow # to use internally a Newton Raphson algorithm with the Eigen sparse LU linear solver lightsim_grid_model.change_algorithm(AlgorithmType.NR_SparseLU)
change_algorithm(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, arg0: str) -> None
Change the AC (or DC) algorithm by registry name. Accepts built-in names and plugin names registered via
load_solver_plugin().See also
change_algorithm()to change it bylightsim2grid.algorithm.AlgorithmTypeinstead.
- change_solver(*args, **kwargs)
Overloaded function.
change_solver(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, arg0: lightsim2grid.lightsim2grid_cpp.AlgorithmType) -> None
DEPRECATED: use ‘change_algorithm’ instead
change_solver(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, arg0: str) -> None
DEPRECATED: use ‘change_algorithm’ instead
- clear(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) None
Clear the solver and to as if the class never performed any powerflow.
- close(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) None
Clear the solver and to as if the class never performed any powerflow.
- compute(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, Vinit: Annotated[numpy.typing.NDArray[numpy.complex128], '[m, 1]'], max_iter: SupportsInt | SupportsIndex, tol: SupportsFloat | SupportsIndex) None
Run the batch: one powerflow per simulation, using whatever was set by modify_* (and, on ScenarioSweep, set_contingency_lines / set_contingency_trafos). Raises if nothing was ever set.
- compute_Vs(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, arg0: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg1: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg2: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg3: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous'], arg4: Annotated[numpy.typing.NDArray[numpy.complex128], '[m, 1]'], arg5: SupportsInt | SupportsIndex, arg6: SupportsFloat | SupportsIndex) int
Compute the voltages (at each bus of the grid model) for some time series of injections (productions, loads, storage units, etc.)
Note
This function must be called before
lightsim2grid.timeSerie.TimeSeriesCPP.compute_flows()andlightsim2grid.timeSerie.TimeSeriesCPP.get_flows(),lightsim2grid.timeSerie.TimeSeriesCPP.get_voltages()orlightsim2grid.timeSerie.TimeSeriesCPP.get_sbuses().Note
During this computation, the GIL is released, allowing easier parrallel computation
- gen_p:
numy.ndarray, float Active generation for each generators. Its counts as many column as the number of generators on the grid and as many rows as the number of steps to compute.
- sgen_p:
numy.ndarray, float Active generation for each static generator. Its counts as many column as the number of static generators on the grid and as many rows as the number of steps to compute.
- load_p:
numy.ndarray, float Active consumption for each loads. Its counts as many column as the number of loads on the grid and as many rows as the number of steps to compute.
- load_q:
numy.ndarray, float Reactive consumption for each loads. Its counts as many column as the number of loads on the grid and as many rows as the number of steps to compute.
- Vinit:
numy.ndarray, complex First voltage at each bus of the grid model (including the disconnected buses)
- max_iter:
int Total number of iteration (>0 integer)
- tol:
float Solver tolerance (> 0. float)
- status:
int The status of the computation. 1 means “success”: all powerflows were computed sucessfully, 0 means there were some errors and that the computation stopped after a certain number of steps.
DEPRECATED: prefer modify_gen_p / modify_sgen_p / modify_load_p / modify_load_q + compute() instead.
- gen_p:
- compute_flows(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.writeable', 'flags.c_contiguous']
Retrieve the flows (in amps, at the origin of each powerlines / high voltage size of each transformers.
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been called.Note
This function must be called before
lightsim2grid.timeSerie.TimeSeriesCPP.get_flows()Note
During this computation, the GIL is released, allowing easier parrallel computation
- compute_power_flows(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.writeable', 'flags.c_contiguous']
Retrieve the active flows (in MW, at the origin of each powerlines / high voltage size of each transformers.
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been called.Note
This function must be called before
lightsim2grid.timeSerie.TimeSeriesCPP.get_flows()Note
During this computation, the GIL is released, allowing easier parrallel computation
- converged_mask(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) list[bool]
Per-row convergence, as a list[bool] of length nb_steps() (row order matches the row order of whatever was solved: my_defaults() for ContingencyAnalysis, the injection / contingency matrices otherwise). Unlike converged() (ContingencyAnalysis-only, and only usable if compute_limit_violations=True was set), this is available on every batch class – TimeSeries, InjectionSweep, ContingencyAnalysis and ScenarioSweep alike – unconditionally, no setup required.
Row i is True iff that row was both invertible and reported convergence by the solver. A row that was never attempted at all (eg every row after the first failure in a TimeSeries, whose steps are chained and so stop there) is False too – indistinguishable from an outright divergence, the same “never attempted” == “did not converge” convention nb_solved() / nb_converged() already use.
- get_algo_config(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) lightsim2grid.lightsim2grid_cpp.AlgoConfig
Config (eg ScalingPolicyType / damping parameters) of the internal solver used for every step. Copied once from the grid model’s own get_ac_algo_config() at construction time, then independent of it; re-apply with set_algo_config() if you change the grid model’s config afterwards, or after change_algorithm().
- get_algo_name(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) str
Registry name of the currently selected algorithm. Unlike get_algo_type(), stays meaningful for plugin solvers (and built-ins with no dedicated AlgorithmType member).
- get_algo_type(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) lightsim2grid.lightsim2grid_cpp.AlgorithmType
Return the type of the solver currently used.
This is equivalent to the get_type of the
lightsim2grid.algorithm.AlgorithmSelector.get_type()of the solver used.
- get_flows(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]']
Get the current flows (in kA) at the origin side / high voltage side of each transformers / powerlines.
Each rows correspond to a time step, each column to a powerline / transformer
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_flows()has been called. (compute_flows also requires thatlightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been caleed)- Returns:
As – The flows (in kA) at the origin side / high voltage side of each transformers / powerlines.
- Return type:
numpy.ndarry(matrix)
- get_power_flows(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]']
Get the active flows (in MW) at the origin side / high voltage side of each transformers / powerlines.
Each rows correspond to a time step, each column to a powerline / transformer
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_power_flows()has been called. (compute_power_flows also requires thatlightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs()has been caleed)- Returns:
Ps – The active flows (in MW) at the origin side / high voltage side of each transformers / powerlines.
- Return type:
numpy.ndarry(matrix)
- get_sbuses(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) Annotated[numpy.typing.NDArray[numpy.complex128], '[m, n]', 'flags.c_contiguous']
Get the complex power injected at each (solver id) bus of the powergrid. Results are given in pair unit. We do not recommend to use it as it uses the solver id and NOT the powergrid bus id (you can refer to
lightsim2grid.network.LSGrid.id_me_to_ac_solver()andlightsim2grid.network.LSGrid.id_ac_solver_to_me()for more information)Each rows correspond to a time step, each column to a bus (bus are identified by their solver id !)
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs().- Returns:
Sbuses – The complex power injected at each bus (pair unit, load sign convention)
- Return type:
numpy.ndarry(matrix)
- get_status(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) int
Status of the solvers (1: success, 0: failure).
Note
Even if the solver failed at some point, some results might still be available (but not totally).
- get_voltages(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) Annotated[numpy.typing.NDArray[numpy.complex128], '[m, n]']
Get the complex voltage angles at each bus of the powergrid.
Each rows correspond to a time step, each column to a bus.
Warning
This function must be called after
lightsim2grid.timeSerie.TimeSeriesCPP.compute_Vs().- Returns:
Vs – The complex voltage angles at each bus of the powergrid.
- Return type:
numpy.ndarry(matrix)
- property init_from_n_powerflow
Whether to initialize the complex voltages of each step with the results of a “n” powerflow (ie a powerflow run at the start of the computation, on the injections of the grid model) or not.
Default:
False, meaning every step is initialized with the input vector given tolightsim2grid.injectionSweep.InjectionSweepCPP.compute_Vs().
- modify_gen_p(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, gen_p: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step active generator setpoints, shape (n_simul, n_gen). See the class docstring: locks / checks the number of simulations against any other modify_* / set_contingency_* call already made on this object.
- modify_gen_v(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, gen_v: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step generator target voltage magnitude, shape (n_simul, n_gen), in pu (vm_pu), NOT kV. Unlike modify_gen_p/modify_sgen_p/modify_load_p/modify_load_q, this does NOT feed the injection (Sbus) – it only re-seeds |V| at each voltage-regulating generator’s regulated bus before that step’s solve. See modify_gen_p() for the shared row-count-lock behavior.
- modify_load_p(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, load_p: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step active load setpoints, shape (n_simul, n_load). See modify_gen_p().
- modify_load_q(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, load_q: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step reactive load setpoints, shape (n_simul, n_load). See modify_gen_p().
- modify_sgen_p(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, sgen_p: Annotated[numpy.typing.NDArray[numpy.float64], '[m, n]', 'flags.c_contiguous']) None
Per-step active static generator setpoints, shape (n_simul, n_sgen). See modify_gen_p().
- nb_converged(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) int
Number of powerflows, among those nb_solved() attempted, that actually converged. Always <= nb_solved(): a row skipped outright (eg a non-invertible / islanding admittance matrix, on ContingencyAnalysis / ScenarioSweep) never reaches the solver at all, so it counts towards neither.
- nb_solved(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) int
Total number of powerflows solved.
- property nb_thread
Number of OS threads used to compute the steps (default
1).With
nb_thread == 1the behaviour is the legacy sequential one. Withnb_thread > 1the steps are split into contiguous ranges, each solved by its own thread (each with its own solver), writing to disjoint rows of the result matrix: the results do NOT depend on the number of threads. Values< 1are clamped to1.Warning
This is only available on
lightsim2grid.injectionSweep.InjectionSweepCPP(and onlightsim2grid.contingencyAnalysis.ContingencyAnalysisCPP), whose computations are independent of one another.On
lightsim2grid.timeSerie.TimeSeriesCPPeach step is initialized with the result of the previous one, so the steps cannot be split over threads without making the results depend on how they were split: setting it to anything but 1 raises aRuntimeError. UseInjectionSweepCPPif you want the very same injections computed in parallel.
- preprocessing_time(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) float
Time spent in pre processing the data (this involves, but is not limited to the computation of the Sbus)
It is given in seconds (
float).
- set_algo_config(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP, config: lightsim2grid.lightsim2grid_cpp.AlgoConfig) None
See get_algo_config().
- solver_time(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) float
Total time spent only in solving the powerflows (excluding pre processing the data, post processing them, initializing everything etc.)
It is given in seconds (
float).
- thread_init_time(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) float
Time (in seconds,
float) spent building the per thread solvers. It is 0. whennb_threadis 1, in which case the (already initialized) internal solver is reused.
- total_time(self: lightsim2grid.lightsim2grid_cpp.InjectionSweepCPP) float
Total time spent in solving the powerflows, pre processing the data, post processing them, initializing everything etc.
It is given in seconds (
float).