From dbe0af0aec63e2ce3d40418fbf703bf247afe2a6 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 21 Nov 2025 11:29:40 +0100 Subject: [PATCH 01/23] try to fix transformer yyn Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../component/transformer.hpp | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 381a03516..e473f7975 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -232,17 +232,29 @@ class Transformer : public Branch { DoubleComplex const y0_series = 1.0 / z0_series; param0 = calc_param_y_sym(y0_series, y_shunt, k * std::exp(1.0i * phase_shift_0)); } - // YNd - if (winding_from_ == WindingType::wye_n && winding_to_ == WindingType::delta && from_status()) { - DoubleComplex const z0_series = 1.0 / y_series + 3.0 * z_grounding_from_ / k / k; - DoubleComplex const y0_series = 1.0 / z0_series; - param0.yff() = (y0_series + y_shunt) / k / k; + // YN* + if (winding_from_ == WindingType::wye_n && from_status()) { + // ground path always possible via magnetization branch + DoubleComplex y0 = y_shunt; + if (winding_to_ == WindingType::delta) { + // additional path via zk + y0 += y_series; + } + DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_from_ / k / k; + y0 = 1.0 / z0; + param0.yff() = y0 / k / k; } - // Dyn - if (winding_from_ == WindingType::delta && winding_to_ == WindingType::wye_n && to_status()) { - DoubleComplex const z0_series = 1.0 / y_series + 3.0 * z_grounding_to_; - DoubleComplex const y0_series = 1.0 / z0_series; - param0.ytt() = (y0_series + y_shunt); + // *YN + if (winding_to_ == WindingType::wye_n && to_status()) { + // ground path always possible via magnetization branch + DoubleComplex y0 = y_shunt; + if (winding_from_ == WindingType::delta) { + // additional path via zk + y0 += y_series; + } + DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_to_; + y0 = 1.0 / z0; + param0.ytt() = y0; } // ZN* // Zero sequence impedance of zigzag winding is approximately 10% of positive sequence impedance From ff68cfb8a811a8fef60db02129ca9981724721d3 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:15:07 +0100 Subject: [PATCH 02/23] fix YNyn Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../include/power_grid_model/component/transformer.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index e473f7975..62f36efca 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -233,7 +233,7 @@ class Transformer : public Branch { param0 = calc_param_y_sym(y0_series, y_shunt, k * std::exp(1.0i * phase_shift_0)); } // YN* - if (winding_from_ == WindingType::wye_n && from_status()) { + else if (winding_from_ == WindingType::wye_n && from_status()) { // ground path always possible via magnetization branch DoubleComplex y0 = y_shunt; if (winding_to_ == WindingType::delta) { @@ -244,8 +244,8 @@ class Transformer : public Branch { y0 = 1.0 / z0; param0.yff() = y0 / k / k; } - // *YN - if (winding_to_ == WindingType::wye_n && to_status()) { + // *yn + else if (winding_to_ == WindingType::wye_n && to_status()) { // ground path always possible via magnetization branch DoubleComplex y0 = y_shunt; if (winding_from_ == WindingType::delta) { From 58ff7980e05244fe2106171f35f46f756817d754 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 21 Nov 2025 13:22:28 +0100 Subject: [PATCH 03/23] fix test Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- tests/cpp_unit_tests/test_transformer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cpp_unit_tests/test_transformer.cpp b/tests/cpp_unit_tests/test_transformer.cpp index 6b6417911..1a0a3920a 100644 --- a/tests/cpp_unit_tests/test_transformer.cpp +++ b/tests/cpp_unit_tests/test_transformer.cpp @@ -485,7 +485,7 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { DoubleComplex const y_0_ff = low_admittance; DoubleComplex const y_0_ft = 0.0; DoubleComplex const y_0_tf = 0.0; - DoubleComplex const y_0_tt = (1.0 / (z_1_series + 3.0 * z_grounding_to)) + y_1_shunt; + DoubleComplex const y_0_tt = (1.0 / (1.0 / (1.0 / z_1_series + y_1_shunt) + 3.0 * z_grounding_to)); // Sequence admittances -> phase addmitance ComplexTensor y_ff_diagonal; @@ -707,7 +707,7 @@ TEST_CASE("Test Transformer - Dyn11 - tap_max and tap_min flipped") { DoubleComplex const y_0_ff = low_admittance; DoubleComplex const y_0_ft = 0.0; DoubleComplex const y_0_tf = 0.0; - DoubleComplex const y_0_tt = (1.0 / (z_1_series + 3.0 * z_grounding_to)) + y_1_shunt; + DoubleComplex const y_0_tt = (1.0 / (1.0 / (1.0 / z_1_series + y_1_shunt) + 3.0 * z_grounding_to)); // Sequence admittances -> phase addmitance ComplexTensor y_ff_diagonal; From 3b632cdd9c3589e1b6c06efa190c99b85ec2b967 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:35:34 +0100 Subject: [PATCH 04/23] add info to debug Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- tests/cpp_unit_tests/test_three_winding_transformer.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cpp_unit_tests/test_three_winding_transformer.cpp b/tests/cpp_unit_tests/test_three_winding_transformer.cpp index 9a8ae7a72..36b07d3a9 100644 --- a/tests/cpp_unit_tests/test_three_winding_transformer.cpp +++ b/tests/cpp_unit_tests/test_three_winding_transformer.cpp @@ -298,11 +298,14 @@ TEST_CASE("Test three winding transformer") { for (size_t trafo = 0; trafo < trafos_vec.size(); ++trafo) { std::array, 3> calc_params = vec[trafo].calc_param(); std::array, 3> test_params = vec[trafo].calc_param(); + INFO("Asym 3w trafo test for trafo no: " << trafo); for (size_t i = 0; i < 3; ++i) { calc_params[i] = trafos_vec[trafo][i].calc_param(); } for (size_t i = 0; i < 3; i++) { + INFO(" Winding no: " << i); for (size_t value_no = 0; value_no < calc_params[i].value.size(); ++value_no) { + INFO(" Value no: " << value_no); CHECK((cabs(calc_params[i].value[value_no] - test_params[i].value[value_no]) < numerical_tolerance) .all()); } From ee6bc78ade99ec72e30fcf0ffc273e5c4747549d Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 21 Nov 2025 14:51:55 +0100 Subject: [PATCH 05/23] add info to debug Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- tests/cpp_unit_tests/test_three_winding_transformer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/cpp_unit_tests/test_three_winding_transformer.cpp b/tests/cpp_unit_tests/test_three_winding_transformer.cpp index 36b07d3a9..0428bb038 100644 --- a/tests/cpp_unit_tests/test_three_winding_transformer.cpp +++ b/tests/cpp_unit_tests/test_three_winding_transformer.cpp @@ -306,6 +306,8 @@ TEST_CASE("Test three winding transformer") { INFO(" Winding no: " << i); for (size_t value_no = 0; value_no < calc_params[i].value.size(); ++value_no) { INFO(" Value no: " << value_no); + INFO(" Calc: " << calc_params[i].value[value_no]); + INFO(" Test: " << test_params[i].value[value_no]); CHECK((cabs(calc_params[i].value[value_no] - test_params[i].value[value_no]) < numerical_tolerance) .all()); } From cf3d2a929a0696b8359205eaece7eed4c966755b Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 21 Nov 2025 15:16:54 +0100 Subject: [PATCH 06/23] avoid exact zero division Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../power_grid_model/component/transformer.hpp | 18 ++++++++++++------ .../test_three_winding_transformer.cpp | 5 ----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 62f36efca..01e76e70a 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -240,9 +240,12 @@ class Transformer : public Branch { // additional path via zk y0 += y_series; } - DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_from_ / k / k; - y0 = 1.0 / z0; - param0.yff() = y0 / k / k; + if (y0 != DoubleComplex{0.0, 0.0}) { + // avoid division by zero + DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_from_ / k / k; + y0 = 1.0 / z0; + param0.yff() = y0 / k / k; + } } // *yn else if (winding_to_ == WindingType::wye_n && to_status()) { @@ -252,9 +255,12 @@ class Transformer : public Branch { // additional path via zk y0 += y_series; } - DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_to_; - y0 = 1.0 / z0; - param0.ytt() = y0; + if (y0 != DoubleComplex{0.0, 0.0}) { + // avoid division by zero + DoubleComplex const z0 = 1.0 / y0 + 3.0 * z_grounding_to_; + y0 = 1.0 / z0; + param0.ytt() = y0; + } } // ZN* // Zero sequence impedance of zigzag winding is approximately 10% of positive sequence impedance diff --git a/tests/cpp_unit_tests/test_three_winding_transformer.cpp b/tests/cpp_unit_tests/test_three_winding_transformer.cpp index 0428bb038..9a8ae7a72 100644 --- a/tests/cpp_unit_tests/test_three_winding_transformer.cpp +++ b/tests/cpp_unit_tests/test_three_winding_transformer.cpp @@ -298,16 +298,11 @@ TEST_CASE("Test three winding transformer") { for (size_t trafo = 0; trafo < trafos_vec.size(); ++trafo) { std::array, 3> calc_params = vec[trafo].calc_param(); std::array, 3> test_params = vec[trafo].calc_param(); - INFO("Asym 3w trafo test for trafo no: " << trafo); for (size_t i = 0; i < 3; ++i) { calc_params[i] = trafos_vec[trafo][i].calc_param(); } for (size_t i = 0; i < 3; i++) { - INFO(" Winding no: " << i); for (size_t value_no = 0; value_no < calc_params[i].value.size(); ++value_no) { - INFO(" Value no: " << value_no); - INFO(" Calc: " << calc_params[i].value[value_no]); - INFO(" Test: " << test_params[i].value[value_no]); CHECK((cabs(calc_params[i].value[value_no] - test_params[i].value[value_no]) < numerical_tolerance) .all()); } From 6507e448d641e9ce99d75b135d9504d8bf86f977 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:25:36 +0100 Subject: [PATCH 07/23] add new validation case Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../asym_output.json | 21 +++++++++++++++++++ .../asym_output.json.license | 3 +++ .../zero_sequence_yyn_transformer/input.json | 21 +++++++++++++++++++ .../input.json.license | 3 +++ .../zero_sequence_yyn_transformer/params.json | 7 +++++++ .../params.json.license | 3 +++ 6 files changed, 58 insertions(+) create mode 100644 tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json create mode 100644 tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license create mode 100644 tests/data/power_flow/zero_sequence_yyn_transformer/input.json create mode 100644 tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license create mode 100644 tests/data/power_flow/zero_sequence_yyn_transformer/params.json create mode 100644 tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json new file mode 100644 index 000000000..90c01815f --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "asym_output", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 1, "energized": 1, "u_pu": [1, 1, 1], "u": [5773.5026918962576, 5773.5026918962576, 5773.5026918962576], "u_angle": [-2.474640575439679e-44, -2.0943951023931953, 2.0943951023931953], "p": [824880.19181322691, 1072224.8788595221, 1102894.9293272516], "q": [218912.27669635782, 40693.031260342112, 344009.43645155017]}, + {"id": 2, "energized": 1, "u_pu": [1.1450055302608289, 0.94457144911056157, 0.91924181371456271], "u": [6610.6925111969977, 5453.4858041281759, 5307.2450859846258], "u_angle": [-0.03356887190092963, -1.984902584683417, 1.9252028204298137], "p": [-949999.9999999979, -1000000.0000000031, -1049999.9999999963], "q": [1.6449686064130695e-08, -3.0224494451098491e-09, 3.984667595393038e-09]} + ], + "transformer": [ + {"id": 4, "energized": 1, "loading": 0.30817316848870924, "p_from": [824880.19181322691, 1072224.8788595221, 1102894.9293272516], "q_from": [218912.27669635782, 40693.031260342126, 344009.43645155017], "i_from": [147.81913770559706, 185.84849584851148, 200.10395179782012], "s_from": [853434.18945704808, 1072996.791066251, 1155300.7043637931], "p_to": [-949999.9999999979, -1000000.0000000031, -1049999.9999999963], "q_to": [1.644994521118116e-08, -2.9986559036607486e-09, 3.9875615770433002e-09], "i_to": [143.70657815212488, 183.36895628169123, 197.84275702149816], "s_to": [949999.9999999979, 1000000.0000000031, 1049999.9999999963]} + ], + "asym_load": [ + {"id": 6, "energized": 1, "p": [950000, 1000000, 1050000], "q": [0, 0, 0], "i": [143.70657815212516, 183.36895628169069, 197.84275702149884], "s": [950000, 1000000, 1050000], "pf": [1, 1, 1]} + ], + "source": [ + {"id": 7, "energized": 1, "p": [824880.19181322691, 1072224.8788595221, 1102894.9293272516], "q": [218912.27669635782, 40693.031260342126, 344009.43645155017], "i": [147.81913770559706, 185.84849584851148, 200.10395179782012], "s": [853434.18945704808, 1072996.791066251, 1155300.7043637931], "pf": [0.96654223840975118, 0.99928060157014831, 0.9546388443817313]} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/input.json b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json new file mode 100644 index 000000000..9acc18b90 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json @@ -0,0 +1,21 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000} + ], + "transformer": [ + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 10000000, "uk": 0.10000000000000001, "pk": 0, "i0": 0.050000000000000003, "p0": 0, "winding_from": 0, "winding_to": 1, "clock": 12, "tap_side": 0, "tap_pos": 0, "tap_min": 0, "tap_max": 0, "tap_nom": 0, "tap_size": 0} + ], + "asym_load": [ + {"id": 6, "node": 2, "status": 1, "type": 0, "p_specified": [950000, 1000000, 1050000], "q_specified": [0, 0, 0]} + ], + "source": [ + {"id": 7, "node": 1, "status": 1, "u_ref": 1, "sk": 1.0000000000000001e+50, "rx_ratio": 0, "z01_ratio": 1} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/params.json b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json new file mode 100644 index 000000000..6a2809e23 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json @@ -0,0 +1,7 @@ +{ + "calculation_method": [ + "newton_raphson" + ], + "rtol": 1e-07, + "atol": 1e-07 +} \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license new file mode 100644 index 000000000..760105916 --- /dev/null +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 From 1bea18dde4ce2c43e7dad15e5e2aacacb200678f Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 09:26:47 +0100 Subject: [PATCH 08/23] [skip ci] add new transformer attributes Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- code_generation/data/attribute_classes/input.json | 2 +- .../include/power_grid_model/auxiliary/input.hpp | 2 ++ .../include/power_grid_model/auxiliary/meta_gen/input.hpp | 4 +++- .../include/power_grid_model_c/dataset_definitions.h | 2 ++ .../power_grid_model_c/src/dataset_definitions.cpp | 2 ++ 5 files changed, 10 insertions(+), 2 deletions(-) diff --git a/code_generation/data/attribute_classes/input.json b/code_generation/data/attribute_classes/input.json index 098bf92dc..e621f65d0 100644 --- a/code_generation/data/attribute_classes/input.json +++ b/code_generation/data/attribute_classes/input.json @@ -223,7 +223,7 @@ }, { "data_type": "double", - "names": ["uk", "pk", "i0", "p0"], + "names": ["uk", "pk", "i0", "p0", "i0_zero_sequence", "p0_zero_sequence"], "description": "short circuit and open testing parameters" }, { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp index 76bed343c..15b6d7bfb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/input.hpp @@ -195,6 +195,8 @@ struct TransformerInput { double pk{nan}; // short circuit and open testing parameters double i0{nan}; // short circuit and open testing parameters double p0{nan}; // short circuit and open testing parameters + double i0_zero_sequence{nan}; // short circuit and open testing parameters + double p0_zero_sequence{nan}; // short circuit and open testing parameters WindingType winding_from{static_cast(na_IntS)}; // winding type at each side WindingType winding_to{static_cast(na_IntS)}; // winding type at each side IntS clock{na_IntS}; // clock number diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp index 1d0c72917..a5fb7aef3 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/meta_gen/input.hpp @@ -188,7 +188,7 @@ struct get_attributes_list { template<> struct get_attributes_list { - static constexpr std::array value{ + static constexpr std::array value{ // all attributes including base class meta_data_gen::get_meta_attribute<&TransformerInput::id>(offsetof(TransformerInput, id), "id"), @@ -203,6 +203,8 @@ struct get_attributes_list { meta_data_gen::get_meta_attribute<&TransformerInput::pk>(offsetof(TransformerInput, pk), "pk"), meta_data_gen::get_meta_attribute<&TransformerInput::i0>(offsetof(TransformerInput, i0), "i0"), meta_data_gen::get_meta_attribute<&TransformerInput::p0>(offsetof(TransformerInput, p0), "p0"), + meta_data_gen::get_meta_attribute<&TransformerInput::i0_zero_sequence>(offsetof(TransformerInput, i0_zero_sequence), "i0_zero_sequence"), + meta_data_gen::get_meta_attribute<&TransformerInput::p0_zero_sequence>(offsetof(TransformerInput, p0_zero_sequence), "p0_zero_sequence"), meta_data_gen::get_meta_attribute<&TransformerInput::winding_from>(offsetof(TransformerInput, winding_from), "winding_from"), meta_data_gen::get_meta_attribute<&TransformerInput::winding_to>(offsetof(TransformerInput, winding_to), "winding_to"), meta_data_gen::get_meta_attribute<&TransformerInput::clock>(offsetof(TransformerInput, clock), "clock"), diff --git a/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h b/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h index ce739b0ee..6af6842d3 100644 --- a/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h +++ b/power_grid_model_c/power_grid_model_c/include/power_grid_model_c/dataset_definitions.h @@ -122,6 +122,8 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_uk; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_pk; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_i0; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_p0; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_i0_zero_sequence; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_p0_zero_sequence; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_winding_from; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_winding_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_transformer_clock; diff --git a/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp b/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp index 00a190c4a..758c3c62a 100644 --- a/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp +++ b/power_grid_model_c/power_grid_model_c/src/dataset_definitions.cpp @@ -111,6 +111,8 @@ PGM_MetaAttribute const* const PGM_def_input_transformer_uk = PGM_meta_get_attri PGM_MetaAttribute const* const PGM_def_input_transformer_pk = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "pk"); PGM_MetaAttribute const* const PGM_def_input_transformer_i0 = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "i0"); PGM_MetaAttribute const* const PGM_def_input_transformer_p0 = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "p0"); +PGM_MetaAttribute const* const PGM_def_input_transformer_i0_zero_sequence = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "i0_zero_sequence"); +PGM_MetaAttribute const* const PGM_def_input_transformer_p0_zero_sequence = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "p0_zero_sequence"); PGM_MetaAttribute const* const PGM_def_input_transformer_winding_from = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "winding_from"); PGM_MetaAttribute const* const PGM_def_input_transformer_winding_to = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "winding_to"); PGM_MetaAttribute const* const PGM_def_input_transformer_clock = PGM_meta_get_attribute_by_name(nullptr, "input", "transformer", "clock"); From 52c899148f50e46f399fe306dc8abaa0d92b25b9 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:18:54 +0100 Subject: [PATCH 09/23] [skip ci] initialize zero-seq i0 p0 Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../include/power_grid_model/component/transformer.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 01e76e70a..1954ff06e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -33,6 +33,10 @@ class Transformer : public Branch { pk_{transformer_input.pk}, i0_{transformer_input.i0}, p0_{transformer_input.p0}, + i0_zero_sequence_{isnan(transformer_input.i0_zero_sequence) ? i0_ : transformer_input.i0_zero_sequence}, + p0_zero_sequence_{isnan(transformer_input.p0_zero_sequence) + ? p0_ + pk_ * (i0_zero_sequence_ * i0_zero_sequence_ - i0_ * i0_) + : transformer_input.p0_zero_sequence}, winding_from_{transformer_input.winding_from}, winding_to_{transformer_input.winding_to}, clock_{transformer_input.clock}, @@ -120,6 +124,8 @@ class Transformer : public Branch { double pk_; double i0_; double p0_; + double i0_zero_sequence_; + double p0_zero_sequence_; WindingType winding_from_; WindingType winding_to_; IntS clock_; From 2286e63d9f6bdc62bf650d2ca9372b17384ee800 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:25:01 +0100 Subject: [PATCH 10/23] [skip ci] define struct Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../power_grid_model/component/transformer.hpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 1954ff06e..59318e3c1 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -18,6 +18,14 @@ namespace power_grid_model { class Transformer : public Branch { + private: + struct TransformerParams { + DoubleComplex y_series{}; + DoubleComplex y_shunt{}; + DoubleComplex y0_shunt{}; + double k{1.0}; + }; + public: using InputType = TransformerInput; using UpdateType = TransformerUpdate; @@ -162,7 +170,7 @@ class Transformer : public Branch { } // calculate transformer parameter - std::tuple transformer_params() const { + TransformerParams transformer_params() const { double const base_y_to = base_i_to_ * base_i_to_ / base_power_1p; // off nominal tap ratio auto const [u1, u2] = [this]() { @@ -211,16 +219,16 @@ class Transformer : public Branch { // y shunt y_shunt = y_shunt / base_y_to; // return - return std::make_tuple(y_series, y_shunt, k); + return TransformerParams{.y_series = y_series, .y_shunt = y_shunt, .k = k}; } // branch param BranchCalcParam sym_calc_param() const final { - auto const [y_series, y_shunt, k] = transformer_params(); + auto const [y_series, y_shunt, [[maybe_unused]] y0_shunt, k] = transformer_params(); return calc_param_y_sym(y_series, y_shunt, k * std::exp(1.0i * (clock_ * deg_30))); } BranchCalcParam asym_calc_param() const final { - auto const [y_series, y_shunt, k] = transformer_params(); + auto const [y_series, y_shunt, y0_shunt, k] = transformer_params(); // positive sequence auto const param1 = calc_param_y_sym(y_series, y_shunt, k * std::exp(1.0i * (clock_ * deg_30))); // negative sequence From 7470426f562cf50bffaeaa4654aa26d06fbfdad1 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:30:35 +0100 Subject: [PATCH 11/23] adjusted core Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../component/transformer.hpp | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 59318e3c1..dd7226038 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -206,25 +206,35 @@ class Transformer : public Branch { z_series.imag(uk_sign * (z_series_imag_squared > 0.0 ? std::sqrt(z_series_imag_squared) : 0.0)); // y series y_series = (1.0 / z_series) / base_y_to; + // shunt DoubleComplex y_shunt; - // Y = I0_2 / (U2/sqrt3) = i0 * (S / sqrt3 / U2) / (U2/sqrt3) = i0 * S * / U2 / U2 + // Y = I0 / (U2/sqrt3) = i0 * (S / sqrt3 / U2) / (U2/sqrt3) = i0 * S * / U2 / U2 double const y_shunt_abs = i0_ * sn_ / u2 / u2; // G = P0 / (U2^2) y_shunt.real(p0_ / u2 / u2); - auto const y_shunt_imag_squared = y_shunt_abs * y_shunt_abs - y_shunt.real() * y_shunt.real(); y_shunt.imag(y_shunt_imag_squared > 0.0 ? -std::sqrt(y_shunt_imag_squared) : 0.0); - - // y shunt y_shunt = y_shunt / base_y_to; + + // shunt zero sequence + DoubleComplex y0_shunt; + // Y0 = I0_0 / (U2/sqrt3) = i0_zero_sequence_ * (S / sqrt3 / U2) / (U2/sqrt3) = i0_zero_sequence_ * S * / U2 / + // U2 + double const y0_shunt_abs = i0_zero_sequence_ * sn_ / u2 / u2; + // G0 = P0_0 / (U2^2) + y0_shunt.real(p0_zero_sequence_ / u2 / u2); + auto const y0_shunt_imag_squared = y0_shunt_abs * y0_shunt_abs - y0_shunt.real() * y0_shunt.real(); + y0_shunt.imag(y0_shunt_imag_squared > 0.0 ? -std::sqrt(y0_shunt_imag_squared) : 0.0); + y0_shunt = y0_shunt / base_y_to; + // return - return TransformerParams{.y_series = y_series, .y_shunt = y_shunt, .k = k}; + return TransformerParams{.y_series = y_series, .y_shunt = y_shunt, .y0_shunt = y0_shunt, .k = k}; } // branch param BranchCalcParam sym_calc_param() const final { - auto const [y_series, y_shunt, [[maybe_unused]] y0_shunt, k] = transformer_params(); + auto const [y_series, y_shunt, y0_shunt, k] = transformer_params(); return calc_param_y_sym(y_series, y_shunt, k * std::exp(1.0i * (clock_ * deg_30))); } BranchCalcParam asym_calc_param() const final { @@ -244,12 +254,12 @@ class Transformer : public Branch { } DoubleComplex const z0_series = 1.0 / y_series + 3.0 * (z_grounding_to_ + z_grounding_from_ / k / k); DoubleComplex const y0_series = 1.0 / z0_series; - param0 = calc_param_y_sym(y0_series, y_shunt, k * std::exp(1.0i * phase_shift_0)); + param0 = calc_param_y_sym(y0_series, y0_shunt, k * std::exp(1.0i * phase_shift_0)); } // YN* else if (winding_from_ == WindingType::wye_n && from_status()) { // ground path always possible via magnetization branch - DoubleComplex y0 = y_shunt; + DoubleComplex y0 = y0_shunt; if (winding_to_ == WindingType::delta) { // additional path via zk y0 += y_series; @@ -264,7 +274,7 @@ class Transformer : public Branch { // *yn else if (winding_to_ == WindingType::wye_n && to_status()) { // ground path always possible via magnetization branch - DoubleComplex y0 = y_shunt; + DoubleComplex y0 = y0_shunt; if (winding_from_ == WindingType::delta) { // additional path via zk y0 += y_series; From fa7a2d670c75902c131832258205a64faf162dce Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:34:26 +0100 Subject: [PATCH 12/23] fix typo Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../include/power_grid_model/component/transformer.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index dd7226038..9edec347d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -41,8 +41,8 @@ class Transformer : public Branch { pk_{transformer_input.pk}, i0_{transformer_input.i0}, p0_{transformer_input.p0}, - i0_zero_sequence_{isnan(transformer_input.i0_zero_sequence) ? i0_ : transformer_input.i0_zero_sequence}, - p0_zero_sequence_{isnan(transformer_input.p0_zero_sequence) + i0_zero_sequence_{is_nan(transformer_input.i0_zero_sequence) ? i0_ : transformer_input.i0_zero_sequence}, + p0_zero_sequence_{is_nan(transformer_input.p0_zero_sequence) ? p0_ + pk_ * (i0_zero_sequence_ * i0_zero_sequence_ - i0_ * i0_) : transformer_input.p0_zero_sequence}, winding_from_{transformer_input.winding_from}, From 5bcb72a541f25ac6f7274e86cdce1e01cbec9033 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:44:37 +0100 Subject: [PATCH 13/23] unit test Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- tests/cpp_unit_tests/test_transformer.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/cpp_unit_tests/test_transformer.cpp b/tests/cpp_unit_tests/test_transformer.cpp index 1a0a3920a..b28161673 100644 --- a/tests/cpp_unit_tests/test_transformer.cpp +++ b/tests/cpp_unit_tests/test_transformer.cpp @@ -418,6 +418,8 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { .pk = 100e3, .i0 = 0.015, .p0 = 30.0e4, + .i0_zero_sequence = 1.0, + .p0_zero_sequence = 50.0e4, .winding_from = WindingType::delta, .winding_to = WindingType::wye_n, .clock = 11, @@ -462,6 +464,16 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { } DoubleComplex const y_1_shunt = (y_shunt_real + 1i * y_shunt_imag) / base_y_to; + double const y0_shunt_abs = input.i0_zero_sequence * input.sn / input.u2 / input.u2; + double const y0_shunt_real = input.p0_zero_sequence / input.u2 / input.u2; + double y0_shunt_imag; + if (y0_shunt_real > y0_shunt_abs) { + y0_shunt_imag = 0.0; + } else { + y0_shunt_imag = -std::sqrt(y0_shunt_abs * y0_shunt_abs - y0_shunt_real * y0_shunt_real); + } + DoubleComplex const y_0_shunt = (y0_shunt_real + 1i * y0_shunt_imag) / base_y_to; + DoubleComplex const tap_ratio_1 = k * std::exp(1.0i * (deg_30 * input.clock)); DoubleComplex const y_1_tt = (1.0 / z_1_series) + 0.5 * y_1_shunt; @@ -485,7 +497,7 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { DoubleComplex const y_0_ff = low_admittance; DoubleComplex const y_0_ft = 0.0; DoubleComplex const y_0_tf = 0.0; - DoubleComplex const y_0_tt = (1.0 / (1.0 / (1.0 / z_1_series + y_1_shunt) + 3.0 * z_grounding_to)); + DoubleComplex const y_0_tt = (1.0 / (1.0 / (1.0 / z_1_series + y_0_shunt) + 3.0 * z_grounding_to)); // Sequence admittances -> phase addmitance ComplexTensor y_ff_diagonal; From 7b6377e54c3639e017aea179f2b66b6834102f9f Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:47:01 +0100 Subject: [PATCH 14/23] unit test Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- tests/cpp_unit_tests/test_transformer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cpp_unit_tests/test_transformer.cpp b/tests/cpp_unit_tests/test_transformer.cpp index b28161673..b9d65c008 100644 --- a/tests/cpp_unit_tests/test_transformer.cpp +++ b/tests/cpp_unit_tests/test_transformer.cpp @@ -419,7 +419,6 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { .i0 = 0.015, .p0 = 30.0e4, .i0_zero_sequence = 1.0, - .p0_zero_sequence = 50.0e4, .winding_from = WindingType::delta, .winding_to = WindingType::wye_n, .clock = 11, @@ -464,8 +463,10 @@ TEST_CASE("Test Transfomer - Test grounding - Dyn11") { } DoubleComplex const y_1_shunt = (y_shunt_real + 1i * y_shunt_imag) / base_y_to; + double const p0_zero_sequence = + input.p0 + input.pk * (input.i0_zero_sequence * input.i0_zero_sequence - input.i0 * input.i0); double const y0_shunt_abs = input.i0_zero_sequence * input.sn / input.u2 / input.u2; - double const y0_shunt_real = input.p0_zero_sequence / input.u2 / input.u2; + double const y0_shunt_real = p0_zero_sequence / input.u2 / input.u2; double y0_shunt_imag; if (y0_shunt_real > y0_shunt_abs) { y0_shunt_imag = 0.0; From b3567af61de9e9417577954f9233093304592873 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:52:52 +0100 Subject: [PATCH 15/23] fix validation test Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../zero_sequence_yyn_transformer/asym_output.json | 10 +++++----- .../zero_sequence_yyn_transformer/input.json | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json index 90c01815f..a51b55322 100644 --- a/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/asym_output.json @@ -5,17 +5,17 @@ "attributes": {}, "data": { "node": [ - {"id": 1, "energized": 1, "u_pu": [1, 1, 1], "u": [5773.5026918962576, 5773.5026918962576, 5773.5026918962576], "u_angle": [-2.474640575439679e-44, -2.0943951023931953, 2.0943951023931953], "p": [824880.19181322691, 1072224.8788595221, 1102894.9293272516], "q": [218912.27669635782, 40693.031260342112, 344009.43645155017]}, - {"id": 2, "energized": 1, "u_pu": [1.1450055302608289, 0.94457144911056157, 0.91924181371456271], "u": [6610.6925111969977, 5453.4858041281759, 5307.2450859846258], "u_angle": [-0.03356887190092963, -1.984902584683417, 1.9252028204298137], "p": [-949999.9999999979, -1000000.0000000031, -1049999.9999999963], "q": [1.6449686064130695e-08, -3.0224494451098491e-09, 3.984667595393038e-09]} + {"id": 1, "energized": 1, "u_pu": [1, 1, 1], "u": [5773.5026918962576, 5773.5026918962576, 5773.5026918962576], "u_angle": [-2.6439876230271684e-44, -2.0943951023931953, 2.0943951023931953], "p": [881329.20767572254, 1037364.8940881646, 1081305.8982361141], "q": [226203.41305523555, 85377.466355255776, 290921.30803535768]}, + {"id": 2, "energized": 1, "u_pu": [1.0141430605715689, 0.96656989153700335, 1.0110998975479204], "u": [5855.1576901778626, 5580.4938706947623, 5837.5879802689487], "u_angle": [0.001939888439272864, -2.1247815189679589, 2.0324414694676975], "p": [-799999.99999999849, -1000000.0000000008, -1199999.9999999972], "q": [7.4587508688682828e-10, 1.7304176386161853e-09, 5.1725865757671641e-09]} ], "transformer": [ - {"id": 4, "energized": 1, "loading": 0.30817316848870924, "p_from": [824880.19181322691, 1072224.8788595221, 1102894.9293272516], "q_from": [218912.27669635782, 40693.031260342126, 344009.43645155017], "i_from": [147.81913770559706, 185.84849584851148, 200.10395179782012], "s_from": [853434.18945704808, 1072996.791066251, 1155300.7043637931], "p_to": [-949999.9999999979, -1000000.0000000031, -1049999.9999999963], "q_to": [1.644994521118116e-08, -2.9986559036607486e-09, 3.9875615770433002e-09], "i_to": [143.70657815212488, 183.36895628169123, 197.84275702149816], "s_to": [949999.9999999979, 1000000.0000000031, 1049999.9999999963]} + {"id": 4, "energized": 1, "loading": 0.30705253328631577, "p_from": [881329.20767572254, 1037364.8940881646, 1081305.8982361141], "q_from": [226203.41305523555, 85377.466355255761, 290921.30803535768], "i_from": [157.59846030784894, 180.28437829560764, 193.9477496411763], "s_from": [909895.13482607121, 1040872.3433965337, 1119757.8546405528], "p_to": [-799999.99999999849, -1000000.0000000008, -1199999.9999999972], "q_to": [7.4606055156303146e-10, 1.7076212935884444e-09, 5.1782885887484745e-09], "i_to": [136.63167455626581, 179.19560941574917, 205.56435364331952], "s_to": [799999.99999999849, 1000000.0000000008, 1199999.9999999972]} ], "asym_load": [ - {"id": 6, "energized": 1, "p": [950000, 1000000, 1050000], "q": [0, 0, 0], "i": [143.70657815212516, 183.36895628169069, 197.84275702149884], "s": [950000, 1000000, 1050000], "pf": [1, 1, 1]} + {"id": 6, "energized": 1, "p": [799999.99999999988, 1000000, 1200000], "q": [0, 0, 0], "i": [136.63167455626603, 179.19560941574903, 205.56435364331998], "s": [799999.99999999988, 1000000, 1200000], "pf": [1, 1, 1]} ], "source": [ - {"id": 7, "energized": 1, "p": [824880.19181322691, 1072224.8788595221, 1102894.9293272516], "q": [218912.27669635782, 40693.031260342126, 344009.43645155017], "i": [147.81913770559706, 185.84849584851148, 200.10395179782012], "s": [853434.18945704808, 1072996.791066251, 1155300.7043637931], "pf": [0.96654223840975118, 0.99928060157014831, 0.9546388443817313]} + {"id": 7, "energized": 1, "p": [881329.20767572254, 1037364.8940881646, 1081305.8982361141], "q": [226203.41305523555, 85377.466355255761, 290921.30803535774], "i": [157.59846030784894, 180.28437829560764, 193.9477496411763], "s": [909895.13482607121, 1040872.3433965337, 1119757.8546405528], "pf": [0.96860525344405857, 0.99663027908213619, 0.96566047181979187]} ] } } \ No newline at end of file diff --git a/tests/data/power_flow/zero_sequence_yyn_transformer/input.json b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json index 9acc18b90..cc4a4de74 100644 --- a/tests/data/power_flow/zero_sequence_yyn_transformer/input.json +++ b/tests/data/power_flow/zero_sequence_yyn_transformer/input.json @@ -9,10 +9,10 @@ {"id": 2, "u_rated": 10000} ], "transformer": [ - {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 10000000, "uk": 0.10000000000000001, "pk": 0, "i0": 0.050000000000000003, "p0": 0, "winding_from": 0, "winding_to": 1, "clock": 12, "tap_side": 0, "tap_pos": 0, "tap_min": 0, "tap_max": 0, "tap_nom": 0, "tap_size": 0} + {"id": 4, "from_node": 1, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 10000000, "uk": 0.10000000000000001, "pk": 0, "i0": 0.050000000000000003, "p0": 0, "i0_zero_sequence": 1, "winding_from": 0, "winding_to": 1, "clock": 12, "tap_side": 0, "tap_pos": 0, "tap_min": 0, "tap_max": 0, "tap_nom": 0, "tap_size": 0} ], "asym_load": [ - {"id": 6, "node": 2, "status": 1, "type": 0, "p_specified": [950000, 1000000, 1050000], "q_specified": [0, 0, 0]} + {"id": 6, "node": 2, "status": 1, "type": 0, "p_specified": [800000, 1000000, 1200000], "q_specified": [0, 0, 0]} ], "source": [ {"id": 7, "node": 1, "status": 1, "u_ref": 1, "sk": 1.0000000000000001e+50, "rx_ratio": 0, "z01_ratio": 1} From 30bdbb342323ffad0c62e8340e9f4182a933aed5 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:19:23 +0100 Subject: [PATCH 16/23] add attribute doc Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- docs/user_manual/components.md | 146 +++++++++++++++++---------------- 1 file changed, 74 insertions(+), 72 deletions(-) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index ce113af7e..cecbaa1bc 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -17,7 +17,7 @@ The base type for all power-grid-model components. #### Input | name | data type | unit | description | required | update | -| ---- | --------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: | :------------------: | +|------|-----------|------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|:--------------------:| | `id` | `int32_t` | - | ID of a component. The ID should be unique across all components within the same scenario, e.g., you cannot have a node with `id=5` and another line with `id=5`. | ✔ | ❌ (see below) | If a component update is uniform and is updating all the elements with the same component type, IDs can be omitted or @@ -33,7 +33,7 @@ An example of the usage of optional IDs is given in [Power Flow Example](./Power #### Steady state output and Short circuit output | name | data type | unit | description | -| ----------- | --------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------- | +|-------------|-----------|------|------------------------------------------------------------------------------------------------------------------------------------| | `id` | `int32_t` | - | ID of a component, the ID should be unique across all components, e.g., you cannot have a node with `id=5` and a line with `id=5`. | | `energized` | `int8_t` | - | Indicates if a component is energized, i.e. connected to a source | @@ -48,13 +48,13 @@ Physically a node can be a busbar, a joint, or other similar component. #### Input | name | data type | unit | description | required | update | valid values | -| --------- | --------- | -------- | ----------------------- | :------: | :------: | :----------: | +|-----------|-----------|----------|-------------------------|:--------:|:--------:|:------------:| | `u_rated` | `double` | volt (V) | rated line-line voltage | ✔ | ❌ | `> 0` | #### Steady state output | name | data type | unit | description | -| --------- | ----------------- | -------------------------- | ----------------------------------------------------------------------------------------------- | +|-----------|-------------------|----------------------------|-------------------------------------------------------------------------------------------------| | `u_pu` | `RealValueOutput` | - | per-unit voltage magnitude | | `u_angle` | `RealValueOutput` | rad | voltage angle | | `u` | `RealValueOutput` | volt (V) | voltage magnitude, line-line for symmetric calculation, line-neutral for asymmetric calculation | @@ -69,7 +69,7 @@ The `p` and `q` output of injection follows the `generator` reference direction #### Short circuit output | name | data type | unit | description | -| --------- | ----------------- | -------- | -------------------------------- | +|-----------|-------------------|----------|----------------------------------| | `u_pu` | `RealValueOutput` | - | per-unit voltage magnitude | | `u_angle` | `RealValueOutput` | rad | voltage angle | | `u` | `RealValueOutput` | volt (V) | voltage magnitude (line-neutral) | @@ -88,7 +88,7 @@ In this case, the attribute `from_status` and `to_status` is always 1. #### Input | name | data type | unit | description | required | update | valid values | -| ------------- | --------- | ---- | ------------------------------ | :------: | :------: | :-------------: | +|---------------|-----------|------|--------------------------------|:--------:|:--------:|:---------------:| | `from_node` | `int32_t` | - | ID of node at from-side | ✔ | ❌ | a valid node ID | | `to_node` | `int32_t` | - | ID of node at to-side | ✔ | ❌ | a valid node ID | | `from_status` | `int8_t` | - | connection status at from-side | ✔ | ✔ | `0` or `1` | @@ -97,7 +97,7 @@ In this case, the attribute `from_status` and `to_status` is always 1. #### Steady state output | name | data type | unit | description | -| --------- | ----------------- | -------------------------- | ---------------------------------------------------------- | +|-----------|-------------------|----------------------------|------------------------------------------------------------| | `p_from` | `RealValueOutput` | watt (W) | active power flowing into the branch at from-side | | `q_from` | `RealValueOutput` | volt-ampere-reactive (var) | reactive power flowing into the branch at from-side | | `i_from` | `RealValueOutput` | ampere (A) | magnitude of current at from-side | @@ -111,7 +111,7 @@ In this case, the attribute `from_status` and `to_status` is always 1. #### Short circuit output | name | data type | unit | description | -| -------------- | ----------------- | ---------- | --------------------------------- | +|----------------|-------------------|------------|-----------------------------------| | `i_from` | `RealValueOutput` | ampere (A) | magnitude of current at from-side | | `i_from_angle` | `RealValueOutput` | rad | current angle at from-side | | `i_to` | `RealValueOutput` | ampere (A) | magnitude of current at to-side | @@ -129,7 +129,7 @@ If `i_n` is not provided, `loading` of line will be a `nan` value. #### Input | name | data type | unit | description | required | update | valid values | -| ------ | --------- | ---------- | -------------------------------------------------- | :---------------------------------------: | :------: | :--------------------------------: | +|--------|-----------|------------|----------------------------------------------------|:-----------------------------------------:|:--------:|:----------------------------------:| | `r1` | `double` | ohm (Ω) | positive-sequence serial resistance | ✔ | ❌ | `r1` and `x1` cannot be both `0.0` | | `x1` | `double` | ohm (Ω) | positive-sequence serial reactance | ✔ | ❌ | `r1` and `x1` cannot be both `0.0` | | `c1` | `double` | farad (F) | positive-sequence shunt capacitance | ✔ | ❌ | | @@ -185,32 +185,34 @@ An example of usage of transformer is given in [Transformer Examples](../example #### Input -| name | data type | unit | description | required | update | valid values | -| ------------------ | ----------------------------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------: | :------: | :--------------------------------------------------------------------: | -| `u1` | `double` | volt (V) | rated voltage at from-side | ✔ | ❌ | `> 0` | -| `u2` | `double` | volt (V) | rated voltage at to-side | ✔ | ❌ | `> 0` | -| `sn` | `double` | volt-ampere (VA) | rated power | ✔ | ❌ | `> 0` | -| `uk` | `double` | - | relative short circuit voltage, `0.1` means 10% | ✔ | ❌ | `>= pk / sn` and `> 0` and `< 1` | -| `pk` | `double` | watt (W) | short circuit (copper) loss | ✔ | ❌ | `>= 0` | -| `i0` | `double` | - | relative no-load current | ✔ | ❌ | `>= p0 / sn` and `< 1` | -| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | -| `winding_from` | {py:class}`WindingType ` | - | from-side winding type | ✔ | ❌ | | -| `winding_to` | {py:class}`WindingType ` | - | to-side winding type | ✔ | ❌ | | -| `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | ✔ | ❌ | `>= -12` and `<= 12` | -| `tap_side` | {py:class}`BranchSide ` | - | side of tap changer | ✔ | ❌ | | -| `tap_pos` | `int8_t` | - | current position of tap changer | ❌ default `tap_nom`, if no `tap_nom` default `0` | ✔ | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` | -| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | ✔ | ❌ | | -| `tap_max` | `int8_t` | - | position of tap changer at maximum voltage | ✔ | ❌ | | -| `tap_nom` | `int8_t` | - | nominal position of tap changer | ❌ default `0` | ❌ | `(tap_min <= tap_nom <= tap_max)` or `(tap_min >= tap_nom >= tap_max)` | -| `tap_size` | `double` | volt (V) | size of each tap of the tap changer | ✔ | ❌ | `>= 0` | -| `uk_min` | `double` | - | relative short circuit voltage at minimum tap | ❌ default same as `uk` | ❌ | `>= pk_min / sn` and `> 0` and `< 1` | -| `uk_max` | `double` | - | relative short circuit voltage at maximum tap | ❌ default same as `uk` | ❌ | `>= pk_max / sn` and `> 0` and `< 1` | -| `pk_min` | `double` | watt (W) | short circuit (copper) loss at minimum tap | ❌ default same as `pk` | ❌ | `>= 0` | -| `pk_max` | `double` | watt (W) | short circuit (copper) loss at maximum tap | ❌ default same as `pk` | ❌ | `>= 0` | -| `r_grounding_from` | `double` | ohm (Ω) | grounding resistance at from-side, if relevant | ❌ default `0` | ❌ | | -| `x_grounding_from` | `double` | ohm (Ω) | grounding reactance at from-side, if relevant | ❌ default `0` | ❌ | | -| `r_grounding_to` | `double` | ohm (Ω) | grounding resistance at to-side, if relevant | ❌ default `0` | ❌ | | -| `x_grounding_to` | `double` | ohm (Ω) | grounding reactance at to-side, if relevant | ❌ default `0` | ❌ | | +| name | data type | unit | description | required | update | valid values | +|--------------------|-------------------------------------------------------------|------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------:|:--------:|:----------------------------------------------------------------------:| +| `u1` | `double` | volt (V) | rated voltage at from-side | ✔ | ❌ | `> 0` | +| `u2` | `double` | volt (V) | rated voltage at to-side | ✔ | ❌ | `> 0` | +| `sn` | `double` | volt-ampere (VA) | rated power | ✔ | ❌ | `> 0` | +| `uk` | `double` | - | relative short circuit voltage, `0.1` means 10% | ✔ | ❌ | `>= pk / sn` and `> 0` and `< 1` | +| `pk` | `double` | watt (W) | short circuit (copper) loss | ✔ | ❌ | `>= 0` | +| `i0` | `double` | - | relative no-load current | ✔ | ❌ | `>= p0 / sn` and `< 1` | +| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | +| `i0_zero_sequence` | `double` | - | zero-sequence relative no-load current | ❌ default `i0` | ❌ | `>= p0_zero_sequence / sn` and `< 1` | +| `p0_zero_sequence` | `double` | watt (W) | zero-sequence no-load (iron) loss | ❌ default `p0 + pk * (i0_zero_sequence^2 - i0^2)` | ❌ | `>= 0` | +| `winding_from` | {py:class}`WindingType ` | - | from-side winding type | ✔ | ❌ | | +| `winding_to` | {py:class}`WindingType ` | - | to-side winding type | ✔ | ❌ | | +| `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | ✔ | ❌ | `>= -12` and `<= 12` | +| `tap_side` | {py:class}`BranchSide ` | - | side of tap changer | ✔ | ❌ | | +| `tap_pos` | `int8_t` | - | current position of tap changer | ❌ default `tap_nom`, if no `tap_nom` default `0` | ✔ | `(tap_min <= tap_pos <= tap_max)` or `(tap_min >= tap_pos >= tap_max)` | +| `tap_min` | `int8_t` | - | position of tap changer at minimum voltage | ✔ | ❌ | | +| `tap_max` | `int8_t` | - | position of tap changer at maximum voltage | ✔ | ❌ | | +| `tap_nom` | `int8_t` | - | nominal position of tap changer | ❌ default `0` | ❌ | `(tap_min <= tap_nom <= tap_max)` or `(tap_min >= tap_nom >= tap_max)` | +| `tap_size` | `double` | volt (V) | size of each tap of the tap changer | ✔ | ❌ | `>= 0` | +| `uk_min` | `double` | - | relative short circuit voltage at minimum tap | ❌ default same as `uk` | ❌ | `>= pk_min / sn` and `> 0` and `< 1` | +| `uk_max` | `double` | - | relative short circuit voltage at maximum tap | ❌ default same as `uk` | ❌ | `>= pk_max / sn` and `> 0` and `< 1` | +| `pk_min` | `double` | watt (W) | short circuit (copper) loss at minimum tap | ❌ default same as `pk` | ❌ | `>= 0` | +| `pk_max` | `double` | watt (W) | short circuit (copper) loss at maximum tap | ❌ default same as `pk` | ❌ | `>= 0` | +| `r_grounding_from` | `double` | ohm (Ω) | grounding resistance at from-side, if relevant | ❌ default `0` | ❌ | | +| `x_grounding_from` | `double` | ohm (Ω) | grounding reactance at from-side, if relevant | ❌ default `0` | ❌ | | +| `r_grounding_to` | `double` | ohm (Ω) | grounding resistance at to-side, if relevant | ❌ default `0` | ❌ | | +| `x_grounding_to` | `double` | ohm (Ω) | grounding reactance at to-side, if relevant | ❌ default `0` | ❌ | | ```{note} It can happen that `tap_min > tap_max`. @@ -256,7 +258,7 @@ the off-nominal ratio must be given to adapt the electrical parameters). #### Input | name | data type | unit | description | required | update | valid values | -| ------- | --------- | ---------------- | ----------------------------- | :--------------------: | :------: | :----------: | +|---------|-----------|------------------|-------------------------------|:----------------------:|:--------:|:------------:| | `r1` | `double` | ohm | positive-sequence resistance | ✔ | ❌ | | | `x1` | `double` | ohm | positive-sequence reactance | ✔ | ❌ | | | `g1` | `double` | siemens | positive-sequence conductance | ✔ | ❌ | | @@ -327,7 +329,7 @@ This representation holds for all values `r_aa` ... `r_nn`, `x_aa` ... `x_nn` an If the neutral values are not provided, the last row and column from the above matrix are omitted. | name | data type | unit | description | required | update | valid values | -| ------ | --------- | ---------- | --------------------------------- | ---------------------------- | :------: | :----------: | +|--------|-----------|------------|-----------------------------------|------------------------------|:--------:|:------------:| | `r_aa` | `double` | ohm (Ω) | Series serial resistance aa | ✔ | ❌ | `> 0` | | `r_ba` | `double` | ohm (Ω) | Series serial resistance ba | ✔ | ❌ | `> 0` | | `r_bb` | `double` | ohm (Ω) | Series serial resistance bb | ✔ | ❌ | `> 0` | @@ -362,7 +364,7 @@ For the r and x matrices providing values for the neutral phase is optional. To clarify which input values are required, please consult the tables below: | r_aa ... r_cc | r_na | r_nb | r_nc | r_nn | result | Validation Error | -| ------------- | -------- | -------- | -------- | -------- | -------- | ------------------------- | +|---------------|----------|----------|----------|----------|----------|---------------------------| | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | @@ -372,7 +374,7 @@ To clarify which input values are required, please consult the tables below: | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | MultiFieldValidationError | | x_aa ... x_cc | x_na | x_nb | x_nc | x_nn | result | Validation Error | -| ------------- | -------- | -------- | -------- | -------- | -------- | ------------------------- | +|---------------|----------|----------|----------|----------|----------|---------------------------| | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ | | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | | ✔ | ✔ | ✔ | ✔ | ❌ | ❌ | MultiFieldValidationError | @@ -387,7 +389,7 @@ Whenever both sets are supplied the powerflow calculations will use `c0`, `c1`. The table below provides guidance in providing valid input. | c_aa ... c_cc | c0 | c1 | result | Validation Error | -| ------------- | -------- | -------- | -------- | ------------------------- | +|---------------|----------|----------|----------|---------------------------| | ✔ | ✔ | ✔ | ✔ | | | ✔ | ✔ | ❌ | ✔ | | | ✔ | ❌ | ❌ | ✔ | | @@ -449,7 +451,7 @@ In reality such switches may not exist. #### Input | name | data type | unit | description | required | update | valid values | -| ---------- | --------- | ---- | --------------------------- | :------: | :------: | :-------------: | +|------------|-----------|------|-----------------------------|:--------:|:--------:|:---------------:| | `node_1` | `int32_t` | - | ID of node at side 1 | ✔ | ❌ | a valid node ID | | `node_2` | `int32_t` | - | ID of node at side 2 | ✔ | ❌ | a valid node ID | | `node_3` | `int32_t` | - | ID of node at side 3 | ✔ | ❌ | a valid node ID | @@ -460,7 +462,7 @@ In reality such switches may not exist. #### Steady state output | name | data type | unit | description | -| --------- | ----------------- | -------------------------- | ---------------------------------------------------------- | +|-----------|-------------------|----------------------------|------------------------------------------------------------| | `p_1` | `RealValueOutput` | watt (W) | active power flowing into the branch at side 1 | | `q_1` | `RealValueOutput` | volt-ampere-reactive (var) | reactive power flowing into the branch at side 1 | | `i_1` | `RealValueOutput` | ampere (A) | current at side 1 | @@ -478,7 +480,7 @@ In reality such switches may not exist. #### Short circuit output | name | data type | unit | description | -| ----------- | ----------------- | ---------- | ----------------------- | +|-------------|-------------------|------------|-------------------------| | `i_1` | `RealValueOutput` | ampere (A) | current at side 1 | | `i_1_angle` | `RealValueOutput` | rad | current angle at side 1 | | `i_2` | `RealValueOutput` | ampere (A) | current at side 2 | @@ -496,7 +498,7 @@ An example of usage of three-winding transformer is given in #### Input | name | data type | unit | description | required | update | valid values | -| --------------- | ----------------------------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------: | :------: | :--------------------------------------------------------------------: | +|-----------------|-------------------------------------------------------------|------------------|-----------------------------------------------------------------------------------------------------------|:-------------------------------------------------------:|:--------:|:----------------------------------------------------------------------:| | `u1` | `double` | volt (V) | rated voltage at side 1 | ✔ | ❌ | `> 0` | | `u2` | `double` | volt (V) | rated voltage at side 2 | ✔ | ❌ | `> 0` | | `u3` | `double` | volt (V) | rated voltage at side 3 | ✔ | ❌ | `> 0` | @@ -567,14 +569,14 @@ The reference direction for power flows is mentioned in {hoverxreftooltip}`user_ #### Input | name | data type | unit | description | required | update | valid values | -| -------- | --------- | ---- | ----------------------------- | :------: | :------: | :-------------: | +|----------|-----------|------|-------------------------------|:--------:|:--------:|:---------------:| | `node` | `int32_t` | - | ID of the coupled node | ✔ | ❌ | a valid node ID | | `status` | `int8_t` | - | connection status to the node | ✔ | ✔ | `0` or `1` | #### Steady state output | name | data type | unit | description | -| ---- | ----------------- | -------------------------- | -------------- | +|------|-------------------|----------------------------|----------------| | `p` | `RealValueOutput` | watt (W) | active power | | `q` | `RealValueOutput` | volt-ampere-reactive (var) | reactive power | | `i` | `RealValueOutput` | ampere (A) | current | @@ -584,7 +586,7 @@ The reference direction for power flows is mentioned in {hoverxreftooltip}`user_ #### Short circuit output | name | data type | unit | description | -| --------- | ----------------- | ---------- | ------------- | +|-----------|-------------------|------------|---------------| | `i` | `RealValueOutput` | ampere (A) | current | | `i_angle` | `RealValueOutput` | rad | current angle | @@ -601,7 +603,7 @@ The impedance is specified by convention as short circuit power. #### Input | name | data type | unit | description | required | update | valid values | -| ------------- | --------- | ---------------- | -------------------------------------------------- | :--------------------------: | :------: | :----------: | +|---------------|-----------|------------------|----------------------------------------------------|:----------------------------:|:--------:|:------------:| | `u_ref` | `double` | - | reference voltage in per-unit | ✨ only for power flow | ✔ | `> 0` | | `u_ref_angle` | `double` | rad | reference voltage angle | ❌ default `0.0` | ✔ | | | `sk` | `double` | volt-ampere (VA) | short circuit power | ❌ default `1e10` | ❌ | `> 0` | @@ -643,7 +645,7 @@ $$ only the type of the load/generation with response to voltage. | name | data type | unit | description | required | update | -| ------ | ----------------------------------------------------------- | ---- | ----------------------------------------------- | :------: | :------: | +|--------|-------------------------------------------------------------|------|-------------------------------------------------|:--------:|:--------:| | `type` | {py:class}`LoadGenType ` | - | type of load/generator with response to voltage | ✔ | ❌ | #### Load/Generator Concrete Types @@ -653,7 +655,7 @@ They share similar attributes: specified active/reactive power. However, the reference direction and meaning of `RealValueInput` is different, as shown in the table below. | type name | reference direction | meaning of `RealValueInput` | -| ----------- | ------------------- | --------------------------- | +|-------------|---------------------|-----------------------------| | `sym_load` | load | `double` | | `sym_gen` | generator | `double` | | `asym_load` | load | `double[3]` | @@ -662,7 +664,7 @@ However, the reference direction and meaning of `RealValueInput` is different, a ##### Input | name | data type | unit | description | required | update | -| ------------- | ---------------- | -------------------------- | ------------------------ | :--------------------------: | :------: | +|---------------|------------------|----------------------------|--------------------------|:----------------------------:|:--------:| | `p_specified` | `RealValueInput` | watt (W) | specified active power | ✨ only for power flow | ✔ | | `q_specified` | `RealValueInput` | volt-ampere-reactive (var) | specified reactive power | ✨ only for power flow | ✔ | @@ -710,7 +712,7 @@ It behaves similar to a load/generator with type `const_impedance`. #### Input | name | data type | unit | description | required | update | -| ---- | --------- | ----------- | ----------------------------------- | :--------------------------------------: | :------: | +|------|-----------|-------------|-------------------------------------|:----------------------------------------:|:--------:| | `g1` | `double` | siemens (S) | positive-sequence shunt conductance | ✔ | ✔ | | `b1` | `double` | siemens (S) | positive-sequence shunt susceptance | ✔ | ✔ | | `g0` | `double` | siemens (S) | zero-sequence shunt conductance | ✨ only for asymmetric calculation | ✔ | @@ -738,7 +740,7 @@ The state estimator uses the data to evaluate the state of the grid with the hig #### Input | name | data type | unit | description | required | update | valid values | -| ----------------- | --------- | ---- | ------------------------- | :------: | :------: | :---------------: | +|-------------------|-----------|------|---------------------------|:--------:|:--------:|:-----------------:| | `measured_object` | `int32_t` | - | ID of the measured object | ✔ | ❌ | a valid object ID | #### Output @@ -757,7 +759,7 @@ It measures the magnitude and (optionally) the angle of the voltage of a `node`. #### Input | name | data type | unit | description | required | update | valid values | -| --------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------- | :--------------------------------: | :------: | :----------: | +|-----------|-----------|----------|-----------------------------------------------------------------------------------------------------------------|:----------------------------------:|:--------:|:------------:| | `u_sigma` | `double` | volt (V) | standard deviation of the measurement error. Usually this is the absolute measurement error range divided by 3. | ✨ only for state estimation | ✔ | `> 0` | #### Voltage Sensor Concrete Types @@ -768,14 +770,14 @@ In a `sym_voltage_sensor` the measured voltage is a line-to-line voltage. In a `asym_voltage_sensor` the measured voltage is a 3-phase line-to-ground voltage. | type name | meaning of `RealValueInput` | -| --------------------- | --------------------------- | +|-----------------------|-----------------------------| | `sym_voltage_sensor` | `double` | | `asym_voltage_sensor` | `double[3]` | ##### Input | name | data type | unit | description | required | update | valid values | -| ------------------ | ---------------- | -------- | -------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------: | :------: | :----------: | +|--------------------|------------------|----------|----------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------:|:--------:|:------------:| | `u_measured` | `RealValueInput` | volt (V) | measured voltage magnitude | ✨ only for state estimation | ✔ | `> 0` | | `u_angle_measured` | `RealValueInput` | rad | measured voltage angle (only possible with phasor measurement units) | ✨ only for state estimation when a current sensor with `global_angle` `angle_measurement_type` is present | ✔ | | @@ -792,7 +794,7 @@ For other calculation types, sensor output is undefined. ``` | name | data type | unit | description | -| ------------------ | ----------------- | -------- | ------------------------------------------------------------------------------------------------------------------------ | +|--------------------|-------------------|----------|--------------------------------------------------------------------------------------------------------------------------| | `u_residual` | `RealValueOutput` | volt (V) | residual value between measured voltage magnitude and calculated voltage magnitude | | `u_angle_residual` | `RealValueOutput` | rad | residual value between measured voltage angle and calculated voltage angle (only possible with phasor measurement units) | @@ -848,7 +850,7 @@ However, such mixing of sensor types is allowed as long as they are on different ##### Input | name | data type | unit | description | required | update | valid values | -| ------------------------ | ----------------------------------------------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------: | :------: | :--------------------------------------------------: | +|--------------------------|-------------------------------------------------------------------------------|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------:|:--------:|:----------------------------------------------------:| | `measured_terminal_type` | {py:class}`MeasuredTerminalType ` | - | indicate if it measures an `appliance` or a `branch` | ✔ | ❌ | the terminal type should match the `measured_object` | | `power_sigma` | `double` | volt-ampere (VA) | standard deviation of the measurement error. Usually this is the absolute measurement error range divided by 3. See {hoverxreftooltip}`user_manual/components:Power Sensor Concrete Types`. | ✨ in certain cases for state estimation. See the explanation for [concrete types](#power-sensor-concrete-types) below. | ✔ | `> 0` | @@ -858,14 +860,14 @@ There are two concrete types of power sensor. They share similar attributes: the meaning of `RealValueInput` is different, as shown in the table below. | type name | meaning of `RealValueInput` | -| ------------------- | --------------------------- | +|---------------------|-----------------------------| | `sym_power_sensor` | `double` | | `asym_power_sensor` | `double[3]` | ##### Input | name | data type | unit | description | required | update | valid values | -| ------------ | ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | :---------------------------------: | :------: | :----------: | +|--------------|------------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------:|:--------:|:------------:| | `p_measured` | `RealValueInput` | watt (W) | measured active power | ✨ only for state estimation | ✔ | | | `q_measured` | `RealValueInput` | volt-ampere-reactive (var) | measured reactive power | ✨ only for state estimation | ✔ | | | `p_sigma` | `RealValueInput` | watt (W) | standard deviation of the active power measurement error. Usually this is the absolute measurement error range divided by 3. | ❌ see the explanation below. | ✔ | `> 0` | @@ -874,7 +876,7 @@ They share similar attributes: the meaning of `RealValueInput` is different, as Valid combinations of `power_sigma`, `p_sigma` and `q_sigma` are: | `power_sigma` | `p_sigma` | `q_sigma` | result | -| :-----------: | :-------: | :-------: | :------: | +|:-------------:|:---------:|:---------:|:--------:| | ✔ | ✔ | ✔ | ✔ | | ✔ | ✔ | | ❌ | | ✔ | | ✔ | ❌ | @@ -907,7 +909,7 @@ For other calculation types, sensor output is undefined. ``` | name | data type | unit | description | -| ------------ | ----------------- | -------------------------- | ---------------------------------------------------------------------------- | +|--------------|-------------------|----------------------------|------------------------------------------------------------------------------| | `p_residual` | `RealValueOutput` | watt (W) | residual value between measured active power and calculated active power | | `q_residual` | `RealValueOutput` | volt-ampere-reactive (var) | residual value between measured reactive power and calculated reactive power | @@ -949,7 +951,7 @@ However, such mixing of sensor types is allowed as long as they are on different ##### Input | name | data type | unit | description | required | update | valid values | -| ------------------------ | ----------------------------------------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------: | :------: | :--------------------------------------------------: | +|--------------------------|-------------------------------------------------------------------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------:|:--------:|:----------------------------------------------------:| | `measured_terminal_type` | {py:class}`MeasuredTerminalType ` | - | indicate the side of the `branch` | ✔ | ❌ | the terminal type should match the `measured_object` | | `angle_measurement_type` | {py:class}`AngleMeasurementType ` | - | indicate whether the measured angle is a global angle or a local angle; (see the [electric model](#local-angle-current-sensors) below) | ✔ | ❌ | | | `i_sigma` | `double` | ampere (A) | standard deviation of the current (`i`) measurement error. Usually this is the absolute measurement error range divided by 3. | ✨ only for state estimation | ✔ | `> 0` | @@ -961,14 +963,14 @@ There are two concrete types of current sensor. They share similar attributes: the meaning of `RealValueInput` is different, as shown in the table below. | type name | meaning of `RealValueInput` | -| --------------------- | --------------------------- | +|-----------------------|-----------------------------| | `sym_current_sensor` | `double` | | `asym_current_sensor` | `double[3]` | ##### Input | name | data type | unit | description | required | update | -| ------------------ | ---------------- | ---------- | ------------------------------------------------------------------------------------------------------- | :--------------------------------: | :------: | +|--------------------|------------------|------------|---------------------------------------------------------------------------------------------------------|:----------------------------------:|:--------:| | `i_measured` | `RealValueInput` | ampere (A) | measured current (`i`) magnitude | ✨ only for state estimation | ✔ | | `i_angle_measured` | `RealValueInput` | rad | measured phase angle of the current (`i`; see the [electric model](#local-angle-current-sensors) below) | ✨ only for state estimation | ✔ | @@ -989,7 +991,7 @@ For other calculation types, sensor output is undefined. ``` | name | data type | unit | description | -| ------------------ | ----------------- | ---------- | ------------------------------------------------------------------------------------------- | +|--------------------|-------------------|------------|---------------------------------------------------------------------------------------------| | `i_residual` | `RealValueOutput` | ampere (A) | residual value between measured current (`i`) and calculated current (`i`) | | `i_angle_residual` | `RealValueOutput` | rad | residual value between measured phase angle and calculated phase angle of the current (`i`) | @@ -1058,7 +1060,7 @@ A fault can only happen at a `node`. #### Input | name | data type | unit | description | required | update | valid values | -| -------------- | --------------------------------------------------------- | ------- | --------------------------------------------------- | :-----------------------------------------------------------------------------------------------------: | :------: | :---------------: | +|----------------|-----------------------------------------------------------|---------|-----------------------------------------------------|:-------------------------------------------------------------------------------------------------------:|:--------:|:-----------------:| | `status` | `int8_t` | - | whether the fault is active | ✔ | ✔ | `0` or `1` | | `fault_type` | {py:class}`FaultType ` | - | the type of the fault | ✨ only for short circuit | ✔ | | | `fault_phase` | {py:class}`FaultPhase ` | - | the phase(s) of the fault | ❌ default `FaultPhase.default_value` (see [below](#fault-types-fault-phases-and-default-values)) | ✔ | | @@ -1084,7 +1086,7 @@ A `fault` has no steady state output. #### Short circuit output | name | data type | unit | description | -| ----------- | ----------------- | ---------- | ------------- | +|-------------|-------------------|------------|---------------| | `i_f` | `RealValueOutput` | ampere (A) | current | | `i_f_angle` | `RealValueOutput` | rad | current angle | @@ -1099,7 +1101,7 @@ In case the `fault_phase` is not specified or is equal to `FaultPhase.default_va The supported values of `fault_phase`, as well as its default value, are listed in the table below. | `fault_type` | supported values of `fault_phase` | `FaultPhase.default_value` | description | -| ---------------------------------- | ------------------------------------------------- | -------------------------- | ---------------------------------------------------------------------- | +|------------------------------------|---------------------------------------------------|----------------------------|------------------------------------------------------------------------| | `FaultType.three_phase` | `FaultPhase.abc` | `FaultPhase.abc` | Three phases are connected with fault impedance. | | `FaultType.single_phase_to_ground` | `FaultPhase.a`, `FaultPhase.b`, `FaultPhase.c` | `FaultPhase.a` | One phase is grounded with fault impedance, and other phases are open. | | `FaultType.two_phase` | `FaultPhase.bc`, `FaultPhase.ac`, `FaultPhase.ab` | `FaultPhase.bc` | Two phases are connected with fault impedance. | @@ -1117,7 +1119,7 @@ Which object types are supported as `regulated_object` is regulator type-depende #### Input | name | data type | unit | description | required | update | valid values | -| ------------------ | --------- | ---- | ----------------------------------------- | :------: | :------: | :-------------------------: | +|--------------------|-----------|------|-------------------------------------------|:--------:|:--------:|:---------------------------:| | `regulated_object` | `int32_t` | - | ID of the regulated object | ✔ | ❌ | a valid regulated object ID | | `status` | `int8_t` | - | connection status to the regulated object | ✔ | ✔ | `0` or `1` | @@ -1147,7 +1149,7 @@ The actual grid state is not changed after calculations are done. #### Input | name | data type | unit | description | required | update | valid values | -| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------- | :--------------------------: | :------: | :--------------------------------------------------------------: | +|----------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|---------------------------------------------------------------------------------------------------------|:----------------------------:|:--------:|:----------------------------------------------------------------:| | `control_side` | {py:class}`BranchSide ` if the regulated object is a {hoverxreftooltip}`user_manual/components:transformer` and {py:class}`Branch3Side ` if it the regulated object is a {hoverxreftooltip}`user_manual/components:Three-Winding Transformer` | - | the controlled side of the transformer | ✨ only for power flow | ❌ | `control_side` should be the relatively further side to a source | | `u_set` | `double` | volt (V) | the voltage setpoint (at the center of the band) | ✨ only for power flow | ✔ | `>= 0` | | `u_band` | `double` | volt (V) | the width of the voltage band ($=2*\left(\Delta U\right)_{\text{acceptable}}$) | ✨ only for power flow | ✔ | `> 0` (see below) | @@ -1170,7 +1172,7 @@ Typical real-world power grids already satisfy these requirements and they shoul #### Steady state output | name | data type | unit | description | -| --------- | --------- | ---- | -------------------- | +|-----------|-----------|------|----------------------| | `tap_pos` | `int8_t` | - | optimal tap position | #### Short circuit output From 649b93f61ff713be6334335266677ad4d785c3d5 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:28:22 +0100 Subject: [PATCH 17/23] add note Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- docs/user_manual/components.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index cecbaa1bc..5e8241b3c 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -219,6 +219,16 @@ It can happen that `tap_min > tap_max`. In this case the winding voltage is decreased if the tap position is increased. ``` +**Note:** +By default, PGM uses the same magnetization current (and thus impedance) for positive- and zero-sequence circuit. +This is typically not the case for 3-leg core-type transformers. +Due to lack of iron-core pass for zero-sequence flux, +the zero-sequence magnetization current is usually significantly higher than positive sequence. +If you want to do asymmetrical calculation with 3-leg core-type transformers, +please set the attribute `i0_zero_sequence`. +If the transformer specificaiton does not provide such an attribute, +a good guess will be `i0_zero_sequence = 1.0`. + #### Electric Model `transformer` is described by a $\pi$ model, where $Z_{\text{series}}$ can be computed as From dd24f5df92fbf06e1dbc60662755eb2a2925d595 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:37:32 +0100 Subject: [PATCH 18/23] use note block Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- docs/user_manual/components.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index 5e8241b3c..229c72599 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -219,7 +219,7 @@ It can happen that `tap_min > tap_max`. In this case the winding voltage is decreased if the tap position is increased. ``` -**Note:** +```{note} By default, PGM uses the same magnetization current (and thus impedance) for positive- and zero-sequence circuit. This is typically not the case for 3-leg core-type transformers. Due to lack of iron-core pass for zero-sequence flux, @@ -228,6 +228,7 @@ If you want to do asymmetrical calculation with 3-leg core-type transformers, please set the attribute `i0_zero_sequence`. If the transformer specificaiton does not provide such an attribute, a good guess will be `i0_zero_sequence = 1.0`. +``` #### Electric Model From 9a4660bc581e8fe3a2e868e3f94873918bbb9af1 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Fri, 28 Nov 2025 13:38:35 +0100 Subject: [PATCH 19/23] use note block Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- docs/user_manual/components.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index 229c72599..d13305211 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -226,7 +226,7 @@ Due to lack of iron-core pass for zero-sequence flux, the zero-sequence magnetization current is usually significantly higher than positive sequence. If you want to do asymmetrical calculation with 3-leg core-type transformers, please set the attribute `i0_zero_sequence`. -If the transformer specificaiton does not provide such an attribute, +If the transformer specification does not provide such an attribute, a good guess will be `i0_zero_sequence = 1.0`. ``` From 960e7d2f626577ca2d7c3d802027e12e42e46c76 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Sun, 30 Nov 2025 10:06:21 +0100 Subject: [PATCH 20/23] add explain Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- docs/user_manual/components.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index d13305211..0666697c2 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -228,6 +228,8 @@ If you want to do asymmetrical calculation with 3-leg core-type transformers, please set the attribute `i0_zero_sequence`. If the transformer specification does not provide such an attribute, a good guess will be `i0_zero_sequence = 1.0`. +See [OpenDSS Documentation](https://opendss.epri.com/3-PhaseTransformerModeling.html) +for detailed explanation. ``` #### Electric Model From fc43639bfd5709182e47c47cdc4a4a1c31347616 Mon Sep 17 00:00:00 2001 From: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> Date: Mon, 1 Dec 2025 10:29:19 +0100 Subject: [PATCH 21/23] Update power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp Co-authored-by: Peter Salemink <66305765+petersalemink95@users.noreply.github.com> Signed-off-by: Tony Xiang <19280867+TonyXiang8787@users.noreply.github.com> --- .../include/power_grid_model/component/transformer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index 9edec347d..7d29b5679 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -219,7 +219,7 @@ class Transformer : public Branch { // shunt zero sequence DoubleComplex y0_shunt; - // Y0 = I0_0 / (U2/sqrt3) = i0_zero_sequence_ * (S / sqrt3 / U2) / (U2/sqrt3) = i0_zero_sequence_ * S * / U2 / + // Y0 = I0_0 / (U2/sqrt3) = i0_zero_sequence_ * (S / sqrt3 / U2) / (U2/sqrt3) = i0_zero_sequence_ * S / U2 / // U2 double const y0_shunt_abs = i0_zero_sequence_ * sn_ / u2 / u2; // G0 = P0_0 / (U2^2) From dd65b76308309ac19a7f5a346567da2f55df2622 Mon Sep 17 00:00:00 2001 From: petersalemink95 Date: Mon, 1 Dec 2025 13:30:36 +0100 Subject: [PATCH 22/23] add magnetizing to i0 docs Signed-off-by: petersalemink95 --- docs/user_manual/components.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index 0666697c2..339e35325 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -192,9 +192,9 @@ An example of usage of transformer is given in [Transformer Examples](../example | `sn` | `double` | volt-ampere (VA) | rated power | ✔ | ❌ | `> 0` | | `uk` | `double` | - | relative short circuit voltage, `0.1` means 10% | ✔ | ❌ | `>= pk / sn` and `> 0` and `< 1` | | `pk` | `double` | watt (W) | short circuit (copper) loss | ✔ | ❌ | `>= 0` | -| `i0` | `double` | - | relative no-load current | ✔ | ❌ | `>= p0 / sn` and `< 1` | +| `i0` | `double` | - | relative no-load (magnetizing) current | ✔ | ❌ | `>= p0 / sn` and `< 1` | | `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | -| `i0_zero_sequence` | `double` | - | zero-sequence relative no-load current | ❌ default `i0` | ❌ | `>= p0_zero_sequence / sn` and `< 1` | +| `i0_zero_sequence` | `double` | - | zero-sequence relative no-load (magnetizing) current | ❌ default `i0` | ❌ | `>= p0_zero_sequence / sn` and `< 1` | | `p0_zero_sequence` | `double` | watt (W) | zero-sequence no-load (iron) loss | ❌ default `p0 + pk * (i0_zero_sequence^2 - i0^2)` | ❌ | `>= 0` | | `winding_from` | {py:class}`WindingType ` | - | from-side winding type | ✔ | ❌ | | | `winding_to` | {py:class}`WindingType ` | - | to-side winding type | ✔ | ❌ | | @@ -524,7 +524,7 @@ An example of usage of three-winding transformer is given in | `pk_12` | `double` | watt (W) | short circuit (copper) loss across side 1-2 | ✔ | ❌ | `>= 0` | | `pk_13` | `double` | watt (W) | short circuit (copper) loss across side 1-3 | ✔ | ❌ | `>= 0` | | `pk_23` | `double` | watt (W) | short circuit (copper) loss across side 2-3 | ✔ | ❌ | `>= 0` | -| `i0` | `double` | - | relative no-load current with respect to side 1 | ✔ | ❌ | `>= p0 / sn` and `< 1` | +| `i0` | `double` | - | relative no-load (magnetizing) current with respect to side 1 | ✔ | ❌ | `>= p0 / sn` and `< 1` | | `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | | `winding_1` | {py:class}`WindingType ` | - | side 1 winding type | ✔ | ❌ | | | `winding_2` | {py:class}`WindingType ` | - | side 2 winding type | ✔ | ❌ | | From 63bc9b3c980aa018ab0f58039f6e1490de257ce5 Mon Sep 17 00:00:00 2001 From: petersalemink95 Date: Mon, 1 Dec 2025 13:53:53 +0100 Subject: [PATCH 23/23] add magnetizing to p0 Signed-off-by: petersalemink95 --- docs/user_manual/components.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index 339e35325..e34baa953 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -193,9 +193,9 @@ An example of usage of transformer is given in [Transformer Examples](../example | `uk` | `double` | - | relative short circuit voltage, `0.1` means 10% | ✔ | ❌ | `>= pk / sn` and `> 0` and `< 1` | | `pk` | `double` | watt (W) | short circuit (copper) loss | ✔ | ❌ | `>= 0` | | `i0` | `double` | - | relative no-load (magnetizing) current | ✔ | ❌ | `>= p0 / sn` and `< 1` | -| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | +| `p0` | `double` | watt (W) | no-load (iron / magnetizing) loss | ✔ | ❌ | `>= 0` | | `i0_zero_sequence` | `double` | - | zero-sequence relative no-load (magnetizing) current | ❌ default `i0` | ❌ | `>= p0_zero_sequence / sn` and `< 1` | -| `p0_zero_sequence` | `double` | watt (W) | zero-sequence no-load (iron) loss | ❌ default `p0 + pk * (i0_zero_sequence^2 - i0^2)` | ❌ | `>= 0` | +| `p0_zero_sequence` | `double` | watt (W) | zero-sequence no-load (iron / magnetizing) loss | ❌ default `p0 + pk * (i0_zero_sequence^2 - i0^2)` | ❌ | `>= 0` | | `winding_from` | {py:class}`WindingType ` | - | from-side winding type | ✔ | ❌ | | | `winding_to` | {py:class}`WindingType ` | - | to-side winding type | ✔ | ❌ | | | `clock` | `int8_t` | - | clock number of phase shift. Even number is not possible if one side is Y(N) winding and the other side is not Y(N) winding. Odd number is not possible, if both sides are Y(N) winding or both sides are not Y(N) winding. | ✔ | ❌ | `>= -12` and `<= 12` | @@ -525,7 +525,7 @@ An example of usage of three-winding transformer is given in | `pk_13` | `double` | watt (W) | short circuit (copper) loss across side 1-3 | ✔ | ❌ | `>= 0` | | `pk_23` | `double` | watt (W) | short circuit (copper) loss across side 2-3 | ✔ | ❌ | `>= 0` | | `i0` | `double` | - | relative no-load (magnetizing) current with respect to side 1 | ✔ | ❌ | `>= p0 / sn` and `< 1` | -| `p0` | `double` | watt (W) | no-load (iron) loss | ✔ | ❌ | `>= 0` | +| `p0` | `double` | watt (W) | no-load (iron / magnetizing) loss | ✔ | ❌ | `>= 0` | | `winding_1` | {py:class}`WindingType ` | - | side 1 winding type | ✔ | ❌ | | | `winding_2` | {py:class}`WindingType ` | - | side 2 winding type | ✔ | ❌ | | | `winding_3` | {py:class}`WindingType ` | - | side 3 winding type | ✔ | ❌ | |