Quick Start

In this quick start we create an extension of the Grid object, generate a random instance of it and perform loadflow calculations and modifactions.

Setting up a grid extension

This shows how to add extra values to a Grid object. If these are present in the PGM output they will updated after a loadflow calculation.

from dataclasses import dataclass

import numpy as np
from numpy.typing import NDArray

from power_grid_model_ds import GraphContainer, Grid
from power_grid_model_ds.arrays import LineArray, NodeArray


class ExtendedNodeArray(NodeArray):
    """Extends the node array with an output value"""

    _defaults = {"u": 0}

    u: NDArray[np.float64]


class ExtendedLineArray(LineArray):
    """Extends the line array with an output value"""

    _defaults = {"i_from": 0}

    i_from: NDArray[np.float64]


@dataclass
class ExtendedGrid(Grid):
    """
    This is my own grid to extend.
    """

    node: ExtendedNodeArray
    line: ExtendedLineArray
    graphs: GraphContainer

Grid Generation

The RadialGridGenerator can be used to create a randomised grid of the preferred size

from power_grid_model_ds.generators import RadialGridGenerator

grid_generator = RadialGridGenerator(grid_class=ExtendedGrid, nr_nodes=5, nr_sources=1, nr_nops=0)
grid = grid_generator.run(seed=0)

Feeder IDs

To analyse network structure from the arrays, you can use feeder ids which identify how the network is connected. All structures connected to a substation node through the same feeding branch get the same feeder_branch_id.

grid.set_feeder_ids()
print(grid.node)
print(grid.line)
 id | u_rated | node_type | feeder_branch_id | feeder_node_id |  u  
 1  | 10500.0 |     0     |        22        |       16       | 0.0 
 2  | 10500.0 |     0     |        18        |       16       | 0.0 
 3  | 10500.0 |     0     |        18        |       16       | 0.0 
 4  | 10500.0 |     0     |        18        |       16       | 0.0 
 5  | 10500.0 |     0     |        18        |       16       | 0.0 
 16 | 10500.0 |     1     |   -2147483648    |  -2147483648   | 0.0 
 id | from_node | to_node | from_status | to_status | feeder_branch_id | feeder_node_id | is_feeder |   r1  |   x1  |  c1 | tan1 |   i_n    | i_from 
 18 |     16    |    5    |      1      |     1     |        18        |       16       |    True   |0.003..|4.538..| 0.0 | 0.0  |303.9194..|  0.0   
 19 |     5     |    3    |      1      |     1     |        18        |       16       |   False   |0.134..|0.015..| 0.0 | 0.0  |425.9880..|  0.0   
 20 |     5     |    4    |      1      |     1     |        18        |       16       |   False   |0.657..|2.575..| 0.0 | 0.0  |1311.550..|  0.0   
 21 |     4     |    2    |      1      |     1     |        18        |       16       |   False   |0.213..|0.016..| 0.0 | 0.0  |114.4995..|  0.0   
 22 |     16    |    1    |      1      |     1     |        22        |       16       |    True   |0.070..|0.006..| 0.0 | 0.0  |729.9817..|  0.0   

Performing Loadflow calculations

Using the PowerGridModelInterface the Grid data can be provided to the calculation engine. Using update_grid values can be transferred to the Grid object.

from power_grid_model_ds import PowerGridModelInterface

core_interface = PowerGridModelInterface(grid=grid)

core_interface.create_input_from_grid()
core_interface.calculate_power_flow()
core_interface.update_grid()

print(grid.node)
print(grid.line)
 id | u_rated | node_type | feeder_branch_id | feeder_node_id |     u     
 1  | 10500.0 |     0     |        22        |       16       |10502.405..
 2  | 10500.0 |     0     |        18        |       16       |10519.046..
 3  | 10500.0 |     0     |        18        |       16       |10512.620..
 4  | 10500.0 |     0     |        18        |       16       |10517.268..
 5  | 10500.0 |     0     |        18        |       16       |10500.888..
 16 | 10500.0 |     1     |   -2147483648    |  -2147483648   |10500.242..
 id | from_node | to_node | from_status | to_status | feeder_branch_id | feeder_node_id | is_feeder |   r1  |   x1  |  c1 | tan1 |   i_n    | i_from 
 18 |     16    |    5    |      1      |     1     |        18        |       16       |    True   |0.003..|4.538..| 0.0 | 0.0  |303.9194..|94.045..
 19 |     5     |    3    |      1      |     1     |        18        |       16       |   False   |0.134..|0.015..| 0.0 | 0.0  |425.9880..|50.191..
 20 |     5     |    4    |      1      |     1     |        18        |       16       |   False   |0.657..|2.575..| 0.0 | 0.0  |1311.550..|14.410..
 21 |     4     |    2    |      1      |     1     |        18        |       16       |   False   |0.213..|0.016..| 0.0 | 0.0  |114.4995..|4.8767..
 22 |     16    |    1    |      1      |     1     |        22        |       16       |    True   |0.070..|0.006..| 0.0 | 0.0  |729.9817..|17.570..

Modifying the Grid

The Grid object can be changed by adding objects or changing normally open points (NOPs).

new_line = ExtendedLineArray(
    from_node=[3],
    to_node=[1],
    r1=[0.6],
    x1=[0.2],
    i_n=[100],
    tan1=[0.0],
    from_status=[1],
    to_status=[1],
    c1=[0.0],
)

grid.add_branch(branch=new_line)

old_line = grid.line.get(19)
grid.make_inactive(branch=old_line)

This will give new outputs of the previous functions

core_interface = PowerGridModelInterface(grid=grid)
core_interface.create_input_from_grid()
core_interface.calculate_power_flow()
core_interface.update_grid()

grid.set_feeder_ids()
print(grid.node)
print(grid.line)
 id | u_rated | node_type | feeder_branch_id | feeder_node_id |     u     
 1  | 10500.0 |     0     |        22        |       16       |10508.537..
 2  | 10500.0 |     0     |        18        |       16       |10518.700..
 3  | 10500.0 |     0     |        22        |       16       |10560.743..
 4  | 10500.0 |     0     |        18        |       16       |10516.922..
 5  | 10500.0 |     0     |        18        |       16       |10500.541..
 16 | 10500.0 |     1     |   -2147483648    |  -2147483648   |10500.240..
 id | from_node | to_node | from_status | to_status | feeder_branch_id | feeder_node_id | is_feeder |   r1  |   x1  |  c1 | tan1 |   i_n    | i_from 
 18 |     16    |    5    |      1      |     1     |        18        |       16       |    True   |0.003..|4.538..| 0.0 | 0.0  |303.9194..|43.872..
 19 |     5     |    3    |      1      |     0     |   -2147483648    |  -2147483648   |   False   |0.134..|0.015..| 0.0 | 0.0  |425.9880..|  0.0   
 20 |     5     |    4    |      1      |     1     |        18        |       16       |   False   |0.657..|2.575..| 0.0 | 0.0  |1311.550..|14.410..
 21 |     4     |    2    |      1      |     1     |        18        |       16       |   False   |0.213..|0.016..| 0.0 | 0.0  |114.4995..|4.8769..
 22 |     16    |    1    |      1      |     1     |        22        |       16       |    True   |0.070..|0.006..| 0.0 | 0.0  |729.9817..|67.481..
 23 |     3     |    1    |      1      |     1     |        22        |       16       |   False   |  0.6  |  0.2  | 0.0 | 0.0  |  100.0   |49.962..

Analyzing Grid structure

The Grid also contains a graph representation which can be used for anayling structure. Such as finding the shortest path between two nodes.

path, length = grid.graphs.active_graph.get_shortest_path(1, 4)
print(f"Shortest path: {path}, Length: {length}")
Shortest path: [1, 16, 5, 4], Length: 3