From 9d6498f6347e9c5ee22d20155925f7e3d902a392 Mon Sep 17 00:00:00 2001 From: leovsch Date: Thu, 3 Oct 2024 17:18:37 +0200 Subject: [PATCH 01/12] Added implementation for asym_line input --- .../data/attribute_classes/input.json | 49 ++++++ .../dataset_definitions.json | 12 +- .../power_grid_model/all_components.hpp | 3 +- .../power_grid_model/auxiliary/input.hpp | 49 ++++++ .../auxiliary/meta_gen/input.hpp | 46 +++++ .../auxiliary/static_asserts/input.hpp | 19 +++ .../power_grid_model/common/common.hpp | 1 + .../power_grid_model/common/exception.hpp | 11 ++ .../common/three_phase_tensor.hpp | 20 +++ .../power_grid_model/component/asym_line.hpp | 139 ++++++++++++++++ .../power_grid_model_c/dataset_definitions.h | 84 ++++++++++ .../src/dataset_definitions.cpp | 84 ++++++++++ .../_core/dataset_definitions.py | 1 + tests/cpp_unit_tests/CMakeLists.txt | 1 + tests/cpp_unit_tests/test_asym_line.cpp | 157 ++++++++++++++++++ 15 files changed, 673 insertions(+), 3 deletions(-) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp create mode 100644 tests/cpp_unit_tests/test_asym_line.cpp diff --git a/code_generation/data/attribute_classes/input.json b/code_generation/data/attribute_classes/input.json index 7cf8b5c97..834390925 100644 --- a/code_generation/data/attribute_classes/input.json +++ b/code_generation/data/attribute_classes/input.json @@ -127,6 +127,55 @@ } ] }, + { + "name": "AsymLineInput", + "base": "BranchInput", + "attributes": [ + { + "data_type": "double", + "names": [ + "r_aa", + "r_ba", + "r_bb", + "r_ca", + "r_cb", + "r_cc", + "r_na", + "r_nb", + "r_nc", + "r_nn", + "x_aa", + "x_ba", + "x_bb", + "x_ca", + "x_cb", + "x_cc", + "x_na", + "x_nb", + "x_nc", + "x_nn", + "c_aa", + "c_ba", + "c_bb", + "c_ca", + "c_cb", + "c_cc", + "c_na", + "c_nb", + "c_nc", + "c_nn", + "c0", + "c1" + ], + "description": "Lower triangle matrix values for R, X and C matrices" + }, + { + "data_type": "double", + "names": "i_n", + "description": "rated current" + } + ] + }, { "name": "GenericBranchInput", "base": "BranchInput", diff --git a/code_generation/data/dataset_class_maps/dataset_definitions.json b/code_generation/data/dataset_class_maps/dataset_definitions.json index e4cb9073d..78834d419 100644 --- a/code_generation/data/dataset_class_maps/dataset_definitions.json +++ b/code_generation/data/dataset_class_maps/dataset_definitions.json @@ -12,6 +12,10 @@ "names": ["line"], "class_name": "LineInput" }, + { + "names": ["asym_line"], + "class_name": "AsymLineInput" + }, { "names": ["link"], "class_name": "LinkInput" @@ -67,7 +71,7 @@ "class_name": "NodeOutput" }, { - "names": ["line", "link", "transformer", "generic_branch"], + "names": ["line", "link", "transformer", "generic_branch", "asym_line"], "class_name": "BranchOutput" }, { @@ -108,6 +112,10 @@ "names": ["line"], "class_name": "BranchUpdate" }, + { + "names": ["asym_line"], + "class_name": "BranchUpdate" + }, { "names": ["link"], "class_name": "BranchUpdate" @@ -159,7 +167,7 @@ "class_name": "NodeShortCircuitOutput" }, { - "names": ["line", "link", "transformer"], + "names": ["line", "link", "transformer", "asym_line"], "class_name": "BranchShortCircuitOutput" }, { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/all_components.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/all_components.hpp index 7ed9be5a3..2293e9dcb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/all_components.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/all_components.hpp @@ -12,6 +12,7 @@ #include "component/fault.hpp" #include "component/generic_branch.hpp" #include "component/line.hpp" +#include "component/asym_line.hpp" #include "component/link.hpp" #include "component/load_gen.hpp" #include "component/node.hpp" @@ -27,7 +28,7 @@ namespace power_grid_model { using AllComponents = - ComponentList; 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 661579d1c..2d1127c88 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 @@ -98,6 +98,55 @@ struct LineInput { operator BranchInput const&() const { return reinterpret_cast(*this); } }; +struct AsymLineInput { + ID id{na_IntID}; // ID of the object + ID from_node{na_IntID}; // node IDs to which this branch is connected at both sides + ID to_node{na_IntID}; // node IDs to which this branch is connected at both sides + IntS from_status{na_IntS}; // whether the branch is connected at each side + IntS to_status{na_IntS}; // whether the branch is connected at each side + double r_aa{nan}; // Lower triangle matrix values for R, X and C matrices + double r_ba{nan}; // Lower triangle matrix values for R, X and C matrices + double r_bb{nan}; // Lower triangle matrix values for R, X and C matrices + double r_ca{nan}; // Lower triangle matrix values for R, X and C matrices + double r_cb{nan}; // Lower triangle matrix values for R, X and C matrices + double r_cc{nan}; // Lower triangle matrix values for R, X and C matrices + double r_na{nan}; // Lower triangle matrix values for R, X and C matrices + double r_nb{nan}; // Lower triangle matrix values for R, X and C matrices + double r_nc{nan}; // Lower triangle matrix values for R, X and C matrices + double r_nn{nan}; // Lower triangle matrix values for R, X and C matrices + double x_aa{nan}; // Lower triangle matrix values for R, X and C matrices + double x_ba{nan}; // Lower triangle matrix values for R, X and C matrices + double x_bb{nan}; // Lower triangle matrix values for R, X and C matrices + double x_ca{nan}; // Lower triangle matrix values for R, X and C matrices + double x_cb{nan}; // Lower triangle matrix values for R, X and C matrices + double x_cc{nan}; // Lower triangle matrix values for R, X and C matrices + double x_na{nan}; // Lower triangle matrix values for R, X and C matrices + double x_nb{nan}; // Lower triangle matrix values for R, X and C matrices + double x_nc{nan}; // Lower triangle matrix values for R, X and C matrices + double x_nn{nan}; // Lower triangle matrix values for R, X and C matrices + double c_aa{nan}; // Lower triangle matrix values for R, X and C matrices + double c_ba{nan}; // Lower triangle matrix values for R, X and C matrices + double c_bb{nan}; // Lower triangle matrix values for R, X and C matrices + double c_ca{nan}; // Lower triangle matrix values for R, X and C matrices + double c_cb{nan}; // Lower triangle matrix values for R, X and C matrices + double c_cc{nan}; // Lower triangle matrix values for R, X and C matrices + double c_na{nan}; // Lower triangle matrix values for R, X and C matrices + double c_nb{nan}; // Lower triangle matrix values for R, X and C matrices + double c_nc{nan}; // Lower triangle matrix values for R, X and C matrices + double c_nn{nan}; // Lower triangle matrix values for R, X and C matrices + double c0{nan}; // Lower triangle matrix values for R, X and C matrices + double c1{nan}; // Lower triangle matrix values for R, X and C matrices + double i_n{nan}; // rated current + + // implicit conversions to BaseInput + operator BaseInput&() { return reinterpret_cast(*this); } + operator BaseInput const&() const { return reinterpret_cast(*this); } + + // implicit conversions to BranchInput + operator BranchInput&() { return reinterpret_cast(*this); } + operator BranchInput const&() const { return reinterpret_cast(*this); } +}; + struct GenericBranchInput { ID id{na_IntID}; // ID of the object ID from_node{na_IntID}; // node IDs to which this branch is connected at both sides 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 27deffff7..b96e7f87c 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 @@ -111,6 +111,52 @@ struct get_attributes_list { }; }; +template<> +struct get_attributes_list { + static constexpr std::array value{ + // all attributes including base class + + meta_data_gen::get_meta_attribute<&AsymLineInput::id>(offsetof(AsymLineInput, id), "id"), + meta_data_gen::get_meta_attribute<&AsymLineInput::from_node>(offsetof(AsymLineInput, from_node), "from_node"), + meta_data_gen::get_meta_attribute<&AsymLineInput::to_node>(offsetof(AsymLineInput, to_node), "to_node"), + meta_data_gen::get_meta_attribute<&AsymLineInput::from_status>(offsetof(AsymLineInput, from_status), "from_status"), + meta_data_gen::get_meta_attribute<&AsymLineInput::to_status>(offsetof(AsymLineInput, to_status), "to_status"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_aa>(offsetof(AsymLineInput, r_aa), "r_aa"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_ba>(offsetof(AsymLineInput, r_ba), "r_ba"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_bb>(offsetof(AsymLineInput, r_bb), "r_bb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_ca>(offsetof(AsymLineInput, r_ca), "r_ca"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_cb>(offsetof(AsymLineInput, r_cb), "r_cb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_cc>(offsetof(AsymLineInput, r_cc), "r_cc"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_na>(offsetof(AsymLineInput, r_na), "r_na"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_nb>(offsetof(AsymLineInput, r_nb), "r_nb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_nc>(offsetof(AsymLineInput, r_nc), "r_nc"), + meta_data_gen::get_meta_attribute<&AsymLineInput::r_nn>(offsetof(AsymLineInput, r_nn), "r_nn"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_aa>(offsetof(AsymLineInput, x_aa), "x_aa"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_ba>(offsetof(AsymLineInput, x_ba), "x_ba"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_bb>(offsetof(AsymLineInput, x_bb), "x_bb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_ca>(offsetof(AsymLineInput, x_ca), "x_ca"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_cb>(offsetof(AsymLineInput, x_cb), "x_cb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_cc>(offsetof(AsymLineInput, x_cc), "x_cc"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_na>(offsetof(AsymLineInput, x_na), "x_na"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_nb>(offsetof(AsymLineInput, x_nb), "x_nb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_nc>(offsetof(AsymLineInput, x_nc), "x_nc"), + meta_data_gen::get_meta_attribute<&AsymLineInput::x_nn>(offsetof(AsymLineInput, x_nn), "x_nn"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_aa>(offsetof(AsymLineInput, c_aa), "c_aa"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_ba>(offsetof(AsymLineInput, c_ba), "c_ba"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_bb>(offsetof(AsymLineInput, c_bb), "c_bb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_ca>(offsetof(AsymLineInput, c_ca), "c_ca"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_cb>(offsetof(AsymLineInput, c_cb), "c_cb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_cc>(offsetof(AsymLineInput, c_cc), "c_cc"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_na>(offsetof(AsymLineInput, c_na), "c_na"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_nb>(offsetof(AsymLineInput, c_nb), "c_nb"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_nc>(offsetof(AsymLineInput, c_nc), "c_nc"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c_nn>(offsetof(AsymLineInput, c_nn), "c_nn"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c0>(offsetof(AsymLineInput, c0), "c0"), + meta_data_gen::get_meta_attribute<&AsymLineInput::c1>(offsetof(AsymLineInput, c1), "c1"), + meta_data_gen::get_meta_attribute<&AsymLineInput::i_n>(offsetof(AsymLineInput, i_n), "i_n"), + }; +}; + template<> struct get_attributes_list { static constexpr std::array value{ diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp index ee0052125..76913f717 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/auxiliary/static_asserts/input.hpp @@ -70,6 +70,25 @@ static_assert(offsetof(LineInput, to_node) == offsetof(BranchInput, to_node)); static_assert(offsetof(LineInput, from_status) == offsetof(BranchInput, from_status)); static_assert(offsetof(LineInput, to_status) == offsetof(BranchInput, to_status)); +// static asserts for AsymLineInput +static_assert(std::is_standard_layout_v); +// static asserts for conversion of AsymLineInput to BaseInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(offsetof(AsymLineInput, id) == offsetof(BaseInput, id)); +// static asserts for conversion of AsymLineInput to BranchInput +static_assert(std::alignment_of_v >= std::alignment_of_v); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(std::same_as); +static_assert(offsetof(AsymLineInput, id) == offsetof(BranchInput, id)); +static_assert(offsetof(AsymLineInput, from_node) == offsetof(BranchInput, from_node)); +static_assert(offsetof(AsymLineInput, to_node) == offsetof(BranchInput, to_node)); +static_assert(offsetof(AsymLineInput, from_status) == offsetof(BranchInput, from_status)); +static_assert(offsetof(AsymLineInput, to_status) == offsetof(BranchInput, to_status)); + // static asserts for GenericBranchInput static_assert(std::is_standard_layout_v); // static asserts for conversion of GenericBranchInput to BaseInput diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp index 740d40531..75c287f90 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp @@ -56,6 +56,7 @@ using DoubleComplex = std::complex; using std::numbers::inv_sqrt3; using std::numbers::pi; using std::numbers::sqrt3; +using std::numbers::e; constexpr DoubleComplex a2{-0.5, -sqrt3 / 2.0}; constexpr DoubleComplex a{-0.5, sqrt3 / 2.0}; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp index 14218306b..025c00fdc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp @@ -59,6 +59,17 @@ class MissingCaseForEnumError : public InvalidArguments { } }; +class UnsupportedInputDescriptionAsymLine : public PowerGridError { + public: + UnsupportedInputDescriptionAsymLine() { + append_msg("Invalid or missing parameters supplied for component asym_line. The following input specifications are allowed"); + append_msg("3 phase x_matrix, 3 phase r_matrix and 3 phase c_matrix"); + append_msg("3 phase + neutral x_matrix, 3 phase + neutral r_matrix and 3 phase + neutral c_matrix"); + append_msg("3 phase x_matrix, 3 phase r_matrix and c1, c0"); + append_msg("3 phase + neutral x_matrix, 3 phase + neutral r_matrix and c1, c0"); + } +}; + class ConflictVoltage : public PowerGridError { public: ConflictVoltage(ID id, ID id1, ID id2, double u1, double u2) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp index afd72324e..a18311b48 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp @@ -22,6 +22,7 @@ namespace three_phase_tensor { template using Eigen3Vector = Eigen::Array; template using Eigen3Tensor = Eigen::Array; +template using Eigen4Tensor = Eigen::Array; template using Eigen3DiagonalTensor = Eigen::DiagonalMatrix; template class Vector : public Eigen3Vector { @@ -61,6 +62,8 @@ template class Tensor : public Eigen3Tensor { // additional constructors explicit Tensor(T const& x) { (*this) << x, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, x; } explicit Tensor(T const& s, T const& m) { (*this) << s, m, m, m, s, m, m, m, s; } + explicit Tensor(T const& x1, T const& x2, T const& x3, T const& x4, T const& x5, T const& x6) { (*this) << x1, x2, x4, x2, x3, x5, x4, x5, x6; } + explicit Tensor(T const& x1, T const& x2, T const& x3, T const& x4, T const& x5, T const& x6, T const& x7, T const& x8, T const& x9) { (*this) << x1, x2, x3, x4, x5, x6, x7, x8, x9; } explicit Tensor(Vector const& v) { (*this) << v(0), 0.0, 0.0, 0.0, v(1), 0.0, 0.0, 0.0, v(2); } // eigen expression template Tensor(Eigen::ArrayBase const& other) : Eigen3Tensor{other} {} @@ -70,6 +73,22 @@ template class Tensor : public Eigen3Tensor { } }; +template class Tensor4 : public Eigen4Tensor { + public: + Tensor4() { (*this) = Eigen4Tensor::Zero(); } + // additional constructors + explicit Tensor4(T const& x) { (*this) << x, 0.0, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, x; } + explicit Tensor4(T const& s, T const& m) { (*this) << s, m, m, m, m, s, m, m, m, m, s, m, m, m, m, s; } + explicit Tensor4(T const& x1, T const& x2, T const& x3, T const& x4, T const& x5, T const& x6, T const& x7, T const& x8, T const& x9, T const& x10) { (*this) << x1, x2, x4, x7, x2, x3, x5, x8, x4, x5, x6, x9, x7, x8, x9, x10; } + explicit Tensor4(Vector const& v) { (*this) << v(0), 0.0, 0.0, 0.0, 0.0, v(1), 0.0, 0.0, 0.0, 0.0, v(2), 0.0, 0.0, 0.0, 0.0, v(3); } + // eigen expression + template Tensor4(Eigen::ArrayBase const& other) : Eigen4Tensor{other} {} + template Tensor4& operator=(Eigen::ArrayBase const& other) { + this->Eigen4Tensor::operator=(other); + return *this; + } +}; + template class DiagonalTensor : public Eigen3DiagonalTensor { public: DiagonalTensor() { (*this).setZero(); } @@ -92,6 +111,7 @@ template using RealTensor = std::conditional_t, double, three_phase_tensor::Tensor>; template using ComplexTensor = std::conditional_t, DoubleComplex, three_phase_tensor::Tensor>; +using ComplexTensor4 = three_phase_tensor::Tensor4; template using RealDiagonalTensor = std::conditional_t, double, three_phase_tensor::DiagonalTensor>; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp new file mode 100644 index 000000000..267ce577e --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp @@ -0,0 +1,139 @@ +#pragma once + +#include + +#include +#include "branch.hpp" + +#include "../auxiliary/input.hpp" +#include "../auxiliary/output.hpp" +#include "../auxiliary/update.hpp" +#include "../calculation_parameters.hpp" +#include "../common/common.hpp" +#include "../common/three_phase_tensor.hpp" + +namespace power_grid_model { + +class AsymLine : public Branch { + public: + using InputType = AsymLineInput; + using UpdateType = BranchUpdate; + static constexpr char const* name = "asym_line"; + + explicit AsymLine(AsymLineInput const& asym_line_input, double system_frequency, double u1, double u2) + : Branch{asym_line_input}, i_n_{asym_line_input.i_n}, base_i_{base_power_3p / u1 / sqrt3} { + if (cabs(u1 - u2) > numerical_tolerance) { + throw ConflictVoltage{id(), from_node(), to_node(), u1, u2}; + } + + ComplexTensor c_matrix = compute_c_matrix_from_input(asym_line_input); + ComplexTensor z_series = compute_z_series_from_input(asym_line_input); + + ComplexTensor empty_tensor; + + if (c_matrix.isZero() || z_series.isZero()) { + throw UnsupportedInputDescriptionAsymLine(); + } + + y_series = inv(z_series); + y_shunt = 2 * pi * system_frequency * c_matrix * 1.0i; + } + + // override getter + double base_i_from() const override { return base_i_; } + double base_i_to() const override { return base_i_; } + double loading(double /* max_s */, double max_i) const override { return max_i / i_n_; }; + double phase_shift() const override { return 0.0; } + bool is_param_mutable() const override { return false; } + + private: + double i_n_; + double base_i_; + ComplexTensor y_series; + ComplexTensor y_shunt; + + ComplexTensor kron_reduction(const ComplexTensor4& matrix_to_reduce) const { + ComplexTensor4 Y = matrix_to_reduce; + ComplexTensor Y_aa = ComplexTensor(Y(0,0), Y(1,0), Y(1, 1), Y(2,0), Y(2,1), Y(2,2)); + ComplexValue Y_ab(Y(0,3), Y(1,3), Y(2,3)); + Eigen::Array Y_ba; + Y_ba << Y(3,0), Y(3,1), Y(3,2); + DoubleComplex Y_bb_inv = 1.0 / Y(3,3); + + return Y_aa - ((Y_ab * Y_bb_inv).matrix() * Y_ba.matrix()).array(); + } + + ComplexTensor compute_z_series_from_input(const power_grid_model::AsymLineInput& asym_line_input) { + ComplexTensor z_series_abc; + if (is_nan(asym_line_input.r_na) && is_nan(asym_line_input.x_na)) { + ComplexTensor r_matrix = ComplexTensor(asym_line_input.r_aa, asym_line_input.r_ba, asym_line_input.r_bb, asym_line_input.r_ca, asym_line_input.r_cb, asym_line_input.r_cc); + ComplexTensor x_matrix = ComplexTensor(asym_line_input.x_aa, asym_line_input.x_ba, asym_line_input.x_bb, asym_line_input.x_ca, asym_line_input.x_cb, asym_line_input.x_cc); + z_series_abc = r_matrix + x_matrix * 1.0i; + } + else { + ComplexTensor4 r_matrix = ComplexTensor4(asym_line_input.r_aa, asym_line_input.r_ba, asym_line_input.r_bb, asym_line_input.r_ca, asym_line_input.r_cb, asym_line_input.r_cc, asym_line_input.r_na, asym_line_input.r_nb, asym_line_input.r_nc, asym_line_input.r_nn); + ComplexTensor4 x_matrix = ComplexTensor4(asym_line_input.x_aa, asym_line_input.x_ba, asym_line_input.x_bb, asym_line_input.x_ca, asym_line_input.x_cb, asym_line_input.x_cc, asym_line_input.x_na, asym_line_input.x_nb, asym_line_input.x_nc, asym_line_input.x_nn); + + ComplexTensor4 y = r_matrix + 1.0i * x_matrix; + z_series_abc = kron_reduction(y); + } + DoubleComplex a = std::pow(e, 1.0i * (2.0 / 3.0) * pi); + ComplexTensor a_matrix = ComplexTensor(1, 1, pow(a, 2), 1, a, pow(a, 2)); + ComplexTensor a_matrix_inv = (1.0/3.0) * ComplexTensor(1, 1, a, 1, pow(a, 2), a); + ComplexTensor z_series = (a_matrix_inv.matrix() * z_series_abc.matrix() * a_matrix.matrix()).array(); + return z_series; + } + + ComplexTensor compute_c_matrix_from_input(const power_grid_model::AsymLineInput& asym_line_input) { + ComplexTensor c_matrix; + if (!is_nan(asym_line_input.c0) && !is_nan(asym_line_input.c1)) { + c_matrix = ComplexTensor(asym_line_input.c0 + asym_line_input.c1, -asym_line_input.c1); + } + else if (is_nan(asym_line_input.c_nn)) { + c_matrix = ComplexTensor(asym_line_input.c_aa, asym_line_input.c_ba, asym_line_input.c_bb, asym_line_input.c_ca, asym_line_input.c_cb, asym_line_input.c_cc); + } + else { + ComplexTensor4 c_matrix_neutral = ComplexTensor4(asym_line_input.c_aa, asym_line_input.c_ba, asym_line_input.c_bb, asym_line_input.c_ca, asym_line_input.c_cb, asym_line_input.c_cc, asym_line_input.c_na, asym_line_input.c_nb, asym_line_input.c_nc, asym_line_input.c_nn); + c_matrix = this->kron_reduction(c_matrix_neutral); + } + return c_matrix; + } + + DoubleComplex average_of_diagonal_of_matrix(const ComplexTensor &matrix) const { + return (matrix(0,0) + matrix(1,1) + matrix(2,2)) / 3.0; + } + + DoubleComplex average_of_off_diagonal_of_matrix(const ComplexTensor &matrix) const { + return (matrix(0,2) + matrix(1,1) + matrix(2,0)) / 3.0; + } + + BranchCalcParam sym_calc_param() const override { + DoubleComplex y1_series_ = average_of_diagonal_of_matrix(y_series) - average_of_off_diagonal_of_matrix(y_series); + DoubleComplex y1_shunt_ = average_of_diagonal_of_matrix(y_shunt) - average_of_off_diagonal_of_matrix(y_shunt); + return calc_param_y_sym(y1_series_, y1_shunt_, 1.0); + } + + BranchCalcParam asym_calc_param() const override { + BranchCalcParam param{}; + // not both connected + if (!branch_status()) { + // single connected + if (from_status() || to_status()) { + // branch_shunt = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); + ComplexTensor branch_shunt = 0.5 * inv(y_shunt) + inv(inv(y_series) + 2.0 * inv(y_shunt)); + // from or to connected + param.yff() = from_status() ? branch_shunt : ComplexTensor(); + param.ytt() = to_status() ? branch_shunt : ComplexTensor(); + } + } + // both connected + else { + param.ytt() = y_series + 0.5 * y_shunt; + param.yff() = param.ytt(); + param.yft() = y_series; + param.ytf() = y_series; + } + return param; + } +}; +} \ No newline at end of file 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 3be340891..2c47dc4fa 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 @@ -47,6 +47,47 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_input_line_x0; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_line_c0; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_line_tan0; PGM_API extern PGM_MetaAttribute const* const PGM_def_input_line_i_n; +// component asym_line +PGM_API extern PGM_MetaComponent const* const PGM_def_input_asym_line; +// attributes of input asym_line +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_from_node; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_to_node; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_from_status; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_to_status; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_aa; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_ba; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_bb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_ca; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_cb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_cc; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_na; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_nb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_nc; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_r_nn; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_aa; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_ba; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_bb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_ca; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_cb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_cc; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_na; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_nb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_nc; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_x_nn; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_aa; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_ba; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_bb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_ca; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_cb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_cc; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_na; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_nb; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_nc; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c_nn; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c0; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_c1; +PGM_API extern PGM_MetaAttribute const* const PGM_def_input_asym_line_i_n; // component link PGM_API extern PGM_MetaComponent const* const PGM_def_input_link; // attributes of input link @@ -340,6 +381,20 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_ PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_q_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_s_to; +// component asym_line +PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_asym_line; +// attributes of sym_output asym_line +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_loading; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_p_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_q_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_s_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_p_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_q_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_s_to; // component transformer_tap_regulator PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_transformer_tap_regulator; // attributes of sym_output transformer_tap_regulator @@ -526,6 +581,20 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_q_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_s_to; +// component asym_line +PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_asym_line; +// attributes of asym_output asym_line +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_loading; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_p_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_q_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_s_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_p_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_q_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_s_to; // component transformer_tap_regulator PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_transformer_tap_regulator; // attributes of asym_output transformer_tap_regulator @@ -656,6 +725,12 @@ PGM_API extern PGM_MetaComponent const* const PGM_def_update_line; PGM_API extern PGM_MetaAttribute const* const PGM_def_update_line_id; PGM_API extern PGM_MetaAttribute const* const PGM_def_update_line_from_status; PGM_API extern PGM_MetaAttribute const* const PGM_def_update_line_to_status; +// component asym_line +PGM_API extern PGM_MetaComponent const* const PGM_def_update_asym_line; +// attributes of update asym_line +PGM_API extern PGM_MetaAttribute const* const PGM_def_update_asym_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_update_asym_line_from_status; +PGM_API extern PGM_MetaAttribute const* const PGM_def_update_asym_line_to_status; // component link PGM_API extern PGM_MetaComponent const* const PGM_def_update_link; // attributes of update link @@ -806,6 +881,15 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_fr PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_from_angle; PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_to_angle; +// component asym_line +PGM_API extern PGM_MetaComponent const* const PGM_def_sc_output_asym_line; +// attributes of sc_output asym_line +PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_from_angle; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_to_angle; // component three_winding_transformer PGM_API extern PGM_MetaComponent const* const PGM_def_sc_output_three_winding_transformer; // attributes of sc_output three_winding_transformer 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 9639a9755..c7d309962 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 @@ -36,6 +36,47 @@ PGM_MetaAttribute const* const PGM_def_input_line_x0 = PGM_meta_get_attribute_by PGM_MetaAttribute const* const PGM_def_input_line_c0 = PGM_meta_get_attribute_by_name(nullptr, "input", "line", "c0"); PGM_MetaAttribute const* const PGM_def_input_line_tan0 = PGM_meta_get_attribute_by_name(nullptr, "input", "line", "tan0"); PGM_MetaAttribute const* const PGM_def_input_line_i_n = PGM_meta_get_attribute_by_name(nullptr, "input", "line", "i_n"); +// component asym_line +PGM_MetaComponent const* const PGM_def_input_asym_line = PGM_meta_get_component_by_name(nullptr, "input", "asym_line"); +// attributes of input asym_line +PGM_MetaAttribute const* const PGM_def_input_asym_line_id = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "id"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_from_node = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "from_node"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_to_node = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "to_node"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_from_status = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "from_status"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_to_status = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "to_status"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_aa = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_aa"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_ba = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_ba"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_bb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_bb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_ca = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_ca"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_cb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_cb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_cc = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_cc"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_na = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_na"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_nb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_nb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_nc = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_nc"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_r_nn = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "r_nn"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_aa = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_aa"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_ba = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_ba"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_bb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_bb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_ca = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_ca"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_cb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_cb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_cc = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_cc"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_na = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_na"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_nb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_nb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_nc = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_nc"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_x_nn = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "x_nn"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_aa = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_aa"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_ba = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_ba"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_bb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_bb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_ca = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_ca"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_cb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_cb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_cc = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_cc"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_na = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_na"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_nb = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_nb"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_nc = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_nc"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c_nn = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c_nn"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c0 = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c0"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_c1 = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "c1"); +PGM_MetaAttribute const* const PGM_def_input_asym_line_i_n = PGM_meta_get_attribute_by_name(nullptr, "input", "asym_line", "i_n"); // component link PGM_MetaComponent const* const PGM_def_input_link = PGM_meta_get_component_by_name(nullptr, "input", "link"); // attributes of input link @@ -329,6 +370,20 @@ PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_p_to = PGM_meta PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "generic_branch", "q_to"); PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "generic_branch", "i_to"); PGM_MetaAttribute const* const PGM_def_sym_output_generic_branch_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "generic_branch", "s_to"); +// component asym_line +PGM_MetaComponent const* const PGM_def_sym_output_asym_line = PGM_meta_get_component_by_name(nullptr, "sym_output", "asym_line"); +// attributes of sym_output asym_line +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_id = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "id"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_energized = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "energized"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_loading = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "loading"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_p_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "p_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_q_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "q_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "i_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_s_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "s_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_p_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "p_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "q_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "i_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_asym_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "asym_line", "s_to"); // component transformer_tap_regulator PGM_MetaComponent const* const PGM_def_sym_output_transformer_tap_regulator = PGM_meta_get_component_by_name(nullptr, "sym_output", "transformer_tap_regulator"); // attributes of sym_output transformer_tap_regulator @@ -515,6 +570,20 @@ PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_p_to = PGM_met PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "generic_branch", "q_to"); PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "generic_branch", "i_to"); PGM_MetaAttribute const* const PGM_def_asym_output_generic_branch_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "generic_branch", "s_to"); +// component asym_line +PGM_MetaComponent const* const PGM_def_asym_output_asym_line = PGM_meta_get_component_by_name(nullptr, "asym_output", "asym_line"); +// attributes of asym_output asym_line +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_id = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "id"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_energized = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "energized"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_loading = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "loading"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_p_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "p_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_q_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "q_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "i_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_s_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "s_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_p_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "p_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "q_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "i_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_asym_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "asym_line", "s_to"); // component transformer_tap_regulator PGM_MetaComponent const* const PGM_def_asym_output_transformer_tap_regulator = PGM_meta_get_component_by_name(nullptr, "asym_output", "transformer_tap_regulator"); // attributes of asym_output transformer_tap_regulator @@ -645,6 +714,12 @@ PGM_MetaComponent const* const PGM_def_update_line = PGM_meta_get_component_by_n PGM_MetaAttribute const* const PGM_def_update_line_id = PGM_meta_get_attribute_by_name(nullptr, "update", "line", "id"); PGM_MetaAttribute const* const PGM_def_update_line_from_status = PGM_meta_get_attribute_by_name(nullptr, "update", "line", "from_status"); PGM_MetaAttribute const* const PGM_def_update_line_to_status = PGM_meta_get_attribute_by_name(nullptr, "update", "line", "to_status"); +// component asym_line +PGM_MetaComponent const* const PGM_def_update_asym_line = PGM_meta_get_component_by_name(nullptr, "update", "asym_line"); +// attributes of update asym_line +PGM_MetaAttribute const* const PGM_def_update_asym_line_id = PGM_meta_get_attribute_by_name(nullptr, "update", "asym_line", "id"); +PGM_MetaAttribute const* const PGM_def_update_asym_line_from_status = PGM_meta_get_attribute_by_name(nullptr, "update", "asym_line", "from_status"); +PGM_MetaAttribute const* const PGM_def_update_asym_line_to_status = PGM_meta_get_attribute_by_name(nullptr, "update", "asym_line", "to_status"); // component link PGM_MetaComponent const* const PGM_def_update_link = PGM_meta_get_component_by_name(nullptr, "update", "link"); // attributes of update link @@ -795,6 +870,15 @@ PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_from = PGM_meta_g PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_from_angle = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "transformer", "i_from_angle"); PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_to = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "transformer", "i_to"); PGM_MetaAttribute const* const PGM_def_sc_output_transformer_i_to_angle = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "transformer", "i_to_angle"); +// component asym_line +PGM_MetaComponent const* const PGM_def_sc_output_asym_line = PGM_meta_get_component_by_name(nullptr, "sc_output", "asym_line"); +// attributes of sc_output asym_line +PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_id = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "asym_line", "id"); +PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_energized = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "asym_line", "energized"); +PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "asym_line", "i_from"); +PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_from_angle = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "asym_line", "i_from_angle"); +PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "asym_line", "i_to"); +PGM_MetaAttribute const* const PGM_def_sc_output_asym_line_i_to_angle = PGM_meta_get_attribute_by_name(nullptr, "sc_output", "asym_line", "i_to_angle"); // component three_winding_transformer PGM_MetaComponent const* const PGM_def_sc_output_three_winding_transformer = PGM_meta_get_component_by_name(nullptr, "sc_output", "three_winding_transformer"); // attributes of sc_output three_winding_transformer diff --git a/src/power_grid_model/_core/dataset_definitions.py b/src/power_grid_model/_core/dataset_definitions.py index d8f8031b8..623aa46a8 100644 --- a/src/power_grid_model/_core/dataset_definitions.py +++ b/src/power_grid_model/_core/dataset_definitions.py @@ -56,6 +56,7 @@ class ComponentType(str, Enum, metaclass=_MetaEnum): node = "node" line = "line" + asym_line = "asym_line" link = "link" generic_branch = "generic_branch" transformer = "transformer" diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index 12c4d801a..44550c2b1 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -13,6 +13,7 @@ set(PROJECT_SOURCES "test_component_update.cpp" "test_three_phase_tensor.cpp" "test_node.cpp" + "test_asym_line.cpp" "test_line.cpp" "test_generic_branch.cpp" "test_link.cpp" diff --git a/tests/cpp_unit_tests/test_asym_line.cpp b/tests/cpp_unit_tests/test_asym_line.cpp new file mode 100644 index 000000000..6cfa8f63f --- /dev/null +++ b/tests/cpp_unit_tests/test_asym_line.cpp @@ -0,0 +1,157 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include + +namespace power_grid_model { + +using namespace std::complex_literals; + +TEST_CASE("Test asym line") { + double system_frequency = 50.0; + AsymLineInput const input{.id = 1, + .from_node = 2, + .to_node = 3, + .from_status = 1, + .to_status = 1, + .r_aa = 0.4369, + .r_ba = 0.0496, + .r_bb = 0.4369, + .r_ca = 0.0485, + .r_cb = 0.0496, + .r_cc = 0.4369, + .r_na = 0.0496, + .r_nb = 0.0485, + .r_nc = 0.0496, + .r_nn = 0.4369, + .x_aa = 0.8538, + .x_ba = 0.7886, + .x_bb = 0.8538, + .x_ca = 0.7663, + .x_cb = 0.7886, + .x_cc = 0.8538, + .x_na = 0.7886, + .x_nb = 0.7663, + .x_nc = 0.7886, + .x_nn = 0.8538, + .c0 = 0.18, + .c1 = 0.308, + .i_n = 216.0}; + AsymLine asym_line{input, system_frequency, 10.0e3, 10.0e3}; + double const base_i = base_power_1p / (10.0e3 / sqrt3); + double const base_y = base_i * base_i / base_power_1p; + Branch& branch = asym_line; + ComplexTensor const y_series = ComplexTensor(0.66303418-0.34266364i, -0.02971114+0.03783535i, 0.04762194+0.00681293i, 0.04762194+0.00681293i, 2.48612768-0.46271628i, 0.05942228-0.07567069i, -0.02971114+0.03783535i, -0.09524388-0.01362585i, 2.48612768-0.46271628i); + + ComplexTensor const y_shunt = 2 * pi * system_frequency * ComplexTensor(input.c0 + input.c1, -input.c1) * 1.0i; + + DoubleComplex const y1_series = (y_series(0,0) + y_series(1,1) + y_series(2,2)) / 3.0 - (y_series(0,2) + y_series(1,1) + y_series(2,0)) / 3.0; + DoubleComplex const y1_shunt = (y_shunt(0,0) + y_shunt(1,1) + y_shunt(2,2)) / 3.0 - (y_shunt(0,2) + y_shunt(1,1) + y_shunt(2,0)) / 3.0; + + // symmetric + DoubleComplex const yff1 = y1_series + 0.5 * y1_shunt; + DoubleComplex const yft1 = -y1_series; + DoubleComplex const ys1 = 0.5 * y1_shunt + 1.0 / (1.0 / y1_series + 2.0 / y1_shunt); + + // asymmetric + ComplexTensor ytt = y_series + 0.5 * y_shunt; + DoubleComplex const yff0 = ytt(0,0); + DoubleComplex const yft0 = -y_series(0,0); + DoubleComplex const ys0 = 0.5 * y_shunt(0,0) + 1.0 / (1.0 / y_series(0,0) + 2.0 / y_shunt(0,0)); + ComplexTensor const yffa{(2.0 * yff1 + yff0) / 3.0, (yff0 - yff1) / 3.0}; + ComplexTensor const yfta{(2.0 * yft1 + yft0) / 3.0, (yft0 - yft1) / 3.0}; + ComplexTensor const ysa{(2.0 * ys1 + ys0) / 3.0, (ys0 - ys1) / 3.0}; + + DoubleComplex const u1f = 1.0; + DoubleComplex const u1t = 0.9; + ComplexValue const uaf{1.0}; + ComplexValue const uat{0.9}; + DoubleComplex const i1f = (yff1 * u1f + yft1 * u1t) * base_i; + DoubleComplex const i1t = (yft1 * u1f + yff1 * u1t) * base_i; + DoubleComplex const s_f = conj(i1f) * u1f * 10e3 * sqrt3; + DoubleComplex const s_t = conj(i1t) * u1t * 10e3 * sqrt3; + double const loading = std::max(cabs(i1f), cabs(i1t)) / 200.0; + + // Short circuit results + DoubleComplex const if_sc{1.0, 1.0}; + DoubleComplex const it_sc{2.0, 2.0 * sqrt(3)}; + ComplexValue const if_sc_asym{1.0 + 1.0i}; + ComplexValue const it_sc_asym{2.0 + (2.0i * sqrt(3))}; + + CHECK(asym_line.math_model_type() == ComponentType::branch); + + SUBCASE("Voltge error") { CHECK_THROWS_AS(AsymLine(input, 50.0, 10.0e3, 50.0e3), ConflictVoltage); } + + SUBCASE("General") { + CHECK(branch.from_node() == 2); + CHECK(branch.to_node() == 3); + CHECK(branch.from_status() == true); + CHECK(branch.to_status() == true); + CHECK(branch.branch_status() == true); + CHECK(branch.status(BranchSide::from) == branch.from_status()); + CHECK(branch.status(BranchSide::to) == branch.to_status()); + CHECK(branch.base_i_from() == doctest::Approx(base_i)); + CHECK(branch.base_i_to() == doctest::Approx(base_i)); + CHECK(branch.phase_shift() == 0.0); + CHECK(!branch.is_param_mutable()); + } + + SUBCASE("Symmetric parameters") { + // double connected + BranchCalcParam param = branch.calc_param(); + CHECK(cabs(param.yff() - yff1) < numerical_tolerance); + CHECK(cabs(param.ytt() - yff1) < numerical_tolerance); + CHECK(cabs(param.ytf() - yft1) < numerical_tolerance); + CHECK(cabs(param.yft() - yft1) < numerical_tolerance); + // to connected + CHECK(branch.update(BranchUpdate{1, false, na_IntS}).topo); + param = branch.calc_param(); + CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); + CHECK(cabs(param.ytt() - ys1) < numerical_tolerance); + CHECK(cabs(param.ytf() - 0.0) < numerical_tolerance); + CHECK(cabs(param.yft() - 0.0) < numerical_tolerance); + // not connected + CHECK(branch.set_status(na_IntS, false)); + param = branch.calc_param(); + CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); + CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); + CHECK(cabs(param.ytf() - 0.0) < numerical_tolerance); + CHECK(cabs(param.yft() - 0.0) < numerical_tolerance); + // not changing + CHECK(!branch.set_status(false, false)); + // from connected + CHECK(branch.set_status(true, na_IntS)); + param = branch.calc_param(); + CHECK(cabs(param.yff() - ys1) < numerical_tolerance); + CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); + CHECK(cabs(param.ytf() - 0.0) < numerical_tolerance); + CHECK(cabs(param.yft() - 0.0) < numerical_tolerance); + } + + SUBCASE("Asymmetric parameters") { + // double connected + BranchCalcParam param = asym_line.calc_param(); + CHECK((cabs(param.yff() - yffa) < numerical_tolerance).all()); + CHECK((cabs(param.ytt() - yffa) < numerical_tolerance).all()); + CHECK((cabs(param.ytf() - yfta) < numerical_tolerance).all()); + CHECK((cabs(param.yft() - yfta) < numerical_tolerance).all()); + // no source + param = branch.calc_param(false); + CHECK((cabs(param.yff() - 0.0) < numerical_tolerance).all()); + CHECK((cabs(param.ytt() - 0.0) < numerical_tolerance).all()); + CHECK((cabs(param.ytf() - 0.0) < numerical_tolerance).all()); + CHECK((cabs(param.yft() - 0.0) < numerical_tolerance).all()); + // from connected + CHECK(branch.set_status(na_IntS, false)); + param = asym_line.calc_param(); + CHECK((cabs(param.yff() - ysa) < numerical_tolerance).all()); + CHECK((cabs(param.ytt() - 0.0) < numerical_tolerance).all()); + CHECK((cabs(param.ytf() - 0.0) < numerical_tolerance).all()); + CHECK((cabs(param.yft() - 0.0) < numerical_tolerance).all()); + } +} + +} // namespace power_grid_model \ No newline at end of file From aae522655db79b47f931fe47fcde391dea32a620 Mon Sep 17 00:00:00 2001 From: leovsch Date: Mon, 3 Feb 2025 17:37:57 +0100 Subject: [PATCH 02/12] rework review comments pt1 --- .../power_grid_model/common/common.hpp | 1 - .../power_grid_model/common/exception.hpp | 11 ----- .../power_grid_model/common/matrix_utils.hpp | 17 ++++++++ .../common/three_phase_tensor.hpp | 5 +-- .../power_grid_model/component/asym_line.hpp | 42 ++++--------------- .../power_grid_model/component/line_utils.hpp | 18 ++++++++ 6 files changed, 46 insertions(+), 48 deletions(-) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp index 75c287f90..740d40531 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/common.hpp @@ -56,7 +56,6 @@ using DoubleComplex = std::complex; using std::numbers::inv_sqrt3; using std::numbers::pi; using std::numbers::sqrt3; -using std::numbers::e; constexpr DoubleComplex a2{-0.5, -sqrt3 / 2.0}; constexpr DoubleComplex a{-0.5, sqrt3 / 2.0}; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp index 025c00fdc..14218306b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp @@ -59,17 +59,6 @@ class MissingCaseForEnumError : public InvalidArguments { } }; -class UnsupportedInputDescriptionAsymLine : public PowerGridError { - public: - UnsupportedInputDescriptionAsymLine() { - append_msg("Invalid or missing parameters supplied for component asym_line. The following input specifications are allowed"); - append_msg("3 phase x_matrix, 3 phase r_matrix and 3 phase c_matrix"); - append_msg("3 phase + neutral x_matrix, 3 phase + neutral r_matrix and 3 phase + neutral c_matrix"); - append_msg("3 phase x_matrix, 3 phase r_matrix and c1, c0"); - append_msg("3 phase + neutral x_matrix, 3 phase + neutral r_matrix and c1, c0"); - } -}; - class ConflictVoltage : public PowerGridError { public: ConflictVoltage(ID id, ID id1, ID id2, double u1, double u2) { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp new file mode 100644 index 000000000..c5361f880 --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +#pragma once + +#include "three_phase_tensor.hpp" + +namespace power_grid_model { + +inline DoubleComplex average_of_diagonal_of_matrix(const ComplexTensor &matrix) { + return (matrix(0,0) + matrix(1,1) + matrix(2,2)) / 3.0; +} + +inline DoubleComplex average_of_off_diagonal_of_matrix(const ComplexTensor &matrix) { + return (matrix(0,2) + matrix(1,1) + matrix(2,0)) / 3.0; +} + +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp index a18311b48..2fade71a4 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp @@ -62,8 +62,7 @@ template class Tensor : public Eigen3Tensor { // additional constructors explicit Tensor(T const& x) { (*this) << x, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, x; } explicit Tensor(T const& s, T const& m) { (*this) << s, m, m, m, s, m, m, m, s; } - explicit Tensor(T const& x1, T const& x2, T const& x3, T const& x4, T const& x5, T const& x6) { (*this) << x1, x2, x4, x2, x3, x5, x4, x5, x6; } - explicit Tensor(T const& x1, T const& x2, T const& x3, T const& x4, T const& x5, T const& x6, T const& x7, T const& x8, T const& x9) { (*this) << x1, x2, x3, x4, x5, x6, x7, x8, x9; } + explicit Tensor(T const& s1, T const& s2, T const& s3, T const& m12, T const& m13, T const& m23) { (*this) << s1, m12, m13, m12, s2, m23, m13, m23, s3; } explicit Tensor(Vector const& v) { (*this) << v(0), 0.0, 0.0, 0.0, v(1), 0.0, 0.0, 0.0, v(2); } // eigen expression template Tensor(Eigen::ArrayBase const& other) : Eigen3Tensor{other} {} @@ -79,7 +78,7 @@ template class Tensor4 : public Eigen4Tensor { // additional constructors explicit Tensor4(T const& x) { (*this) << x, 0.0, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, x; } explicit Tensor4(T const& s, T const& m) { (*this) << s, m, m, m, m, s, m, m, m, m, s, m, m, m, m, s; } - explicit Tensor4(T const& x1, T const& x2, T const& x3, T const& x4, T const& x5, T const& x6, T const& x7, T const& x8, T const& x9, T const& x10) { (*this) << x1, x2, x4, x7, x2, x3, x5, x8, x4, x5, x6, x9, x7, x8, x9, x10; } + explicit Tensor4(T const& s1, T const& s2, T const& s3, T const& s4, const& m12, T const& m13, T const& m14, T const& m23, T const& m24, T const& m34) { (*this) << s1, m12, m13, m14, m12, s2, m23, m24, m13, m23, s3, m34, m14, m24, m34, s4; } explicit Tensor4(Vector const& v) { (*this) << v(0), 0.0, 0.0, 0.0, 0.0, v(1), 0.0, 0.0, 0.0, 0.0, v(2), 0.0, 0.0, 0.0, 0.0, v(3); } // eigen expression template Tensor4(Eigen::ArrayBase const& other) : Eigen4Tensor{other} {} diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp index 267ce577e..475268d66 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp @@ -11,6 +11,8 @@ #include "../calculation_parameters.hpp" #include "../common/common.hpp" #include "../common/three_phase_tensor.hpp" +#include "../common/matrix_utils.hpp" +#include "line_utils.hpp" namespace power_grid_model { @@ -29,12 +31,6 @@ class AsymLine : public Branch { ComplexTensor c_matrix = compute_c_matrix_from_input(asym_line_input); ComplexTensor z_series = compute_z_series_from_input(asym_line_input); - ComplexTensor empty_tensor; - - if (c_matrix.isZero() || z_series.isZero()) { - throw UnsupportedInputDescriptionAsymLine(); - } - y_series = inv(z_series); y_shunt = 2 * pi * system_frequency * c_matrix * 1.0i; } @@ -52,34 +48,22 @@ class AsymLine : public Branch { ComplexTensor y_series; ComplexTensor y_shunt; - ComplexTensor kron_reduction(const ComplexTensor4& matrix_to_reduce) const { - ComplexTensor4 Y = matrix_to_reduce; - ComplexTensor Y_aa = ComplexTensor(Y(0,0), Y(1,0), Y(1, 1), Y(2,0), Y(2,1), Y(2,2)); - ComplexValue Y_ab(Y(0,3), Y(1,3), Y(2,3)); - Eigen::Array Y_ba; - Y_ba << Y(3,0), Y(3,1), Y(3,2); - DoubleComplex Y_bb_inv = 1.0 / Y(3,3); - - return Y_aa - ((Y_ab * Y_bb_inv).matrix() * Y_ba.matrix()).array(); - } - ComplexTensor compute_z_series_from_input(const power_grid_model::AsymLineInput& asym_line_input) { ComplexTensor z_series_abc; if (is_nan(asym_line_input.r_na) && is_nan(asym_line_input.x_na)) { - ComplexTensor r_matrix = ComplexTensor(asym_line_input.r_aa, asym_line_input.r_ba, asym_line_input.r_bb, asym_line_input.r_ca, asym_line_input.r_cb, asym_line_input.r_cc); - ComplexTensor x_matrix = ComplexTensor(asym_line_input.x_aa, asym_line_input.x_ba, asym_line_input.x_bb, asym_line_input.x_ca, asym_line_input.x_cb, asym_line_input.x_cc); + ComplexTensor r_matrix = ComplexTensor(asym_line_input.r_aa, asym_line_input.r_bb, asym_line_input.r_cc, asym_line_input.r_ba, asym_line_input.r_ca, asym_line_input.r_cb); + ComplexTensor x_matrix = ComplexTensor(asym_line_input.x_aa, asym_line_input.x_bb, asym_line_input.x_cc, asym_line_input.x_ba, asym_line_input.x_ca, asym_line_input.x_cb); z_series_abc = r_matrix + x_matrix * 1.0i; } else { - ComplexTensor4 r_matrix = ComplexTensor4(asym_line_input.r_aa, asym_line_input.r_ba, asym_line_input.r_bb, asym_line_input.r_ca, asym_line_input.r_cb, asym_line_input.r_cc, asym_line_input.r_na, asym_line_input.r_nb, asym_line_input.r_nc, asym_line_input.r_nn); - ComplexTensor4 x_matrix = ComplexTensor4(asym_line_input.x_aa, asym_line_input.x_ba, asym_line_input.x_bb, asym_line_input.x_ca, asym_line_input.x_cb, asym_line_input.x_cc, asym_line_input.x_na, asym_line_input.x_nb, asym_line_input.x_nc, asym_line_input.x_nn); + ComplexTensor4 r_matrix = ComplexTensor4(asym_line_input.r_aa, asym_line_input.r_bb, asym_line_input.r_cc, asym_line_input.r_nn, asym_line_input.r_ba, asym_line_input.r_ca, asym_line_input.r_na, asym_line_input.r_cb, asym_line_input.r_nb, asym_line_input.r_nc); + ComplexTensor4 x_matrix = ComplexTensor4(asym_line_input.x_aa, asym_line_input.x_bb, asym_line_input.x_cc, asym_line_input.x_nn, asym_line_input.x_ba, asym_line_input.x_ca, asym_line_input.x_na, asym_line_input.x_cb, asym_line_input.x_nb, asym_line_input.x_nc); ComplexTensor4 y = r_matrix + 1.0i * x_matrix; z_series_abc = kron_reduction(y); } - DoubleComplex a = std::pow(e, 1.0i * (2.0 / 3.0) * pi); - ComplexTensor a_matrix = ComplexTensor(1, 1, pow(a, 2), 1, a, pow(a, 2)); - ComplexTensor a_matrix_inv = (1.0/3.0) * ComplexTensor(1, 1, a, 1, pow(a, 2), a); + ComplexTensor a_matrix = get_sym_matrix(); + ComplexTensor a_matrix_inv = get_sym_matrix_inv(); ComplexTensor z_series = (a_matrix_inv.matrix() * z_series_abc.matrix() * a_matrix.matrix()).array(); return z_series; } @@ -94,19 +78,11 @@ class AsymLine : public Branch { } else { ComplexTensor4 c_matrix_neutral = ComplexTensor4(asym_line_input.c_aa, asym_line_input.c_ba, asym_line_input.c_bb, asym_line_input.c_ca, asym_line_input.c_cb, asym_line_input.c_cc, asym_line_input.c_na, asym_line_input.c_nb, asym_line_input.c_nc, asym_line_input.c_nn); - c_matrix = this->kron_reduction(c_matrix_neutral); + c_matrix = kron_reduction(c_matrix_neutral); } return c_matrix; } - DoubleComplex average_of_diagonal_of_matrix(const ComplexTensor &matrix) const { - return (matrix(0,0) + matrix(1,1) + matrix(2,2)) / 3.0; - } - - DoubleComplex average_of_off_diagonal_of_matrix(const ComplexTensor &matrix) const { - return (matrix(0,2) + matrix(1,1) + matrix(2,0)) / 3.0; - } - BranchCalcParam sym_calc_param() const override { DoubleComplex y1_series_ = average_of_diagonal_of_matrix(y_series) - average_of_off_diagonal_of_matrix(y_series); DoubleComplex y1_shunt_ = average_of_diagonal_of_matrix(y_shunt) - average_of_off_diagonal_of_matrix(y_shunt); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp new file mode 100644 index 000000000..631730888 --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project + +#pragma once + +#include "../common/three_phase_tensor.hpp" + +namespace power_grid_model { + +inline ComplexTensor kron_reduction(const ComplexTensor4& matrix_to_reduce) { + ComplexTensor4 Y = matrix_to_reduce; + ComplexTensor Y_aa = ComplexTensor(Y(0,0), Y(1,0), Y(1, 1), Y(2,0), Y(2,1), Y(2,2)); + ComplexValue Y_ab(Y(0,3), Y(1,3), Y(2,3)); + ComplexValue Y_ba(Y(3,0), Y(3,1), Y(3,2)); + DoubleComplex Y_bb_inv = 1.0 / Y(3,3); + return Y_aa - vector_outer_product(Y_ba, Y_ab) * Y_bb_inv; +} + +} // namespace power_grid_model From 0ccb30a02167231c9a2efd52a1bfb5e06305f345 Mon Sep 17 00:00:00 2001 From: leovsch Date: Tue, 11 Feb 2025 09:49:22 +0100 Subject: [PATCH 03/12] rework review comments pt2 --- .../power_grid_model/common/three_phase_tensor.hpp | 2 +- .../include/power_grid_model/component/asym_line.hpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp index 2fade71a4..ec5433c4b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/three_phase_tensor.hpp @@ -78,7 +78,7 @@ template class Tensor4 : public Eigen4Tensor { // additional constructors explicit Tensor4(T const& x) { (*this) << x, 0.0, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, x, 0.0, 0.0, 0.0, 0.0, x; } explicit Tensor4(T const& s, T const& m) { (*this) << s, m, m, m, m, s, m, m, m, m, s, m, m, m, m, s; } - explicit Tensor4(T const& s1, T const& s2, T const& s3, T const& s4, const& m12, T const& m13, T const& m14, T const& m23, T const& m24, T const& m34) { (*this) << s1, m12, m13, m14, m12, s2, m23, m24, m13, m23, s3, m34, m14, m24, m34, s4; } + explicit Tensor4(T const& s1, T const& s2, T const& s3, T const& s4, T const& m12, T const& m13, T const& m14, T const& m23, T const& m24, T const& m34) { (*this) << s1, m12, m13, m14, m12, s2, m23, m24, m13, m23, s3, m34, m14, m24, m34, s4; } explicit Tensor4(Vector const& v) { (*this) << v(0), 0.0, 0.0, 0.0, 0.0, v(1), 0.0, 0.0, 0.0, 0.0, v(2), 0.0, 0.0, 0.0, 0.0, v(3); } // eigen expression template Tensor4(Eigen::ArrayBase const& other) : Eigen4Tensor{other} {} diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp index 475268d66..f244d3513 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp @@ -36,11 +36,11 @@ class AsymLine : public Branch { } // override getter - double base_i_from() const override { return base_i_; } - double base_i_to() const override { return base_i_; } - double loading(double /* max_s */, double max_i) const override { return max_i / i_n_; }; - double phase_shift() const override { return 0.0; } - bool is_param_mutable() const override { return false; } + constexpr double base_i_from() const override { return base_i_; } + constexpr double base_i_to() const override { return base_i_; } + constexpr double loading(double /* max_s */, double max_i) const override { return max_i / i_n_; }; + constexpr double phase_shift() const override { return 0.0; } + constexpr bool is_param_mutable() const override { return false; } private: double i_n_; @@ -112,4 +112,4 @@ class AsymLine : public Branch { return param; } }; -} \ No newline at end of file +} From 845b7806b713e8d760d0a01c63d4983d2bd9f057 Mon Sep 17 00:00:00 2001 From: leovsch Date: Wed, 12 Feb 2025 10:59:23 +0100 Subject: [PATCH 04/12] rework review comments pt3 --- .../power_grid_model/common/matrix_utils.hpp | 2 +- .../power_grid_model/component/asym_line.hpp | 35 ++++++++-------- .../power_grid_model/component/line_utils.hpp | 2 +- tests/cpp_unit_tests/test_asym_line.cpp | 42 +++++-------------- 4 files changed, 29 insertions(+), 52 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp index c5361f880..1ab56abe3 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/matrix_utils.hpp @@ -11,7 +11,7 @@ inline DoubleComplex average_of_diagonal_of_matrix(const ComplexTensor &matrix) { - return (matrix(0,2) + matrix(1,1) + matrix(2,0)) / 3.0; + return (matrix(0,1) + matrix(1,2) + matrix(1,0) + matrix(1,2) + matrix(2,0) + matrix(2,1)) / 6.0; } } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp index f244d3513..23e6363cb 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp @@ -31,8 +31,8 @@ class AsymLine : public Branch { ComplexTensor c_matrix = compute_c_matrix_from_input(asym_line_input); ComplexTensor z_series = compute_z_series_from_input(asym_line_input); - y_series = inv(z_series); - y_shunt = 2 * pi * system_frequency * c_matrix * 1.0i; + _y_series_abc = inv(z_series); + _y_shunt_abc = 2 * pi * system_frequency * c_matrix * 1.0i; } // override getter @@ -45,8 +45,8 @@ class AsymLine : public Branch { private: double i_n_; double base_i_; - ComplexTensor y_series; - ComplexTensor y_shunt; + ComplexTensor _y_series_abc; + ComplexTensor _y_shunt_abc; ComplexTensor compute_z_series_from_input(const power_grid_model::AsymLineInput& asym_line_input) { ComplexTensor z_series_abc; @@ -58,34 +58,30 @@ class AsymLine : public Branch { else { ComplexTensor4 r_matrix = ComplexTensor4(asym_line_input.r_aa, asym_line_input.r_bb, asym_line_input.r_cc, asym_line_input.r_nn, asym_line_input.r_ba, asym_line_input.r_ca, asym_line_input.r_na, asym_line_input.r_cb, asym_line_input.r_nb, asym_line_input.r_nc); ComplexTensor4 x_matrix = ComplexTensor4(asym_line_input.x_aa, asym_line_input.x_bb, asym_line_input.x_cc, asym_line_input.x_nn, asym_line_input.x_ba, asym_line_input.x_ca, asym_line_input.x_na, asym_line_input.x_cb, asym_line_input.x_nb, asym_line_input.x_nc); - ComplexTensor4 y = r_matrix + 1.0i * x_matrix; z_series_abc = kron_reduction(y); } - ComplexTensor a_matrix = get_sym_matrix(); - ComplexTensor a_matrix_inv = get_sym_matrix_inv(); - ComplexTensor z_series = (a_matrix_inv.matrix() * z_series_abc.matrix() * a_matrix.matrix()).array(); - return z_series; + return z_series_abc; } ComplexTensor compute_c_matrix_from_input(const power_grid_model::AsymLineInput& asym_line_input) { ComplexTensor c_matrix; if (!is_nan(asym_line_input.c0) && !is_nan(asym_line_input.c1)) { - c_matrix = ComplexTensor(asym_line_input.c0 + asym_line_input.c1, -asym_line_input.c1); + c_matrix = ComplexTensor{(2.0 * asym_line_input.c1 + asym_line_input.c0) / 3.0, (asym_line_input.c0 - asym_line_input.c1) / 3.0 }; } else if (is_nan(asym_line_input.c_nn)) { - c_matrix = ComplexTensor(asym_line_input.c_aa, asym_line_input.c_ba, asym_line_input.c_bb, asym_line_input.c_ca, asym_line_input.c_cb, asym_line_input.c_cc); + c_matrix = ComplexTensor(asym_line_input.c_aa, asym_line_input.c_bb, asym_line_input.c_cc, asym_line_input.c_ba, asym_line_input.c_ca, asym_line_input.c_cb); } else { - ComplexTensor4 c_matrix_neutral = ComplexTensor4(asym_line_input.c_aa, asym_line_input.c_ba, asym_line_input.c_bb, asym_line_input.c_ca, asym_line_input.c_cb, asym_line_input.c_cc, asym_line_input.c_na, asym_line_input.c_nb, asym_line_input.c_nc, asym_line_input.c_nn); + ComplexTensor4 c_matrix_neutral = ComplexTensor4(asym_line_input.c_aa, asym_line_input.c_bb, asym_line_input.c_cc, asym_line_input.c_nn, asym_line_input.c_ba, asym_line_input.c_ca, asym_line_input.c_na, asym_line_input.c_cb, asym_line_input.c_nb, asym_line_input.c_nc); c_matrix = kron_reduction(c_matrix_neutral); } return c_matrix; } BranchCalcParam sym_calc_param() const override { - DoubleComplex y1_series_ = average_of_diagonal_of_matrix(y_series) - average_of_off_diagonal_of_matrix(y_series); - DoubleComplex y1_shunt_ = average_of_diagonal_of_matrix(y_shunt) - average_of_off_diagonal_of_matrix(y_shunt); + DoubleComplex y1_series_ = average_of_diagonal_of_matrix(_y_series_abc) - average_of_off_diagonal_of_matrix(_y_series_abc); + DoubleComplex y1_shunt_ = average_of_diagonal_of_matrix(_y_shunt_abc) - average_of_off_diagonal_of_matrix(_y_shunt_abc); return calc_param_y_sym(y1_series_, y1_shunt_, 1.0); } @@ -96,7 +92,10 @@ class AsymLine : public Branch { // single connected if (from_status() || to_status()) { // branch_shunt = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); - ComplexTensor branch_shunt = 0.5 * inv(y_shunt) + inv(inv(y_series) + 2.0 * inv(y_shunt)); + ComplexTensor branch_shunt = ComplexTensor(); + if ((cabs(_y_shunt_abc) >= numerical_tolerance).all()) { + branch_shunt = 0.5 * inv(_y_shunt_abc) + inv(inv(_y_series_abc) + 2.0 * inv(_y_shunt_abc)); + } // from or to connected param.yff() = from_status() ? branch_shunt : ComplexTensor(); param.ytt() = to_status() ? branch_shunt : ComplexTensor(); @@ -104,10 +103,10 @@ class AsymLine : public Branch { } // both connected else { - param.ytt() = y_series + 0.5 * y_shunt; + param.ytt() = _y_series_abc + 0.5 * _y_shunt_abc; param.yff() = param.ytt(); - param.yft() = y_series; - param.ytf() = y_series; + param.yft() = _y_series_abc; + param.ytf() = _y_series_abc; } return param; } diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp index 631730888..3c107fb06 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/line_utils.hpp @@ -8,7 +8,7 @@ namespace power_grid_model { inline ComplexTensor kron_reduction(const ComplexTensor4& matrix_to_reduce) { ComplexTensor4 Y = matrix_to_reduce; - ComplexTensor Y_aa = ComplexTensor(Y(0,0), Y(1,0), Y(1, 1), Y(2,0), Y(2,1), Y(2,2)); + ComplexTensor Y_aa = ComplexTensor(Y(0,0), Y(1,1), Y(2, 2), Y(1,0), Y(2,0), Y(2,1)); ComplexValue Y_ab(Y(0,3), Y(1,3), Y(2,3)); ComplexValue Y_ba(Y(3,0), Y(3,1), Y(3,2)); DoubleComplex Y_bb_inv = 1.0 / Y(3,3); diff --git a/tests/cpp_unit_tests/test_asym_line.cpp b/tests/cpp_unit_tests/test_asym_line.cpp index 6cfa8f63f..bf311657b 100644 --- a/tests/cpp_unit_tests/test_asym_line.cpp +++ b/tests/cpp_unit_tests/test_asym_line.cpp @@ -44,12 +44,11 @@ TEST_CASE("Test asym line") { double const base_i = base_power_1p / (10.0e3 / sqrt3); double const base_y = base_i * base_i / base_power_1p; Branch& branch = asym_line; - ComplexTensor const y_series = ComplexTensor(0.66303418-0.34266364i, -0.02971114+0.03783535i, 0.04762194+0.00681293i, 0.04762194+0.00681293i, 2.48612768-0.46271628i, 0.05942228-0.07567069i, -0.02971114+0.03783535i, -0.09524388-0.01362585i, 2.48612768-0.46271628i); + ComplexTensor const y_series = ComplexTensor(1.87842984-0.42269873i, 1.87842984-0.42269873i, 1.87842984-0.42269873i, -0.62560863-0.00463073i, -0.57187623+0.12931409i, -0.62560863-0.00463073i); + ComplexTensor const y_shunt = 2 * pi * system_frequency * ComplexTensor{(2.0 * input.c1 + input.c0) / 3.0, (input.c0 - input.c1) / 3.0 } * 1.0i; - ComplexTensor const y_shunt = 2 * pi * system_frequency * ComplexTensor(input.c0 + input.c1, -input.c1) * 1.0i; - - DoubleComplex const y1_series = (y_series(0,0) + y_series(1,1) + y_series(2,2)) / 3.0 - (y_series(0,2) + y_series(1,1) + y_series(2,0)) / 3.0; - DoubleComplex const y1_shunt = (y_shunt(0,0) + y_shunt(1,1) + y_shunt(2,2)) / 3.0 - (y_shunt(0,2) + y_shunt(1,1) + y_shunt(2,0)) / 3.0; + DoubleComplex const y1_series = (y_series(0,0) + y_series(1,1) + y_series(2,2)) / 3.0 - (y_series(0,1) + y_series(1,2) + y_series(1,0) + y_series(1,2) + y_series(2,0) + y_series(2,1)) / 6.0; + DoubleComplex const y1_shunt = (y_shunt(0,0) + y_shunt(1,1) + y_shunt(2,2)) / 3.0 - (y_shunt(0,1) + y_shunt(1,2) + y_shunt(1,0) + y_shunt(1,2) + y_shunt(2,0) + y_shunt(2,1)) / 6.0; // symmetric DoubleComplex const yff1 = y1_series + 0.5 * y1_shunt; @@ -58,28 +57,7 @@ TEST_CASE("Test asym line") { // asymmetric ComplexTensor ytt = y_series + 0.5 * y_shunt; - DoubleComplex const yff0 = ytt(0,0); - DoubleComplex const yft0 = -y_series(0,0); - DoubleComplex const ys0 = 0.5 * y_shunt(0,0) + 1.0 / (1.0 / y_series(0,0) + 2.0 / y_shunt(0,0)); - ComplexTensor const yffa{(2.0 * yff1 + yff0) / 3.0, (yff0 - yff1) / 3.0}; - ComplexTensor const yfta{(2.0 * yft1 + yft0) / 3.0, (yft0 - yft1) / 3.0}; - ComplexTensor const ysa{(2.0 * ys1 + ys0) / 3.0, (ys0 - ys1) / 3.0}; - - DoubleComplex const u1f = 1.0; - DoubleComplex const u1t = 0.9; - ComplexValue const uaf{1.0}; - ComplexValue const uat{0.9}; - DoubleComplex const i1f = (yff1 * u1f + yft1 * u1t) * base_i; - DoubleComplex const i1t = (yft1 * u1f + yff1 * u1t) * base_i; - DoubleComplex const s_f = conj(i1f) * u1f * 10e3 * sqrt3; - DoubleComplex const s_t = conj(i1t) * u1t * 10e3 * sqrt3; - double const loading = std::max(cabs(i1f), cabs(i1t)) / 200.0; - - // Short circuit results - DoubleComplex const if_sc{1.0, 1.0}; - DoubleComplex const it_sc{2.0, 2.0 * sqrt(3)}; - ComplexValue const if_sc_asym{1.0 + 1.0i}; - ComplexValue const it_sc_asym{2.0 + (2.0i * sqrt(3))}; + ComplexTensor branch_shunt = 0.5 * inv(y_shunt) + inv(inv(y_series) + 2.0 * inv(y_shunt)); CHECK(asym_line.math_model_type() == ComponentType::branch); @@ -134,10 +112,10 @@ TEST_CASE("Test asym line") { SUBCASE("Asymmetric parameters") { // double connected BranchCalcParam param = asym_line.calc_param(); - CHECK((cabs(param.yff() - yffa) < numerical_tolerance).all()); - CHECK((cabs(param.ytt() - yffa) < numerical_tolerance).all()); - CHECK((cabs(param.ytf() - yfta) < numerical_tolerance).all()); - CHECK((cabs(param.yft() - yfta) < numerical_tolerance).all()); + CHECK((cabs(param.yff() - ytt) < numerical_tolerance).all()); + CHECK((cabs(param.ytt() - ytt) < numerical_tolerance).all()); + CHECK((cabs(param.ytf() - y_series) < numerical_tolerance).all()); + CHECK((cabs(param.yft() - y_series) < numerical_tolerance).all()); // no source param = branch.calc_param(false); CHECK((cabs(param.yff() - 0.0) < numerical_tolerance).all()); @@ -147,7 +125,7 @@ TEST_CASE("Test asym line") { // from connected CHECK(branch.set_status(na_IntS, false)); param = asym_line.calc_param(); - CHECK((cabs(param.yff() - ysa) < numerical_tolerance).all()); + CHECK((cabs(param.yff() - branch_shunt) < numerical_tolerance).all()); // Fail CHECK((cabs(param.ytt() - 0.0) < numerical_tolerance).all()); CHECK((cabs(param.ytf() - 0.0) < numerical_tolerance).all()); CHECK((cabs(param.yft() - 0.0) < numerical_tolerance).all()); From 7778c66f1dc0c01ba37e6595e0ab45db0c1dc92c Mon Sep 17 00:00:00 2001 From: leovsch Date: Thu, 13 Feb 2025 15:44:47 +0100 Subject: [PATCH 05/12] rework review comments pt4 --- .../power_grid_model/component/asym_line.hpp | 35 +-- tests/cpp_unit_tests/test_asym_line.cpp | 261 +++++++++++++++--- 2 files changed, 244 insertions(+), 52 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp index 23e6363cb..0be35d78b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp @@ -31,8 +31,9 @@ class AsymLine : public Branch { ComplexTensor c_matrix = compute_c_matrix_from_input(asym_line_input); ComplexTensor z_series = compute_z_series_from_input(asym_line_input); - _y_series_abc = inv(z_series); - _y_shunt_abc = 2 * pi * system_frequency * c_matrix * 1.0i; + y_series_abc_ = inv(z_series); + y_shunt_abc_ = 2 * pi * system_frequency * c_matrix * 1.0i; + } // override getter @@ -45,21 +46,21 @@ class AsymLine : public Branch { private: double i_n_; double base_i_; - ComplexTensor _y_series_abc; - ComplexTensor _y_shunt_abc; + ComplexTensor y_series_abc_; + ComplexTensor y_shunt_abc_; ComplexTensor compute_z_series_from_input(const power_grid_model::AsymLineInput& asym_line_input) { ComplexTensor z_series_abc; if (is_nan(asym_line_input.r_na) && is_nan(asym_line_input.x_na)) { ComplexTensor r_matrix = ComplexTensor(asym_line_input.r_aa, asym_line_input.r_bb, asym_line_input.r_cc, asym_line_input.r_ba, asym_line_input.r_ca, asym_line_input.r_cb); ComplexTensor x_matrix = ComplexTensor(asym_line_input.x_aa, asym_line_input.x_bb, asym_line_input.x_cc, asym_line_input.x_ba, asym_line_input.x_ca, asym_line_input.x_cb); - z_series_abc = r_matrix + x_matrix * 1.0i; + z_series_abc = r_matrix + 1.0i * x_matrix; } else { ComplexTensor4 r_matrix = ComplexTensor4(asym_line_input.r_aa, asym_line_input.r_bb, asym_line_input.r_cc, asym_line_input.r_nn, asym_line_input.r_ba, asym_line_input.r_ca, asym_line_input.r_na, asym_line_input.r_cb, asym_line_input.r_nb, asym_line_input.r_nc); ComplexTensor4 x_matrix = ComplexTensor4(asym_line_input.x_aa, asym_line_input.x_bb, asym_line_input.x_cc, asym_line_input.x_nn, asym_line_input.x_ba, asym_line_input.x_ca, asym_line_input.x_na, asym_line_input.x_cb, asym_line_input.x_nb, asym_line_input.x_nc); - ComplexTensor4 y = r_matrix + 1.0i * x_matrix; - z_series_abc = kron_reduction(y); + ComplexTensor4 z = r_matrix + 1.0i * x_matrix; + z_series_abc = kron_reduction(z); } return z_series_abc; } @@ -79,13 +80,13 @@ class AsymLine : public Branch { return c_matrix; } - BranchCalcParam sym_calc_param() const override { - DoubleComplex y1_series_ = average_of_diagonal_of_matrix(_y_series_abc) - average_of_off_diagonal_of_matrix(_y_series_abc); - DoubleComplex y1_shunt_ = average_of_diagonal_of_matrix(_y_shunt_abc) - average_of_off_diagonal_of_matrix(_y_shunt_abc); - return calc_param_y_sym(y1_series_, y1_shunt_, 1.0); + BranchCalcParam sym_calc_param() const override final { + DoubleComplex y1_series = average_of_diagonal_of_matrix(y_series_abc_) - average_of_off_diagonal_of_matrix(y_series_abc_); + DoubleComplex y1_shunt = average_of_diagonal_of_matrix(y_shunt_abc_) - average_of_off_diagonal_of_matrix(y_shunt_abc_); + return calc_param_y_sym(y1_series, y1_shunt, 1.0); } - BranchCalcParam asym_calc_param() const override { + BranchCalcParam asym_calc_param() const override final { BranchCalcParam param{}; // not both connected if (!branch_status()) { @@ -93,8 +94,8 @@ class AsymLine : public Branch { if (from_status() || to_status()) { // branch_shunt = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); ComplexTensor branch_shunt = ComplexTensor(); - if ((cabs(_y_shunt_abc) >= numerical_tolerance).all()) { - branch_shunt = 0.5 * inv(_y_shunt_abc) + inv(inv(_y_series_abc) + 2.0 * inv(_y_shunt_abc)); + if ((cabs(y_shunt_abc_) >= numerical_tolerance).all()) { + branch_shunt = 0.5 * inv(y_shunt_abc_) + inv(inv(y_series_abc_) + 2.0 * inv(y_shunt_abc_)); } // from or to connected param.yff() = from_status() ? branch_shunt : ComplexTensor(); @@ -103,10 +104,10 @@ class AsymLine : public Branch { } // both connected else { - param.ytt() = _y_series_abc + 0.5 * _y_shunt_abc; + param.ytt() = y_series_abc_ + 0.5 * y_shunt_abc_; param.yff() = param.ytt(); - param.yft() = _y_series_abc; - param.ytf() = _y_series_abc; + param.yft() = -y_series_abc_; + param.ytf() = -y_series_abc_; } return param; } diff --git a/tests/cpp_unit_tests/test_asym_line.cpp b/tests/cpp_unit_tests/test_asym_line.cpp index bf311657b..0c9eff3a9 100644 --- a/tests/cpp_unit_tests/test_asym_line.cpp +++ b/tests/cpp_unit_tests/test_asym_line.cpp @@ -10,41 +10,16 @@ namespace power_grid_model { using namespace std::complex_literals; -TEST_CASE("Test asym line") { +void execute_subcases(const AsymLineInput& input, const ComplexTensor& y_series) +{ + CAPTURE(input.id); + CAPTURE(y_series); double system_frequency = 50.0; - AsymLineInput const input{.id = 1, - .from_node = 2, - .to_node = 3, - .from_status = 1, - .to_status = 1, - .r_aa = 0.4369, - .r_ba = 0.0496, - .r_bb = 0.4369, - .r_ca = 0.0485, - .r_cb = 0.0496, - .r_cc = 0.4369, - .r_na = 0.0496, - .r_nb = 0.0485, - .r_nc = 0.0496, - .r_nn = 0.4369, - .x_aa = 0.8538, - .x_ba = 0.7886, - .x_bb = 0.8538, - .x_ca = 0.7663, - .x_cb = 0.7886, - .x_cc = 0.8538, - .x_na = 0.7886, - .x_nb = 0.7663, - .x_nc = 0.7886, - .x_nn = 0.8538, - .c0 = 0.18, - .c1 = 0.308, - .i_n = 216.0}; - AsymLine asym_line{input, system_frequency, 10.0e3, 10.0e3}; - double const base_i = base_power_1p / (10.0e3 / sqrt3); + double voltage_lvl = 10.0e3; + AsymLine asym_line{input, system_frequency, voltage_lvl, voltage_lvl}; + double const base_i = base_power_1p / (voltage_lvl / sqrt3); double const base_y = base_i * base_i / base_power_1p; Branch& branch = asym_line; - ComplexTensor const y_series = ComplexTensor(1.87842984-0.42269873i, 1.87842984-0.42269873i, 1.87842984-0.42269873i, -0.62560863-0.00463073i, -0.57187623+0.12931409i, -0.62560863-0.00463073i); ComplexTensor const y_shunt = 2 * pi * system_frequency * ComplexTensor{(2.0 * input.c1 + input.c0) / 3.0, (input.c0 - input.c1) / 3.0 } * 1.0i; DoubleComplex const y1_series = (y_series(0,0) + y_series(1,1) + y_series(2,2)) / 3.0 - (y_series(0,1) + y_series(1,2) + y_series(1,0) + y_series(1,2) + y_series(2,0) + y_series(2,1)) / 6.0; @@ -59,6 +34,22 @@ TEST_CASE("Test asym line") { ComplexTensor ytt = y_series + 0.5 * y_shunt; ComplexTensor branch_shunt = 0.5 * inv(y_shunt) + inv(inv(y_series) + 2.0 * inv(y_shunt)); + DoubleComplex const u1f = 1.0; + DoubleComplex const u1t = 0.9; + ComplexValue const uaf{1.0}; + ComplexValue const uat{0.9}; + DoubleComplex const i1f = (yff1 * u1f + yft1 * u1t) * base_i; + DoubleComplex const i1t = (yft1 * u1f + yff1 * u1t) * base_i; + DoubleComplex const s_f = conj(i1f) * u1f * 10e3 * sqrt3; + DoubleComplex const s_t = conj(i1t) * u1t * 10e3 * sqrt3; + double const loading = std::max(cabs(i1f), cabs(i1t)) / 200.0; + + // Short circuit results + DoubleComplex const if_sc{1.0, 1.0}; + DoubleComplex const it_sc{2.0, 2.0 * sqrt(3)}; + ComplexValue const if_sc_asym{1.0 + 1.0i}; + ComplexValue const it_sc_asym{2.0 + (2.0i * sqrt(3))}; + CHECK(asym_line.math_model_type() == ComponentType::branch); SUBCASE("Voltge error") { CHECK_THROWS_AS(AsymLine(input, 50.0, 10.0e3, 50.0e3), ConflictVoltage); } @@ -114,8 +105,8 @@ TEST_CASE("Test asym line") { BranchCalcParam param = asym_line.calc_param(); CHECK((cabs(param.yff() - ytt) < numerical_tolerance).all()); CHECK((cabs(param.ytt() - ytt) < numerical_tolerance).all()); - CHECK((cabs(param.ytf() - y_series) < numerical_tolerance).all()); - CHECK((cabs(param.yft() - y_series) < numerical_tolerance).all()); + CHECK((cabs(param.ytf() - (-y_series)) < numerical_tolerance).all()); + CHECK((cabs(param.yft() - (-y_series)) < numerical_tolerance).all()); // no source param = branch.calc_param(false); CHECK((cabs(param.yff() - 0.0) < numerical_tolerance).all()); @@ -130,6 +121,206 @@ TEST_CASE("Test asym line") { CHECK((cabs(param.ytf() - 0.0) < numerical_tolerance).all()); CHECK((cabs(param.yft() - 0.0) < numerical_tolerance).all()); } + + SUBCASE("Symmetric results") { + BranchOutput output = branch.get_output(1.0, 0.9); + CHECK(output.id == 1); + CHECK(output.energized); + CHECK(output.loading == doctest::Approx(loading)); + CHECK(output.i_from == doctest::Approx(cabs(i1f))); + CHECK(output.i_to == doctest::Approx(cabs(i1t))); + CHECK(output.s_from == doctest::Approx(cabs(s_f))); + CHECK(output.s_to == doctest::Approx(cabs(s_t))); + CHECK(output.p_from == doctest::Approx(real(s_f))); + CHECK(output.p_to == doctest::Approx(real(s_t))); + CHECK(output.q_from == doctest::Approx(imag(s_f))); + CHECK(output.q_to == doctest::Approx(imag(s_t))); + } + + SUBCASE("Symmetric results with direct power and current output") { + BranchSolverOutput branch_solver_output{}; + branch_solver_output.i_f = 1.0 - 2.0i; + branch_solver_output.i_t = 2.0 - 1.0i; + branch_solver_output.s_f = 1.0 - 1.5i; + branch_solver_output.s_t = 1.5 - 1.5i; + BranchOutput output = branch.get_output(branch_solver_output); + CHECK(output.id == 1); + CHECK(output.energized); + CHECK(output.loading == doctest::Approx(cabs(2.0 - 1.0i) * base_i / input.i_n)); + CHECK(output.i_from == doctest::Approx(cabs(1.0 - 2.0i) * base_i)); + CHECK(output.i_to == doctest::Approx(cabs(2.0 - 1.0i) * base_i)); + CHECK(output.s_from == doctest::Approx(cabs(1.0 - 1.5i) * base_power)); + CHECK(output.s_to == doctest::Approx(cabs(1.5 - 1.5i) * base_power)); + CHECK(output.p_from == doctest::Approx(1.0 * base_power)); + CHECK(output.p_to == doctest::Approx(1.5 * base_power)); + CHECK(output.q_from == doctest::Approx(-1.5 * base_power)); + CHECK(output.q_to == doctest::Approx(-1.5 * base_power)); + } + + SUBCASE("No source results") { + BranchOutput output = branch.get_null_output(); + CHECK(output.id == 1); + CHECK(!output.energized); + CHECK(output.loading == 0.0); + CHECK(output.i_from(0) == 0.0); + CHECK(output.i_to(1) == 0.0); + CHECK(output.s_from(2) == 0.0); + CHECK(output.s_to(0) == 0.0); + CHECK(output.p_from(1) == 0.0); + CHECK(output.p_to(2) == 0.0); + CHECK(output.q_from(0) == 0.0); + CHECK(output.q_to(1) == 0.0); + } + + SUBCASE("No source short circuit results") { + BranchShortCircuitOutput output = branch.get_null_sc_output(); + CHECK(output.id == 1); + CHECK(!output.energized); + CHECK(output.i_from(0) == 0.0); + CHECK(output.i_to(1) == 0.0); + CHECK(output.i_from_angle(0) == 0.0); + CHECK(output.i_to_angle(1) == 0.0); + } + + SUBCASE("Asymmetric results") { + BranchOutput output = branch.get_output(uaf, uat); + CHECK(output.id == 1); + CHECK(output.energized); + CHECK(output.loading == doctest::Approx(loading)); + CHECK(output.i_from(0) == doctest::Approx(cabs(i1f))); + CHECK(output.i_to(1) == doctest::Approx(cabs(i1t))); + CHECK(output.s_from(2) == doctest::Approx(cabs(s_f) / 3.0)); + CHECK(output.s_to(0) == doctest::Approx(cabs(s_t) / 3.0)); + CHECK(output.p_from(1) == doctest::Approx(real(s_f) / 3.0)); + CHECK(output.p_to(2) == doctest::Approx(real(s_t) / 3.0)); + CHECK(output.q_from(0) == doctest::Approx(imag(s_f) / 3.0)); + CHECK(output.q_to(1) == doctest::Approx(imag(s_t) / 3.0)); + } + + SUBCASE("Asym short circuit results") { + BranchShortCircuitOutput asym_output = branch.get_sc_output(if_sc_asym, it_sc_asym); + CHECK(asym_output.id == 1); + CHECK(asym_output.energized); + CHECK(asym_output.i_from(1) == doctest::Approx(cabs(if_sc) * base_i)); + CHECK(asym_output.i_from(2) == doctest::Approx(cabs(if_sc) * base_i)); + CHECK(asym_output.i_to(0) == doctest::Approx(cabs(it_sc) * base_i)); + CHECK(asym_output.i_to(1) == doctest::Approx(cabs(it_sc) * base_i)); + CHECK(asym_output.i_from_angle(0) == doctest::Approx(pi / 4)); + CHECK(asym_output.i_from_angle(2) == doctest::Approx(pi / 4 + deg_120)); + CHECK(asym_output.i_to_angle(1) == doctest::Approx(pi / 3 - deg_120)); + CHECK(asym_output.i_to_angle(2) == doctest::Approx(pi / 3 + deg_120)); + CHECK(asym_output.id == 1); + } + + SUBCASE("Sym short circuit results") { + BranchShortCircuitOutput sym_output = branch.get_sc_output(if_sc, it_sc); + BranchShortCircuitOutput asym_output = branch.get_sc_output(if_sc_asym, it_sc_asym); + CHECK(sym_output.energized == asym_output.energized); + CHECK(sym_output.i_from(1) == doctest::Approx(asym_output.i_from(1))); + CHECK(sym_output.i_from(2) == doctest::Approx(asym_output.i_from(2))); + CHECK(sym_output.i_to(0) == doctest::Approx(asym_output.i_to(0))); + CHECK(sym_output.i_to(1) == doctest::Approx(asym_output.i_to(1))); + CHECK(sym_output.i_from_angle(0) == doctest::Approx(asym_output.i_from_angle(0))); + CHECK(sym_output.i_from_angle(2) == doctest::Approx(asym_output.i_from_angle(2))); + CHECK(sym_output.i_to_angle(1) == doctest::Approx(asym_output.i_to_angle(1))); + CHECK(sym_output.i_to_angle(2) == doctest::Approx(asym_output.i_to_angle(2))); + } + + SUBCASE("Update inverse") { + BranchUpdate branch_update{1, na_IntS, na_IntS}; + auto expected = branch_update; + + SUBCASE("Identical") { + // default values + } + + SUBCASE("From status") { + SUBCASE("same") { branch_update.from_status = static_cast(asym_line.from_status()); } + SUBCASE("different") { branch_update.from_status = IntS{0}; } + expected.from_status = static_cast(asym_line.from_status()); + } + + SUBCASE("To status") { + SUBCASE("same") { branch_update.to_status = static_cast(asym_line.to_status()); } + SUBCASE("different") { branch_update.to_status = IntS{0}; } + expected.to_status = static_cast(asym_line.to_status()); + } + + SUBCASE("multiple") { + branch_update.from_status = IntS{0}; + branch_update.to_status = IntS{0}; + expected.from_status = static_cast(asym_line.from_status()); + expected.to_status = static_cast(asym_line.to_status()); + } + + auto const inv = asym_line.inverse(branch_update); + + CHECK(inv.id == expected.id); + CHECK(inv.from_status == expected.from_status); + CHECK(inv.to_status == expected.to_status); + } +} + +TEST_CASE("Test asym line") { + + SUBCASE("R and X matrix c0, c1 including neutral") { + AsymLineInput input = {.id = 1, + .from_node = 2, + .to_node = 3, + .from_status = 1, + .to_status = 1, + .r_aa = 0.4369, + .r_ba = 0.0496, + .r_bb = 0.4369, + .r_ca = 0.0485, + .r_cb = 0.0496, + .r_cc = 0.4369, + .r_na = 0.0496, + .r_nb = 0.0485, + .r_nc = 0.0496, + .r_nn = 0.4369, + .x_aa = 0.8538, + .x_ba = 0.7886, + .x_bb = 0.8538, + .x_ca = 0.7663, + .x_cb = 0.7886, + .x_cc = 0.8538, + .x_na = 0.7886, + .x_nb = 0.7663, + .x_nc = 0.7886, + .x_nn = 0.8538, + .c0 = 0.18, + .c1 = 0.308, + .i_n = 216.0}; + + ComplexTensor const y_series = ComplexTensor(1.87842984-0.42269873i, 1.87842984-0.42269873i, 1.87842984-0.42269873i, -0.62560863-0.00463073i, -0.57187623+0.12931409i, -0.62560863-0.00463073i); + execute_subcases(input, y_series); + } + + SUBCASE("R and X matrix, c0, c1 excluding neutral") { + AsymLineInput input = {.id = 2, + .from_node = 2, + .to_node = 3, + .from_status = 1, + .to_status = 1, + .r_aa = 0.4369, + .r_ba = 0.0496, + .r_bb = 0.4369, + .r_ca = 0.0485, + .r_cb = 0.0496, + .r_cc = 0.4369, + .x_aa = 0.8538, + .x_ba = 0.7886, + .x_bb = 0.8538, + .x_ca = 0.7663, + .x_cb = 0.7886, + .x_cc = 0.8538, + .c0 = 0.18, + .c1 = 0.308, + .i_n = 216.0}; + ComplexTensor const y_series = ComplexTensor(1.68079-0.470259i, 1.70433-0.383139i, 1.68079-0.470259i, -0.816117-0.00584238i, -0.769521+0.0817541i, -0.816117-0.00584238i); + execute_subcases(input, y_series); + } } -} // namespace power_grid_model \ No newline at end of file +} // namespace power_grid_model From 5cd16aa832a9d467672ffdbdcc04480b64515d07 Mon Sep 17 00:00:00 2001 From: leovsch Date: Thu, 13 Feb 2025 16:54:35 +0100 Subject: [PATCH 06/12] add data validation for asym_line --- src/power_grid_model/validation/validation.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py index 69baa895f..193ea1ec1 100644 --- a/src/power_grid_model/validation/validation.py +++ b/src/power_grid_model/validation/validation.py @@ -307,6 +307,7 @@ def validate_required_values( required["branch"] = required["base"] + ["from_node", "to_node", "from_status", "to_status"] required["link"] = required["branch"].copy() required["line"] = required["branch"] + ["r1", "x1", "c1", "tan1"] + required["asym_line"] = required["branch"] + ["r_aa", "r_ba", "r_bb", "r_ca", "r_cb", "r_cc", "x_aa", "x_ba", "x_bb", "x_ca", "x_cb", "x_cc"] required["transformer"] = required["branch"] + [ "u1", "u2", @@ -477,6 +478,7 @@ def validate_values(data: SingleDataset, calculation_type: CalculationType | Non component_validators = { "node": validate_node, "line": validate_line, + "asym_line": validate_asym_line, "link": lambda d: validate_branch(d, ComponentType.link), "generic_branch": validate_generic_branch, "transformer": validate_transformer, @@ -544,6 +546,44 @@ def validate_line(data: SingleDataset) -> list[ValidationError]: return errors +def validate_asym_line(data : SingleDataset) -> list[ValidationError]: + errors = validate_branch(data, ComponentType.line) + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_aa") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_ba") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_bb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_ca") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_cb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_cc") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_na") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_nb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_nc") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_nn") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_aa") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_ba") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_bb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_ca") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_cb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_cc") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_na") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_nb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_nc") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_nn") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_aa") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_ba") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_bb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_ca") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_cb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_cc") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_na") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_nb") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_nc") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_nn") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c0") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "c1") + errors += _all_greater_than_zero(data, ComponentType.asym_line, "i_n") + return errors + + def validate_generic_branch(data: SingleDataset) -> list[ValidationError]: errors = validate_branch(data, ComponentType.generic_branch) errors += _all_greater_than_zero(data, ComponentType.generic_branch, "k") From 9ac84f0d90a6d68c23ebebb94fb3423c45fecd06 Mon Sep 17 00:00:00 2001 From: leovsch Date: Fri, 14 Feb 2025 09:32:11 +0100 Subject: [PATCH 07/12] add on the fly calculation of y matrix in tests --- tests/cpp_unit_tests/test_asym_line.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/cpp_unit_tests/test_asym_line.cpp b/tests/cpp_unit_tests/test_asym_line.cpp index 0c9eff3a9..71b620e0c 100644 --- a/tests/cpp_unit_tests/test_asym_line.cpp +++ b/tests/cpp_unit_tests/test_asym_line.cpp @@ -293,7 +293,10 @@ TEST_CASE("Test asym line") { .c1 = 0.308, .i_n = 216.0}; - ComplexTensor const y_series = ComplexTensor(1.87842984-0.42269873i, 1.87842984-0.42269873i, 1.87842984-0.42269873i, -0.62560863-0.00463073i, -0.57187623+0.12931409i, -0.62560863-0.00463073i); + ComplexTensor4 r_matrix = ComplexTensor4(input.r_aa, input.r_bb, input.r_cc, input.r_nn, input.r_ba, input.r_ca, input.r_na, input.r_cb, input.r_nb, input.r_nc); + ComplexTensor4 x_matrix = ComplexTensor4(input.x_aa, input.x_bb, input.x_cc, input.x_nn, input.x_ba, input.x_ca, input.x_na, input.x_cb, input.x_nb, input.x_nc); + ComplexTensor4 z = r_matrix + 1.0i * x_matrix; + ComplexTensor y_series = inv(kron_reduction(z)); execute_subcases(input, y_series); } @@ -318,7 +321,9 @@ TEST_CASE("Test asym line") { .c0 = 0.18, .c1 = 0.308, .i_n = 216.0}; - ComplexTensor const y_series = ComplexTensor(1.68079-0.470259i, 1.70433-0.383139i, 1.68079-0.470259i, -0.816117-0.00584238i, -0.769521+0.0817541i, -0.816117-0.00584238i); + ComplexTensor r_matrix = ComplexTensor(input.r_aa, input.r_bb, input.r_cc, input.r_ba, input.r_ca, input.r_cb); + ComplexTensor x_matrix = ComplexTensor(input.x_aa, input.x_bb, input.x_cc, input.x_ba, input.x_ca, input.x_cb); + ComplexTensor const y_series = inv(r_matrix + 1.0i * x_matrix); execute_subcases(input, y_series); } } From 4b73febda1deea5934aab99ed67fd0efc5025d58 Mon Sep 17 00:00:00 2001 From: leovsch Date: Fri, 14 Feb 2025 10:11:08 +0100 Subject: [PATCH 08/12] fix compilation error --- .../include/power_grid_model/main_core/input.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp index 67a2124fb..c20443e77 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/input.hpp @@ -42,7 +42,7 @@ inline void add_component(MainModelState& state, ForwardIter double const u1 = get_component(state, input.from_node).u_rated(); double const u2 = get_component(state, input.to_node).u_rated(); // set system frequency for line - if constexpr (std::same_as) { + if constexpr (std::same_as || std::same_as) { emplace_component(state, id, input, system_frequency, u1, u2); } else { emplace_component(state, id, input, u1, u2); From eb3818f4d82d5adcf103662481168a08f7d92cf7 Mon Sep 17 00:00:00 2001 From: leovsch Date: Fri, 14 Feb 2025 17:32:28 +0100 Subject: [PATCH 09/12] finished validation function and started with adding validate asym_line input data tests --- src/power_grid_model/validation/validation.py | 58 ++++++------ .../unit/validation/test_input_validation.py | 89 +++++++++++++++++++ 2 files changed, 114 insertions(+), 33 deletions(-) diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py index 193ea1ec1..6905a25f0 100644 --- a/src/power_grid_model/validation/validation.py +++ b/src/power_grid_model/validation/validation.py @@ -547,40 +547,32 @@ def validate_line(data: SingleDataset) -> list[ValidationError]: def validate_asym_line(data : SingleDataset) -> list[ValidationError]: - errors = validate_branch(data, ComponentType.line) - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_aa") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_ba") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_bb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_ca") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_cb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_cc") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_na") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_nb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_nc") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "r_nn") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_aa") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_ba") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_bb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_ca") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_cb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_cc") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_na") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_nb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_nc") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "x_nn") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_aa") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_ba") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_bb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_ca") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_cb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_cc") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_na") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_nb") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_nc") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c_nn") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c0") - errors += _all_greater_than_zero(data, ComponentType.asym_line, "c1") + errors = validate_branch(data, ComponentType.asym_line) errors += _all_greater_than_zero(data, ComponentType.asym_line, "i_n") + required_fields = ["r_aa", "r_ba", "r_bb", "r_ca", "r_cb", "r_cc", "x_aa", "x_ba", "x_bb", "x_ca", "x_cb", "x_cc"] + optional_fields = ["r_na", "r_nb", "r_nc", "r_nn", "x_na", "x_nb", "x_nc", "x_nn"] + required_c_matrix_fields = ["c_na", "c_nb", "c_nc"] + c_fields = ["c0", "c1"] + for field in required_fields + optional_fields + required_c_matrix_fields + c_fields: + errors += _all_greater_than_zero(data, ComponentType.asym_line, field) + + for i_data_record in range(0,len(data)): + new_errors = _none_missing(data, ComponentType.asym_line, optional_fields, i_data_record) + if 0 < len(new_errors) < len(optional_fields): + errors += new_errors + + new_errors_c_matrix = _none_missing(data, ComponentType.asym_line, required_c_matrix_fields, i_data_record) + if 0 < len(new_errors_c_matrix) < len(required_c_matrix_fields): + errors += new_errors_c_matrix + + new_errors_c1_c0 = _none_missing(data, ComponentType.asym_line, field, i_data_record) + if 0 < len(new_errors_c1_c0) < len(c_fields): + errors += new_errors_c1_c0 + + if len(new_errors_c_matrix) == len(required_c_matrix_fields) and len(new_errors_c1_c0) == len(c_fields): + errors += new_errors_c_matrix + errors += new_errors_c1_c0 + return errors diff --git a/tests/unit/validation/test_input_validation.py b/tests/unit/validation/test_input_validation.py index aef0061b5..063aee3ca 100644 --- a/tests/unit/validation/test_input_validation.py +++ b/tests/unit/validation/test_input_validation.py @@ -24,6 +24,7 @@ InvalidAssociatedEnumValueError, InvalidEnumValueError, InvalidIdError, + MissingValueError, MultiComponentNotUniqueError, NotBetweenError, NotBetweenOrAtError, @@ -57,6 +58,46 @@ def original_data() -> dict[ComponentType, np.ndarray]: line["x0"] = [0, 0, 50] line["i_n"] = [-3, 0, 50] + asym_line = initialize_array(DatasetType.input, ComponentType.asym_line, 2) + asym_line["id"] = [52, 53] + asym_line["from_node"] = [0, 1] + asym_line["to_node"] = [1, 2] + asym_line["from_status"] = [1, 1] + asym_line["to_status"] = [1, 1] + asym_line["r_aa"] = [-1, 2] + asym_line["r_ba"] = [-1, 2] + asym_line["r_bb"] = [-1, 2] + asym_line["r_ca"] = [-1, 2] + asym_line["r_cb"] = [-1, 2] + asym_line["r_cc"] = [-1, 2] + asym_line["r_na"] = [-1, 2] + asym_line["r_nb"] = [-1, 2] + asym_line["r_nc"] = [-1, 2] + asym_line["r_nn"] = [-1, 2] + asym_line["x_aa"] = [-1, 2] + asym_line["x_ba"] = [-1, 2] + asym_line["x_bb"] = [-1, 2] + asym_line["x_ca"] = [-1, 2] + asym_line["x_cb"] = [-1, 2] + asym_line["x_cc"] = [-1, 2] + asym_line["x_na"] = [-1, 2] + asym_line["x_nb"] = [-1, 2] + asym_line["x_nc"] = [-1, 2] + asym_line["x_nn"] = [-1, 2] + asym_line["c_aa"] = [-1, np.nan] + asym_line["c_ba"] = [-1, np.nan] + asym_line["c_bb"] = [-1, np.nan] + asym_line["c_ca"] = [-1, np.nan] + asym_line["c_cb"] = [-1, np.nan] + asym_line["c_cc"] = [-1, np.nan] + asym_line["c_na"] = [-1, np.nan] + asym_line["c_nb"] = [-1, np.nan] + asym_line["c_nc"] = [-1, np.nan] + asym_line["c_nn"] = [-1, np.nan] + asym_line["c0"] = [-1, np.nan] + asym_line["c1"] = [-1, np.nan] + asym_line["i_n"] = [50, 50] + generic_branch = initialize_array(DatasetType.input, ComponentType.generic_branch, 1) generic_branch["id"] = [6] generic_branch["from_node"] = [1] @@ -692,3 +733,51 @@ def test_generic_branch_input_data(input_data): validation_errors = validate_input_data(input_data, symmetric=True) assert NotGreaterThanError("generic_branch", "k", [6], 0) in validation_errors assert NotGreaterOrEqualError("generic_branch", "sn", [6], 0) in validation_errors + + +def test_asym_line_input_data(input_data): + validation_errors = validate_input_data(input_data, symmetric=True) + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_aa", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_ba", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_bb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_ca", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_cb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_cc", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_na", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_nb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_nc", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "r_nn", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_aa", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_ba", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_bb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_ca", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_cb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_cc", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_na", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_nb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_nc", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "x_nn", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_aa", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_ba", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_bb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_ca", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_cb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_cc", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_na", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_nb", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_nc", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c_nn", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c0", [52], 0) in validation_errors + assert NotGreaterOrEqualError(ComponentType.asym_line, "c1", [52], 0) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_aa", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_ba", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_bb", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_ca", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_cb", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_cc", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_na", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_nb", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_nc", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_nn", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c0", [53]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c1", [53]) in validation_errors From 4c9edaf00ba5bd01f2dd8f5d3dab8b2206b73cfa Mon Sep 17 00:00:00 2001 From: leovsch Date: Mon, 17 Feb 2025 15:14:10 +0100 Subject: [PATCH 10/12] continuing with input validation tests potential bug found in none_missing --- src/power_grid_model/validation/validation.py | 25 +++-- .../unit/validation/test_input_validation.py | 92 +++++++++---------- 2 files changed, 62 insertions(+), 55 deletions(-) diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py index 6905a25f0..c3ac20f9a 100644 --- a/src/power_grid_model/validation/validation.py +++ b/src/power_grid_model/validation/validation.py @@ -551,26 +551,33 @@ def validate_asym_line(data : SingleDataset) -> list[ValidationError]: errors += _all_greater_than_zero(data, ComponentType.asym_line, "i_n") required_fields = ["r_aa", "r_ba", "r_bb", "r_ca", "r_cb", "r_cc", "x_aa", "x_ba", "x_bb", "x_ca", "x_cb", "x_cc"] optional_fields = ["r_na", "r_nb", "r_nc", "r_nn", "x_na", "x_nb", "x_nc", "x_nn"] - required_c_matrix_fields = ["c_na", "c_nb", "c_nc"] + required_c_matrix_fields = ["c_aa", "c_ba", "c_bb", "c_ca", "c_cb", "c_cc"] + optional_c_matrix_fields = ["c_na", "c_nb", "c_nc", "c_nn"] c_fields = ["c0", "c1"] - for field in required_fields + optional_fields + required_c_matrix_fields + c_fields: + for field in required_fields + optional_fields + required_c_matrix_fields + c_fields + optional_c_matrix_fields: errors += _all_greater_than_zero(data, ComponentType.asym_line, field) - for i_data_record in range(0,len(data)): + for i_data_record in range(0,len(data[ComponentType.asym_line])): new_errors = _none_missing(data, ComponentType.asym_line, optional_fields, i_data_record) if 0 < len(new_errors) < len(optional_fields): errors += new_errors - new_errors_c_matrix = _none_missing(data, ComponentType.asym_line, required_c_matrix_fields, i_data_record) - if 0 < len(new_errors_c_matrix) < len(required_c_matrix_fields): - errors += new_errors_c_matrix + new_errors_c_matrix_req = _none_missing(data, ComponentType.asym_line, required_c_matrix_fields, i_data_record) + print(f"{len(new_errors_c_matrix_req)} of missing value erros for data with index: {i_data_record} and id: {data[ComponentType.asym_line]["id"][i_data_record]}") + if 0 < len(new_errors_c_matrix_req) < len(new_errors_c_matrix_req): + errors += new_errors_c_matrix_req - new_errors_c1_c0 = _none_missing(data, ComponentType.asym_line, field, i_data_record) + new_errors_c_matrix_opt = _none_missing(data, ComponentType.asym_line, optional_c_matrix_fields, i_data_record) + if 0 < len(new_errors_c_matrix_opt) < len(new_errors_c_matrix_opt): + errors += new_errors_c_matrix_opt + + new_errors_c1_c0 = _none_missing(data, ComponentType.asym_line, c_fields, i_data_record) + print(f"{len(new_errors_c1_c0)} of missing value erros for data with index: {i_data_record} and id: {data[ComponentType.asym_line]["id"][i_data_record]}") if 0 < len(new_errors_c1_c0) < len(c_fields): errors += new_errors_c1_c0 - if len(new_errors_c_matrix) == len(required_c_matrix_fields) and len(new_errors_c1_c0) == len(c_fields): - errors += new_errors_c_matrix + if len(required_c_matrix_fields) == len(new_errors_c_matrix_req) and len(new_errors_c1_c0) == len(c_fields): + errors += new_errors_c_matrix_req errors += new_errors_c1_c0 return errors diff --git a/tests/unit/validation/test_input_validation.py b/tests/unit/validation/test_input_validation.py index 063aee3ca..eef712d0b 100644 --- a/tests/unit/validation/test_input_validation.py +++ b/tests/unit/validation/test_input_validation.py @@ -59,7 +59,7 @@ def original_data() -> dict[ComponentType, np.ndarray]: line["i_n"] = [-3, 0, 50] asym_line = initialize_array(DatasetType.input, ComponentType.asym_line, 2) - asym_line["id"] = [52, 53] + asym_line["id"] = [55, 56] asym_line["from_node"] = [0, 1] asym_line["to_node"] = [1, 2] asym_line["from_status"] = [1, 1] @@ -311,10 +311,10 @@ def original_data() -> dict[ComponentType, np.ndarray]: fault["fault_object"] = [200, 3] + list(range(10, 28, 2)) + 9 * [0] fault["r_f"] = [-1.0, 0.0, 1.0] + 17 * [_nan_type("fault", "r_f")] fault["x_f"] = [-1.0, 0.0, 1.0] + 17 * [_nan_type("fault", "x_f")] - data = { ComponentType.node: node, ComponentType.line: line, + ComponentType.asym_line: asym_line, ComponentType.generic_branch: generic_branch, ComponentType.link: link, ComponentType.transformer: transformer, @@ -737,47 +737,47 @@ def test_generic_branch_input_data(input_data): def test_asym_line_input_data(input_data): validation_errors = validate_input_data(input_data, symmetric=True) - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_aa", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_ba", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_bb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_ca", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_cb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_cc", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_na", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_nb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_nc", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "r_nn", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_aa", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_ba", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_bb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_ca", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_cb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_cc", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_na", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_nb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_nc", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "x_nn", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_aa", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_ba", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_bb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_ca", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_cb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_cc", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_na", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_nb", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_nc", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c_nn", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c0", [52], 0) in validation_errors - assert NotGreaterOrEqualError(ComponentType.asym_line, "c1", [52], 0) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_aa", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_ba", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_bb", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_ca", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_cb", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_cc", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_na", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_nb", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_nc", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c_nn", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c0", [53]) in validation_errors - assert MissingValueError(ComponentType.asym_line, "c1", [53]) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_aa", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_ba", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_bb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_ca", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_cb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_cc", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_na", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_nb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_nc", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "r_nn", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_aa", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_ba", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_bb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_ca", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_cb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_cc", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_na", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_nb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_nc", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "x_nn", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_aa", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_ba", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_bb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_ca", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_cb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_cc", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_na", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_nb", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_nc", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c_nn", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c0", [55], 0) in validation_errors + assert NotGreaterThanError(ComponentType.asym_line, "c1", [55], 0) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_aa", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_ba", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_bb", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_ca", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_cb", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_cc", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_na", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_nb", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_nc", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c_nn", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c0", [56]) in validation_errors + assert MissingValueError(ComponentType.asym_line, "c1", [56]) in validation_errors From 93835ea46368ea4c19353afe083e8f18b35e79ff Mon Sep 17 00:00:00 2001 From: leovsch Date: Mon, 17 Feb 2025 16:06:58 +0100 Subject: [PATCH 11/12] translate psysical values into per-unit values --- .../power_grid_model/component/asym_line.hpp | 6 ++++-- tests/cpp_unit_tests/test_asym_line.cpp | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp index 0be35d78b..4722ccfb9 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/asym_line.hpp @@ -31,8 +31,10 @@ class AsymLine : public Branch { ComplexTensor c_matrix = compute_c_matrix_from_input(asym_line_input); ComplexTensor z_series = compute_z_series_from_input(asym_line_input); - y_series_abc_ = inv(z_series); - y_shunt_abc_ = 2 * pi * system_frequency * c_matrix * 1.0i; + double const base_y = base_i_ / (u1 / sqrt3); + + y_series_abc_ = 1 / base_y * inv(z_series); + y_shunt_abc_ = 1 / base_y * (2 * pi * system_frequency * c_matrix * 1.0i); } diff --git a/tests/cpp_unit_tests/test_asym_line.cpp b/tests/cpp_unit_tests/test_asym_line.cpp index 71b620e0c..929cc0b5a 100644 --- a/tests/cpp_unit_tests/test_asym_line.cpp +++ b/tests/cpp_unit_tests/test_asym_line.cpp @@ -10,17 +10,13 @@ namespace power_grid_model { using namespace std::complex_literals; -void execute_subcases(const AsymLineInput& input, const ComplexTensor& y_series) +void execute_subcases(const AsymLineInput& input, const ComplexTensor& y_series, const double base_i, const double base_y, const double system_frequency, const double voltage_lvl) { CAPTURE(input.id); CAPTURE(y_series); - double system_frequency = 50.0; - double voltage_lvl = 10.0e3; AsymLine asym_line{input, system_frequency, voltage_lvl, voltage_lvl}; - double const base_i = base_power_1p / (voltage_lvl / sqrt3); - double const base_y = base_i * base_i / base_power_1p; Branch& branch = asym_line; - ComplexTensor const y_shunt = 2 * pi * system_frequency * ComplexTensor{(2.0 * input.c1 + input.c0) / 3.0, (input.c0 - input.c1) / 3.0 } * 1.0i; + ComplexTensor const y_shunt = 1 / base_y * (2 * pi * system_frequency * ComplexTensor{(2.0 * input.c1 + input.c0) / 3.0, (input.c0 - input.c1) / 3.0 } * 1.0i); DoubleComplex const y1_series = (y_series(0,0) + y_series(1,1) + y_series(2,2)) / 3.0 - (y_series(0,1) + y_series(1,2) + y_series(1,0) + y_series(1,2) + y_series(2,0) + y_series(2,1)) / 6.0; DoubleComplex const y1_shunt = (y_shunt(0,0) + y_shunt(1,1) + y_shunt(2,2)) / 3.0 - (y_shunt(0,1) + y_shunt(1,2) + y_shunt(1,0) + y_shunt(1,2) + y_shunt(2,0) + y_shunt(2,1)) / 6.0; @@ -263,6 +259,11 @@ void execute_subcases(const AsymLineInput& input, const ComplexTensor y_series = inv(kron_reduction(z)); - execute_subcases(input, y_series); + ComplexTensor const y_series = 1 / base_y * inv(kron_reduction(z)); + execute_subcases(input, y_series, base_i, base_y, system_frequency, voltage_lvl); } SUBCASE("R and X matrix, c0, c1 excluding neutral") { @@ -323,8 +324,8 @@ TEST_CASE("Test asym line") { .i_n = 216.0}; ComplexTensor r_matrix = ComplexTensor(input.r_aa, input.r_bb, input.r_cc, input.r_ba, input.r_ca, input.r_cb); ComplexTensor x_matrix = ComplexTensor(input.x_aa, input.x_bb, input.x_cc, input.x_ba, input.x_ca, input.x_cb); - ComplexTensor const y_series = inv(r_matrix + 1.0i * x_matrix); - execute_subcases(input, y_series); + ComplexTensor const y_series = 1 / base_y * inv(r_matrix + 1.0i * x_matrix); + execute_subcases(input, y_series, base_i, base_y, system_frequency, voltage_lvl); } } From f83a87566cb036650e720038c2c1d5e774b43276 Mon Sep 17 00:00:00 2001 From: leovsch Date: Tue, 18 Feb 2025 10:17:59 +0100 Subject: [PATCH 12/12] remove debug prints --- src/power_grid_model/validation/validation.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/power_grid_model/validation/validation.py b/src/power_grid_model/validation/validation.py index c3ac20f9a..6cee02866 100644 --- a/src/power_grid_model/validation/validation.py +++ b/src/power_grid_model/validation/validation.py @@ -563,7 +563,6 @@ def validate_asym_line(data : SingleDataset) -> list[ValidationError]: errors += new_errors new_errors_c_matrix_req = _none_missing(data, ComponentType.asym_line, required_c_matrix_fields, i_data_record) - print(f"{len(new_errors_c_matrix_req)} of missing value erros for data with index: {i_data_record} and id: {data[ComponentType.asym_line]["id"][i_data_record]}") if 0 < len(new_errors_c_matrix_req) < len(new_errors_c_matrix_req): errors += new_errors_c_matrix_req @@ -572,7 +571,6 @@ def validate_asym_line(data : SingleDataset) -> list[ValidationError]: errors += new_errors_c_matrix_opt new_errors_c1_c0 = _none_missing(data, ComponentType.asym_line, c_fields, i_data_record) - print(f"{len(new_errors_c1_c0)} of missing value erros for data with index: {i_data_record} and id: {data[ComponentType.asym_line]["id"][i_data_record]}") if 0 < len(new_errors_c1_c0) < len(c_fields): errors += new_errors_c1_c0