Skip to content

Commit

Permalink
first test in adding support for detachment feature
Browse files Browse the repository at this point in the history
Signed-off-by: DONNOT Benjamin <[email protected]>
  • Loading branch information
BDonnot committed Dec 16, 2024
1 parent af4d62e commit 6ad01dc
Show file tree
Hide file tree
Showing 8 changed files with 413 additions and 15 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ TODO: in `main.cpp` check the returned policy of pybind11 and also the `py::call
TODO: a cpp class that is able to compute (DC powerflow) ContingencyAnalysis and TimeSeries using PTDF and LODF
TODO: integration test with pandapower (see `pandapower/contingency/contingency.py` and import `lightsim2grid_installed` and check it's True)

[0.9.3] 2024-12-16
-------------------
- [FIXED] an issue with the storage units (when asking it to produce / consume
but deactivating them with the same action the grid did not diverge)
- [IMPROVED] add the grid2op "detachement" support (loads and generators are allowed
to be disconnected from the grid)

[0.9.2.post2] 2024-11-29
--------------------------
- [FIXED] The attribute `can_output_theta` (of base `Backend` class)
Expand Down
109 changes: 109 additions & 0 deletions basic_perf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import warnings
import pandapower as pp
import numpy as np
from grid2op import make, Parameters
from grid2op.Chronics import FromNPY
from lightsim2grid import LightSimBackend
import tempfile
import os

try:
from tabulate import tabulate
TABULATE_AVAIL = True
except ImportError:
print("The tabulate package is not installed. Some output might not work properly")
TABULATE_AVAIL = False


case_names = [
# "case14.json",
"case118.json",
# "case_illinois200.json",
# "case300.json",
# "case1354pegase.json",
"case1888rte.json",
# "GBnetwork.json", # 2224 buses
"case2848rte.json",
# "case2869pegase.json",
# "case3120sp.json",
"case6495rte.json",
"case6515rte.json",
"case9241pegase.json"
]

case_name = "case6495rte.json"
case_name = "case14.json"

def make_grid2op_env(pp_case, case_name, load_p, load_q, gen_p, sgen_p):
param = Parameters.Parameters()
param.init_from_dict({"NO_OVERFLOW_DISCONNECTION": True})

with warnings.catch_warnings():
warnings.filterwarnings("ignore")
env_lightsim = make("blank",
param=param,
test=True,
backend=LightSimBackend(),
chronics_class=FromNPY,
data_feeding_kwargs={"load_p": load_p,
"load_q": load_q,
"prod_p": gen_p
},
grid_path=case_name,
_add_to_name=f"{case_name}",
)
return env_lightsim

if __name__ == "__main__":

import pandapower.networks as pn
for case_name in case_names:
tmp_nm = os.path.splitext(case_name)[0]
print(f"====================== {tmp_nm} ======================")
case = getattr(pn,tmp_nm)()
pp.runpp(case) # for slack

load_p_init = 1.0 * case.load["p_mw"].values
load_q_init = 1.0 * case.load["q_mvar"].values
gen_p_init = 1.0 * case.gen["p_mw"].values
sgen_p_init = 1.0 * case.sgen["p_mw"].values

nb_ts = 1
# add slack !
slack_gens = np.zeros((nb_ts, case.ext_grid.shape[0]))
if "res_ext_grid" in case:
slack_gens += np.tile(case.res_ext_grid["p_mw"].values.reshape(1,-1), (nb_ts, 1))
gen_p_g2op = np.concatenate((gen_p_init.reshape(1,-1), slack_gens), axis=1)

with tempfile.TemporaryDirectory() as tmpdirname:
pp.to_json(case, os.path.join(tmpdirname, case_name))
with open(os.path.join(tmpdirname, "config.py"), "w") as f:
f.write("config = {}")

env = make_grid2op_env(None,
os.path.join(tmpdirname, case_name),
load_p=load_p_init.reshape(1,-1),
load_q=load_q_init.reshape(1,-1),
gen_p=gen_p_g2op.reshape(1,-1),
sgen_p=None)

env.backend._grid.tell_solver_need_reset()
_ = env.step(env.action_space())
ls_solver = env.backend._grid.get_solver()
nb_iter_solver = ls_solver.get_nb_iter()
timers = ls_solver.get_timers_jacobian()
(timer_Fx, timer_solve, timer_init, timer_check,
timer_compute_dS, timer_fillJ, timer_compVa_Vm, timer_preproc, timer_total) = timers
print(f"Total time for the powerflow (=pre proc + NR + post proc): {env.backend._grid.timer_last_ac_pf:.2e}s")
print(f"Total time spent in the Newton Raphson: {timer_total:.2e}s")
print(f"Time to pre process input data: {timer_preproc:.2e}s")
print(f"Time to intialize linear solver: {timer_init:.2e}s")
print(f"Then for all iterations (cumulated time over all {nb_iter_solver} iterations)")
print(f"\ttotal time to compute dS/dVm and dS/dVa: {timer_compute_dS:.2e}s")
print(f"\ttotal time fill jacobian matrix (from dS/dVm and dS/dVa): {timer_fillJ:.2e}s")
print(f"\ttotal time to solve J.x = b: {timer_solve:.2e}s")
print(f"\ttotal time to compute V, Va and Vm: {timer_compVa_Vm:.2e}s")
print(f"\ttotal time to compute p, q mismatch at buses: {timer_Fx:.2e}s")
print(f"\ttotal time to check if p,q mismatch at buses are within tolerance: {timer_check:.2e}s")
print(f"====================== {' '*len(tmp_nm)} ======================")

192 changes: 192 additions & 0 deletions benchmarks/benchmark_gauss_seidel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# Copyright (c) 2024, RTE (https://www.rte-france.com)
# See AUTHORS.txt
# This Source Code Form is subject to the terms of the Mozilla Public License, version 2.0.
# If a copy of the Mozilla Public License, version 2.0 was not distributed with this file,
# you can obtain one at http://mozilla.org/MPL/2.0/.
# SPDX-License-Identifier: MPL-2.0
# This file is part of LightSim2grid, LightSim2grid a implements a c++ backend targeting the Grid2Op platform.

import warnings
import copy
import pandapower as pp
import numpy as np
import hashlib
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt
from grid2op import make, Parameters
from grid2op.Chronics import FromNPY, ChangeNothing
from grid2op.Backend import PandaPowerBackend
from grid2op.Exceptions import Grid2OpException
import lightsim2grid
from lightsim2grid import LightSimBackend
from benchmark_grid_size import (get_loads_gens,
make_grid2op_env_pp,
run_grid2op_env,
make_grid2op_env)
from benchmark_solvers import solver_gs, solver_names, order_solver_print

from tqdm import tqdm
import os
from utils_benchmark import print_configuration, get_env_name_displayed
from benchmark_solvers import solver_names

try:
from tabulate import tabulate
TABULATE_AVAIL = True
except ImportError:
print("The tabulate package is not installed. Some output might not work properly")
TABULATE_AVAIL = False

VERBOSE = False
MAKE_PLOT = False
WITH_PP = False
DEBUG = False

case_names = [
"case14.json",
"case118.json",
"case_illinois200.json",
"case300.json",
"case1354pegase.json",
"case1888rte.json",
# # "GBnetwork.json", # 2224 buses
# "case2848rte.json",
# "case2869pegase.json",
# "case3120sp.json",
# "case6495rte.json",
# "case6515rte.json",
# "case9241pegase.json"
]


if __name__ == "__main__":
prng = np.random.default_rng(42)
case_names_displayed = [get_env_name_displayed(el) for el in case_names]
nb_iters = []
ts_sizes = []
errors = {}
for case_name in tqdm(case_names):

if not os.path.exists(case_name):
import pandapower.networks as pn
case = getattr(pn, os.path.splitext(case_name)[0])()
pp.to_json(case, case_name)

# load the case file
case = pp.from_json(case_name)
ts_sizes.append(case.bus.shape[0])
pp.runpp(case) # for slack

# create the env
param = Parameters.Parameters()
param.init_from_dict({"NO_OVERFLOW_DISCONNECTION": True})

with warnings.catch_warnings():
warnings.filterwarnings("ignore")
env_pp = make("blank",
param=param, test=True,
backend=PandaPowerBackend(lightsim2grid=False),
chronics_class=ChangeNothing,
grid_path=case_name,
_add_to_name=f"{case_name}",
)
env_ls = make("blank",
param=param, test=True,
backend=LightSimBackend(),
chronics_class=ChangeNothing,
grid_path=case_name,
_add_to_name=f"{case_name}",
)
env_ls.backend.set_solver_type(lightsim2grid.SolverType.GaussSeidel)
all_iters = [1, 3, 10, 30, 100, 300, 1_000, 3_000,
10_000, 30_000,
100_000, 300_000
]
iters = []
errors_p = []
errors_q = []
for max_iter in all_iters:
env_ls.backend.set_solver_max_iter(max_iter)
env_ls.backend._grid.tell_solver_need_reset()
conv = True
try:
obs = env_ls.reset()
except Grid2OpException as exc_:
conv = False
iters.append(env_ls.backend._grid.get_solver().get_nb_iter())
v_tmp = env_ls.backend._grid.get_solver().get_V()
res_tmp = env_ls.backend._grid.check_solution(v_tmp, False)
error_p = 1. * np.abs(res_tmp.real).max()
error_q = 1. * np.abs(res_tmp.imag).max()
errors_p.append(error_p)
errors_q.append(error_q)
if conv:
break
if conv:
nb_iters.append(iters[-1])
else:
nb_iters.append(None)

errors[case.bus.shape[0]] = (errors_p, errors_q)

print("Configuration:")
print_configuration()
print(f"Solver used for linear algebra: {lightsim2grid.SolverType.GaussSeidel}")
print()
hds = ["grid size (nb bus)", "gauss seidel max iter"]
tab = []
for sz, nb_it in zip(ts_sizes, nb_iters):
tab.append([sz, nb_it])

if TABULATE_AVAIL:
res_use_with_grid2op_2 = tabulate(tab, headers=hds, tablefmt="rst")
print(res_use_with_grid2op_2)
else:
print(tab)

print(errors[118][0])
print(errors[118][1])
import pickle
with open("res_gauss_seidel.pickle", "wb") as f:
pickle.dump(errors, file=f)
with open("res_gauss_seidel_nb_iters.pickle", "wb") as f:
pickle.dump(nb_iters, file=f)
print()
print()


# total computation time : 1h27min16s
# Configuration:

# - date: 2024-12-02 18:46 CET
# - system: Linux 5.15.0-56-generic
# - OS: ubuntu 20.04
# - processor: Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
# - python version: 3.8.10.final.0 (64 bit)
# - numpy version: 1.24.3
# - pandas version: 2.0.3
# - pandapower version: 2.14.0
# - grid2op version: 1.11.0.dev2
# - lightsim2grid version: 0.9.2.post2
# - lightsim2grid extra information:

# - klu_solver_available: True
# - nicslu_solver_available: False
# - cktso_solver_available: False
# - compiled_march_native: False
# - compiled_o3_optim: False

# Solver used for linear algebra: SolverType.GaussSeidel

# ==================== =======================
# grid size (nb bus) gauss seidel max iter
# ==================== =======================
# 14 278
# 118 3274
# 200 8360
# 300 40783
# 1354 122169
# 1888
# ==================== =======================
# [31.858705410410803, 13.801689961508492, 7.912199121114395, 6.387621207822959, 4.5494311573542525, 1.3539274305627065, 0.01652457790687702, 5.5928201247405206e-08, 9.957519963773673e-09]
# [111.7637849724719, 52.1105433668106, 6.3902552555152345, 1.1851759157023143, 0.8457897295792693, 0.25197455746676584, 0.0030761171444685202, 1.0415372012959338e-08, 1.8561325626140559e-09]
8 changes: 5 additions & 3 deletions benchmarks/benchmark_grid_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,9 @@ def run_grid2op_env(env_lightsim, case, reset_solver,
g2op_step_time,
ls_solver_time,
ls_gridmodel_time,
g2op_sizes
g2op_sizes,
sgen_p,
nb_ts
):
_ = env_lightsim.reset()
done = False
Expand Down Expand Up @@ -330,7 +332,7 @@ def run_grid2op_env(env_lightsim, case, reset_solver,
g2op_step_time_reset,
ls_solver_time_reset,
ls_gridmodel_time_reset,
g2op_sizes_reset
g2op_sizes_reset, sgen_p, nb_ts
)

reset_solver = False # default
Expand All @@ -340,7 +342,7 @@ def run_grid2op_env(env_lightsim, case, reset_solver,
g2op_step_time,
ls_solver_time,
ls_gridmodel_time,
g2op_sizes
g2op_sizes, sgen_p, nb_ts
)

# Perform the computation using TimeSerie
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
author = 'Benjamin DONNOT'

# The full version, including alpha/beta/rc tags
release = "0.9.2.post2"
release = "0.9.3"
version = '0.9'

# -- General configuration ---------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion lightsim2grid/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# SPDX-License-Identifier: MPL-2.0
# This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.

__version__ = "0.9.2.post2"
__version__ = "0.9.3"

__all__ = ["newtonpf", "SolverType", "ErrorType", "solver", "compilation_options"]

Expand Down
Loading

0 comments on commit 6ad01dc

Please sign in to comment.