Repository: Grid2op/lightsim2grid (language: python)

Issue:
Feature request: change tap ratio, hybrid AC/DC power flow and TDPF
LightSimBackend import error: No module named 'grid2op'
PhysicalLawChecker import error: No module named 'grid2op'
TimeSerie import error: cannot import name 'TimeSerie' from 'lightsim2grid.timeSerie' (C:\Users\xxxxxx\Documents\repositories\pandapower\venv-tutorial-test\Lib\site-packages\lightsim2grid\timeSerie.py)
ContingencyAnalysis import error: cannot import name 'ContingencyAnalysis' from 'lightsim2grid.contingencyAnalysis' (C:\Users\xxxxxx\Documents\repositories\pandapower\venv-tutorial-test\Lib\site-packages\lightsim2grid\contingencyAnalysis.py)
rewards import error: No module named 'grid2op'

Dear @BDonnot ,

We are encountering warnings at import of pandapower when lightsim2grid is installed (we are adding lightsim2grid as a required dependency of pandapower in all future versions).

As grid2op is optional and lightsim2grid can be used as a standalone library for the power flow and contingency analysis backend of pandapower, these warnings are superfluous.

Can you please remove these warnings?

**edit** (BDonnot) : this has been done in version 0.8.2. I keep this post open because it speaks about other things now.
Feature request: change tap ratio, hybrid AC/DC power flow and TDPF
LightSimBackend import error: No module named 'grid2op'
PhysicalLawChecker import error: No module named 'grid2op'
TimeSerie import error: cannot import name 'TimeSerie' from 'lightsim2grid.timeSerie' (C:\Users\xxxxxx\Documents\repositories\pandapower\venv-tutorial-test\Lib\site-packages\lightsim2grid\timeSerie.py)
ContingencyAnalysis import error: cannot import name 'ContingencyAnalysis' from 'lightsim2grid.contingencyAnalysis' (C:\Users\xxxxxx\Documents\repositories\pandapower\venv-tutorial-test\Lib\site-packages\lightsim2grid\contingencyAnalysis.py)
rewards import error: No module named 'grid2op'

Dear @BDonnot ,

We are encountering warnings at import of pandapower when lightsim2grid is installed (we are adding lightsim2grid as a required dependency of pandapower in all future versions).

As grid2op is optional and lightsim2grid can be used as a standalone library for the power flow and contingency analysis backend of pandapower, these warnings are superfluous.

Can you please remove these warnings?

**edit** (BDonnot) : this has been done in version 0.8.2. I keep this post open because it speaks about other things now.


Discussion / hints:

Fix patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 8f6291b..6bd3179 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -199,6 +199,11 @@ jobs:
                     make
                     CC=gcc python setup.py build
                     python -m pip install .[test]
+            - run:
+                name: "Show package versions"
+                command: |
+                    source venv_test/bin/activate
+                    pip freeze
             - run:
                 name: "make tests"
                 command: |
@@ -380,6 +385,11 @@ jobs:
                     make
                     CC=clang python setup.py build
                     CC=clang python -m pip install -e .[test]
+            - run:
+                name: "Show package versions"
+                command: |
+                    source venv_test/bin/activate
+                    pip freeze
             - run:
                 name: "make tests"
                 command: |
@@ -418,6 +428,7 @@ jobs:
                     git submodule update
                     python setup.py build
                     python -m pip install -e .[test]
+                    pip freeze
             - run:
                 name: "make tests"
                 command: |
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index dadcd64..011512b 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -10,9 +10,8 @@ on:
 jobs:
   manylinux_build:
     # build wheels for some linux
-    name: Build linux ${{ matrix.python.name }} wheel
+    name: Build linux ${{ matrix.python.name }} wheel on ${{ matrix.cont.name}}
     runs-on: ubuntu-latest
-    container: quay.io/pypa/manylinux2014_x86_64
     strategy:
       matrix:
         python:
@@ -47,7 +46,28 @@ jobs:
             version: '3.12',
           }
 
+        cont:
+          - {
+            name: manylinux2014_x86_64, 
+            val: quay.io/pypa/manylinux2014_x86_64,
+            arch: amd64
+          }
+          # - {
+          #   name: manylinux2014_aarch64, 
+          #   val: quay.io/pypa/manylinux2014_aarch64,
+          #   arch: arm64
+          # }
+
+    container: 
+      image: ${{matrix.cont.val}}
+      # does not work if not manylinux2014_x86_64...
+
     steps:
+      # - name: Set up QEMU
+      #   if: matrix.cont.name == 'manylinux2014_aarch64'
+      #   uses: docker/setup-qemu-action@v2
+      #   with:
+      #     platforms: arm64
 
       - name: Checkout sources
         uses: actions/checkout@v3 # v4 not working...
@@ -63,7 +83,8 @@ jobs:
           python -m pip install -r requirements.txt
 
       - name: Compile SuiteSparse
-        run: make
+        run: 
+          make
 
       - name: Build wheel
         run: |
@@ -80,11 +101,10 @@ jobs:
           pip3 install wheelhouse/*.whl --user
           pip freeze
 
-      # - name: Install GDB
-      #   run: yum install -y gdb
-
       - name: Check package can be imported (bare install)
         run: |
+          mkdir tmp_for_import_checking
+          cd tmp_for_import_checking
           python3 -c "import lightsim2grid"
           python3 -c "from lightsim2grid import *"
           python3 -c "from lightsim2grid.newtonpf import newtonpf"
@@ -99,13 +119,14 @@ jobs:
           pip install urllib3==1.26.6
           # otherwise urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips  26 Jan 2017'
 
-      - name: Check LightSimBackend can be imported (install grid2op)
+      - name: Install grid2op
         run: | 
           python3 -m pip install grid2op
           python3 -m pip freeze
 
       - name: Check extra can be imported can be imported (with grid2op)
         run:
+          cd tmp_for_import_checking
           python3 -v -c "from lightsim2grid import LightSimBackend"
           python3 -c "from lightsim2grid.timeSerie import TimeSerie"
           python3 -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysis"
@@ -114,12 +135,13 @@ jobs:
       
       - name: Check LightSimBackend can be used to create env
         run:
+          cd tmp_for_import_checking
           python3 -v -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
 
       - name: Upload wheel
         uses: actions/upload-artifact@v3  # v4 broken
         with:
-          name: lightsim2grid-wheel-linux-${{ matrix.python.name }}
+          name: lightsim2grid-wheel-linux-${{ matrix.python.name }}-${{ matrix.cont.name }}
           path: wheelhouse/*.whl
 
       - name: Upload source archive
@@ -131,7 +153,7 @@ jobs:
 
   windows_build:
     # build wheels for windows
-    name: Build windows ${{ matrix.python.name }} wheel
+    name: Build windows ${{ matrix.python.name }} wheel for ${{ matrix.win_arch.msvc}}
     runs-on: windows-2019
     strategy:
       matrix:
@@ -160,6 +182,15 @@ jobs:
             name: cp312,
             version: '3.12',
           }
+        win_arch:
+          - {
+            name: "AMD64",
+            msvc: x64
+          }
+          # - {
+          #   name: "x86",
+          #   msvc: x86
+          # }
     env:
       RUNNER_OS: windows-2019
       PYTHON_VERSION: ${{ matrix.python.version }}
@@ -171,10 +202,16 @@ jobs:
         with:
           submodules: true
 
-      - name: Setup Python
+      - name: Setup Python ${{ matrix.python.version }} ${{ matrix.win_arch.msvc}}
         uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python.version }}
+          architecture: ${{ matrix.win_arch.msvc}}
+
+      - name: Setup MSVC ${{ matrix.win_arch.msvc}}
+        uses: bus1/cabuild/action/msdevshell@e22aba57d6e74891d059d66501b6b5aed8123c4d # v1
+        with:
+          architecture: ${{ matrix.win_arch.msvc}}
 
       - name: Install Python dependencies
         run: |
@@ -220,15 +257,15 @@ jobs:
           python -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
 
       - name: Upload wheel
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v3
         with:
-          name: lightsim2grid-wheel-${{ matrix.config.name }}-${{ matrix.python.name }}
+          name: lightsim2grid-wheel-win-${{ matrix.python.name }}-${{ matrix.win_arch.msvc}}
           path: dist/*.whl
 
-  macos_build_37:
-    # build wheel for python 3.7 for macos
-    name: Build macos ${{ matrix.python.name }} wheel
-    runs-on: macos-latest
+  macos_build_37_:
+    ## build wheel for python 3.7 and above for macos (only >= 3.10 for arm64 )
+    name: Build darwin ${{ matrix.python.name }} wheel on ${{ matrix.runner.arch}}
+    runs-on: ${{ matrix.runner.name }}
     strategy:
       matrix:
         python:
@@ -236,7 +273,55 @@ jobs:
             name: cp37,
             version: '3.7',
           }
+          - {
+            name: cp38,
+            version: '3.8',
+          }
+          - {
+            name: cp39,
+            version: '3.9',
+          }
+          - {
+            name: cp310,
+            version: '3.10',
+          }
+          - {
+            name: cp311,
+            version: '3.11',
+          }
+          - {
+            name: cp312,
+            version: '3.12',
+          }
+        runner:
+          - {
+            name: macos-13,
+            arch: x86_64
+          }
+          - {
+            name: macos-14,
+            arch: arm64
+          }
+        exclude:
+          - python:  # does not work
+              name: cp37  
+            runner:
+              arch: arm64
+          - python:  # does not work
+              name: cp38  
+            runner: 
+              arch: arm64
+          - python:  # does not work
+              name: cp39
+            runner:
+              arch: arm64
+
+    env:
+      RUNNER_OS: ${{ matrix.runner.name }}
+      PYTHON_VERSION: ${{ matrix.python.version }}
+
     steps:
+
       - name: Checkout sources
         uses: actions/checkout@v4
         with:
@@ -250,49 +335,90 @@ jobs:
       - name: Install Python dependencies
         run: |
           python -m pip install --upgrade pip
+          python -m pip install --upgrade setuptools  # for python >= 3.12
           python -m pip install -r requirements.txt
 
       - name: Compile SuiteSparse make
         run: |
           make
           export __O3_OPTIM=1
-          python3 setup.py build
+          python setup.py build
 
       - name: Build wheel
         run: python setup.py bdist_wheel
 
       - name: Install wheel
         shell: bash
-        run: python -m pip install dist/*.whl --user
+        run: |
+          python -m pip install dist/*.whl --user
+          python -m pip freeze
 
-      - name: Check package can be imported
+      - name: Check package can be imported (bare install)
         run: |
           mkdir tmp_for_import_checking
           cd tmp_for_import_checking
           python -c "import lightsim2grid"
           python -c "from lightsim2grid import *"
           python -c "from lightsim2grid.newtonpf import newtonpf"
-          cd ..
+          python -c "from lightsim2grid.timeSerie import TimeSeriesCPP"
+          python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP"
+          python -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP"
+          python -c "from lightsim2grid.gridmodel import init, GridModel"
       
-      - name: Check LightSimBackend can be imported
+      - name: Fix urllib3 (python 3.7)
+        if: matrix.python.name == 'cp37'
+        run:
+          pip install urllib3==1.26.6
+          # otherwise urllib3 v2.0 only supports OpenSSL 1.1.1+, currently the 'ssl' module is compiled with 'OpenSSL 1.0.2k-fips  26 Jan 2017'
+
+      - name: Install grid2op
+        run: | 
+          python -m pip install grid2op
+          python -m pip freeze
+
+      - name: Check extra can be imported can be imported (with grid2op)
         run: |
           cd tmp_for_import_checking
-          python -m pip install grid2op
-          python -c "from lightsim2grid import LightSimBackend"
-          python -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
-        
+          python -v -c "from lightsim2grid import LightSimBackend"
+          python -c "from lightsim2grid.timeSerie import TimeSerie"
+          python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysis"
+          python -c "from lightsim2grid.physical_law_checker import PhysicalLawChecker"
+          python -c "from lightsim2grid.securityAnalysis import SecurityAnalysis"
+      
+      - name: Check LightSimBackend can be used to create env
+        run: |
+          cd tmp_for_import_checking
+          python -v -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
+
       - name: Upload wheel
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v3
         with:
-          name: lightsim2grid-wheel-darwin-${{ matrix.python.name }}
+          name: lightsim2grid-wheel-darwin-${{ matrix.python.name }}-${{ matrix.runner.arch}}
           path: dist/*.whl
 
-  macos_build_38_:
-    # build wheel for python 3.8 and above for macos
-    name: Build darwin ${{ matrix.python.name }} wheel
-    runs-on: macos-latest
+  exotic_build:
+    # build wheel using emulation for "exotic"things
+    # see https://github.com/cvxpy/cvxpy/blob/master/.github/workflows/build.yml
+    name: Build ${{ matrix.runner.name }} ${{ matrix.python.name }} wheel with cibuildwheel
+    runs-on: ${{ matrix.runner.name }}
     strategy:
       matrix:
+        runner:
+          - {
+            name: macos-14,  # host on arm64
+            whl_nm: macos_arm64,
+            cibuildwheel: macos
+          }
+          - {
+            name: windows-2019,  # host on x86_64
+            whl_nm: windows_arm64,
+            cibuildwheel: windows
+          }
+          # - {
+          #   name: ubuntu-latest,  # host on x86_64  # takes forever, like 20 mins x 2 at least
+          #   whl_nm: linux_arm64,
+          #   cibuildwheel: linux
+          # }
         python:
           - {
             name: cp38,
@@ -314,57 +440,80 @@ jobs:
             name: cp312,
             version: '3.12',
           }
+        exclude:
+          - python: 
+              name: cp310  # because already done natively above
+            runner:
+              name: macos-14
+          - python: 
+              name: cp311  # because already done natively above
+            runner:
+              name: macos-14
+          - python: 
+              name: cp312  # because already done natively above
+            runner:
+              name: macos-14
+          - python: 
+              name: cp38  # does not work
+            runner:
+              name: windows-2019
     env:
-      RUNNER_OS: macos-latest
+      RUNNER_OS: ${{ matrix.runner.name }}
       PYTHON_VERSION: ${{ matrix.python.version }}
 
     steps:
-
       - name: Checkout sources
         uses: actions/checkout@v4
         with:
           submodules: true
 
-      - name: Setup Python
-        uses: actions/setup-python@v5
+      - name: Set up QEMU
+        if: runner.os == 'Linux'
+        uses: docker/setup-qemu-action@v3
         with:
-          python-version: ${{ matrix.python.version }}
-
-      - name: Set Additional Envs
-        shell: bash
-        run: |
-          echo "PYTHON_SUBVERSION=$(echo $PYTHON_VERSION | cut -c 3-)" >> $GITHUB_ENV
-          echo "DEPLOY=$( [[ $GITHUB_EVENT_NAME == 'push' && $GITHUB_REF == 'refs/tags'* ]] && echo 'True' || echo 'False' )" >> $GITHUB_ENV
+          platforms: all
 
       - name: Compile with cibuildwheel
-        uses: pypa/cibuildwheel@v2.16.2
+        uses: pypa/cibuildwheel@v2.17.0
         env:
-          CIBW_BUILD: "cp3${{env.PYTHON_SUBVERSION}}-*"  # see https://github.com/cvxpy/cvxpy/blob/master/.github/workflows/build.yml
-          CIBW_ARCHS_LINUX: auto aarch64  # not used I believe
-          CIBW_ARCHS_MACOS: x86_64 arm64
+          CIBW_PLATFORM: "${{ matrix.runner.cibuildwheel}}"
+          CIBW_BUILD: "${{ matrix.python.name}}-*"
+          CIBW_ARCHS_LINUX: aarch64 
+          CIBW_ARCHS_MACOS: arm64 
+          CIBW_ARCHS_WINDOWS: ARM64 
           CIBW_ENVIRONMENT: __O3_OPTIM=1
-          CIBW_BEFORE_ALL: python -m pip install --upgrade setuptools wheel pybind11
-          CIBW_BEFORE_BUILD: make clean && make CC=clang CXX=clang++  # and not CIBW_BEFORE_ALL !
+          CIBW_BEFORE_ALL: python -m pip install --upgrade setuptools wheel pybind11 pip
+          CIBW_BEFORE_BUILD_MACOS: make clean && make CC=clang CXX=clang++  # no need to cross compile this because host is already arm64 based
+          CIBW_BEFORE_BUILD_LINUX: make clean && make  # maybe we need to cross compile this (host x64) but maybe not (qemu) ?
+          CIBW_BEFORE_BUILD_WINDOWS: > 
+            cd build_cmake &&
+            python generate_c_files.py &&
+            mkdir build &&
+            cd build  &&
+            cmake -DCMAKE_INSTALL_PREFIX=..\built -DCMAKE_BUILD_TYPE=Release -DCMAKE_GENERATOR_PLATFORM=arm64 .. &&
+            cmake --build . --config Release &&
+            cmake --install . --prefix ..\built
           CIBW_TEST_REQUIRES: grid2op pandapower
-          CIBW_TEST_SKIP: "cp312-* *-macosx_arm64"  # to silence warning "While arm64 wheels can be built on x86_64, they cannot be tested."
+          CIBW_TEST_SKIP: "cp312-* *-macosx_arm64 *-win_arm64" # to silence warning "While arm64 wheels can be built on x86_64, they cannot be tested."
           CIBW_TEST_COMMAND: >
-            python -c "import lightsim2grid" && 
+            python -c "import lightsim2grid" &&
             python -c "from lightsim2grid import *" &&
-            python -c "from lightsim2grid.newtonpf import newtonpf" && 
-            python -c "from lightsim2grid.solver import KLUSolver" && 
-            python -c "from lightsim2grid import LightSimBackend" &&
-            python -c "from lightsim2grid import LightSimBackend; import grid2op; env = grid2op.make('l2rpn_case14_sandbox', test=True, backend=LightSimBackend())"
-
+            python -c "from lightsim2grid.newtonpf import newtonpf" &&
+            python -c "from lightsim2grid.timeSerie import TimeSeriesCPP" &&
+            python -c "from lightsim2grid.contingencyAnalysis import ContingencyAnalysisCPP" &&
+            python -c "from lightsim2grid.securityAnalysis import SecurityAnalysisCPP" &&
+            python -c "from lightsim2grid.gridmodel import init, GridModel"
       - name: Upload wheel
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v3
         with:
-          name: wheels-darwin-${{ matrix.python.name }}
+          name: lightsim2grid-wheel-${{ matrix.runner.whl_nm}}-${{ matrix.python.name }}
           path: ./wheelhouse/*.whl
 
   package:
     name: Package wheels
     runs-on: ubuntu-latest
-    needs: [manylinux_build, windows_build, macos_build_37, macos_build_38_]
+    # needs: [manylinux_build, windows_build, macos_build_37_]
+    needs: [exotic_build, macos_build_37_, windows_build, manylinux_build]
 
     steps:
       - name: Download wheels
@@ -373,7 +522,7 @@ jobs:
           path: download
 
       - name: Upload wheels
-        uses: actions/upload-artifact@v4
+        uses: actions/upload-artifact@v3
         with:
           name: lightsim2grid-wheels
           path: |
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index ca87f38..41b3179 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -18,6 +18,23 @@ Change Log
 - maybe have a look at suitesparse "sliplu" tools ?
 - easier building (get rid of the "make" part)
 
+[0.8.2] 2024-04-22
+--------------------
+- [FIXED] CI was broken after migration to artifact v4, set it back to v3 
+  (and make the names of the folder clearer)
+- [FIXED] CI when using latest pandapower version (2.14) which broke some previous tests
+- [ADDED] the computation of the LODF (line outage distribution factor) in 
+  lightsim2grid
+- [ADDED] some convenience functions to retrieve in a vectorized way the 
+  buses to which each elements of a given container is connected 
+  (*eg* `gridmodel.get_lines().get_bus_from()`)
+- [ADDED] more binaries (windows `arm64` and macos `arm64`)
+- [IMPROVED] remove some compilation warnings for clang
+- [IMPROVED] possibility to specify generator used as slack by its name when initializing
+  from `pypowsybl`.
+- [IMPROVED] removing some warnings when grid2op is not installed
+  (it should not raise any warning as lightsim2grid does not require grid2op)
+
 [0.8.1] 2024-03-26
 --------------------
 - [FIXED] a bug with shunts when `nb_busbar_per_sub` >= 2
diff --git a/README.md b/README.md
index c989f34..ce8f150 100644
--- a/README.md
+++ b/README.md
@@ -74,12 +74,13 @@ Since version 0.5.3, lightsim2grid is can be installed like most python packages
 `python -m pip install lightsim2grid`
 
 It includes faster grid2op backend and the `SuiteSparse` faster `KLU` solver, even on windows. This is definitely the 
-easiest method to install lightsim2grid on your system and have it running without too much issues.
+easiest method to install lightsim2grid on your system and have it running.
 
 Note though that these packages have been compiled on a different platform that the one you are using. You might still
-get some benefit (in terms of performances) to install it from your on your machine.
+get some benefit (in terms of performances) to install it from your on your machine with the proper compilations flags (
+see section [6.1 Customization of the compilation](#Customization-of-the-compilation) for more information)
 
-Pypi packages are available for linux, windows and macos with python versions: 
+Pypi packages are available for linux (`x86_64` cpu architecture), windows (`x86_64` cpu architecture) and macos (`x86_64` cpu architecture) with python versions: 
 
 - 3.7
 - 3.8
@@ -88,8 +89,17 @@ Pypi packages are available for linux, windows and macos with python versions:
 - 3.11 (lightsim2grid >= 0.7.1)
 - 3.12 (lightsim2grid >= 0.7.5)
 
+
+As from version 0.8.2, we also distribute windows `arm64` and macos `arm64` binaries of lightsim2grid that can be installed
+directly with pip too (requires python >= 3.8 for macos and python >= 3.9 for windows). We do not currently produce `arm64` (`aarch64`) linux binaries because it takes too long to build. If you really want them, let us know and we'll see what we can do.
+
+
 **NB** on some version of MacOs (thanks Apple !), especially the one using M1 or M2 chip, lightsim2grid is only available
-on pypi starting from version 0.7.3
+on pypi starting from version 0.7.3 We attempted to deliver arm64 lightsim2grid version but we could not test them. So if you 
+want a reliable working and tested version of lightsim2grid on newest version of macos (with M1 or M2 chips for example) please
+use lightsim2grid >= 0.8.2
+
+**NB** we do not currently build any 32 bits lightsim2grid libraries.
 
 ## Installation (from source, for more advanced user)
 
@@ -222,7 +232,7 @@ For example: `export PATH_NICSLU=/home/user/Documents/cktso`
 
 #### Enable 03 optimization
 By default, at least on ubuntu, only the "-O2" compiler flags is used. To use the O3 optimization flag, you need
-to specify the `__O3_OPTIM` environment variable: `set __O3_OPTIM=1` before the compilation (so before
+to specify the `__O3_OPTIM` environment variable: `set __O3_OPTIM=1` (or `$Env:__O3_OPTIM=1` in powershell) before the compilation (so before
 `python3 setup.py build` or `python -m pip install -e .`)
 
 This compilation argument will increase the compilation time, but will make the package faster.
diff --git a/benchmarks/benchmark_py_g2op_version.py b/benchmarks/benchmark_py_g2op_version.py
new file mode 100644
index 0000000..bee9ada
--- /dev/null
+++ b/benchmarks/benchmark_py_g2op_version.py
@@ -0,0 +1,88 @@
+# Copyright (c) 2023, 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 subprocess
+import os
+import shutil
+from tqdm import tqdm
+
+numpy_ver = '1.24.4'  # latest on sept. 8th 2023 for all tested python
+pds_ver = '2.0.3'  # latest on sept. 8th 2023 for all tested python
+pyarrow_ver = '13.0.0'  # latest on sept. 8th 2023 for all tested python
+pp_ver = '2.13.1'  # latest on sept. 8th 2023 for all tested python
+
+py_ver = "3.9"
+g2op_ver = "1.7.0"
+for py_ver in tqdm([# "3.8", 
+                    "3.10", "3.11"]):
+  for g2op_ver in tqdm([
+                        "1.7.0", "1.7.1", "1.7.2", 
+                        "1.8.0", "1.8.1",
+                        "1.9.0", 
+                        "1.9.1", 
+                        "1.9.2", "1.9.3", "1.9.4"],
+                       leave=False):
+      # create the venv
+      venv_nm = f"venv_py{py_ver}_g2op{g2op_ver}"
+      subprocess.run([f"python{py_ver}", "-m", "venv", venv_nm])
+      py_exec = f"{venv_nm}/bin/python"
+
+      my_env = {}
+      my_env["VIRTUAL_ENV"] = f"{os.path.abspath('.')}/venv_nm"
+      my_env["PATH"] = f"{my_env['VIRTUAL_ENV']}/bin:{os.environ['PATH']}"
+      my_env["PATH_NICSLU"] = "/home/benjamin/Documents/powerflow_klu/nicslu/nicslu202110"
+      my_env["PATH_CKTSO"] = "/home/benjamin/Documents/powerflow_klu/cktso"
+      my_env["__COMPILE_MARCHNATIVE"] = "1"
+      my_env["__O3_OPTIM"] = "1"
+
+      # install everything in the venv
+      res = subprocess.run([py_exec, "-m", "pip", "install", "--upgrade", 
+                            f"grid2op=={g2op_ver}",
+                            f"numpy=={numpy_ver}",
+                            f"pandas=={pds_ver}",
+                            f"pyarrow=={pyarrow_ver}",
+                            f"pandapower=={pp_ver}",
+                            "pybind11",
+                            "tabulate",
+                            "py-cpuinfo",
+                            "distro"
+                            ],
+                            capture_output=True,
+                            env=my_env)
+
+      # fix the "dtype" in grid2op issue
+      shutil.copyfile("../../grid2op/grid2op/dtypes.py",
+                      f"{venv_nm}/lib/python{py_ver}/site-packages/grid2op/dtypes.py")
+
+      # prepare compilation of lightsim2grid
+      res = subprocess.run([py_exec, "-m", "pip", "install", ".."],
+                            env=my_env,
+                            capture_output=True)
+      res = subprocess.run([py_exec, "-c", "import lightsim2grid; print(lightsim2grid.__version__)"],
+                            env=my_env,
+                            capture_output=True)
+      ls_ver = res.stdout.decode("utf-8")
+
+      # run the benchmarks
+      res = subprocess.run([py_exec, "benchmark_solvers.py",
+                            "--name", "l2rpn_case14_sandbox", 
+                            "--no_test",
+                            "--number", "1000",
+                            "--save_results", f"py{py_ver}_gop{g2op_ver}_ls{ls_ver}_case14.md"],
+                            capture_output=True,
+                            env=my_env)
+      res = subprocess.run([py_exec, "benchmark_solvers.py",
+                            "--name", "l2rpn_neurips_2020_track2_small",                             
+                            "--no_test",
+                            "--number", "1000",
+                            "--save_results", f"py{py_ver}_gop{g2op_ver}_ls{ls_ver}_case118.md"],
+                            capture_output=True,
+                            env=my_env)
+
+      # remove the venv
+      shutil.rmtree(venv_nm)
diff --git a/benchmarks/benchmark_solvers.py b/benchmarks/benchmark_solvers.py
index 55dfa24..329027c 100644
--- a/benchmarks/benchmark_solvers.py
+++ b/benchmarks/benchmark_solvers.py
@@ -35,7 +35,7 @@
 
 MAX_TS = 1000
 ENV_NAME = "rte_case14_realistic"
-
+DONT_SAVE = "__DONT_SAVE"
 NICSLU_LICENSE_AVAIL = os.path.exists("./nicslu.lic") and os.path.isfile("./nicslu.lic")
 
 solver_names = {lightsim2grid.SolverType.GaussSeidel: "GS",
@@ -95,7 +95,8 @@ def main(max_ts,
          test=True,
          no_gs=False,
          no_gs_synch=False,
-         no_pp=False):
+         no_pp=False,
+         save_results=DONT_SAVE):
     param = Parameters()
     param.init_from_dict({"NO_OVERFLOW_DISCONNECTION": True})
 
@@ -183,6 +184,9 @@ def main(max_ts,
     if TABULATE_AVAIL:
         res_use_with_grid2op_1 = tabulate(tab, headers=hds,  tablefmt="rst")
         print(res_use_with_grid2op_1)
+        if save_results != DONT_SAVE:
+            with open(save_results, "w", encoding="utf-8") as f:
+                f.write(res_use_with_grid2op_1)
     else:
         print(tab)
     print()
@@ -237,6 +241,8 @@ def main(max_ts,
     parser.add_argument('--no_pp', type=str2bool, nargs='?',
                         const=True, default=False,
                         help='Do not benchmark pandapower method (default: evaluate it)')
+    parser.add_argument("--save_results", default=DONT_SAVE, type=str,
+                        help='Name of the file in which you want to save the result table')
     args = parser.parse_args()
 
     max_ts = int(args.number)
@@ -247,4 +253,5 @@ def main(max_ts,
          test_env,
          no_gs=args.no_gs,
          no_gs_synch=args.no_gs_synch,
-         no_pp=args.no_pp)
+         no_pp=args.no_pp,
+         save_results=args.save_results)
diff --git a/docs/benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.0.rst b/docs/benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.1.rst
similarity index 99%
rename from docs/benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.0.rst
rename to docs/benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.1.rst
index 2f17aa4..534484a 100644
--- a/docs/benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.0.rst
+++ b/docs/benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.1.rst
@@ -1,4 +1,4 @@
-Lightsim2grid 0.8.0 and grid2op 1.10.0
+Lightsim2grid 0.8.1 and grid2op 1.10.1
 ======================================
 
 l2rpn_case14_sandbox
diff --git a/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1.rst b/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1.rst
new file mode 100644
index 0000000..9b6ed6d
--- /dev/null
+++ b/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1.rst
@@ -0,0 +1,153 @@
+Lightsim2grid 0.8.1 and grid2op 1.10.1
+======================================
+
+l2rpn_case14_sandbox
+---------------------
+
+Configuration:
+
+- date: 2024-03-26 10:52  CET
+- system: Linux 5.4.0-153-generic
+- OS: ubuntu 20.04
+- processor: Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
+- python version: 3.10.13.final.0 (64 bit)
+- numpy version: 1.23.5
+- pandas version: 2.2.1
+- pandapower version: 2.13.1
+- grid2op version: 1.10.1
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information: 
+
+	- klu_solver_available: True 
+	- nicslu_solver_available: True 
+	- cktso_solver_available: True 
+	- compiled_march_native: True 
+	- compiled_o3_optim: True 
+
+====================  ======================  ===================================  ============================
+case14_sandbox          grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+====================  ======================  ===================================  ============================
+PP                                      41.9                               20.5                          7.14
+GS                                     678                                  0.507                        0.395
+GS synch                               677                                  0.506                        0.393
+NR single (SLU)                        858                                  0.198                        0.0823
+NR (SLU)                               832                                  0.208                        0.0856
+NR single (KLU)                        910                                  0.136                        0.0232
+NR (KLU)                               909                                  0.134                        0.0213
+NR single (NICSLU *)                   898                                  0.138                        0.023
+NR (NICSLU *)                          898                                  0.135                        0.0212
+NR single (CKTSO *)                    895                                  0.137                        0.0221
+NR (CKTSO *)                           903                                  0.134                        0.0198
+FDPF XB (SLU)                          894                                  0.148                        0.0351
+FDPF BX (SLU)                          890                                  0.16                         0.0489
+FDPF XB (KLU)                          885                                  0.143                        0.0294
+FDPF BX (KLU)                          891                                  0.151                        0.0412
+FDPF XB (NICSLU *)                     891                                  0.143                        0.0299
+FDPF BX (NICSLU *)                     881                                  0.156                        0.0425
+FDPF XB (CKTSO *)                      890                                  0.142                        0.0295
+FDPF BX (CKTSO *)                      892                                  0.152                        0.0414
+====================  ======================  ===================================  ============================
+
+
+Differences:
+
+============================  ==============  ==============  ================
+case14_sandbox (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+============================  ==============  ==============  ================
+PP (ref)                            0               0                 0
+GS                                  0.000122        7.63e-06          7.63e-06
+GS synch                            0.000122        7.63e-06          7.63e-06
+NR single (SLU)                     0.000122        7.63e-06          7.63e-06
+NR (SLU)                            0.000122        7.63e-06          7.63e-06
+NR single (KLU)                     0.000122        7.63e-06          7.63e-06
+NR (KLU)                            0.000122        7.63e-06          7.63e-06
+NR single (NICSLU *)                0.000122        7.63e-06          7.63e-06
+NR (NICSLU *)                       0.000122        7.63e-06          7.63e-06
+NR single (CKTSO *)                 0.000122        7.63e-06          7.63e-06
+NR (CKTSO *)                        0.000122        7.63e-06          7.63e-06
+FDPF XB (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (NICSLU *)                  0.000122        7.63e-06          7.63e-06
+FDPF BX (NICSLU *)                  0.000122        7.63e-06          7.63e-06
+FDPF XB (CKTSO *)                   0.000122        7.63e-06          7.63e-06
+FDPF BX (CKTSO *)                   0.000122        7.63e-06          7.63e-06
+============================  ==============  ==============  ================
+
+
+
+l2rpn_neurips_2020_track2_small
+---------------------------------
+
+Configuration:
+
+- date: 2024-03-26 10:59  CET
+- system: Linux 5.4.0-153-generic
+- OS: ubuntu 20.04
+- processor: Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
+- python version: 3.10.13.final.0 (64 bit)
+- numpy version: 1.23.5
+- pandas version: 2.2.1
+- pandapower version: 2.13.1
+- grid2op version: 1.10.1
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information: 
+
+	- klu_solver_available: True 
+	- nicslu_solver_available: True 
+	- cktso_solver_available: True 
+	- compiled_march_native: True 
+	- compiled_o3_optim: True 
+
+=====================  ======================  ===================================  ============================
+neurips_2020_track2      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+=====================  ======================  ===================================  ============================
+PP                                      38.3                                22.5                           9.18
+GS                                       3.81                              261                           261
+GS synch                                29.2                                33.2                          33
+NR single (SLU)                        494                                   0.912                         0.76
+NR (SLU)                               484                                   0.935                         0.777
+NR single (KLU)                        709                                   0.302                         0.155
+NR (KLU)                               714                                   0.29                          0.143
+NR single (NICSLU *)                   706                                   0.295                         0.146
+NR (NICSLU *)                          717                                   0.28                          0.132
+NR single (CKTSO *)                    712                                   0.286                         0.138
+NR (CKTSO *)                           722                                   0.272                         0.126
+FDPF XB (SLU)                          658                                   0.414                         0.271
+FDPF BX (SLU)                          645                                   0.436                         0.292
+FDPF XB (KLU)                          680                                   0.366                         0.225
+FDPF BX (KLU)                          667                                   0.388                         0.244
+FDPF XB (NICSLU *)                     674                                   0.364                         0.22
+FDPF BX (NICSLU *)                     665                                   0.384                         0.239
+FDPF XB (CKTSO *)                      677                                   0.362                         0.22
+FDPF BX (CKTSO *)                      665                                   0.383                         0.24
+=====================  ======================  ===================================  ============================
+
+
+Differences:
+
+=================================  ==============  ==============  ================
+neurips_2020_track2 (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+=================================  ==============  ==============  ================
+PP (ref)                                  0              0                 0
+GS                                        6.1e-05        3.81e-06          1.53e-05
+GS synch                                  6.1e-05        3.81e-06          1.53e-05
+NR single (SLU)                           6.1e-05        0                 9.54e-07
+NR (SLU)                                  6.1e-05        0                 9.54e-07
+NR single (KLU)                           6.1e-05        0                 9.54e-07
+NR (KLU)                                  6.1e-05        0                 9.54e-07
+NR single (NICSLU *)                      6.1e-05        0                 9.54e-07
+NR (NICSLU *)                             6.1e-05        0                 9.54e-07
+NR single (CKTSO *)                       6.1e-05        0                 9.54e-07
+NR (CKTSO *)                              6.1e-05        0                 9.54e-07
+FDPF XB (SLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (SLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (KLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (KLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (NICSLU *)                        6.1e-05        1.91e-06          1.53e-05
+FDPF BX (NICSLU *)                        6.1e-05        1.91e-06          7.63e-06
+FDPF XB (CKTSO *)                         6.1e-05        1.91e-06          1.53e-05
+FDPF BX (CKTSO *)                         6.1e-05        1.91e-06          7.63e-06
+=================================  ==============  ==============  ================
+
diff --git a/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py311.rst b/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py311.rst
new file mode 100644
index 0000000..c2cee52
--- /dev/null
+++ b/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py311.rst
@@ -0,0 +1,150 @@
+Lightsim2grid 0.8.1 and grid2op 1.10.1 (python 3.11)
+====================================================
+
+l2rpn_case14_sandbox
+---------------------
+
+Configuration:
+
+- date: 2024-03-26 11:42  CET
+- system: Linux 5.4.0-153-generic
+- OS: ubuntu 20.04
+- processor: Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
+- python version: 3.11.8.final.0 (64 bit)
+- numpy version: 1.26.4
+- pandas version: 2.2.1
+- pandapower version: 2.13.1
+- grid2op version: 1.10.1
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information: 
+
+	- klu_solver_available: True 
+	- nicslu_solver_available: True 
+	- cktso_solver_available: True 
+	- compiled_march_native: True 
+	- compiled_o3_optim: True 
+
+====================  ======================  ===================================  ============================
+case14_sandbox          grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+====================  ======================  ===================================  ============================
+PP                                      32.9                               27.4                         15.8
+GS                                     729                                  0.499                        0.396
+GS synch                               728                                  0.507                        0.404
+NR single (SLU)                        912                                  0.196                        0.0844
+NR (SLU)                               935                                  0.193                        0.0846
+NR single (KLU)                       1000                                  0.128                        0.0232
+NR (KLU)                               989                                  0.128                        0.0218
+NR single (NICSLU *)                   996                                  0.128                        0.0232
+NR (NICSLU *)                         1000                                  0.126                        0.0212
+NR single (CKTSO *)                   1010                                  0.126                        0.0217
+NR (CKTSO *)                          1010                                  0.124                        0.0199
+FDPF XB (SLU)                          992                                  0.138                        0.0347
+FDPF BX (SLU)                          974                                  0.153                        0.0492
+FDPF XB (KLU)                          996                                  0.132                        0.0286
+FDPF BX (KLU)                          988                                  0.144                        0.0414
+FDPF XB (NICSLU *)                     978                                  0.135                        0.0301
+FDPF BX (NICSLU *)                     973                                  0.146                        0.0426
+FDPF XB (CKTSO *)                      994                                  0.132                        0.0291
+FDPF BX (CKTSO *)                      989                                  0.144                        0.0412
+====================  ======================  ===================================  ============================
+
+Differences:
+
+============================  ==============  ==============  ================
+case14_sandbox (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+============================  ==============  ==============  ================
+PP (ref)                            0               0                 0
+GS                                  0.000122        7.63e-06          7.63e-06
+GS synch                            0.000122        7.63e-06          7.63e-06
+NR single (SLU)                     0.000122        7.63e-06          7.63e-06
+NR (SLU)                            0.000122        7.63e-06          7.63e-06
+NR single (KLU)                     0.000122        7.63e-06          7.63e-06
+NR (KLU)                            0.000122        7.63e-06          7.63e-06
+NR single (NICSLU *)                0.000122        7.63e-06          7.63e-06
+NR (NICSLU *)                       0.000122        7.63e-06          7.63e-06
+NR single (CKTSO *)                 0.000122        7.63e-06          7.63e-06
+NR (CKTSO *)                        0.000122        7.63e-06          7.63e-06
+FDPF XB (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (NICSLU *)                  0.000122        7.63e-06          7.63e-06
+FDPF BX (NICSLU *)                  0.000122        7.63e-06          7.63e-06
+FDPF XB (CKTSO *)                   0.000122        7.63e-06          7.63e-06
+FDPF BX (CKTSO *)                   0.000122        7.63e-06          7.63e-06
+============================  ==============  ==============  ================
+
+l2rpn_neurips_2020_track2_small
+---------------------------------
+
+Configuration:
+
+- date: 2024-03-26 11:49  CET
+- system: Linux 5.4.0-153-generic
+- OS: ubuntu 20.04
+- processor: Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
+- python version: 3.11.8.final.0 (64 bit)
+- numpy version: 1.26.4
+- pandas version: 2.2.1
+- pandapower version: 2.13.1
+- grid2op version: 1.10.1
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information: 
+
+	- klu_solver_available: True 
+	- nicslu_solver_available: True 
+	- cktso_solver_available: True 
+	- compiled_march_native: True 
+	- compiled_o3_optim: True 
+
+=====================  ======================  ===================================  ============================
+neurips_2020_track2      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+=====================  ======================  ===================================  ============================
+PP                                      29.1                                31.2                          19.3
+GS                                       4.12                              241                           241
+GS synch                                29.6                                32.7                          32.6
+NR single (SLU)                        531                                   0.888                         0.749
+NR (SLU)                               513                                   0.929                         0.784
+NR single (KLU)                        785                                   0.284                         0.148
+NR (KLU)                               793                                   0.268                         0.133
+NR single (NICSLU *)                   784                                   0.274                         0.137
+NR (NICSLU *)                          795                                   0.262                         0.125
+NR single (CKTSO *)                    784                                   0.27                          0.132
+NR (CKTSO *)                           812                                   0.25                          0.116
+FDPF XB (SLU)                          728                                   0.386                         0.256
+FDPF BX (SLU)                          714                                   0.409                         0.279
+FDPF XB (KLU)                          750                                   0.345                         0.215
+FDPF BX (KLU)                          737                                   0.367                         0.236
+FDPF XB (NICSLU *)                     724                                   0.354                         0.219
+FDPF BX (NICSLU *)                     740                                   0.361                         0.231
+FDPF XB (CKTSO *)                      756                                   0.339                         0.209
+FDPF BX (CKTSO *)                      744                                   0.359                         0.229
+=====================  ======================  ===================================  ============================
+
+
+
+Differences:
+
+=================================  ==============  ==============  ================
+neurips_2020_track2 (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+=================================  ==============  ==============  ================
+PP (ref)                                  0              0                 0
+GS                                        6.1e-05        3.81e-06          1.53e-05
+GS synch                                  6.1e-05        3.81e-06          1.53e-05
+NR single (SLU)                           6.1e-05        0                 9.54e-07
+NR (SLU)                                  6.1e-05        0                 9.54e-07
+NR single (KLU)                           6.1e-05        0                 9.54e-07
+NR (KLU)                                  6.1e-05        0                 9.54e-07
+NR single (NICSLU *)                      6.1e-05        0                 9.54e-07
+NR (NICSLU *)                             6.1e-05        0                 9.54e-07
+NR single (CKTSO *)                       6.1e-05        0                 9.54e-07
+NR (CKTSO *)                              6.1e-05        0                 9.54e-07
+FDPF XB (SLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (SLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (KLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (KLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (NICSLU *)                        6.1e-05        1.91e-06          1.53e-05
+FDPF BX (NICSLU *)                        6.1e-05        1.91e-06          7.63e-06
+FDPF XB (CKTSO *)                         6.1e-05        1.91e-06          1.53e-05
+FDPF BX (CKTSO *)                         6.1e-05        1.91e-06          7.63e-06
+=================================  ==============  ==============  ================
diff --git a/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py312.rst b/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py312.rst
new file mode 100644
index 0000000..0753bdd
--- /dev/null
+++ b/docs/benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py312.rst
@@ -0,0 +1,150 @@
+Lightsim2grid 0.8.1 and grid2op 1.10.1 (python 3.12)
+====================================================
+
+l2rpn_case14_sandbox
+---------------------
+
+Configuration:
+
+- date: 2024-03-26 13:42  CET
+- system: Linux 5.4.0-153-generic
+- OS: ubuntu 20.04
+- processor: Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
+- python version: 3.12.2.final.0 (64 bit)
+- numpy version: 1.26.4
+- pandas version: 2.2.1
+- pandapower version: 2.13.1
+- grid2op version: 1.10.1
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information: 
+
+	- klu_solver_available: True 
+	- nicslu_solver_available: True 
+	- cktso_solver_available: True 
+	- compiled_march_native: True 
+	- compiled_o3_optim: True 
+
+====================  ======================  ===================================  ============================
+case14_sandbox          grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+====================  ======================  ===================================  ============================
+PP                                      31.3                               28.9                         16.8
+GS                                     716                                  0.502                        0.393
+GS synch                               696                                  0.522                        0.41
+NR single (SLU)                        912                                  0.196                        0.0829
+NR (SLU)                               911                                  0.197                        0.084
+NR single (KLU)                        971                                  0.133                        0.023
+NR (KLU)                               973                                  0.132                        0.0213
+NR single (NICSLU *)                   955                                  0.136                        0.023
+NR (NICSLU *)                          952                                  0.135                        0.0213
+NR single (CKTSO *)                    970                                  0.132                        0.0216
+NR (CKTSO *)                           975                                  0.13                         0.0199
+FDPF XB (SLU)                          961                                  0.145                        0.0355
+FDPF BX (SLU)                          949                                  0.158                        0.0491
+FDPF XB (KLU)                          968                                  0.137                        0.0285
+FDPF BX (KLU)                          957                                  0.15                         0.0412
+FDPF XB (NICSLU *)                     963                                  0.139                        0.0295
+FDPF BX (NICSLU *)                     943                                  0.154                        0.0429
+FDPF XB (CKTSO *)                      971                                  0.138                        0.0291
+FDPF BX (CKTSO *)                      956                                  0.151                        0.0416
+====================  ======================  ===================================  ============================
+
+
+Differences:
+
+============================  ==============  ==============  ================
+case14_sandbox (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+============================  ==============  ==============  ================
+PP (ref)                            0               0                 0
+GS                                  0.000122        7.63e-06          7.63e-06
+GS synch                            0.000122        7.63e-06          7.63e-06
+NR single (SLU)                     0.000122        7.63e-06          7.63e-06
+NR (SLU)                            0.000122        7.63e-06          7.63e-06
+NR single (KLU)                     0.000122        7.63e-06          7.63e-06
+NR (KLU)                            0.000122        7.63e-06          7.63e-06
+NR single (NICSLU *)                0.000122        7.63e-06          7.63e-06
+NR (NICSLU *)                       0.000122        7.63e-06          7.63e-06
+NR single (CKTSO *)                 0.000122        7.63e-06          7.63e-06
+NR (CKTSO *)                        0.000122        7.63e-06          7.63e-06
+FDPF XB (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (NICSLU *)                  0.000122        7.63e-06          7.63e-06
+FDPF BX (NICSLU *)                  0.000122        7.63e-06          7.63e-06
+FDPF XB (CKTSO *)                   0.000122        7.63e-06          7.63e-06
+FDPF BX (CKTSO *)                   0.000122        7.63e-06          7.63e-06
+============================  ==============  ==============  ================
+
+l2rpn_neurips_2020_track2_small
+---------------------------------
+
+Configuration:
+
+- date: 2024-03-26 13:51  CET
+- system: Linux 5.4.0-153-generic
+- OS: ubuntu 20.04
+- processor: Intel(R) Core(TM) i7-5960X CPU @ 3.00GHz
+- python version: 3.12.2.final.0 (64 bit)
+- numpy version: 1.26.4
+- pandas version: 2.2.1
+- pandapower version: 2.13.1
+- grid2op version: 1.10.1
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information: 
+
+	- klu_solver_available: True 
+	- nicslu_solver_available: True 
+	- cktso_solver_available: True 
+	- compiled_march_native: True 
+	- compiled_o3_optim: True 
+
+=====================  ======================  ===================================  ============================
+neurips_2020_track2      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+=====================  ======================  ===================================  ============================
+PP                                      28.1                                32.3                          20.4
+GS                                       4.05                              245                           245
+GS synch                                29.4                                33                            32.9
+NR single (SLU)                        519                                   0.9                           0.754
+NR (SLU)                               518                                   0.917                         0.771
+NR single (KLU)                        763                                   0.293                         0.151
+NR (KLU)                               770                                   0.28                          0.139
+NR single (NICSLU *)                   777                                   0.279                         0.139
+NR (NICSLU *)                          774                                   0.27                          0.127
+NR single (CKTSO *)                    792                                   0.27                          0.13
+NR (CKTSO *)                           786                                   0.26                          0.119
+FDPF XB (SLU)                          700                                   0.406                         0.268
+FDPF BX (SLU)                          688                                   0.431                         0.294
+FDPF XB (KLU)                          725                                   0.36                          0.223
+FDPF BX (KLU)                          719                                   0.376                         0.24
+FDPF XB (NICSLU *)                     730                                   0.351                         0.215
+FDPF BX (NICSLU *)                     732                                   0.365                         0.229
+FDPF XB (CKTSO *)                      748                                   0.343                         0.209
+FDPF BX (CKTSO *)                      729                                   0.367                         0.232
+=====================  ======================  ===================================  ============================
+
+Differences:
+
+=================================  ==============  ==============  ================
+neurips_2020_track2 (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+=================================  ==============  ==============  ================
+PP (ref)                                  0              0                 0
+GS                                        6.1e-05        3.81e-06          1.53e-05
+GS synch                                  6.1e-05        3.81e-06          1.53e-05
+NR single (SLU)                           6.1e-05        0                 9.54e-07
+NR (SLU)                                  6.1e-05        0                 9.54e-07
+NR single (KLU)                           6.1e-05        0                 9.54e-07
+NR (KLU)                                  6.1e-05        0                 9.54e-07
+NR single (NICSLU *)                      6.1e-05        0                 9.54e-07
+NR (NICSLU *)                             6.1e-05        0                 9.54e-07
+NR single (CKTSO *)                       6.1e-05        0                 9.54e-07
+NR (CKTSO *)                              6.1e-05        0                 9.54e-07
+FDPF XB (SLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (SLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (KLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (KLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (NICSLU *)                        6.1e-05        1.91e-06          1.53e-05
+FDPF BX (NICSLU *)                        6.1e-05        1.91e-06          7.63e-06
+FDPF XB (CKTSO *)                         6.1e-05        1.91e-06          1.53e-05
+FDPF BX (CKTSO *)                         6.1e-05        1.91e-06          7.63e-06
+=================================  ==============  ==============  ================
+
diff --git a/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.5_py38.rst b/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.5_py38.rst
new file mode 100644
index 0000000..d9ae890
--- /dev/null
+++ b/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.5_py38.rst
@@ -0,0 +1,118 @@
+Lightsim2grid 0.8.1 and grid2op 1.9.5 (python 3.8)
+====================================================
+
+l2rpn_case14_sandbox
+---------------------
+
+Configuration:
+
+- date: 2024-03-27 22:19  Paris, Madrid
+- system: Windows 10
+- OS:
+- processor: AMD Ryzen 7 4800HS with Radeon Graphics
+- python version: 3.8.3.final.0 (64 bit)
+- numpy version: 1.21.0
+- pandas version: 2.0.3
+- pandapower version: 2.13.1
+- grid2op version: 1.9.5
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information:
+
+        - klu_solver_available: True
+        - nicslu_solver_available: False
+        - cktso_solver_available: False
+        - compiled_march_native: True
+        - compiled_o3_optim: True
+
+**NB** Due to issue with dll, cktso and nicslu could not be benchmarked
+
+================  ======================  ===================================  ============================
+case14_sandbox      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+================  ======================  ===================================  ============================
+PP                                  48.1                               14.9                          5.16
+GS                                 728                                  0.6                          0.501
+GS synch                           663                                  0.729                        0.63
+NR single (SLU)                   1070                                  0.167                        0.0673
+NR (SLU)                          1050                                  0.172                        0.0714
+NR single (KLU)                   1120                                  0.119                        0.0212
+NR (KLU)                          1120                                  0.122                        0.0237
+FDPF XB (SLU)                     1100                                  0.136                        0.0393
+FDPF BX (SLU)                     1070                                  0.156                        0.0572
+FDPF XB (KLU)                     1110                                  0.128                        0.0293
+FDPF BX (KLU)                     1090                                  0.14                         0.0424
+================  ======================  ===================================  ============================
+
+Differences:
+
+============================  ==============  ==============  ================
+case14_sandbox (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+============================  ==============  ==============  ================
+PP (ref)                            0               0                 0
+GS                                  0.000122        7.63e-06          7.63e-06
+GS synch                            0.000122        7.63e-06          7.63e-06
+NR single (SLU)                     0.000122        7.63e-06          7.63e-06
+NR (SLU)                            0.000122        7.63e-06          7.63e-06
+NR single (KLU)                     0.000122        7.63e-06          7.63e-06
+NR (KLU)                            0.000122        7.63e-06          7.63e-06
+FDPF XB (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (KLU)                       0.000122        7.63e-06          7.63e-06
+============================  ==============  ==============  ================
+
+l2rpn_neurips_2020_track2_small
+---------------------------------
+
+Configuration:
+
+- date: 2024-03-27 22:28  Paris, Madrid
+- system: Windows 10
+- OS:
+- processor: AMD Ryzen 7 4800HS with Radeon Graphics
+- python version: 3.8.3.final.0 (64 bit)
+- numpy version: 1.21.0
+- pandas version: 2.0.3
+- pandapower version: 2.13.1
+- grid2op version: 1.9.5
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information:
+
+        - klu_solver_available: True
+        - nicslu_solver_available: False
+        - cktso_solver_available: False
+        - compiled_march_native: True
+        - compiled_o3_optim: True
+
+=====================  ======================  ===================================  ============================
+neurips_2020_track2      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+=====================  ======================  ===================================  ============================
+PP                                      21.2                                17                             6.61
+GS                                       6.28                              158                           158
+GS synch                                26.8                                36.1                          35.9
+NR single (SLU)                        616                                   0.716                         0.583
+NR (SLU)                               564                                   0.789                         0.637
+NR single (KLU)                        921                                   0.228                         0.105
+NR (KLU)                               901                                   0.245                         0.122
+FDPF XB (SLU)                          795                                   0.389                         0.268
+FDPF BX (SLU)                          783                                   0.414                         0.293
+FDPF XB (KLU)                          848                                   0.323                         0.203
+FDPF BX (KLU)                          838                                   0.34                          0.222
+=====================  ======================  ===================================  ============================
+
+Differences:
+
+=================================  ==============  ==============  ================
+neurips_2020_track2 (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+=================================  ==============  ==============  ================
+PP (ref)                                  0              0                 0
+GS                                        6.1e-05        3.81e-06          1.53e-05
+GS synch                                  6.1e-05        3.81e-06          1.53e-05
+NR single (SLU)                           6.1e-05        0                 9.54e-07
+NR (SLU)                                  6.1e-05        0                 9.54e-07
+NR single (KLU)                           6.1e-05        0                 9.54e-07
+NR (KLU)                                  6.1e-05        0                 9.54e-07
+FDPF XB (SLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (SLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (KLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (KLU)                             6.1e-05        1.91e-06          7.63e-06
+=================================  ==============  ==============  ================
\ No newline at end of file
diff --git a/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.6_py38.rst b/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.6_py38.rst
new file mode 100644
index 0000000..61eaa2d
--- /dev/null
+++ b/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.6_py38.rst
@@ -0,0 +1,116 @@
+Lightsim2grid 0.8.1 and grid2op 1.9.6 (python 3.8)
+====================================================
+
+l2rpn_case14_sandbox
+---------------------
+
+Configuration:
+
+- date: 2024-03-28 07:21  Paris, Madrid
+- system: Windows 10
+- OS:
+- processor: AMD Ryzen 7 4800HS with Radeon Graphics
+- python version: 3.8.3.final.0 (64 bit)
+- numpy version: 1.21.0
+- pandas version: 2.0.3
+- pandapower version: 2.13.1
+- grid2op version: 1.9.6
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information:
+
+        - klu_solver_available: True
+        - nicslu_solver_available: False
+        - cktso_solver_available: False
+        - compiled_march_native: True
+        - compiled_o3_optim: True
+
+================  ======================  ===================================  ============================
+case14_sandbox      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+================  ======================  ===================================  ============================
+PP                                    49                               14.6                          5.09
+GS                                   733                                0.593                        0.495
+GS synch                             653                                0.716                        0.611
+NR single (SLU)                     1060                                0.168                        0.0674
+NR (SLU)                            1050                                0.172                        0.0715
+NR single (KLU)                     1130                                0.118                        0.0205
+NR (KLU)                            1130                                0.12                         0.0233
+FDPF XB (SLU)                       1110                                0.136                        0.0393
+FDPF BX (SLU)                       1080                                0.155                        0.0573
+FDPF XB (KLU)                       1120                                0.126                        0.0288
+FDPF BX (KLU)                       1090                                0.14                         0.0418
+================  ======================  ===================================  ============================
+
+Differences:
+
+============================  ==============  ==============  ================
+case14_sandbox (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+============================  ==============  ==============  ================
+PP (ref)                            0               0                 0
+GS                                  0.000122        7.63e-06          7.63e-06
+GS synch                            0.000122        7.63e-06          7.63e-06
+NR single (SLU)                     0.000122        7.63e-06          7.63e-06
+NR (SLU)                            0.000122        7.63e-06          7.63e-06
+NR single (KLU)                     0.000122        7.63e-06          7.63e-06
+NR (KLU)                            0.000122        7.63e-06          7.63e-06
+FDPF XB (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (KLU)                       0.000122        7.63e-06          7.63e-06
+============================  ==============  ==============  ================
+
+l2rpn_neurips_2020_track2_small
+---------------------------------
+
+Configuration:
+
+- date: 2024-03-28 07:28  Paris, Madrid
+- system: Windows 10
+- OS:
+- processor: AMD Ryzen 7 4800HS with Radeon Graphics
+- python version: 3.8.3.final.0 (64 bit)
+- numpy version: 1.21.0
+- pandas version: 2.0.3
+- pandapower version: 2.13.1
+- grid2op version: 1.9.6
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information:
+
+        - klu_solver_available: True
+        - nicslu_solver_available: False
+        - cktso_solver_available: False
+        - compiled_march_native: True
+        - compiled_o3_optim: True
+
+=====================  ======================  ===================================  ============================
+neurips_2020_track2      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+=====================  ======================  ===================================  ============================
+PP                                      21.3                                16.9                           6.58
+GS                                       6.26                              158                           158
+GS synch                                26.7                                36.2                          36
+NR single (SLU)                        556                                   0.767                         0.609
+NR (SLU)                               592                                   0.769                         0.639
+NR single (KLU)                        803                                   0.256                         0.114
+NR (KLU)                               849                                   0.257                         0.128
+FDPF XB (SLU)                          717                                   0.416                         0.278
+FDPF BX (SLU)                          735                                   0.43                          0.301
+FDPF XB (KLU)                          708                                   0.367                         0.215
+FDPF BX (KLU)                          734                                   0.373                         0.234
+=====================  ======================  ===================================  ============================
+
+Differences:
+
+=================================  ==============  ==============  ================
+neurips_2020_track2 (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+=================================  ==============  ==============  ================
+PP (ref)                                  0              0                 0
+GS                                        6.1e-05        3.81e-06          1.53e-05
+GS synch                                  6.1e-05        3.81e-06          1.53e-05
+NR single (SLU)                           6.1e-05        0                 9.54e-07
+NR (SLU)                                  6.1e-05        0                 9.54e-07
+NR single (KLU)                           6.1e-05        0                 9.54e-07
+NR (KLU)                                  6.1e-05        0                 9.54e-07
+FDPF XB (SLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (SLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (KLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (KLU)                             6.1e-05        1.91e-06          7.63e-06
+=================================  ==============  ==============  ================
diff --git a/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.7_py38.rst b/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.7_py38.rst
new file mode 100644
index 0000000..dc96c75
--- /dev/null
+++ b/docs/benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.7_py38.rst
@@ -0,0 +1,112 @@
+Lightsim2grid 0.8.1 and grid2op 1.9.7 (python 3.8)
+====================================================
+
+l2rpn_case14_sandbox
+---------------------
+
+Configuration:
+
+- date: 2024-03-28 07:56  Paris, Madrid
+- system: Windows 10
+- OS:
+- processor: AMD Ryzen 7 4800HS with Radeon Graphics
+- python version: 3.8.3.final.0 (64 bit)
+- numpy version: 1.21.0
+- pandas version: 2.0.3
+- pandapower version: 2.13.1
+- grid2op version: 1.9.7
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information:
+
+        - klu_solver_available: True
+        - nicslu_solver_available: False
+        - cktso_solver_available: False
+        - compiled_march_native: True
+        - compiled_o3_optim: True
+
+================  ======================  ===================================  ============================
+case14_sandbox      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+================  ======================  ===================================  ============================
+PP                                  49.4                               14.5                          5.04
+GS                                 734                                  0.591                        0.492
+GS synch                           676                                  0.704                        0.605
+NR single (SLU)                   1060                                  0.166                        0.0663
+NR (SLU)                          1050                                  0.172                        0.0715
+NR single (KLU)                   1130                                  0.118                        0.0202
+NR (KLU)                          1120                                  0.122                        0.023
+FDPF XB (SLU)                     1090                                  0.138                        0.0388
+FDPF BX (SLU)                     1090                                  0.153                        0.0556
+FDPF XB (KLU)                     1120                                  0.126                        0.0283
+FDPF BX (KLU)                     1100                                  0.138                        0.0411
+================  ======================  ===================================  ============================
+
+============================  ==============  ==============  ================
+case14_sandbox (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+============================  ==============  ==============  ================
+PP (ref)                            0               0                 0
+GS                                  0.000122        7.63e-06          7.63e-06
+GS synch                            0.000122        7.63e-06          7.63e-06
+NR single (SLU)                     0.000122        7.63e-06          7.63e-06
+NR (SLU)                            0.000122        7.63e-06          7.63e-06
+NR single (KLU)                     0.000122        7.63e-06          7.63e-06
+NR (KLU)                            0.000122        7.63e-06          7.63e-06
+FDPF XB (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (SLU)                       0.000122        7.63e-06          7.63e-06
+FDPF XB (KLU)                       0.000122        7.63e-06          7.63e-06
+FDPF BX (KLU)                       0.000122        7.63e-06          7.63e-06
+============================  ==============  ==============  ================
+
+l2rpn_neurips_2020_track2_small
+---------------------------------
+
+Configuration:
+
+- date: 2024-03-28 08:15  Paris, Madrid
+- system: Windows 10
+- OS:
+- processor: AMD Ryzen 7 4800HS with Radeon Graphics
+- python version: 3.8.3.final.0 (64 bit)
+- numpy version: 1.21.0
+- pandas version: 2.0.3
+- pandapower version: 2.13.1
+- grid2op version: 1.9.7
+- lightsim2grid version: 0.8.1
+- lightsim2grid extra information:
+
+        - klu_solver_available: True
+        - nicslu_solver_available: False
+        - cktso_solver_available: False
+        - compiled_march_native: True
+        - compiled_o3_optim: True
+
+=====================  ======================  ===================================  ============================
+neurips_2020_track2      grid2op speed (it/s)    grid2op 'backend.runpf' time (ms)    solver powerflow time (ms)
+=====================  ======================  ===================================  ============================
+PP                                      21.4                                16.9                           6.57
+GS                                       6.31                              157                           157
+GS synch                                26.7                                36.3                          36.1
+NR single (SLU)                        607                                   0.729                         0.595
+NR (SLU)                               593                                   0.769                         0.635
+NR single (KLU)                        902                                   0.233                         0.107
+NR (KLU)                               885                                   0.25                          0.123
+FDPF XB (SLU)                          808                                   0.384                         0.267
+FDPF BX (SLU)                          770                                   0.419                         0.297
+FDPF XB (KLU)                          838                                   0.324                         0.205
+FDPF BX (KLU)                          805                                   0.348                         0.226
+=====================  ======================  ===================================  ============================
+
+=================================  ==============  ==============  ================
+neurips_2020_track2 (1000 iter)      Δ aor (amps)    Δ gen_p (MW)    Δ gen_q (MVAr)
+=================================  ==============  ==============  ================
+PP (ref)                                  0              0                 0
+GS                                        6.1e-05        3.81e-06          1.53e-05
+GS synch                                  6.1e-05        3.81e-06          1.53e-05
+NR single (SLU)                           6.1e-05        0                 9.54e-07
+NR (SLU)                                  6.1e-05        0                 9.54e-07
+NR single (KLU)                           6.1e-05        0                 9.54e-07
+NR (KLU)                                  6.1e-05        0                 9.54e-07
+FDPF XB (SLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (SLU)                             6.1e-05        1.91e-06          7.63e-06
+FDPF XB (KLU)                             6.1e-05        1.91e-06          1.53e-05
+FDPF BX (KLU)                             6.1e-05        1.91e-06          7.63e-06
+=================================  ==============  ==============  ================
\ No newline at end of file
diff --git a/docs/benchmarks.rst b/docs/benchmarks.rst
index f4f028d..f607b25 100644
--- a/docs/benchmarks.rst
+++ b/docs/benchmarks.rst
@@ -315,10 +315,33 @@ The results can be found in:
   :maxdepth: 1
   :caption: For a laptop with a i7 of 2015 wth a frequency of 2.70 GHz
 
-  benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.0
+  benchmark_solver/ubuntu_2004_dell/ls0.8.1_glop1.10.1
   benchmark_solver/ubuntu_2004_dell/ls0.8.0_glop1.10.0
   benchmark_solver/ubuntu_2004_dell/ls0.8.0_glop1.9.8
 
+.. toctree::
+  :maxdepth: 1
+  :caption: For a laptop with a i7 of 2014 wth a frequency of 3.0 GHz
+
+  benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1
+  benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py311
+  benchmark_solver/ubuntu_2004_server/ls0.8.1_glop1.10.1_py312
+
+.. note::
+  Any contribution here is more than welcomed. You can write a github discussion here 
+  https://github.com/BDonnot/lightsim2grid/discussions/new?category=show-and-tell 
+  and describe rapidly your setup and we'll make sure to include your benchmark in future release.
+
+  Thanks !
+
+.. toctree::
+  :maxdepth: 1
+  :caption: For a laptop with a ryzen 7 of 2020 wth a frequency of 4.2 GHz
+
+  benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.7_py38
+  benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.6_py38
+  benchmark_solver/windows_10_portable/ls0.8.1_glop1.9.5_py38
+
 Benchmarks of other lightsim2grid functions
 --------------------------------------------
 
diff --git a/docs/conf.py b/docs/conf.py
index 3e4db7b..efd79ca 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -22,7 +22,7 @@
 author = 'Benjamin DONNOT'
 
 # The full version, including alpha/beta/rc tags
-release = "0.8.1"
+release = "0.8.2"
 version = '0.8'
 
 # -- General configuration ---------------------------------------------------
diff --git a/lightsim2grid/__init__.py b/lightsim2grid/__init__.py
index 85ece59..bce4cab 100644
--- a/lightsim2grid/__init__.py
+++ b/lightsim2grid/__init__.py
@@ -5,7 +5,8 @@
 # you can obtain one at http://mozilla.org/MPL/2.0/.
 # SPDX-License-Identifier: MPL-2.0
 # This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.
-__version__ = "0.8.1"
+
+__version__ = "0.8.2"
 
 __all__ = ["newtonpf", "SolverType", "ErrorType", "solver", "compilation_options"]
 
@@ -19,7 +20,7 @@
 except ImportError as exc_:
     # grid2op is not installed, the Backend will not be available
     pass
-    print(f"LightSimBackend import error: {exc_}")
+    # print(f"LightSimBackend import error: {exc_}")
 
 try:
     from lightsim2grid.physical_law_checker import PhysicalLawChecker
@@ -27,7 +28,7 @@
 except ImportError as exc_:
     # grid2op is not installed, the PhysicalLawChecker will not be available
     pass
-    print(f"PhysicalLawChecker import error: {exc_}")
+    # print(f"PhysicalLawChecker import error: {exc_}")
 
 try:
     from lightsim2grid.timeSerie import TimeSerie
@@ -36,7 +37,7 @@
 except ImportError as exc_:
     # grid2op is not installed, the TimeSeries module will not be available
     pass
-    print(f"TimeSerie import error: {exc_}")
+    # print(f"TimeSerie import error: {exc_}")
 
 try:
     from lightsim2grid.contingencyAnalysis import ContingencyAnalysis
@@ -45,7 +46,7 @@
 except ImportError as exc_:
     # grid2op is not installed, the SecurtiyAnalysis module will not be available
     pass
-    print(f"ContingencyAnalysis import error: {exc_}")
+    # print(f"ContingencyAnalysis import error: {exc_}")
     
 try:
     from lightsim2grid.rewards import *
@@ -53,4 +54,4 @@
 except ImportError as exc_:
     # grid2op is not installed, the SecurtiyAnalysis module will not be available
     pass
-    print(f"rewards import error: {exc_}")
+    # print(f"rewards import error: {exc_}")
diff --git a/lightsim2grid/gridmodel/from_pypowsybl.py b/lightsim2grid/gridmodel/from_pypowsybl.py
index 798742c..7159d1a 100644
--- a/lightsim2grid/gridmodel/from_pypowsybl.py
+++ b/lightsim2grid/gridmodel/from_pypowsybl.py
@@ -10,6 +10,7 @@
 import numpy as np
 import pandas as pd
 import pypowsybl as pypo
+from typing import Union
 
 from lightsim2grid_cpp import GridModel
 
@@ -36,7 +37,7 @@ def _aux_get_bus(bus_df, df, conn_key="connected", bus_key="bus_id"):
 
 
 def init(net : pypo.network,
-         gen_slack_id: int = None,
+         gen_slack_id: Union[int, str] = None,
          slack_bus_id: int = None,
          sn_mva = 100.,
          sort_index=True,
@@ -260,7 +261,17 @@ def init(net : pypo.network,
     elif gen_slack_id is not None:
         if slack_bus_id is not None:
             raise RuntimeError(f"You provided both gen_slack_id and slack_bus_id which is not possible.")
-        model.add_gen_slackbus(gen_slack_id, 1.)
+        
+        if isinstance(gen_slack_id, str):
+            gen_slack_id_int = int((df_gen.index == gen_slack_id).nonzero()[0][0])
+        else:
+            try:
+                gen_slack_id_int = int(gen_slack_id)
+            except Exception:
+                raise RuntimeError("'slack_bus_id' should be either an int or a generator names")
+            if gen_slack_id_int != gen_slack_id:
+                raise RuntimeError("'slack_bus_id' should be either an int or a generator names")
+        model.add_gen_slackbus(gen_slack_id_int, 1.)
     elif slack_bus_id is not None:
         gen_bus = np.array([el.bus_id for el in model.get_generators()])
         gen_is_conn_slack = gen_bus == model._orig_to_ls[slack_bus_id]
diff --git a/lightsim2grid/lightSimBackend.py b/lightsim2grid/lightSimBackend.py
index 7119b80..01b611a 100644
--- a/lightsim2grid/lightSimBackend.py
+++ b/lightsim2grid/lightSimBackend.py
@@ -556,7 +556,7 @@ def _load_grid_pypowsybl(self, path=None, filename=None):
         grid_tmp = pypow_net.load(full_path)
         gen_slack_id = None
         if "gen_slack_id" in loader_kwargs:
-            gen_slack_id = int(loader_kwargs["gen_slack_id"])
+            gen_slack_id = loader_kwargs["gen_slack_id"]
         self._grid, subs_id = init_pypow(grid_tmp, gen_slack_id=gen_slack_id, sort_index=True, return_sub_id=True)
         (buses_sub_id, gen_sub, load_sub, (lor_sub, tor_sub), (lex_sub, tex_sub), batt_sub, sh_sub, hvdc_sub_from_id, hvdc_sub_to_id) = subs_id
         self.__nb_bus_before = len(self._grid.get_bus_vn_kv())
diff --git a/lightsim2grid/newtonpf/newtonpf.py b/lightsim2grid/newtonpf/newtonpf.py
index 59d9496..aa84f68 100644
--- a/lightsim2grid/newtonpf/newtonpf.py
+++ b/lightsim2grid/newtonpf/newtonpf.py
@@ -39,7 +39,7 @@ def _get_valid_solver(options, Ybus):
     else:
         solver = KLUSolverSingleSlack() if KLU_solver_available else SparseLUSolverSingleSlack()
 
-    if ~sparse.isspmatrix_csc(Ybus):
+    if not sparse.isspmatrix_csc(Ybus):
         Ybus = sparse.csc_matrix(Ybus)
 
     if not Ybus.has_canonical_format:
diff --git a/setup.py b/setup.py
index a8ca33b..614a645 100644
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@
 from pybind11.setup_helpers import Pybind11Extension, build_ext
 
 
-__version__ = "0.8.1"
+__version__ = "0.8.2"
 KLU_SOLVER_AVAILABLE = False
 
 # Try to link against SuiteSparse (if available)
@@ -357,7 +357,7 @@
         "test": [
             "grid2op>=1.6.4",
             "numba",
-            "pandapower>=2.8.0",
+            "pandapower>=2.14.0",  # interface changed for pandapower, not backward compatible
             "packaging", 
             "pypowsybl"
         ]
diff --git a/src/ChooseSolver.h b/src/ChooseSolver.h
index 383f12b..af76606 100644
--- a/src/ChooseSolver.h
+++ b/src/ChooseSolver.h
@@ -276,6 +276,20 @@ class ChooseSolver
             return res;
         }
 
+        RealMat get_lodf(const Eigen::SparseMatrix<cplx_type> & dcYbus,
+                         const IntVect & from_bus,
+                         const IntVect & to_bus){
+                if(_solver_type != SolverType::DC && 
+                   _solver_type != SolverType::KLUDC && 
+                   _solver_type != SolverType::NICSLUDC &&
+                   _solver_type != SolverType::CKTSODC){
+                throw std::runtime_error("ChooseSolver::get_lodf: cannot get ptdf for a solver that is not DC.");
+                }
+            auto p_solver = get_prt_solver("get_lodf", true);
+            const auto & res =  p_solver -> get_lodf(dcYbus, from_bus, to_bus);
+            return res;
+        }
+
         void tell_solver_control(const SolverControl & solver_control){
             auto p_solver = get_prt_solver("tell_solver_control", false);
             p_solver -> tell_solver_control(solver_control);
@@ -306,6 +320,12 @@ class ChooseSolver
             return p_solver -> get_timers_jacobian();
         }
 
+        TimerPTDFLODFType get_timers_ptdf_lodf() const
+        {
+            const BaseAlgo * p_solver = get_prt_solver("get_timers_ptdf_lodf", true);
+            return p_solver -> get_timers_ptdf_lodf();
+        }
+
         ErrorType get_error() const{
             auto p_solver = get_prt_solver("get_error", true);
             return p_solver -> get_error();
diff --git a/src/GridModel.cpp b/src/GridModel.cpp
index 1ca5fe0..66364f5 100644
--- a/src/GridModel.cpp
+++ b/src/GridModel.cpp
@@ -920,6 +920,17 @@ RealMat GridModel::get_ptdf(){
     return _dc_solver.get_ptdf(Ybus_dc_);
 }
 
+RealMat GridModel::get_lodf(){
+    if(Ybus_dc_.size() == 0){
+        throw std::runtime_error("GridModel::get_lodf: Cannot get the ptdf without having first computed a DC powerflow.");
+    }
+    IntVect from_bus(powerlines_.nb() + trafos_.nb());
+    IntVect to_bus(powerlines_.nb() + trafos_.nb());
+    from_bus << powerlines_.get_bus_from(), trafos_.get_bus_from();
+    to_bus << powerlines_.get_bus_to(), trafos_.get_bus_to();
+    return _dc_solver.get_lodf(Ybus_dc_, from_bus, to_bus);
+}
+
 Eigen::SparseMatrix<real_type> GridModel::get_Bf(){
     if(Ybus_dc_.size() == 0){
         throw std::runtime_error("GridModel::get_Bf: Cannot get the Bf matrix without having first computed a DC powerflow.");
@@ -986,23 +997,23 @@ void GridModel::remove_gen_slackbus(int gen_id){
 }
 
 /** GRID2OP SPECIFIC REPRESENTATION **/
-void GridModel::update_bus_status(int nb_bus_before,
-                                  Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, 2, Eigen::RowMajor> > active_bus)
-{
-    for(int bus_id = 0; bus_id < active_bus.rows(); ++bus_id)
-    {
-        if(active_bus(bus_id, 0)){
-            reactivate_bus(bus_id);
-        }else{
-            deactivate_bus(bus_id);
-        }
-        if(active_bus(bus_id, 1)){
-            reactivate_bus(bus_id + nb_bus_before);
-        }else{
-            deactivate_bus(bus_id + nb_bus_before);
-        }
-    }
-}
+// void GridModel::update_bus_status(int nb_bus_before,
+//                                   Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, 2, Eigen::RowMajor> > active_bus)
+// {
+//     for(int bus_id = 0; bus_id < active_bus.rows(); ++bus_id)
+//     {
+//         if(active_bus(bus_id, 0)){
+//             reactivate_bus(bus_id);
+//         }else{
+//             deactivate_bus(bus_id);
+//         }
+//         if(active_bus(bus_id, 1)){
+//             reactivate_bus(bus_id + nb_bus_before);
+//         }else{
+//             deactivate_bus(bus_id + nb_bus_before);
+//         }
+//     }
+// }
 
 void GridModel::update_gens_p(Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, Eigen::RowMajor> > has_changed,
                               Eigen::Ref<Eigen::Array<float, Eigen::Dynamic, Eigen::RowMajor> > new_values)
diff --git a/src/GridModel.h b/src/GridModel.h
index 2ffd4f3..2541a80 100644
--- a/src/GridModel.h
+++ b/src/GridModel.h
@@ -303,6 +303,8 @@ class GridModel : public GenericContainer
                        real_type tol  // not used for DC
                        );
         RealMat get_ptdf();
+        RealMat get_lodf();
+        
         Eigen::SparseMatrix<real_type> get_Bf();
 
         // ac powerflow
@@ -558,10 +560,13 @@ class GridModel : public GenericContainer
         real_type get_computation_time() const{ return _solver.get_computation_time();}
         real_type get_dc_computation_time() const{ return _dc_solver.get_computation_time();}
 
+    // private:
+    //     using GenericContainer::update_bus_status;  // to silence clang warnings (overload-virtual)
+    // public:
+    //     void update_bus_status(int nb_bus_before,
+    //                            Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, 2, Eigen::RowMajor> > active_bus);
         // part dedicated to grid2op backend, optimized for grid2op data representation (for speed)
         // this is not recommended to use it outside of its intended usage within grid2op !
-        void update_bus_status(int nb_bus_before,
-                               Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, 2, Eigen::RowMajor> > active_bus);
         void update_gens_p(Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, Eigen::RowMajor> > has_changed,
                            Eigen::Ref<Eigen::Array<float, Eigen::Dynamic, Eigen::RowMajor> > new_values);
         void update_sgens_p(Eigen::Ref<Eigen::Array<bool, Eigen::Dynamic, Eigen::RowMajor> > has_changed,
@@ -659,10 +664,16 @@ class GridModel : public GenericContainer
         }
 
         //for FDPF
+    private:
+        using GenericContainer::fillBp_Bpp;  // silence clang warning overload-virtual
+    public:
         void fillBp_Bpp(Eigen::SparseMatrix<real_type> & Bp, 
                         Eigen::SparseMatrix<real_type> & Bpp, 
                         FDPFMethod xb_or_bx) const;
 
+    private:
+        using GenericContainer::fillBf_for_PTDF;  // silence clang warning overload-virtual
+    public:
         void fillBf_for_PTDF(Eigen::SparseMatrix<real_type> & Bf, bool transpose=false) const;
 
         Eigen::SparseMatrix<real_type> debug_get_Bp_python(FDPFMethod xb_or_bx){
@@ -714,6 +725,9 @@ class GridModel : public GenericContainer
                             const Eigen::VectorXi & slack_bus_id_me,
                             Eigen::VectorXi & slack_bus_id_solver
                         );
+    private:
+        using GenericContainer::fillYbus;  // to silence the overload-virtual warning in clang
+    protected:
         void fillYbus(Eigen::SparseMatrix<cplx_type> & res, bool ac, const std::vector<int>& id_me_to_solver);
         void fillSbus_me(CplxVect & res, bool ac, const std::vector<int>& id_me_to_solver);
         void fillpv_pq(const std::vector<int>& id_me_to_solver,
diff --git a/src/batch_algorithm/BaseBatchSolverSynch.h b/src/batch_algorithm/BaseBatchSolverSynch.h
index 42c1ae5..7006ecc 100644
--- a/src/batch_algorithm/BaseBatchSolverSynch.h
+++ b/src/batch_algorithm/BaseBatchSolverSynch.h
@@ -53,6 +53,7 @@ class BaseBatchSolverSynch
             }
 
         BaseBatchSolverSynch(const BaseBatchSolverSynch&) = delete;
+        virtual ~BaseBatchSolverSynch() = default;  // to avoid warning about overload virtual
     
         // solver "control"
         void change_solver(const SolverType & type){
diff --git a/src/element_container/DCLineContainer.cpp b/src/element_container/DCLineContainer.cpp
index 7992598..6c00533 100644
--- a/src/element_container/DCLineContainer.cpp
+++ b/src/element_container/DCLineContainer.cpp
@@ -66,8 +66,8 @@ void DCLineContainer::init(const Eigen::VectorXi & branch_from_id,
 void DCLineContainer::nb_line_end(std::vector<int> & res) const
 {
     const Eigen::Index nb = from_gen_.nb();
-    const auto & bus_or_id = get_bus_id_or();
-    const auto & bus_ex_id = get_bus_id_ex();
+    const auto & bus_or_id = get_bus_from();
+    const auto & bus_ex_id = get_bus_to();
     for(Eigen::Index i = 0; i < nb; ++i){
         if(!status_[i]) continue;
         auto bus_or = bus_or_id(i);
@@ -81,8 +81,8 @@ void DCLineContainer::nb_line_end(std::vector<int> & res) const
 void DCLineContainer::disconnect_if_not_in_main_component(std::vector<bool> & busbar_in_main_component)
 {
     const Eigen::Index nb = from_gen_.nb();
-    const auto & bus_or_id = get_bus_id_or();
-    const auto & bus_ex_id = get_bus_id_ex(); 
+    const auto & bus_or_id = get_bus_from();
+    const auto & bus_ex_id = get_bus_to(); 
     SolverControl unused_solver_control;
     for(Eigen::Index i = 0; i < nb; ++i){
         if(!status_[i]) continue;
diff --git a/src/element_container/DCLineContainer.h b/src/element_container/DCLineContainer.h
index 400c1a5..c244987 100644
--- a/src/element_container/DCLineContainer.h
+++ b/src/element_container/DCLineContainer.h
@@ -289,8 +289,6 @@ class DCLineContainer : public GenericContainer
     }
 
     const std::vector<bool>& get_status() const {return status_;}
-    const Eigen::VectorXi & get_bus_id_or() const {return from_gen_.get_bus_id();}
-    const Eigen::VectorXi & get_bus_id_ex() const {return to_gen_.get_bus_id();}
     
     tuple3d get_or_res() const {return from_gen_.get_res();}
     tuple3d get_ex_res() const {return to_gen_.get_res();}
@@ -299,6 +297,8 @@ class DCLineContainer : public GenericContainer
     
     Eigen::Ref<const RealVect> get_theta_or() const {return from_gen_.get_theta();}
     Eigen::Ref<const RealVect> get_theta_ex() const {return to_gen_.get_theta();}
+    Eigen::Ref<const Eigen::VectorXi> get_bus_from() const {return from_gen_.get_bus_id();}
+    Eigen::Ref<const Eigen::VectorXi> get_bus_to() const {return to_gen_.get_bus_id();}
 
     protected:
         // it is modeled as 2 generators that are "linked" together
diff --git a/src/element_container/GeneratorContainer.h b/src/element_container/GeneratorContainer.h
index 8f5e0a0..299311c 100644
--- a/src/element_container/GeneratorContainer.h
+++ b/src/element_container/GeneratorContainer.h
@@ -328,7 +328,7 @@ class GeneratorContainer: public GenericContainer
     Eigen::Ref<const RealVect> get_theta() const {return res_theta_;}
 
     const std::vector<bool>& get_status() const {return status_;}
-    const Eigen::VectorXi & get_bus_id() const {return bus_id_;}
+    Eigen::Ref<const Eigen::VectorXi> get_bus_id() const {return bus_id_;}
 
     void cout_v(){
         for(const auto & el : vm_pu_){
diff --git a/src/element_container/GenericContainer.cpp b/src/element_container/GenericContainer.cpp
index e7c7ccd..3ed8dc4 100644
--- a/src/element_container/GenericContainer.cpp
+++ b/src/element_container/GenericContainer.cpp
@@ -29,38 +29,25 @@ void GenericContainer::_get_amps(RealVect & a, const RealVect & p, const RealVec
 }
 
 void GenericContainer::_reactivate(int el_id, std::vector<bool> & status){
-    bool val = status.at(el_id);
-    status.at(el_id) = true;  //TODO why it's needed to do that again
+    _check_in_range(static_cast<std::vector<bool>::size_type>(el_id),
+                    status,
+                    "_reactivate");
+    status[el_id] = true;  //TODO why it's needed to do that again
 }
 
 void GenericContainer::_deactivate(int el_id, std::vector<bool> & status){
-    bool val = status.at(el_id);
-    status.at(el_id) = false;  //TODO why it's needed to do that again
+    _check_in_range(static_cast<std::vector<bool>::size_type>(el_id),
+                    status,
+                    "_deactivate");
+    status[el_id] = false;
 }
 
 void GenericContainer::_change_bus(int el_id, int new_bus_me_id, Eigen::VectorXi & el_bus_ids, SolverControl & solver_control, int nb_bus){
     // bus id here "me_id" and NOT "solver_id"
     // throw error: object id does not exist
-    if(el_id >= el_bus_ids.size())
-    {
-        // TODO DEBUG MODE: only check in debug mode
-        std::ostringstream exc_;
-        exc_ << "GenericContainer::_change_bus: Cannot change the bus of element with id ";
-        exc_ << el_id;
-        exc_ << " while the grid counts ";
-        exc_ << el_bus_ids.size();
-        exc_ << " such elements (id too high)";
-        throw std::out_of_range(exc_.str());
-    }
-    if(el_id < 0)
-    {
-        // TODO DEBUG MODE: only check in debug mode
-        std::ostringstream exc_;
-        exc_ << "GenericContainer::_change_bus: Cannot change the bus of element with id ";
-        exc_ << el_id;
-        exc_ << " (id should be >= 0)";
-        throw std::out_of_range(exc_.str());
-    }
+    _check_in_range(static_cast<Eigen::Index>(el_id),
+                    el_bus_ids,
+                    "_change_bus");
 
     // throw error: bus id does not exist
     if(new_bus_me_id >= nb_bus)
@@ -98,8 +85,11 @@ void GenericContainer::_change_bus(int el_id, int new_bus_me_id, Eigen::VectorXi
 
 int GenericContainer::_get_bus(int el_id, const std::vector<bool> & status_, const Eigen::VectorXi & bus_id_) const
 {
+    _check_in_range(static_cast<std::vector<bool>::size_type>(el_id),
+                    status_,
+                    "_get_bus");
     int res;
-    bool val = status_.at(el_id);  // also check if the el_id is out of bound
+    bool val = status_[el_id];  // also check if the el_id is out of bound
     if(!val) res = _deactivated_bus_id;
     else{
         res = bus_id_(el_id);
diff --git a/src/element_container/GenericContainer.h b/src/element_container/GenericContainer.h
index 98050a0..cb59b61 100644
--- a/src/element_container/GenericContainer.h
+++ b/src/element_container/GenericContainer.h
@@ -116,6 +116,34 @@ class GenericContainer : public BaseConstants
         std::vector<std::string> names_;
 
     protected:
+        template<typename Cont, typename FunName, typename IntType>
+        // todo automatically "unwrap" IntType to be either cont::size_type for stl container and
+        // Eigen::Index for Eigen containers
+        void _check_in_range(IntType el_id, const Cont& cont, FunName fun_name="") const
+        {
+            // TODO debug mode: only in debug mode
+            if(el_id >= cont.size())
+            {
+                // TODO DEBUG MODE: only check in debug mode
+                std::ostringstream exc_;
+                exc_ << "GenericContainer::"<<fun_name<<": Cannot access element with id";
+                exc_ << el_id;
+                exc_ << " while the grid counts ";
+                exc_ << cont.size();
+                exc_ << " such elements (id too high)";
+                throw std::out_of_range(exc_.str());
+            }
+            if(el_id < 0)
+            {
+                // TODO DEBUG MODE: only check in debug mode
+                std::ostringstream exc_;
+                exc_ << "GenericContainer::"<< fun_name <<" Cannot change the bus of element with id ";
+                exc_ << el_id;
+                exc_ << " (id should be >= 0)";
+                throw std::out_of_range(exc_.str());
+            }
+        }
+
         /**
         activation / deactivation of elements
         **/
diff --git a/src/element_container/LoadContainer.h b/src/element_container/LoadContainer.h
index 0dc86cd..9a6710b 100644
--- a/src/element_container/LoadContainer.h
+++ b/src/element_container/LoadContainer.h
@@ -181,7 +181,7 @@ class LoadContainer : public GenericContainer
     
     Eigen::Ref<const RealVect> get_theta() const {return res_theta_;}
     const std::vector<bool>& get_status() const {return status_;}
-    const Eigen::VectorXi & get_bus_id() const {return bus_id_;}
+    Eigen::Ref<const Eigen::VectorXi> get_bus_id() const {return bus_id_;}
 
     protected:
         // physical properties
diff --git a/src/element_container/SGenContainer.h b/src/element_container/SGenContainer.h
index 6a3f831..0540147 100644
--- a/src/element_container/SGenContainer.h
+++ b/src/element_container/SGenContainer.h
@@ -201,7 +201,7 @@ class SGenContainer: public GenericContainer
     tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);}
     Eigen::Ref<const RealVect> get_theta() const {return res_theta_;}
     const std::vector<bool>& get_status() const {return status_;}
-    const Eigen::VectorXi & get_bus_id() const {return bus_id_;}
+    Eigen::Ref<const Eigen::VectorXi> get_bus_id() const {return bus_id_;}
 
     protected:
         // physical properties
diff --git a/src/element_container/ShuntContainer.h b/src/element_container/ShuntContainer.h
index 59c4a8a..e0fd79c 100644
--- a/src/element_container/ShuntContainer.h
+++ b/src/element_container/ShuntContainer.h
@@ -185,6 +185,7 @@ class ShuntContainer : public GenericContainer
     tuple4d get_res_full() const {return tuple4d(res_p_, res_q_, res_v_, res_theta_);}
     
     Eigen::Ref<const RealVect> get_theta() const {return res_theta_;}
+    Eigen::Ref<const Eigen::VectorXi> get_bus_id() const {return bus_id_;}
     const std::vector<bool>& get_status() const {return status_;}
 
     protected:
diff --git a/src/linear_solvers/CKTSOSolver.cpp b/src/linear_solvers/CKTSOSolver.cpp
index 4c5a01b..11d8756 100644
--- a/src/linear_solvers/CKTSOSolver.cpp
+++ b/src/linear_solvers/CKTSOSolver.cpp
@@ -33,14 +33,16 @@ ErrorType CKTSOLinearSolver::reset(){
     return ErrorType::NoError;
 }
 
-ErrorType CKTSOLinearSolver::initialize(Eigen::SparseMatrix<real_type> & J){
+ErrorType CKTSOLinearSolver::initialize(const Eigen::SparseMatrix<real_type> & J){
     const long long *oparm = oparm_;
     int ret_ = CKTSO_CreateSolver(&solver_, &iparm_, &oparm);
     if (ret_ < 0){   // fail
         if (ret_ == -99){
             // fail to initialize because of a license issue
             std::string msg = "Fail to initilize the CKTSO solver because we cannot find the cktso.lic file. ";
-            msg += "Please copy this file at the location you want to use the CKTSO solver.";
+            msg += "Please copy this file at the location you want to use the CKTSO solver (the place where the lib is located). ";
+            msg += "See `import lightsim2grid; print(lightsim2grid.compilation_options.cktso_lib)` and then copy paste ";
+            msg += "the cktso/license/cktso.lib there. ";
             std::cout << msg << std::endl;
         }
         return ErrorType::LicenseError;
@@ -87,10 +89,9 @@ ErrorType CKTSOLinearSolver::initialize(Eigen::SparseMatrix<real_type> & J){
     return err;
 }
 
-ErrorType CKTSOLinearSolver::solve(Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor){
+ErrorType CKTSOLinearSolver::solve(const Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor){
     // solves (for x) the linear system J.x = b
     // with standard use of lightsim2grid, the solver should have already been initialized
-    // J is const even if it does not compile if said const
     int ret;
     bool stop = false;
     RealVect x;
diff --git a/src/linear_solvers/CKTSOSolver.h b/src/linear_solvers/CKTSOSolver.h
index af98c93..5e94829 100644
--- a/src/linear_solvers/CKTSOSolver.h
+++ b/src/linear_solvers/CKTSOSolver.h
@@ -61,8 +61,8 @@ class CKTSOLinearSolver
 
         // public api
         ErrorType reset();
-        ErrorType initialize(Eigen::SparseMatrix<real_type> & J);
-        ErrorType solve(Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor);
+        ErrorType initialize(const Eigen::SparseMatrix<real_type> & J);
+        ErrorType solve(const Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor);
 
         // can this linear solver solve problem where RHS is a matrix
         static const bool CAN_SOLVE_MAT;
diff --git a/src/linear_solvers/KLUSolver.cpp b/src/linear_solvers/KLUSolver.cpp
index 4e05361..1e24f4a 100644
--- a/src/linear_solvers/KLUSolver.cpp
+++ b/src/linear_solvers/KLUSolver.cpp
@@ -21,26 +21,34 @@ ErrorType KLULinearSolver::reset(){
     return ErrorType::NoError;
 }
 
-ErrorType KLULinearSolver::initialize(Eigen::SparseMatrix<real_type>&  J){
+ErrorType KLULinearSolver::initialize(const Eigen::SparseMatrix<real_type>&  J){
     // default Eigen representation: column major, which is good for klu !
-    // J is const here, even if it's not said in klu_analyze
+    // J is const here, but `klu_analyze` signature expects arrays and not const arrays
+    // so I const_cast
     const auto n = J.cols();
     common_ = klu_common();
     ErrorType res = ErrorType::NoError; 
-    symbolic_ = klu_analyze(n, J.outerIndexPtr(), J.innerIndexPtr(), &common_);
+    symbolic_ = klu_analyze(n,
+                            const_cast<Eigen::SparseMatrix<real_type>::StorageIndex *>(J.outerIndexPtr()),
+                            const_cast<Eigen::SparseMatrix<real_type>::StorageIndex *>(J.innerIndexPtr()),
+                            &common_);
     if(common_.status != KLU_OK){
         res = ErrorType::SolverAnalyze; 
     }else{
-        numeric_ = klu_factor(J.outerIndexPtr(), J.innerIndexPtr(), J.valuePtr(), symbolic_, &common_);
+        numeric_ = klu_factor(const_cast<Eigen::SparseMatrix<real_type>::StorageIndex *>(J.outerIndexPtr()),
+                              const_cast<Eigen::SparseMatrix<real_type>::StorageIndex *>(J.innerIndexPtr()),
+                              const_cast<real_type*>(J.valuePtr()),
+                              symbolic_, &common_);
         if(common_.status != KLU_OK) res = ErrorType::SolverFactor; 
     }
     return res;
 }
 
-ErrorType KLULinearSolver::solve(Eigen::SparseMatrix<real_type>& J, RealVect & b, bool doesnt_need_refactor){
+ErrorType KLULinearSolver::solve(const Eigen::SparseMatrix<real_type>& J, RealVect & b, bool doesnt_need_refactor){
     // solves (for x) the linear system J.x = b
     // supposes that the solver has been initialized (call klu_solver.analyze() before calling that)
-    // J is const even if it does not compile if said const
+    // J is const here, but `klu_refactor` signature expects arrays and not const arrays
+    // so I const_cast
     int ok;
     ErrorType err = ErrorType::NoError;
     bool stop = false;
@@ -48,7 +56,10 @@ ErrorType KLULinearSolver::solve(Eigen::SparseMatrix<real_type>& J, RealVect & b
         // if the call to "klu_factor" has been made this iteration, there is no need
         // to re factor again the matrix
         // i'm in the case where it has not
-        ok = klu_refactor(J.outerIndexPtr(), J.innerIndexPtr(), J.valuePtr(), symbolic_, numeric_, &common_);
+        ok = klu_refactor(const_cast<Eigen::SparseMatrix<real_type>::StorageIndex *>(J.outerIndexPtr()),
+                          const_cast<Eigen::SparseMatrix<real_type>::StorageIndex *>(J.innerIndexPtr()),
+                          const_cast<real_type*>(J.valuePtr()),
+                          symbolic_, numeric_, &common_);
         if (ok != 1) {
             // std::cout << "\t KLU: refactor error" << std::endl;
             err = ErrorType::SolverReFactor;
diff --git a/src/linear_solvers/KLUSolver.h b/src/linear_solvers/KLUSolver.h
index f75b554..1d2a0a0 100644
--- a/src/linear_solvers/KLUSolver.h
+++ b/src/linear_solvers/KLUSolver.h
@@ -45,8 +45,8 @@ class KLULinearSolver
 
         // public api
         ErrorType reset();
-        ErrorType initialize(Eigen::SparseMatrix<real_type>& J);
-        ErrorType solve(Eigen::SparseMatrix<real_type>& J, RealVect & b, bool doesnt_need_refactor);
+        ErrorType initialize(const Eigen::SparseMatrix<real_type>& J);
+        ErrorType solve(const Eigen::SparseMatrix<real_type>& J, RealVect & b, bool doesnt_need_refactor);
 
         // can this linear solver solve problem where RHS is a matrix
         static const bool CAN_SOLVE_MAT;
diff --git a/src/linear_solvers/NICSLUSolver.cpp b/src/linear_solvers/NICSLUSolver.cpp
index a6f39a1..428bba1 100644
--- a/src/linear_solvers/NICSLUSolver.cpp
+++ b/src/linear_solvers/NICSLUSolver.cpp
@@ -35,7 +35,7 @@ ErrorType NICSLULinearSolver::reset(){
     return ErrorType::NoError;
 }
 
-ErrorType NICSLULinearSolver::initialize(Eigen::SparseMatrix<real_type> & J){
+ErrorType NICSLULinearSolver::initialize(const Eigen::SparseMatrix<real_type> & J){
     // default Eigen representation: column major, which is good for klu !
     const auto n = J.cols(); // should be equal to J_.nrows()
     int ret;
@@ -75,10 +75,9 @@ ErrorType NICSLULinearSolver::initialize(Eigen::SparseMatrix<real_type> & J){
     return err;
 }
 
-ErrorType NICSLULinearSolver::solve(Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor){
+ErrorType NICSLULinearSolver::solve(const Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor){
     // solves (for x) the linear system J.x = b
     // supposes that the solver has been initialized (call klu_solver.analyze() before calling that)
-    // J is const even if it does not compile if said const
     int ret;
     bool stop = false;
     RealVect x;
diff --git a/src/linear_solvers/NICSLUSolver.h b/src/linear_solvers/NICSLUSolver.h
index bb6412c..c83057c 100644
--- a/src/linear_solvers/NICSLUSolver.h
+++ b/src/linear_solvers/NICSLUSolver.h
@@ -53,8 +53,8 @@ class NICSLULinearSolver
 
         // public api
         ErrorType reset();
-        ErrorType initialize(Eigen::SparseMatrix<real_type> & J);
-        ErrorType solve(Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor);
+        ErrorType initialize(const Eigen::SparseMatrix<real_type> & J);
+        ErrorType solve(const Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor);
 
         // can this linear solver solve problem where RHS is a matrix
         static const bool CAN_SOLVE_MAT;
diff --git a/src/linear_solvers/SparseLUSolver.cpp b/src/linear_solvers/SparseLUSolver.cpp
index 5a1b6ab..3118aa2 100644
--- a/src/linear_solvers/SparseLUSolver.cpp
+++ b/src/linear_solvers/SparseLUSolver.cpp
@@ -26,7 +26,6 @@ ErrorType SparseLULinearSolver::initialize(const Eigen::SparseMatrix<real_type>
 ErrorType SparseLULinearSolver::solve(const Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor){
     // solves (for x) the linear system J.x = b
     // supposes that the solver has been initialized (call sparselu_solver.analyze() before calling that)
-    // J is const even if it does not compile if said const
     ErrorType err = ErrorType::NoError;
     bool stop = false;
     if(!doesnt_need_refactor){
diff --git a/src/linear_solvers/SparseLUSolver.h b/src/linear_solvers/SparseLUSolver.h
index 710abcc..869726d 100644
--- a/src/linear_solvers/SparseLUSolver.h
+++ b/src/linear_solvers/SparseLUSolver.h
@@ -35,7 +35,7 @@ class SparseLULinearSolver
         // public api
         ErrorType initialize(const Eigen::SparseMatrix<real_type> & J);
         ErrorType solve(const Eigen::SparseMatrix<real_type> & J, RealVect & b, bool doesnt_need_refactor);
-        ErrorType reset(){ return ErrorType::NoError; }
+        ErrorType reset(){return ErrorType::NoError; }
 
         // can this linear solver solve problem where RHS is a matrix
         static const bool CAN_SOLVE_MAT;
diff --git a/src/main.cpp b/src/main.cpp
index b8aac5b..bba1c24 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -446,6 +446,7 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("get_computation_time", &ChooseSolver::get_computation_time, DocSolver::get_computation_time.c_str())
         .def("get_timers", &ChooseSolver::get_timers, "TODO")
         .def("get_timers_jacobian", &ChooseSolver::get_timers_jacobian, "TODO")
+        .def("get_timers_ptdf_lodf", &ChooseSolver::get_timers_ptdf_lodf, "TODO")
         .def("get_fdpf_xb_lu", &ChooseSolver::get_fdpf_xb_lu, py::return_value_policy::reference, DocGridModel::_internal_do_not_use.c_str())  // TODO this for all solver !
         .def("get_fdpf_bx_lu", &ChooseSolver::get_fdpf_bx_lu, py::return_value_policy::reference, DocGridModel::_internal_do_not_use.c_str());
 
@@ -453,9 +454,11 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
     py::class_<GeneratorContainer>(m, "GeneratorContainer", DocIterator::GeneratorContainer.c_str())
         .def("__len__", [](const GeneratorContainer & data) { return data.nb(); })
         .def("__getitem__", [](const GeneratorContainer & data, int k){return data[k]; } )
-        .def("__iter__", [](const GeneratorContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+        .def("__iter__", [](const GeneratorContainer & data)  {
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_id", &GeneratorContainer::get_bus_id, "TODO doc", py::keep_alive<0, 1>())
+        ; 
 
     py::class_<GeneratorContainer::GenInfo>(m, "GenInfo", DocIterator::GenInfo.c_str())
         .def_readonly("id", &GeneratorContainer::GenInfo::id, DocIterator::id.c_str())
@@ -481,8 +484,10 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("__len__", [](const SGenContainer & data) { return data.nb(); })
         .def("__getitem__", [](const SGenContainer & data, int k){return data[k]; } )
         .def("__iter__", [](const SGenContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_id", &SGenContainer::get_bus_id, "TODO doc", py::keep_alive<0, 1>())
+        ; 
 
     py::class_<SGenContainer::SGenInfo>(m, "SGenInfo", DocIterator::SGenInfo.c_str())
         .def_readonly("id", &SGenContainer::SGenInfo::id, DocIterator::id.c_str())
@@ -506,8 +511,10 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("__len__", [](const LoadContainer & data) { return data.nb(); })
         .def("__getitem__", [](const LoadContainer & data, int k){return data[k]; } )
         .def("__iter__", [](const LoadContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_id", &LoadContainer::get_bus_id, "TODO doc", py::keep_alive<0, 1>())
+        ; 
 
     py::class_<LoadContainer::LoadInfo>(m, "LoadInfo", DocIterator::LoadInfo.c_str())
         .def_readonly("id", &LoadContainer::LoadInfo::id, DocIterator::id.c_str())
@@ -527,8 +534,10 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("__len__", [](const ShuntContainer & data) { return data.nb(); })
         .def("__getitem__", [](const ShuntContainer & data, int k){return data[k]; } )
         .def("__iter__", [](const ShuntContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_id", &ShuntContainer::get_bus_id, "TODO doc", py::keep_alive<0, 1>())
+        ; 
 
     py::class_<ShuntContainer::ShuntInfo>(m, "ShuntInfo", DocIterator::ShuntInfo.c_str())
         .def_readonly("id", &ShuntContainer::ShuntInfo::id, DocIterator::id.c_str())
@@ -548,8 +557,11 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("__len__", [](const TrafoContainer & data) { return data.nb(); })
         .def("__getitem__", [](const TrafoContainer & data, int k){return data[k]; } )
         .def("__iter__", [](const TrafoContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_from", &TrafoContainer::get_bus_from, "TODO doc", py::keep_alive<0, 1>())
+        .def("get_bus_to", &TrafoContainer::get_bus_to, "TODO doc", py::keep_alive<0, 1>())
+        ; 
 
     py::class_<TrafoContainer::TrafoInfo>(m, "TrafoInfo", DocIterator::TrafoInfo.c_str())
         .def_readonly("id", &TrafoContainer::TrafoInfo::id, DocIterator::id.c_str())
@@ -580,8 +592,10 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("__len__", [](const LineContainer & data) { return data.nb(); })
         .def("__getitem__", [](const LineContainer & data, int k){return data[k]; } )
         .def("__iter__", [](const LineContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_from", &LineContainer::get_bus_from, "TODO doc", py::keep_alive<0, 1>())
+        .def("get_bus_to", &LineContainer::get_bus_to, "TODO doc", py::keep_alive<0, 1>());
 
     py::class_<LineContainer::LineInfo>(m, "LineInfo", DocIterator::LineInfo.c_str())
         .def_readonly("id", &LineContainer::LineInfo::id, DocIterator::id.c_str())
@@ -611,8 +625,10 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("__len__", [](const DCLineContainer & data) { return data.nb(); })
         .def("__getitem__", [](const DCLineContainer & data, int k){return data[k]; } )
         .def("__iter__", [](const DCLineContainer & data) {
-       return py::make_iterator(data.begin(), data.end());
-    }, py::keep_alive<0, 1>()); /* Keep vector alive while iterator is used */
+                return py::make_iterator(data.begin(), data.end());
+            }, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
+        .def("get_bus_from", &DCLineContainer::get_bus_from)
+        .def("get_bus_to", &DCLineContainer::get_bus_to);
 
     py::class_<DCLineContainer::DCLineInfo>(m, "DCLineInfo", DocIterator::DCLineInfo.c_str())
         .def_readonly("id", &DCLineContainer::DCLineInfo::id, DocIterator::id.c_str())
@@ -895,11 +911,12 @@ PYBIND11_MODULE(lightsim2grid_cpp, m)
         .def("get_solver_control", &GridModel::get_solver_control, "TODO")
         .def("compute_newton", &GridModel::ac_pf, DocGridModel::ac_pf.c_str())
         .def("get_ptdf", &GridModel::get_ptdf, DocGridModel::_internal_do_not_use.c_str()) // TODO PTDF
+        .def("get_lodf", &GridModel::get_lodf, DocGridModel::_internal_do_not_use.c_str()) // TODO PTDF
         .def("get_Bf", &GridModel::get_Bf, DocGridModel::_internal_do_not_use.c_str()) // TODO PTDF
 
          // apply action faster (optimized for grid2op representation)
          // it is not recommended to use it outside of grid2Op.
-        .def("update_bus_status", &GridModel::update_bus_status, DocGridModel::_internal_do_not_use.c_str())
+        // .def("update_bus_status", &GridModel::update_bus_status, DocGridModel::_internal_do_not_use.c_str())
         .def("update_gens_p", &GridModel::update_gens_p, DocGridModel::_internal_do_not_use.c_str())
         .def("update_sgens_p", &GridModel::update_sgens_p, DocGridModel::_internal_do_not_use.c_str())
         .def("update_gens_v", &GridModel::update_gens_v, DocGridModel::_internal_do_not_use.c_str())
diff --git a/src/powerflow_algorithm/BaseAlgo.h b/src/powerflow_algorithm/BaseAlgo.h
index fc7ce46..4801776 100644
--- a/src/powerflow_algorithm/BaseAlgo.h
+++ b/src/powerflow_algorithm/BaseAlgo.h
@@ -33,6 +33,7 @@ class GridModel;
 typedef std::tuple<double, double, double, double, 
                    double, double, double, double, 
                    double> TimerJacType;
+typedef std::tuple<double, double, double> TimerPTDFLODFType;
 
 /**
 This class represents a algorithm to compute powerflow.
@@ -104,6 +105,16 @@ class BaseAlgo : public BaseConstants
             };
             return res;
         }
+        
+        virtual TimerPTDFLODFType get_timers_ptdf_lodf() const
+        {
+            TimerPTDFLODFType res = {
+                -1.,  // not available for non NR solver, so I put -1
+                -1.,  // not available for non NR solver, so I put -1
+                -1.,  // not available for non NR solver, so I put -1
+            };
+            return res;
+        }
 
         virtual
         bool compute_pf(const Eigen::SparseMatrix<cplx_type> & Ybus,
@@ -124,7 +135,9 @@ class BaseAlgo : public BaseConstants
         virtual RealMat get_ptdf(const Eigen::SparseMatrix<cplx_type> & dcYbus){
             throw std::runtime_error("Impossible to get the PTDF matrix with this solver type.");
         }
-        virtual Eigen::SparseMatrix<real_type> get_lodf(){  // TODO interface is likely to change
+        virtual RealMat get_lodf(const Eigen::SparseMatrix<cplx_type> & dcYbus,
+                                 const IntVect & from_bus,
+                                 const IntVect & to_bus){  // TODO interface is likely to change
             throw std::runtime_error("Impossible to get the LODF matrix with this solver type.");
         }
         virtual Eigen::SparseMatrix<real_type> get_bsdf(){  // TODO interface is likely to change
diff --git a/src/powerflow_algorithm/BaseDCAlgo.h b/src/powerflow_algorithm/BaseDCAlgo.h
index 06e6935..5421e68 100644
--- a/src/powerflow_algorithm/BaseDCAlgo.h
+++ b/src/powerflow_algorithm/BaseDCAlgo.h
@@ -19,12 +19,29 @@ class BaseDCAlgo: public BaseAlgo
             BaseAlgo(false),
             _linear_solver(),
             need_factorize_(true),
+            timer_ptdf_(0.),
+            timer_lodf_(0.),
             sizeYbus_with_slack_(0),
             sizeYbus_without_slack_(0){};
 
         ~BaseDCAlgo(){}
 
         virtual void reset();
+        virtual void reset_timer(){
+            BaseAlgo::reset_timer();
+            timer_ptdf_ = 0.;
+            timer_lodf_ = 0.;
+        }
+
+        virtual TimerPTDFLODFType get_timers_ptdf_lodf() const
+        {
+            TimerPTDFLODFType res = {
+                timer_ptdf_,  
+                timer_lodf_ - timer_ptdf_,
+                -1.,  // not available yet so I put -1
+            };
+            return res;
+        }
 
         // TODO SLACK : this should be handled in Sbus by the gridmodel maybe ?
         virtual
@@ -39,9 +56,11 @@ class BaseDCAlgo: public BaseAlgo
                         real_type tol
                         );
 
-        virtual RealMat get_ptdf(const Eigen::SparseMatrix<cplx_type> & dcYbus);  // TODO PTDF
-        virtual Eigen::SparseMatrix<real_type> get_lodf();  // TODO PTDF
-        virtual Eigen::SparseMatrix<real_type> get_bsdf();  // TODO PTDF
+        virtual RealMat get_ptdf(const Eigen::SparseMatrix<cplx_type> & dcYbus);
+        virtual RealMat get_lodf(const Eigen::SparseMatrix<cplx_type> & dcYbus,
+                                 const IntVect & from_bus,
+                                 const IntVect & to_bus);  // TODO LODF
+        virtual Eigen::SparseMatrix<real_type> get_bsdf();  // TODO BSDF
 
     private:
         // no copy allowed
@@ -60,6 +79,9 @@ class BaseDCAlgo: public BaseAlgo
         LinearSolver  _linear_solver;
         bool need_factorize_;
 
+        double timer_ptdf_;
+        double timer_lodf_;
+
         // save this not to recompute them when not needed
         int sizeYbus_with_slack_;
         int sizeYbus_without_slack_;
diff --git a/src/powerflow_algorithm/BaseDCAlgo.tpp b/src/powerflow_algorithm/BaseDCAlgo.tpp
index 7de831f..124aa80 100644
--- a/src/powerflow_algorithm/BaseDCAlgo.tpp
+++ b/src/powerflow_algorithm/BaseDCAlgo.tpp
@@ -7,6 +7,8 @@
 // This file is part of LightSim2grid, LightSim2grid implements a c++ backend targeting the Grid2Op platform.
 
 // #include "DCSolver.h"
+#include <limits>  // for nans
+#include <cmath>  // for nans
 
 // TODO SLACK !!!
 template<class LinearSolver>
@@ -232,6 +234,7 @@ void BaseDCAlgo<LinearSolver>::reset(){
 
 template<class LinearSolver>
 RealMat BaseDCAlgo<LinearSolver>::get_ptdf(const Eigen::SparseMatrix<cplx_type> & dcYbus){
+    auto timer = CustTimer();
     Eigen::SparseMatrix<real_type> Bf_T_with_slack;
     RealMat PTDF;
     RealVect rhs = RealVect::Zero(sizeYbus_without_slack_);  // TODO dist slack: -1 or -mat_bus_id_.size() here ????
@@ -256,9 +259,9 @@ RealMat BaseDCAlgo<LinearSolver>::get_ptdf(const Eigen::SparseMatrix<cplx_type>
 
     // solve iteratively the linear systems (one per powerline)
     PTDF = RealMat::Zero(Bf_T_with_slack.cols(), Bf_T_with_slack.rows());  // rows and cols are "inverted" because the matrix Bf is transposed
-    for (int line_id=0; line_id < nb_pow_tr; ++line_id){
+    for (int row_id=0; row_id < nb_pow_tr; ++row_id){
         // build the rhs vector
-        for (typename Eigen::SparseMatrix<real_type>::InnerIterator it(Bf_T_with_slack, line_id); it; ++it)
+        for (typename Eigen::SparseMatrix<real_type>::InnerIterator it(Bf_T_with_slack, row_id); it; ++it)
         {
             const auto bus_id = it.row();
             if(mat_bus_id_(bus_id) == -1) continue;  // I don't add anything if it's the slack
@@ -269,21 +272,36 @@ RealMat BaseDCAlgo<LinearSolver>::get_ptdf(const Eigen::SparseMatrix<cplx_type>
         _linear_solver.solve(dcYbus_noslack_, rhs, true);  // I don't need to refactorize the matrix (hence the `true`)
 
         // assign results to the PTDF matrix
-        PTDF(line_id, ind_no_slack) = rhs;
+        PTDF(row_id, ind_no_slack) = rhs;
 
         // reset the rhs vector to 0.
         rhs.array() = 0.;
         // rhs = RealVect::Zero(sizeYbus_without_slack_);
     }
+    timer_ptdf_ = timer.duration();
     // TODO PTDF: if the solver can solve the MAT directly, do that instead
     return PTDF;
 }
 
 template<class LinearSolver>
-Eigen::SparseMatrix<real_type> BaseDCAlgo<LinearSolver>::get_lodf(){
-    // TODO
-    return dcYbus_noslack_;
-
+RealMat BaseDCAlgo<LinearSolver>::get_lodf(const Eigen::SparseMatrix<cplx_type> & dcYbus,
+                                           const IntVect & from_bus,
+                                           const IntVect & to_bus){
+    auto timer = CustTimer();
+    const RealMat PTDF = get_ptdf(dcYbus);  // size n_line x n_bus
+    RealMat LODF = RealMat::Zero(from_bus.size(), from_bus.rows());  // nb_line, nb_line
+    for(Eigen::Index line_id=0; line_id < from_bus.size(); ++line_id){
+        LODF.col(line_id).array() = PTDF.col(from_bus(line_id)).array() - PTDF.col(to_bus(line_id)).array();
+        const real_type diag_coeff = LODF(line_id, line_id);
+        if (diag_coeff != 1.){
+            LODF.col(line_id).array() /= (1. - diag_coeff);
+            LODF(line_id, line_id) = -1.;
+        }else{
+            LODF.col(line_id).array() = std::numeric_limits<real_type>::quiet_NaN();
+        }
+    }
+    timer_lodf_ = timer.duration();
+    return LODF;
 }
 
 template<class LinearSolver>
diff --git a/src/powerflow_algorithm/BaseNRAlgo.tpp b/src/powerflow_algorithm/BaseNRAlgo.tpp
index e889771..7cf118a 100644
--- a/src/powerflow_algorithm/BaseNRAlgo.tpp
+++ b/src/powerflow_algorithm/BaseNRAlgo.tpp
@@ -583,7 +583,7 @@ void BaseNRAlgo<LinearSolver>::fill_value_map(
     // row_map_ = std::vector<int> (J_.nonZeros());
 
     const auto n_row = J_.cols();
-    unsigned int pos_el = 0;
+    // unsigned int pos_el = 0;
     for (Eigen::Index col_=1; col_ < n_row; ++col_){  // last column is never updated (slack equation)
         for (Eigen::SparseMatrix<real_type>::InnerIterator it(J_, col_); it; ++it)
         {
@@ -640,7 +640,7 @@ void BaseNRAlgo<LinearSolver>::fill_value_map(
                 }
             }
             // go to the next element
-            ++pos_el;
+            // ++pos_el;
         }
     }
     dS_dVa_.makeCompressed();
diff --git a/src/powerflow_algorithm/BaseNRSingleSlackAlgo.tpp b/src/powerflow_algorithm/BaseNRSingleSlackAlgo.tpp
index efd86b5..5749d83 100644
--- a/src/powerflow_algorithm/BaseNRSingleSlackAlgo.tpp
+++ b/src/powerflow_algorithm/BaseNRSingleSlackAlgo.tpp
@@ -393,7 +393,7 @@ void BaseNRSingleSlackAlgo<LinearSolver>::fill_value_map(
     BaseNRAlgo<LinearSolver>::value_map_.reserve(BaseNRAlgo<LinearSolver>::J_.nonZeros());
 
     const int n_col = static_cast<int>(BaseNRAlgo<LinearSolver>::J_.cols());
-    unsigned int pos_el = 0;
+    // unsigned int pos_el = 0;
     for (int col_=0; col_ < n_col; ++col_){
         for (Eigen::SparseMatrix<real_type>::InnerIterator it(BaseNRAlgo<LinearSolver>::J_, col_); it; ++it)
         {
@@ -437,7 +437,7 @@ void BaseNRSingleSlackAlgo<LinearSolver>::fill_value_map(
             }
 
             // go to the next element
-            ++pos_el;
+            // ++pos_el;
         }
     }
     // BaseNRAlgo<LinearSolver>::dS_dVa_.makeCompressed();


Test patch:
diff --git a/lightsim2grid/tests/test_SameResPP.py b/lightsim2grid/tests/test_SameResPP.py
index 13ae6a8..3b6fe05 100644
--- a/lightsim2grid/tests/test_SameResPP.py
+++ b/lightsim2grid/tests/test_SameResPP.py
@@ -246,9 +246,13 @@ def _aux_test(self, pn_net):
         try:
             baseMVA, bus, gen, branch, ref, pv, pq, on, gbus, _, refgen = _get_pf_variables_from_ppci(ppci)
         except ValueError:
-            # change in pandapower 2.12
-            baseMVA, bus, gen, branch, svc, tcsc, ref, pv, pq, on, gbus, V0, ref_gens = _get_pf_variables_from_ppci(ppci)
-            
+            try:
+                # change in pandapower 2.12
+                baseMVA, bus, gen, branch, svc, tcsc, ref, pv, pq, on, gbus, V0, ref_gens = _get_pf_variables_from_ppci(ppci)
+            except ValueError:
+                # change in pandapower 2.14
+                baseMVA, bus, gen, branch, svc, tcsc, ssc, ref, pv, pq, on, gbus, V0, ref_gens = _get_pf_variables_from_ppci(ppci)
+        
         Va0 = bus[:, VA] * (np.pi / 180.)
         try:
             B, Bf, Pbusinj, Pfinj = makeBdc(bus, branch)
diff --git a/lightsim2grid/tests/test_dist_slack_jacobian.py b/lightsim2grid/tests/test_dist_slack_jacobian.py
index 929dce0..32e03e6 100644
--- a/lightsim2grid/tests/test_dist_slack_jacobian.py
+++ b/lightsim2grid/tests/test_dist_slack_jacobian.py
@@ -24,7 +24,7 @@ def setUp(self) -> None:
         with warnings.catch_warnings():
             warnings.filterwarnings("ignore", category=FutureWarning)
             self.net = pp.from_json("./dist_slack_test.json")
-            pp.runpp(self.net, lightsim2grid=False, numba=True, distributed_slack=True)
+            pp.runpp(self.net, lightsim2grid=False, numba=True, distributed_slack=True, init="flat")
     
     def test_jacobian_dist_slack(self):    
         """that's the grid described in the issue 
@@ -52,7 +52,7 @@ def test_jacobian_single_slack(self):
         """that's the grid described in the issue 
         https://github.com/e2nIEE/pandapower/pull/1455
         """
-        pp.runpp(self.net, lightsim2grid=False, numba=True, distributed_slack=False)
+        pp.runpp(self.net, lightsim2grid=False, numba=True, distributed_slack=False, init="flat")
         options = {"max_iteration": 10, "tolerance_mva": 1e-8, "distributed_slack": False}
         V, converged, iterations, J, Vm_it, Va_it = newtonpf_new(self.net._ppc["internal"]["Ybus"], 
                                                                  self.net._ppc["internal"]["Sbus"],
diff --git a/lightsim2grid/tests/test_fdpf.py b/lightsim2grid/tests/test_fdpf.py
index 3dd8926..8e7971a 100644
--- a/lightsim2grid/tests/test_fdpf.py
+++ b/lightsim2grid/tests/test_fdpf.py
@@ -30,8 +30,8 @@ def get_solving_method(self):
         return FDPFMethod.XB
     
     def get_algo_pp(self):
-        # return "fdxb" if self.fdpf_meth == FDPFMethod.XB else "fdbx"  # in theory
-        return "fdbx" if self.fdpf_meth == FDPFMethod.XB else "fdxb"  # but.... https://github.com/e2nIEE/pandapower/issues/2142
+        return "fdxb" if self.fdpf_meth == FDPFMethod.XB else "fdbx"  # in theory
+        # return "fdbx" if self.fdpf_meth == FDPFMethod.XB else "fdxb"  # but.... https://github.com/e2nIEE/pandapower/issues/2142
     
     def get_network(self):
         return pn.case14()
@@ -82,7 +82,7 @@ def _aux_get_Bp_Bpp(self):
         # convert pandapower net to ppc
         ppc, ppci = _pd2ppc(self.net)
         self.net["_ppc"] = ppc
-        baseMVA, bus, gen, branch, svc, tcsc, ref, pv, pq, *_, gbus, V0, ref_gens = _get_pf_variables_from_ppci(ppci)
+        baseMVA, bus, gen, branch, svc, tcsc, ssc, ref, pv, pq, on, gbus, V0, ref_gens = _get_pf_variables_from_ppci(ppci)
         pp_Bp, pp_Bpp = makeB(baseMVA, bus, np.real(branch), self.alg)
         return pp_Bp, pp_Bpp, pv, pq, V0
         
@@ -113,6 +113,8 @@ def test_Bp_Bpp_solver(self):
         pp_Bpp = grid_Bpp[np.array([pq]).T, pq].tocsc()
         
         # check they match
+        # NB: if pandapower change signature of `_get_pf_variables_from_ppci`
+        # you might get weird error here
         assert np.abs(pp_Bp - ls_Bp).max() <= self.tol, f"error in Bp: max {np.abs(pp_Bp - ls_Bp).max():.2f}"
         assert np.abs(pp_Bpp - ls_Bpp).max() <= self.tol, f"error in Bpp: max {np.abs(pp_Bpp - ls_Bpp).max():.2f}"
         
diff --git a/lightsim2grid/tests/test_lodf.py b/lightsim2grid/tests/test_lodf.py
new file mode 100644
index 0000000..1571c08
--- /dev/null
+++ b/lightsim2grid/tests/test_lodf.py
@@ -0,0 +1,156 @@
+# Copyright (c) 2023, 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 implements a c++ backend targeting the Grid2Op platform.
+
+import unittest
+import pandapower as pp
+import pandapower.networks as pn
+import numpy as np
+import scipy
+import warnings
+
+from pandapower.pypower.makeLODF import update_LODF_diag
+from lightsim2grid.gridmodel import init
+from lightsim2grid.solver import SolverType
+
+import pdb
+
+class TestLODFCase14SLU(unittest.TestCase):
+    def make_grid(self):
+        case14 = pn.case14()
+        return case14
+
+    def get_solver_type(self):
+        return SolverType.DC
+    
+    def setUp(self) -> None:
+        self.case = self.make_grid()
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore")
+            self.gridmodel = init(self.case)
+        self.V_init = 1. * self.gridmodel.get_bus_vn_kv()
+        solver_type = self.get_solver_type()
+        if solver_type not in self.gridmodel.available_solvers():
+            self.skipTest("Solver type not supported on this platform")
+        self.gridmodel.change_solver(solver_type)
+        V = self.gridmodel.dc_pf(1. * self.V_init, 1, 1e-8)
+        assert len(V), f"dc pf has diverged with error {self.gridmodel.get_dc_solver().get_error()}"
+        self.dcYbus = 1.0 * self.gridmodel.get_dcYbus()
+        self.dcSbus = 1.0 * self.gridmodel.get_dcSbus().real
+        self.Bbus = 1.0 * self.dcYbus.real
+        self.res_powerflow = 1.0 * np.concatenate((self.gridmodel.get_lineor_res()[0], self.gridmodel.get_trafohv_res()[0]))
+        self.nb = self.case.bus.shape[0]
+        self.nbr = self.case.line.shape[0] + self.case.trafo.shape[0]
+        self.slack_bus = self.case.ext_grid.iloc[0]["bus"]
+        self.noref = np.arange(1, self.nb)      ## use bus 1 for voltage angle reference
+        self.noslack = np.flatnonzero(np.arange(self.nb) != self.slack_bus)
+        self.tol = 1e-6
+        return super().setUp()
+
+    def test_from_PTDF(self):
+        """compare the ls implementation pypower (in pandapowerer)
+        implementation and see if they match"""
+        PTDF = 1.0 * self.gridmodel.get_ptdf()
+        
+        # pypower implementation
+        f_ = np.concatenate((1 * self.gridmodel.get_lines().get_bus_from(), 1 * self.gridmodel.get_trafos().get_bus_from()))
+        t_ = np.concatenate((1 * self.gridmodel.get_lines().get_bus_to(), 1 * self.gridmodel.get_trafos().get_bus_to()))
+        Cft = scipy.sparse.csr_matrix((np.r_[np.ones(self.nbr), -np.ones(self.nbr)],
+                                       (np.r_[f_, t_], np.r_[np.arange(self.nbr), np.arange(self.nbr)])),
+                                      (self.nb, self.nbr))
+
+        H = PTDF * Cft
+        h = np.diag(H, 0)
+        den = (np.ones((self.nbr, 1)) * h.T * -1 + 1.)
+        with np.errstate(divide='ignore', invalid='ignore'):
+            LODF_pypower = (H / den)
+        update_LODF_diag(LODF_pypower)
+        # end pypower implementation
+        
+        LODF_ls = 1.0 * self.gridmodel.get_lodf()
+        
+        for l_id in range(LODF_ls.shape[0]):
+            pypow = 1. * LODF_pypower[:,l_id]
+            ls = 1. * LODF_ls[:,l_id]
+            if np.all(np.isfinite(pypow)):
+                # if everything works on pyower, it should work on lightsim2grid too
+                assert np.all(np.isfinite(ls)), f"error for line id {l_id}"
+            if np.all(np.isfinite(ls)):
+                # and the opposite too
+                assert np.all(np.isfinite(pypow)), f"error for line id {l_id}"
+            if np.any(~np.isfinite(pypow)):
+                # if it does not work for a given line, then 
+                # every other flow are nan
+                assert np.all(~np.isfinite(pypow)), f"error for line id {l_id}"
+                # every flow for ls are nans too
+                assert np.all(~np.isfinite(ls)), f"error for line id {l_id}"
+            if np.any(~np.isfinite(ls)):
+                # if it does not work for a given line, then 
+                # every other flow are nan
+                assert np.all(~np.isfinite(ls)), f"error for line id {l_id}"  
+                # every flow for pypower are nans too
+                assert np.all(~np.isfinite(pypow)), f"error for line id {l_id}" 
+            if np.all(np.isfinite(pypow)):
+                assert np.abs(pypow - ls).max() <= 1e-6, f"error for line id {l_id}"
+
+    def test_with_powerflow(self):
+        """compute powerflow with LODF and with "standard" powerflow
+        and see if it matches
+        """
+        LODF_ls = 1.0 * self.gridmodel.get_lodf()
+        nb_powerlines = len(self.gridmodel.get_lines())
+        for l_id in range(LODF_ls.shape[0]):
+            if l_id < nb_powerlines:
+                self.gridmodel.deactivate_powerline(l_id)
+            else:
+                self.gridmodel.deactivate_trafo(l_id - nb_powerlines)
+                
+            V = self.gridmodel.dc_pf(1. * self.V_init, 1, 1e-8)
+            if V.shape[0] > 0:
+                # it has converged
+                por_pow = np.concatenate((self.gridmodel.get_lineor_res()[0],
+                                          self.gridmodel.get_trafohv_res()[0]))
+                por_lodf = self.res_powerflow + LODF_ls[:, l_id] * self.res_powerflow[l_id]
+                assert np.abs(por_lodf - por_pow).max() <= 1e-6, f"error for line id {l_id}"
+            else:
+                # it has diverged
+                assert np.all(~np.isfinite(LODF_ls[:,l_id])), f"error for line id {l_id}"
+                
+            if l_id < nb_powerlines:
+                self.gridmodel.reactivate_powerline(l_id)
+            else:
+                self.gridmodel.reactivate_trafo(l_id - nb_powerlines)
+
+class TestLODFCase30SLU(TestLODFCase14SLU):
+    def make_grid(self):
+        res = pn.case30()
+        return res
+
+
+class TestLODFCase118SLU(TestLODFCase14SLU):
+    def make_grid(self):
+        res = pn.case118()
+        return res
+    
+    
+class TestLODFCase14KLU(TestLODFCase14SLU):
+    def get_solver_type(self):
+        return SolverType.KLUDC
+    
+    
+class TestLODFCase30KLU(TestLODFCase30SLU):
+    def get_solver_type(self):
+        return SolverType.KLUDC
+    
+    
+class TestLODFCase118KLU(TestLODFCase118SLU):
+    def get_solver_type(self):
+        return SolverType.KLUDC
+    
+    
+if __name__ == "__main__":
+    unittest.main()
diff --git a/lightsim2grid/tests/test_ptdf.py b/lightsim2grid/tests/test_ptdf.py
index 4a98e4a..4c66659 100644
--- a/lightsim2grid/tests/test_ptdf.py
+++ b/lightsim2grid/tests/test_ptdf.py
@@ -75,7 +75,6 @@ def test_ptdf_from_ls(self):
             assert solve_error <= self.tol, f"error for line {line_id}: {solve_error:.2e}MW"
         # test powerflow are correct
         res_ptdf2 = np.dot(PTDF2, self.dcSbus * self.gridmodel.get_sn_mva())
-        np.where(np.abs(res_ptdf2 - self.res_powerflow) >= 1e3)
         assert np.abs(res_ptdf2 - self.res_powerflow).max() <= self.tol, f"max error for powerflow: {np.abs(res_ptdf2 - self.res_powerflow).max():.2e}MW"