Transformer Example

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

Both two-winding transformer and three-winding transformer are covered. We will do one-time power flow calculation and one-time state estimation for both types of tranformers.

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.

Transformer (Two-winding Transformer)

Transformer 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 2 nodes, 1 source, 1 load and 1 transformer. As shown below:

   source_1 --- node_2 --- transformer_3 --- node_4 --- load_5

# some basic imports
import numpy as np
import warnings

with warnings.catch_warnings(action="ignore", category=DeprecationWarning):
    # suppress warning about pyarrow as future required dependency
    import pandas as pd

from power_grid_model import LoadGenType
from power_grid_model import PowerGridModel, CalculationMethod, CalculationType, MeasuredTerminalType
from power_grid_model import 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("input", "node", 2)
node["id"] = np.array([2, 4])
node["u_rated"] = [1e4, 4e2]

# load
sym_load = initialize_array("input", "sym_load", 1)
sym_load["id"] = [5]
sym_load["node"] = [4]
sym_load["status"] = [1]
sym_load["type"] = [LoadGenType.const_power]
sym_load["p_specified"] = [1e3]
sym_load["q_specified"] = [5e3]

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

# transformer
transformer = initialize_array("input", "transformer", 1)
transformer["id"] = [3]
transformer["from_node"] = [2]
transformer["to_node"] = [4]
transformer["from_status"] = [1]
transformer["to_status"] = [1]
transformer["u1"] = [1e4]
transformer["u2"] = [4e2]
transformer["sn"] = [1e5]
transformer["uk"] = [0.1]
transformer["pk"] = [1e3]
transformer["i0"] = [1.0e-6]
transformer["p0"] = [0.1]
transformer["winding_from"] = [2]
transformer["winding_to"] = [1]
transformer["clock"] = [5]
transformer["tap_side"] = [0]
transformer["tap_pos"] = [3]
transformer["tap_min"] = [-11]
transformer["tap_max"] = [9]
transformer["tap_size"] = [100]

# all
input_data = {
    "node": node, 
    "transformer": transformer, 
    "sym_load": sym_load, 
    "source": source
}

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

print(pd.DataFrame(input_data["transformer"]))
   id  from_node  to_node  from_status  to_status       u1     u2        sn  \
0   3          2        4            1          1  10000.0  400.0  100000.0   

    uk      pk  ...  tap_nom  tap_size  uk_min  uk_max  pk_min  pk_max  \
0  0.1  1000.0  ...     -128     100.0     NaN     NaN     NaN     NaN   

   r_grounding_from  x_grounding_from  r_grounding_to  x_grounding_to  
0               NaN               NaN             NaN             NaN  

[1 rows x 29 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=True, 
    error_tolerance=1e-8, 
    max_iterations=20, 
    calculation_method=CalculationMethod.newton_raphson
)

# result dataset
print("------node result------")
print(pd.DataFrame(output_data["node"]))
------node result------
   id  energized      u_pu            u       u_angle            p  \
0   2          1  0.999999  9999.994897 -4.976260e-08  1002.882212   
1   4          1  0.965618   386.247005 -2.618522e+00 -1000.000000   

             q  
0  5027.744841  
1 -5000.000000  

One-time State Estimation

Below we present a simple example of state estimation for a network with a two-winding transformer.

NOTE: In power-grid-model, two-winding transformers 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
sym_voltage_sensor = initialize_array("input", "sym_voltage_sensor", 2)
sym_voltage_sensor["id"] = [6, 7]
sym_voltage_sensor["measured_object"] = [2, 4]
sym_voltage_sensor["u_sigma"] = [1.0, 1.0]
sym_voltage_sensor["u_measured"] = [1e5, 4e2]

# power sensor
sym_power_sensor = initialize_array("input", "sym_power_sensor", 2)
sym_power_sensor["id"] = [8, 9]
sym_power_sensor["measured_object"] = [3, 3]
sym_power_sensor["measured_terminal_type"] = [
    MeasuredTerminalType.branch_from,
    MeasuredTerminalType.branch_to,
]
sym_power_sensor["power_sigma"] = [1.0, 1.0]
sym_power_sensor["p_measured"] = [2e6, 1e5]
sym_power_sensor["q_measured"] = [2e7, 1e6]

# use components from former input dataset cell.
input_data2 = {
    "node": node,
    "transformer": transformer,
    "sym_load": sym_load,
    "source": source,
    "sym_voltage_sensor": sym_voltage_sensor,
    "sym_power_sensor": sym_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=True, 
    error_tolerance=1e-8, 
    max_iterations=20, 
    calculation_method=CalculationMethod.iterative_linear
)

# result dataset
print("------node result------")
print(pd.DataFrame(output_data2["node"]))
------node result------
   id  energized      u_pu             u   u_angle              p  \
0   2          1  9.987392  99873.919714  0.000000  470658.914282   
1   4          1  9.209290   3683.716125 -2.617974 -446912.927660   

              q  
0  4.700696e+06  
1 -4.464515e+06  

Three-Winding Transformer

Three-winding transformer is described as 3 transformers of pi model each connected together in star configuration, and it belongs to the branch3 component type which connects three nodes with possibly different voltage levels.

Example Network

We use a simple network with 3 nodes, 1 source, 1 load and 1 three-winding transformer. As shown below:

   source_1 --- node_2 --- three_winding_transformer_3 --- node_4 --- load_5
                                        |
                                        -------------------node_6 --- load_7
                                    

Input Dataset

We use the helper function initialize_array to create an input dataset.

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

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

# load
sym_load = initialize_array("input", "sym_load", 2)
sym_load["id"] = [5, 7]
sym_load["node"] = [4, 6]
sym_load["status"] = [1]
sym_load["type"] = [LoadGenType.const_power]
sym_load["p_specified"] = [1e3, 1e3]
sym_load["q_specified"] = [5e3, 5e3]

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

# three-winding transformer
three_winding_transformer = initialize_array("input", "three_winding_transformer", 1)
three_winding_transformer["id"] = [3]
three_winding_transformer["node_1"] = [2]
three_winding_transformer["node_2"] = [4]
three_winding_transformer["node_3"] = [6]
three_winding_transformer["status_1"] = [1]
three_winding_transformer["status_2"] = [1]
three_winding_transformer["status_3"] = [1]
three_winding_transformer["u1"] = [1e4]
three_winding_transformer["u2"] = [1e2]
three_winding_transformer["u3"] = [1e2]
three_winding_transformer["sn_1"] = [1e5]
three_winding_transformer["sn_2"] = [1e5]
three_winding_transformer["sn_3"] = [1e5]
three_winding_transformer["uk_12"] = [0.09]
three_winding_transformer["uk_13"] = [0.06]
three_winding_transformer["uk_23"] = [0.06]
three_winding_transformer["pk_12"] = [1e3]
three_winding_transformer["pk_13"] = [1e3]
three_winding_transformer["pk_23"] = [1e3]
three_winding_transformer["i0"] = [0]
three_winding_transformer["p0"] = [0]
three_winding_transformer["winding_1"] = [2]
three_winding_transformer["winding_2"] = [1]
three_winding_transformer["winding_3"] = [1]
three_winding_transformer["clock_12"] = [5]
three_winding_transformer["clock_13"] = [5]
three_winding_transformer["tap_side"] = [0]
three_winding_transformer["tap_pos"] = [0]
three_winding_transformer["tap_min"] = [-10]
three_winding_transformer["tap_max"] = [10]
three_winding_transformer["tap_nom"] = [0]
three_winding_transformer["tap_size"] = [1380]

# all
input_data3 = {
    "node": node,
    "three_winding_transformer": three_winding_transformer,
    "sym_load": sym_load,
    "source": source
}

One-time power flow calculation

# validation (optional)
from power_grid_model.validation import assert_valid_input_data
assert_valid_input_data(input_data=input_data3, calculation_type=CalculationType.power_flow)

# construction
model3 = PowerGridModel(input_data3)

# one-time power flow calculation
output_data3 = model3.calculate_power_flow(
    symmetric=True,
    error_tolerance=1e-8,
    max_iterations=20,
    calculation_method=CalculationMethod.newton_raphson)

# result dataset
print("------node result------")
print(pd.DataFrame(output_data3["node"]))
------node result------
   id  energized      u_pu            u       u_angle            p  \
0   2          1  0.999999  9999.989788 -9.966674e-08  2007.896574   
1   4          1  0.993097    99.309655 -2.618590e+00 -1000.000000   
2   6          1  0.994637    99.463733 -2.618281e+00 -1000.000000   

              q  
0  10062.592544  
1  -5000.000000  
2  -5000.000000  

One-time State Estimation

Below we present a simple example of state estimation for a network with a three-winding transformer.

NOTE: In power-grid-model, three-winding transformers belong to branch3 component type, therefore the measured_terminal_type of power sensors should be assigned to MeasuredTerminalType.branch3_1/_2/_3.

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

# voltage sensor
sym_voltage_sensor = initialize_array("input", "sym_voltage_sensor", 3)
sym_voltage_sensor["id"] = [8, 9, 10]
sym_voltage_sensor["measured_object"] = [2, 4, 6]
sym_voltage_sensor["u_sigma"] = [1.0, 1.0, 1.0]
sym_voltage_sensor["u_measured"] = [1e4, 1e2, 1e2]

# power sensor
sym_power_sensor = initialize_array("input", "sym_power_sensor", 3)
sym_power_sensor["id"] = [11, 12, 13]
sym_power_sensor["measured_object"] = [3, 3, 3]
sym_power_sensor["measured_terminal_type"] = [
    MeasuredTerminalType.branch3_1,
    MeasuredTerminalType.branch3_2,
    MeasuredTerminalType.branch3_3,
]
sym_power_sensor["power_sigma"] = [1.0, 1.0, 1.0]
sym_power_sensor["p_measured"] = [2e3, 1e3, 1e3]
sym_power_sensor["q_measured"] = [1e4, 5e3, 5e3]

# use components from the one-time power flow calculation with three-winding transformer
input_data4 = {
    "node": node,
    "three_winding_transformer": three_winding_transformer,
    "sym_load": sym_load,
    "source": source,
    "sym_voltage_sensor": sym_voltage_sensor,
    "sym_power_sensor": sym_power_sensor,
}

# validation (optional)
from power_grid_model.validation import assert_valid_input_data

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

# construction
model4 = PowerGridModel(input_data4)

# one-time state estimation
output_data4 = model4.calculate_state_estimation(
    symmetric=True, 
    error_tolerance=1e-8, 
    max_iterations=20, 
    calculation_method=CalculationMethod.iterative_linear
)

# result dataset
print("------three-winding transformer result------")
print(pd.DataFrame(output_data4["three_winding_transformer"]))
------three-winding transformer result------
   id  energized   loading         p_1         q_1       i_1          s_1  \
0   3          1  0.033993  667.156598  3333.23678  0.196261  3399.347785   

          p_2          q_2       i_2          s_2         p_3          q_3  \
0 -333.400686 -1662.691395  9.813068  1695.788516 -332.889246 -1663.677083   

        i_3          s_3  
0  9.813068  1696.654557