PyPowSyBl

The PyPowSyBl project gives access PowSyBl Java framework to Python developers. This Python integration relies on GraalVM to compile Java code to a native library.

Installation

PyPowSyBl is released on PyPi.

First, make sure you have an up-to-date version of pip and setuptools:

pip3 install --upgrade setuptools pip --user

Then you can install PyPowSyBl using pip:

pip3 install pypowsybl --user

Build from sources

Requirements:

To build from sources and install PyPowSyBl package:

git clone --recursive https://github.com/powsybl/pypowsybl.git
export JAVA_HOME=<path to GraalVM>
pip3 install --upgrade setuptools pip --user
pip3 install . --user

To run unit tests:

python3 -m unittest tests/test.py

Usage

First, we have to import pypowsybl:

import pypowsybl as pp

Then we can display the version of the PowSyBl modules:

pp.print_version()
Powsybl versions:
+-----------------------------+-----------------------+------------+------------------------------------------+-------------------------------+
| Repository name             | Maven project version | Git branch | Git version                              | Build timestamp               |
+-----------------------------+-----------------------+------------+------------------------------------------+-------------------------------+
| powsybl-open-loadflow       | X.Y.Z                 |            |                                          |                               |
| powsybl-single-line-diagram | X.Y.Z                 |            |                                          |                               |
| powsybl-core                | X.Y.Z                 |            |                                          |                               |
+-----------------------------+-----------------------+------------+------------------------------------------+-------------------------------+

We can create an IEEE 14 buses network and run a load flow computation:

n = pp.network.create_ieee14()
results = pp.loadflow.run_ac(n)
for result in results:
    print(result)
LoadFlowComponentResult(component_num=0, status=CONVERGED, iteration_count=3, slack_bus_id='VL4_0', slack_bus_active_power_mismatch=-0.006081)

We can re-run the load flow computation in DC mode:

results = pp.loadflow.run_dc(n)

Or with different parameters:

parameters = pp.loadflow.Parameters(distributed_slack=False)
results = pp.loadflow.run_ac(n, parameters)

We can now iterate over buses and print calculated voltage:

for bus in n.buses:
    print(f"Bus {bus.id!r}: v_mag={bus.v_magnitude}, v_ang={bus.v_angle}")
Bus 'VL1_0': v_mag=1.06, v_ang=10.313243381060664
Bus 'VL2_0': v_mag=1.045, v_ang=5.330504871947214
Bus 'VL3_0': v_mag=1.01, v_ang=-2.4121176767072106
Bus 'VL4_0': v_mag=1.0176698517255092, v_ang=0.0
Bus 'VL5_0': v_mag=1.019513126069881, v_ang=1.5391224927328597
Bus 'VL6_0': v_mag=1.07, v_ang=-3.908001888907669
Bus 'VL7_0': v_mag=1.0615190502807328, v_ang=-3.0467156954546497
Bus 'VL8_0': v_mag=1.09, v_ang=-3.0467156954546497
Bus 'VL9_0': v_mag=1.0559312123363436, v_ang=-4.625603385486276
Bus 'VL10_0': v_mag=1.0509841969760743, v_ang=-4.784365794405052
Bus 'VL11_0': v_mag=1.0569062925416597, v_ang=-4.477688311883925
Bus 'VL12_0': v_mag=1.0551885297773924, v_ang=-4.762642162506649
Bus 'VL13_0': v_mag=1.0503816324228432, v_ang=-4.843335457191098
Bus 'VL14_0': v_mag=1.0355296164107972, v_ang=-5.720717197261967

We can also get buses data (like any other network elements) as a Pandas dataframe:

df = n.create_buses_data_frame()
print(df)
        v_mag  v_angle
VL1_0   1.060     0.00
VL2_0   1.045    -4.98
VL3_0   1.010   -12.72
VL4_0   1.019   -10.33
VL5_0   1.020    -8.78
VL6_0   1.070   -14.22
VL7_0   1.062   -13.37
VL8_0   1.090   -13.36
VL9_0   1.056   -14.94
VL10_0  1.051   -15.10
VL11_0  1.057   -14.79
VL12_0  1.055   -15.07
VL13_0  1.050   -15.16
VL14_0  1.036   -16.04

To disconnect or reconnect a line:

n.disconnect('L1-2-1')
n.connect('L1-2-1')

To open or close a switch:

n.open_switch('a_switch')
n.close_switch('a_switch')

To go further, you can also load a case file instead of creating the IEEE 14 buses network:

n = pp.network.load('test.uct')

And dump the network to another format:

n.dump('test.xiidm', 'XIIDM')

We can generate a single line diagram for a voltage level in the SVG format:

n.write_single_line_diagram_svg('VL1', '/tmp/VL1.svg')

To run a security analysis and print results table:

sa = pp.security.create_analysis()
sa.add_single_element_contingency('L1-2-1', 'c1')
sa.add_single_element_contingency('L2-3-1', 'c2')
sa.add_multiple_elements_contingency(['L1-2-1', 'L1-5-1'], 'c3')
sa_result = sa.run_ac(n)
print(sa_result.get_table())
+----------------+-----------+--------------+----------------+------------+-------+------------+---------------------+-----------------+-------+------+
| Contingency ID |   Status  | Equipment ID | Equipment name | Limit type | Limit | Limit name | Acceptable duration | Limit reduction | Value | Side |
+----------------+-----------+--------------+----------------+------------+-------+------------+---------------------+-----------------+-------+------+
|       c3       | CONVERGED |              |                |            |       |            |                     |                 |       |      |
|       c1       | CONVERGED |              |                |            |       |            |                     |                 |       |      |
|       c2       | CONVERGED |              |                |            |       |            |                     |                 |       |      |
+----------------+-----------+--------------+----------------+------------+-------+------------+---------------------+-----------------+-------+------+

To run a sensitivity analysis and print post contingency sensitivity matrix (Pandas dataframe):

sa = pp.sensitivity.create_dc_analysis()
sa.add_single_element_contingency('L1-2-1')
sa.set_branch_flow_factor_matrix(['L1-5-1', 'L2-3-1'], ['B1-G', 'B2-G', 'B3-G'])
sa_result = sa.run(n)
df = sa_result.get_post_contingency_sensitivity_matrix_flows('L1-2-1')
print(df)
      L1-5-1    L2-3-1
B1-G     0.5 -0.084423
B2-G    -0.5  0.084423
B3-G    -0.5 -0.490385

To run a load flow with hades2 instead of OLF:

Download Hades2

Create a config.yml under $HOME/.itools/

hades2:
    homeDir: <path-to-hades2>

Then specify Hades2 provider:

pp.loadflow.run_ac(n, provider="Hades2")

GitHub

https://github.com/powsybl/pypowsybl