BDonnot / lightsim2grid

LightSim2grid implements a c++ backend targeting the Grid2Op (https://github.com/rte-france/grid2op) platform.
https://lightsim2grid.readthedocs.io/en/latest/
Mozilla Public License 2.0
46 stars 9 forks source link

DC solver does not detect game over #58

Closed Mleyliabadi closed 9 months ago

Mleyliabadi commented 1 year ago

Environment

Bug description

When performing some simulation using DC solver, the admittance matrix returned by DC solver (using env.backend._grid.get_dcYbus()) contains rows and columns including only zeros, where the same does not happen using AC solver. I have noticed that for a specific action that I have provided below.

How to reproduce

To reproduce the bug, I have provided a Python code snippet (see below). In this provided example, after applying the action, the AC solver enter the game over state, however, its admittance matrix looks correct. But, the AC solver does not enter the Game over state, and its admittance matrix contains rows and columns including only zeros.

Code snippet

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

#### AC Simulation
print("************* AC SIMULATION *************")
# setting the environment parameters, and seeds
param = Parameters()
env_params = {
    "NO_OVERFLOW_DISCONNECTION": True,
    "MAX_LINE_STATUS_CHANGED": 999999,
    "MAX_SUB_CHANGED": 999999,
    "NB_TIMESTEP_COOLDOWN_LINE": 0,
    "NB_TIMESTEP_COOLDOWN_SUB": 0}
param.init_from_dict(env_params)

env_seed = 1
initial_chronics_id = 864

# create the environment with specific parameters
env = grid2op.make("l2rpn_case14_sandbox", backend=LightSimBackend(), param=param)
env.seed(env_seed)
env.chronics_handler.set_filter(lambda path: re.match("^((?!(.*9[0-9][0-9].*)).)*$", path) is not None)
env.chronics_handler.real_data.reset()
env.set_id(initial_chronics_id)
obs = env.reset()

# Make the action in question
topo_vect = np.array([ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1, -1,  1,  1,  1, -1,  1,  1,
                       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                       1,  1, -1,  2,  2,  2,  1, -1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                       1,  1,  1,  1,  1,  1], dtype=int)
action_list = [(idx, el) for idx, el in enumerate(topo_vect)]

action = env.action_space({})
action.set_bus = action_list

# Apply the action
obs, reward, done, info = env.step(action)
print("AC topo_vect", obs.topo_vect)
#assert done is False

Ybus = env.backend._grid.get_Ybus().todense()
print("The dimension of Ybus in the case of AC: ", Ybus.shape)
print("The row with all zeros: ", np.where(~Ybus.any(axis=1))[0])
print("The column with all zeros: ", np.where(~Ybus.any(axis=0))[1])

#### DC simulation
print("************* DC SIMULATION *************")

param = Parameters()
env_params = {
    "NO_OVERFLOW_DISCONNECTION": True,
    "MAX_LINE_STATUS_CHANGED": 999999,
    "MAX_SUB_CHANGED": 999999,
    "NB_TIMESTEP_COOLDOWN_LINE": 0,
    "NB_TIMESTEP_COOLDOWN_SUB": 0}
param.init_from_dict(env_params)
param.ENV_DC = True

# create the environment with specific parameters
env = grid2op.make("l2rpn_case14_sandbox", backend=LightSimBackend(), param=param)
env.seed(env_seed)
env.chronics_handler.set_filter(lambda path: re.match("^((?!(.*9[0-9][0-9].*)).)*$", path) is not None)
env.chronics_handler.real_data.reset()
env.set_id(initial_chronics_id)
obs = env.reset()

obs, reward, done, info = env.step(action)
print("DC topo_vect", obs.topo_vect)
assert done is False

Ybus_dc = env.backend._grid.get_dcYbus().todense()
print("The dimension of Ybus in the case of DC: ", Ybus_dc.shape)
print("The row with all zeros: ", np.where(~Ybus_dc.any(axis=1))[0])
print("The column with all zeros: ", np.where(~Ybus_dc.any(axis=0))[1])

Current output

The dimension of Ybus in the case of DC: (15, 15)
The row with all zeros:  [8]
The column with all zeros:  [8]

Expected output

The expected output should not contain rows and columns with all zeros as is the case for AC solver.

The dimension of Ybus in the case of DC: (14, 14)
The row with all zeros:  [ ]
The column with all zeros:  [ ]
BDonnot commented 1 year ago

Hello,

I just run your code and it appears that it isolates the load 5, so it makes the grid diverge. And if the grid diverges, you should not look in the solver it might be in a "unstable" state.

As you noticed, the "topo_vect" is [-1, -1, ...]

I am not sure the Ybus is updated if the powerflow diverge for example.

Mleyliabadi commented 1 year ago

Hello again,

I'm agree with you when using AC solver. I've checked the divergence through env.infos["exception"].

However, when using the DC solver by setting param.ENV_DC = True, there is no report concerning the grid divergence and env.infos["exception"] is empty and "topo_vect" is not [-1, -1, ...]. So, I don't know if there is another parameter to verify the divergence when using DC solver ? Any help is appreciated.

BDonnot commented 1 year ago

Hi,

This probably means the grid converges in DC. But it does not make sense to compare the size of the Ybus in DC (where it's updated and it converges) to the one in AC (where it might not be updated because it diverges)

Having an example of mismatch between AC and DC would be helpful provided that they both converges.

Mleyliabadi commented 1 year ago

Completely agree with you to provide a more fair comparable example between AC and DC. However, I hope that the provided example shows somehow the encountered problem.

I have also verified the wrong dimension of admittance matrix (for DC solver) through the following commands after the application of mentioned action:

nb_bus, unique_bus, bus_or, bus_ex = obs._aux_fun_get_bus()
print(len(unique_bus))
> 14

It means that the admittance matrix should be 14x14 and not 15x15 with a row including only zeros.

BDonnot commented 1 year ago

Hello,

After a closer look at the issue:

So no, the provided example does absolutely not explain the problem encountered. Problem that is not even a problem, as far as I understand.

To "fix" your issue, connect the load to the grid for example by connecting to bus 2 the line disconnected at the right side (the side of the load alone) and you'll see you won't have any "issue"

Let me know if you encounter the same kind of issue with a grid that converges next time.

Mleyliabadi commented 1 year ago

Hey,

All your answers and assumption would be true if DC solver returns "done=True" when a load or generation is isolated, which is not the case. The DC solver (I insist DC solver) continues to compute flow even if there are isolated injections. Only AC solver behaves as expected and returns "done=True" in the presence of isolated loads or generations.

BDonnot commented 1 year ago

DC should be doing that, and on my machine it does not.

WIth your script slightly modified:

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

#### AC Simulation
print("************* AC SIMULATION *************")
# setting the environment parameters, and seeds
param = Parameters()
env_params = {
    "NO_OVERFLOW_DISCONNECTION": True,
    "MAX_LINE_STATUS_CHANGED": 999999,
    "MAX_SUB_CHANGED": 999999,
    "NB_TIMESTEP_COOLDOWN_LINE": 0,
    "NB_TIMESTEP_COOLDOWN_SUB": 0}
param.init_from_dict(env_params)

env_seed = 1
initial_chronics_id = 864

# create the environment with specific parameters
env = grid2op.make("l2rpn_case14_sandbox",
                   backend=LightSimBackend(),
                   param=param)
env.seed(env_seed)
env.chronics_handler.set_filter(lambda path: re.match("^((?!(.*9[0-9][0-9].*)).)*$", path) is not None)
env.chronics_handler.real_data.reset()
env.set_id(initial_chronics_id)
obs = env.reset()

# Make the action in question
topo_vect = np.array([ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1, -1,  1,  1,  1, -1,  1,  1,
                       1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                       1,  1, -1,  2,  2,  2,  1, -1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
                       1,  1,  1,  1,  1,  1], dtype=int)
action_list = [(idx, el) for idx, el in enumerate(topo_vect)]

action = env.action_space({})
action.set_bus = action_list
# print(action)

# Apply the action
print("doing the step now")
obs, reward, done, info = env.step(action)
# print("AC topo_vect", obs.topo_vect)
assert done
print(info["exception"])

#### DC simulation
print("************* DC SIMULATION *************")

param = Parameters()
env_params = {
    "NO_OVERFLOW_DISCONNECTION": True,
    "MAX_LINE_STATUS_CHANGED": 999999,
    "MAX_SUB_CHANGED": 999999,
    "NB_TIMESTEP_COOLDOWN_LINE": 0,
    "NB_TIMESTEP_COOLDOWN_SUB": 0}
param.init_from_dict(env_params)
param.ENV_DC = True

# create the environment with specific parameters
env = grid2op.make("l2rpn_case14_sandbox", backend=LightSimBackend(), param=param)
env.seed(env_seed)
env.chronics_handler.set_filter(lambda path: re.match("^((?!(.*9[0-9][0-9].*)).)*$", path) is not None)
env.chronics_handler.real_data.reset()
env.set_id(initial_chronics_id)
obs = env.reset()

obs, reward, done, info = env.step(action)
assert done
print(info["exception"])

I got:

************* AC SIMULATION *************
doing the step now
[Grid2OpException DivergingPowerFlow DivergingPowerFlow('Divergence of DC powerflow (non connected grid) at the initialization of AC powerflow. Detailed error: ErrorType.SolverSolve')]
************* DC SIMULATION *************
[Grid2OpException DivergingPowerFlow DivergingPowerFlow('Divergence of DC powerflow (non connected grid). Detailed error: ErrorType.SolverSolve')]

Clearly indicating that in both cases "done" is True (see the assert) AND the DC has diverged in this case.

Mleyliabadi commented 1 year ago

It is not the case for me when I execute your code! I receive an "AssertionError" for DC simulator and info["Exception"] is empty. I have the last versions of "LightSim2grid: 0.7.1" and "Grid2op: 1.8.1".

BDonnot commented 1 year ago

Which type of solver do you use [env.backend.get_solver_types()] ?

Have you installed the package from source or from pypi ?

Mleyliabadi commented 1 year ago

It was the command env.backend._grid.get_solver_type()

I obtain the following results:

env.backend._grid.get_solver_type()
> <SolverType.KLUSingleSlack: 7>
env.backend._grid.get_dc_solver_type()
> <SolverType.KLUDC: 9>

I have installed the packages from Pypi if I remember correctly.

BDonnot commented 1 year ago

Please uninstall entirely and re install from pypi. Let's see if this fixes the issue.

Mleyliabadi commented 1 year ago

I have just created a clean virtual environment and installing only Grid2op and Lightsim2grid using the following commands:

virtualenv -p /usr/bin/python3.8 test_issue
source test_issue/bin/activate
pip install grid2op
pip install lightsim2grid
pip install numba

and when running the script containing your code, I have the following output:

************* AC SIMULATION *************
doing the step now
[Grid2OpException DivergingPowerFlow DivergingPowerFlow('Divergence of AC powerflow. Detailed error: ErrorType.TooManyIterations')]
************* DC SIMULATION *************
Traceback (most recent call last):
  File "issue_DC_Ben.py", line 72, in <module>
    assert done
AssertionError

Here is the result of pip list:

Package            Version
------------------ ---------
certifi            2022.12.7
charset-normalizer 3.1.0
deepdiff           6.3.0
Grid2Op            1.8.1
idna               3.4
importlib-metadata 6.6.0
LightSim2Grid      0.7.1
llvmlite           0.39.1
networkx           3.1
numba              0.56.4
numpy              1.23.5
ordered-set        4.1.0
packaging          23.1
pandapower         2.12.1
pandas             2.0.1
pip                23.1.2
python-dateutil    2.8.2
pytz               2023.3
requests           2.29.0
scipy              1.10.1
setuptools         62.0.0
six                1.16.0
tqdm               4.65.0
tzdata             2023.3
urllib3            1.26.15
wheel              0.37.1
zipp               3.15.0

For information I use Ubuntu 20.04 on WSL2

BDonnot commented 9 months ago

As there are no activity for a long time i'll close this.

Feel free to re open it with if there are some news (don't forget to upgrade to use most recent version).