Asym Line Example

In this notebook we will present examples of asymmetric lines in power-grid-model.

Different input formats are covered. We will do one-time power flow calculation and one-time state estimation.

This notebook serves as an example of how to use the Python API. For detailed API documentation, refer to Python API reference and Native Data Interface.

Asym Line

Asym Line is described as a pi model in power-grid-model, and it belongs to the branch component type which connects two nodes with possibly different voltage levels.

Example Network

We use a simple network with 3 nodes, 1 source, 1 load and 2 asym lines. As shown below:

   source_1 --- node_2 --- asym_line_3 --- node_4 --- asym_line_5 --- node_6 --- load_7
# some basic imports
import numpy as np
import pandas as pd

from power_grid_model import (
    CalculationMethod,
    CalculationType,
    ComponentType,
    DatasetType,
    LoadGenType,
    MeasuredTerminalType,
    PowerGridModel,
    initialize_array,
)

Input Dataset

We create an input dataset by using the helper function initialize_array.

Please refer to Components for detailed explanation of all component types and their input/output attributes.

# node
node = initialize_array(DatasetType.input, ComponentType.node, 3)
node["id"] = np.array([2, 4, 6])
node["u_rated"] = [1e3, 1e3, 1e3]

# load
asym_load = initialize_array(DatasetType.input, ComponentType.asym_load, 1)
asym_load["id"] = [7]
asym_load["node"] = [6]
asym_load["status"] = [1]
asym_load["type"] = [LoadGenType.const_power]
asym_load["p_specified"] = [[1000.0, 2000.0, 3000.0]]
asym_load["q_specified"] = [[1000.0, 2000.0, 3000.0]]

# source
source = initialize_array(DatasetType.input, ComponentType.source, 1)
source["id"] = [1]
source["node"] = [2]
source["status"] = [1]
source["u_ref"] = [1.0]

# asym_line
asym_line = initialize_array(DatasetType.input, ComponentType.asym_line, 2)
asym_line["id"] = [3, 5]
asym_line["from_node"] = [2, 4]
asym_line["to_node"] = [4, 6]
asym_line["from_status"] = [1, 1]
asym_line["to_status"] = [1, 1]
asym_line["r_aa"] = [0.6904, 0.6904]
asym_line["r_ba"] = [0.0495, 0.0495]
asym_line["r_bb"] = [0.6904, 0.6904]
asym_line["r_ca"] = [0.0492, 0.0492]
asym_line["r_cb"] = [0.0495, 0.0495]
asym_line["r_cc"] = [0.6904, 0.6904]
asym_line["r_na"] = [0.0495, np.nan]
asym_line["r_nb"] = [0.0492, np.nan]
asym_line["r_nc"] = [0.0495, np.nan]
asym_line["r_nn"] = [0.6904, np.nan]
asym_line["x_aa"] = [0.8316, 0.8316]
asym_line["x_ba"] = [0.7559, 0.7559]
asym_line["x_bb"] = [0.8316, 0.8316]
asym_line["x_ca"] = [0.7339, 0.7339]
asym_line["x_cb"] = [0.7559, 0.7559]
asym_line["x_cc"] = [0.8316, 0.8316]
asym_line["x_na"] = [0.7559, np.nan]
asym_line["x_nb"] = [0.7339, np.nan]
asym_line["x_nc"] = [0.7559, np.nan]
asym_line["x_nn"] = [0.8316, np.nan]
asym_line["c0"] = [0.32e-9, np.nan]
asym_line["c1"] = [0.54e-9, np.nan]
asym_line["c_aa"] = [np.nan, 0.3200e-09]
asym_line["c_ba"] = [np.nan, 0.5400e-09]
asym_line["c_bb"] = [np.nan, 0.3200e-09]
asym_line["c_ca"] = [np.nan, 0.7600e-09]
asym_line["c_cb"] = [np.nan, 0.5400e-09]
asym_line["c_cc"] = [np.nan, 0.3200e-09]
asym_line["i_n"] = [1000, 1000]

# all
input_data = {
    ComponentType.node: node,
    ComponentType.asym_line: asym_line,
    ComponentType.asym_load: asym_load,
    ComponentType.source: source,
}

We can print the input dataset by converting the numpy array to dataframe.

print(pd.DataFrame(input_data[ComponentType.asym_line]))
   id  from_node  to_node  from_status  to_status    r_aa    r_ba    r_bb  \
0   3          2        4            1          1  0.6904  0.0495  0.6904   
1   5          4        6            1          1  0.6904  0.0495  0.6904   

     r_ca    r_cb  ...    x_nn          c_aa          c_ba          c_bb  \
0  0.0492  0.0495  ...  0.8316           NaN           NaN           NaN   
1  0.0492  0.0495  ...     NaN  3.200000e-10  5.400000e-10  3.200000e-10   

           c_ca          c_cb          c_cc            c0            c1  \
0           NaN           NaN           NaN  3.200000e-10  5.400000e-10   
1  7.600000e-10  5.400000e-10  3.200000e-10           NaN           NaN   

      i_n  
0  1000.0  
1  1000.0  

[2 rows x 34 columns]

One-time Power Flow Calculation

You can call the method calculate_power_flow to do a one-time calculation based on the current network data in the model.

For detailed explanation of the arguments, batch calculations and asymmetric calculations, we refer to the Power Flow Example and Asymmetric Calculation Example.

# validation (optional)
from power_grid_model.validation import assert_valid_input_data

assert_valid_input_data(input_data=input_data, calculation_type=CalculationType.power_flow)

# construction
model = PowerGridModel(input_data)

# one-time power flow calculation
output_data = model.calculate_power_flow(
    symmetric=False, error_tolerance=1e-8, max_iterations=20, calculation_method=CalculationMethod.newton_raphson
)

# result dataset
print("------node voltage result------")
print(pd.DataFrame(output_data[ComponentType.node]["u"]))
print("------node angle result------")
print(pd.DataFrame(output_data[ComponentType.node]["u_angle"]))
------node voltage result------
            0           1           2
0  577.350081  577.349890  577.349692
1  577.543188  574.815533  571.914289
2  579.346994  570.159376  567.087326
------node angle result------
              0         1         2
0 -2.686835e-07 -2.094396  2.094394
1  4.811479e-05 -2.087729  2.097964
2  2.919948e-03 -2.079969  2.097696

One-time State Estimation

Below we present a simple example of state estimation for a network with two asym lines.

NOTE: In power-grid-model, asym lines belong to branch component type, therefore the measured_terminal_type of power sensors should be assigned to MeasuredTerminalType.branch_from/_to.

For detailed explanation of the arguments, batch calculations and asymmetric calculations, we refer to the State Estimation Example and Asymmetric Calculation Example.

# voltage sensor
asym_voltage_sensor = initialize_array(DatasetType.input, ComponentType.asym_voltage_sensor, 1)
asym_voltage_sensor["id"] = [8]
asym_voltage_sensor["measured_object"] = [6]
asym_voltage_sensor["u_sigma"] = [1.0]
asym_voltage_sensor["u_measured"] = [[1000, 1000, 1000]]

# power sensor
asym_power_sensor = initialize_array(DatasetType.input, ComponentType.asym_power_sensor, 4)
asym_power_sensor["id"] = [9, 10, 11, 12]
asym_power_sensor["measured_object"] = [3, 3, 5, 5]
asym_power_sensor["measured_terminal_type"] = [
    MeasuredTerminalType.branch_from,
    MeasuredTerminalType.branch_to,
    MeasuredTerminalType.branch_from,
    MeasuredTerminalType.branch_to,
]
asym_power_sensor["power_sigma"] = [500.0, 500.0, 500.0, 500.0]
asym_power_sensor["p_measured"] = [[1000, 2000, 3000], [1000, 2000, 3000], [1000, 2000, 3000], [1000, 2000, 3000]]
asym_power_sensor["q_measured"] = [[1000, 2000, 3000], [1000, 2000, 3000], [1000, 2000, 3000], [1000, 2000, 3000]]

# use components from former input dataset cell.
input_data2 = {
    ComponentType.node: node,
    ComponentType.asym_line: asym_line,
    ComponentType.asym_load: asym_load,
    ComponentType.source: source,
    ComponentType.asym_voltage_sensor: asym_voltage_sensor,
    ComponentType.asym_power_sensor: asym_power_sensor,
}

# validation (optional)
from power_grid_model.validation import assert_valid_input_data

assert_valid_input_data(input_data=input_data2, calculation_type=CalculationType.state_estimation)

# construction
model2 = PowerGridModel(input_data2)

# one-time state estimation
output_data2 = model2.calculate_state_estimation(
    symmetric=False, error_tolerance=1e-8, max_iterations=20, calculation_method=CalculationMethod.iterative_linear
)

# result dataset
print("------node result------")
print(pd.DataFrame(output_data2[ComponentType.node]["u"]))
------node result------
             0           1            2
0  1000.000001  999.999991  1000.000007
1  1000.000019  999.999988   999.999997
2  1000.000001  999.999999   999.999999