Quick Start
In this quick start we create an extension of the Grid object, generate a random instance of it and perform power flow calculations and modifications.
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 be updated after a power flow calculation.
from dataclasses import dataclass
from typing import ClassVar
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: ClassVar = {"u": 0}
u: NDArray[np.float64]
class ExtendedLineArray(LineArray):
"""Extends the line array with an output value"""
_defaults: ClassVar = {"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 power flow 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.append(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 analyzing 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