From ed989e8e41a81eaeb365b5c563ea8dfea820287b Mon Sep 17 00:00:00 2001 From: Martijn Govers Date: Tue, 18 Aug 2026 15:53:14 +0200 Subject: [PATCH 01/15] save state, not yet compiling Signed-off-by: Martijn Govers --- docs/user_manual/components.md | 50 +++- .../power_grid_model/all_components.hpp | 3 +- .../include/power_grid_model/common/enum.hpp | 1 + .../power_grid_model/component/asym_line.hpp | 3 +- .../power_grid_model/component/branch.hpp | 222 +-------------- .../power_grid_model/component/component.hpp | 1 + .../power_grid_model/component/edge.hpp | 256 ++++++++++++++++++ .../component/generic_branch.hpp | 1 - .../power_grid_model/component/line.hpp | 1 - .../power_grid_model/component/link.hpp | 9 +- .../component/transformer.hpp | 1 - .../power_grid_model/main_core/input.hpp | 1 + .../power_grid_model/main_core/output.hpp | 5 +- .../main_core/state_queries.hpp | 9 +- .../power_grid_model/main_core/topology.hpp | 33 ++- .../power_grid_model/main_model_impl.hpp | 3 + .../optimizer/tap_position_optimizer.hpp | 5 +- .../power_grid_model_c/dataset_definitions.h | 56 ++-- .../src/dataset_definitions.cpp | 56 ++-- .../component/test_asym_line.cpp | 3 +- .../component/test_generic_branch.cpp | 3 +- tests/cpp_unit_tests/component/test_line.cpp | 6 +- tests/cpp_unit_tests/component/test_link.cpp | 5 +- .../component/test_transformer.cpp | 2 - 24 files changed, 411 insertions(+), 324 deletions(-) create mode 100644 power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index cee257d898..08fa9bd561 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -79,13 +79,13 @@ The `p` and `q` output of injection follows the `generator` reference direction | `u_angle` | `RealValueOutput` | rad | voltage angle | | `u` | `RealValueOutput` | volt (V) | voltage magnitude (line-neutral) | -## Branch +## Edge -* type name: `branch` +* type name: `edge` * base: [base](#base) -`branch` is the abstract base type for the component which connects two (possibly identical) nodes. -For each branch two switches are always defined at from- and to-side of the branch. +`edge` is the abstract base type for the component which connects two (possibly identical) nodes. +For each edge two switches are always defined at from- and to-side of the edge. In reality such switches may not exist. For example, a cable usually permanently connects two joints. In this case, the attribute `from_status` and `to_status` is always 1. @@ -122,6 +122,15 @@ In this case, the attribute `from_status` and `to_status` is always 1. | `i_to` | `RealValueOutput` | ampere (A) | magnitude of current at to-side | | `i_to_angle` | `RealValueOutput` | rad | current angle at to-side | +## Branch + +* type name: `branch` +* base: [edge](#edge) + +`branch` is the abstract base type for the component which connects two (possibly identical) nodes with finite +impedance. +All input, update and output attributes are identical to the ones for [Edges](#edge). + ### Line * type name: `line` @@ -165,19 +174,38 @@ $$ * type name: `link` -`link` is a [branch](#branch) which usually represents a short internal cable/connection -between two busbars inside a substation. -It has a very high admittance (small impedance) which is set to a fixed per-unit value (equivalent to 10e6 siemens for -10kV network). -Therefore, it is chosen by design that no sensors can be coupled to a `link`. -There is no additional attribute for `link`. +`link` is an [edge](#edge) which usually represents a short internal cable/connection between two busbars inside a +substation. +In reality, it has a very high admittance (small impedance). + +Because of this, the power-grid-model choses to model this accordingly: + +* If there are no node injection sensors in the grid, links are modeled as infinite (but equal) admittance connections. +* If there are node injection sensors in the grid, link admittances are modeled with a fixed per-unit value, equivalent + to 10e6 siemens for a 10kV network. + +```{note} +New in version `v1.13.142`: links may be modeled as infinite (but equal) admittance connections. +In the old behavior, link admittences are always modeled with the same fixed per-unit value. +Starting with version `v2.0.0`, link admittances are always modeled as infinite-admittance connections. +``` + +Because links have very high admittance, it also is chosen by design that no sensors can be coupled to a `link`. +There are no additional attributes for `link`. It is explicitly allowed to connect a link between nodes with different voltage levels to allow modeling [ideal transformers](./non-native-components.md#ideal-transformer). #### Electric Model -`link` is modeled by a constant admittance $Y_{\text{series}}$, where +`link` is modeled by a constant admittance $Y_{\text{series}}$. +If there are no node injection sensors in the grid: + +$$ +Y_{\text{series}}\rightarrow \infty +$$ + +If there are node injection sensors in the grid: $$ Y_{\text{series}} = (1 + \mathrm{j}) \cdot 10^6 \,\mathrm{p.u.} 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 d30627520c..bb920e4c75 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 @@ -15,6 +15,7 @@ #include "component/branch.hpp" #include "component/branch3.hpp" #include "component/current_sensor.hpp" +#include "component/edge.hpp" #include "component/fault.hpp" #include "component/generic_branch.hpp" #include "component/line.hpp" @@ -40,7 +41,7 @@ using AllComponents = ComponentList; using AllExtraRetrievableTypes = - ExtraRetrievableTypes; } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp index 5d0e67c8d5..d000d41940 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/enum.hpp @@ -68,6 +68,7 @@ enum class ComponentType : IntS { regulator = 11, transformer_tap_regulator = 12, voltage_regulator = 13, + link = 14, test = -128 // any stub or mock may use this. do not use this in production }; 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 0db4d44ec3..a476a3e0bf 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 @@ -45,7 +45,6 @@ class AsymLine : public Branch { 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_{}; @@ -103,7 +102,7 @@ class AsymLine : public Branch { BranchCalcParam asym_calc_param() const final { BranchCalcParam param{}; // not both connected - if (!branch_status()) { + if (!edge_status()) { // single connected if (from_status() || to_status()) { // branch_shunt = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); // NOSONAR(S125) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp index 6c87faac87..a3b8438174 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp @@ -5,6 +5,7 @@ #pragma once #include "base.hpp" +#include "edge.hpp" #include "../auxiliary/input.hpp" #include "../auxiliary/output.hpp" @@ -25,233 +26,16 @@ namespace power_grid_model { -class Branch : public Base { +class Branch : public Edge { public: using InputType = BranchInput; using UpdateType = BranchUpdate; template using OutputType = BranchOutput; - using ShortCircuitOutputType = BranchShortCircuitOutput; - using SideType = BranchSide; static constexpr char const* name = "branch"; ComponentType math_model_type() const final { return ComponentType::branch; } - explicit Branch(BranchInput const& branch_input) - : Base{branch_input}, - from_node_{branch_input.from_node}, - to_node_{branch_input.to_node}, - from_status_{static_cast(branch_input.from_status)}, - to_status_{static_cast(branch_input.to_status)} {} - - // getter - constexpr ID from_node() const { return from_node_; } - constexpr ID to_node() const { return to_node_; } - constexpr ID node(BranchSide side) const { - switch (side) { - case BranchSide::from: - return from_node(); - case BranchSide::to: - return to_node(); - default: - throw MissingCaseForEnumError{"node(BranchSide)", side}; - } - } - constexpr bool from_status() const { return from_status_; } - constexpr bool to_status() const { return to_status_; } - constexpr bool branch_status() const { return from_status() && to_status(); } - constexpr bool status(BranchSide side) const { - switch (side) { - case BranchSide::from: - return from_status(); - case BranchSide::to: - return to_status(); - default: - throw MissingCaseForEnumError{"status(BranchSide)", side}; - } - } - template BranchCalcParam calc_param(bool is_connected_to_source = true) const { - if (!energized(is_connected_to_source)) { - return BranchCalcParam{}; - } - if constexpr (is_symmetric_v) { - return sym_calc_param(); - } else { - return asym_calc_param(); - } - } - - // virtual getter - bool energized(bool is_connected_to_source) const final { - return is_connected_to_source && (from_status_ || to_status_); - } - virtual double base_i_from() const = 0; - virtual double base_i_to() const = 0; - virtual double loading(double max_s, double max_i) const = 0; - virtual double phase_shift() const = 0; // shift theta_from - theta_to - virtual bool is_param_mutable() const = 0; - - template - BranchOutput get_output(BranchSolverOutput const& branch_solver_output) const { - // result object - BranchOutput output{}; - static_cast(output) = base_output(true); - // calculate result - output.p_from = base_power * real(branch_solver_output.s_f); - output.q_from = base_power * imag(branch_solver_output.s_f); - output.i_from = base_i_from() * cabs(branch_solver_output.i_f); - output.s_from = base_power * cabs(branch_solver_output.s_f); - output.p_to = base_power * real(branch_solver_output.s_t); - output.q_to = base_power * imag(branch_solver_output.s_t); - output.i_to = base_i_to() * cabs(branch_solver_output.i_t); - output.s_to = base_power * cabs(branch_solver_output.s_t); - double const max_s = std::max(sum_val(output.s_from), sum_val(output.s_to)); - double const max_i = std::max(max_val(output.i_from), max_val(output.i_to)); - output.loading = loading(max_s, max_i); - return output; - } - - BranchShortCircuitOutput get_sc_output(ComplexValue const& i_f, - ComplexValue const& i_t) const { - return get_sc_output(BranchShortCircuitSolverOutput{.i_f = i_f, .i_t = i_t}); - } - BranchShortCircuitOutput get_sc_output(ComplexValue const& i_f, - ComplexValue const& i_t) const { - return get_sc_output(BranchShortCircuitSolverOutput{.i_f = i_f, .i_t = i_t}); - } - - BranchShortCircuitOutput - get_sc_output(BranchShortCircuitSolverOutput const& branch_solver_output) const { - BranchShortCircuitOutput output{}; - static_cast(output) = base_output(true); - // calculate result - output.i_from = base_i_from() * cabs(branch_solver_output.i_f); - output.i_to = base_i_to() * cabs(branch_solver_output.i_t); - output.i_from_angle = arg(branch_solver_output.i_f); - output.i_to_angle = arg(branch_solver_output.i_t); - return output; - } - - BranchShortCircuitOutput - get_sc_output(BranchShortCircuitSolverOutput const& branch_solver_output) const { - return get_sc_output( - BranchShortCircuitSolverOutput{.i_f = ComplexValue{branch_solver_output.i_f}, - .i_t = ComplexValue{branch_solver_output.i_t}}); - } - - template BranchOutput get_null_output() const { - BranchOutput output{.loading = {}, - .p_from = {}, - .q_from = {}, - .i_from = {}, - .s_from = {}, - .p_to = {}, - .q_to = {}, - .i_to = {}, - .s_to = {}}; - static_cast(output) = base_output(false); - return output; - } - - BranchShortCircuitOutput get_null_sc_output() const { - BranchShortCircuitOutput output{.i_from = {}, .i_from_angle = {}, .i_to = {}, .i_to_angle = {}}; - static_cast(output) = base_output(false); - return output; - } - - // setter - bool set_status(IntS new_from_status, IntS new_to_status) { - bool const set_from = new_from_status != na_IntS; - bool const set_to = new_to_status != na_IntS; - bool changed = false; - if (set_from) { - changed = changed || (from_status_ != static_cast(new_from_status)); - from_status_ = static_cast(new_from_status); - } - if (set_to) { - changed = changed || (to_status_ != static_cast(new_to_status)); - to_status_ = static_cast(new_to_status); - } - return changed; - } - - // default update for branch, will be hidden for transformer - UpdateChange update(BranchUpdate const& update_data) { - assert(update_data.id == this->id() || is_nan(update_data.id)); - bool const changed = set_status(update_data.from_status, update_data.to_status); - // change branch connection will change both topo and param - return {.topo = changed, .param = changed}; - } - - auto inverse(std::convertible_to auto update_data) const { - assert(update_data.id == this->id() || is_nan(update_data.id)); - - set_if_not_nan(update_data.from_status, status_to_int(from_status_)); - set_if_not_nan(update_data.to_status, status_to_int(to_status_)); - - return update_data; - } - - protected: - // calculate branch param based on symmetric component - BranchCalcParam - calc_param_y_sym(DoubleComplex const& y_series, // y_series must be converted to the "to" side of the branch - DoubleComplex const& y_shunt, // y_shunt must be converted to the "to" side of the branch - DoubleComplex const& tap_ratio) const { - double const tap = cabs(tap_ratio); - BranchCalcParam param{}; - // not both connected - if (!branch_status()) { - // single connected - if (from_status() || to_status()) { - DoubleComplex branch_shunt; - // shunt value - if (cabs(y_shunt) < numerical_tolerance) { - branch_shunt = 0.0; - } else { - // branch_shunt = y_shunt/2 + 1/(1/y_series + 2/y_shunt) // NOSONAR(S125) - branch_shunt = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); - } - // from or to connected - param.yff() = from_status() ? (1.0 / tap / tap) * branch_shunt : 0.0; - param.ytt() = to_status() ? branch_shunt : 0.0; - } - } - // both connected - else { - param.ytt() = y_series + 0.5 * y_shunt; - param.yff() = (1.0 / tap / tap) * param.ytt(); - param.yft() = (-1.0 / conj(tap_ratio)) * y_series; - param.ytf() = (-1.0 / tap_ratio) * y_series; - } - return param; - } - // calculate branch param for asymmetric - BranchCalcParam calc_param_y_asym(DoubleComplex const& y1_series, DoubleComplex const& y1_shunt, - DoubleComplex const& y0_series, DoubleComplex const& y0_shunt, - DoubleComplex const& tap_ratio) const { - BranchCalcParam const param1 = calc_param_y_sym(y1_series, y1_shunt, tap_ratio); - BranchCalcParam const param0 = calc_param_y_sym(y0_series, y0_shunt, tap_ratio); - // abc matrix - // 1/3 * - // [[2y1+y0, y0-y1, y0-y1], - // [y0-y1, 2y1+y0, y0-y1], - // [y0-y1, y0-y1, 2y1+y0]] - BranchCalcParam param{}; - for (size_t i = 0; i < 4; ++i) { - param.value[i] = ComplexTensor{(2.0 * param1.value[i] + param0.value[i]) / 3.0, - (param0.value[i] - param1.value[i]) / 3.0}; - } - return param; - } - - private: - ID from_node_; - ID to_node_; - bool from_status_; - bool to_status_; - - virtual BranchCalcParam sym_calc_param() const = 0; - virtual BranchCalcParam asym_calc_param() const = 0; + explicit Branch(BranchInput const& branch_input): Edge{branch_input} {} }; } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/component.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/component.hpp index 1ce8efce39..b6c67411e8 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/component.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/component.hpp @@ -51,6 +51,7 @@ static_assert(is_generator_v); // Forward declarations of all components class Base; class Node; +class Edge; class Branch; class Branch3; class Appliance; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp new file mode 100644 index 0000000000..16d55c74ee --- /dev/null +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp @@ -0,0 +1,256 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#pragma once + +#include "base.hpp" + +#include "../auxiliary/input.hpp" +#include "../auxiliary/output.hpp" +#include "../auxiliary/update.hpp" +#include "../calculation_parameters.hpp" +#include "../common/common.hpp" +#include "../common/enum.hpp" +#include "../common/exception.hpp" +#include "../common/three_phase_tensor.hpp" +#include "component.hpp" + +#include + +#include +#include +#include +#include + +namespace power_grid_model { + +class Edge : public Base { + public: + using InputType = BranchInput; + using UpdateType = BranchUpdate; + template using OutputType = BranchOutput; + using ShortCircuitOutputType = BranchShortCircuitOutput; + using SideType = BranchSide; + + static constexpr char const* name = "edge"; + + explicit Edge(BranchInput const& edge_input) + : Base{edge_input}, + from_node_{edge_input.from_node}, + to_node_{edge_input.to_node}, + from_status_{static_cast(edge_input.from_status)}, + to_status_{static_cast(edge_input.to_status)} {} + + // getter + constexpr ID from_node() const { return from_node_; } + constexpr ID to_node() const { return to_node_; } + constexpr ID node(BranchSide side) const { + switch (side) { + case BranchSide::from: + return from_node(); + case BranchSide::to: + return to_node(); + default: + throw MissingCaseForEnumError{"node(BranchSide)", side}; + } + } + constexpr bool from_status() const { return from_status_; } + constexpr bool to_status() const { return to_status_; } + constexpr bool edge_status() const { return from_status() && to_status(); } + constexpr bool status(BranchSide side) const { + switch (side) { + case BranchSide::from: + return from_status(); + case BranchSide::to: + return to_status(); + default: + throw MissingCaseForEnumError{"status(BranchSide)", side}; + } + } + template BranchCalcParam calc_param(bool is_connected_to_source = true) const { + // TODO(mgovers): cleanup v2: move to Branch + if (!energized(is_connected_to_source)) { + return BranchCalcParam{}; + } + if constexpr (is_symmetric_v) { + return sym_calc_param(); + } else { + return asym_calc_param(); + } + } + + // virtual getter + bool energized(bool is_connected_to_source) const final { + return is_connected_to_source && (from_status_ || to_status_); + } + virtual double base_i_from() const = 0; + virtual double base_i_to() const = 0; + virtual double loading(double max_s, double max_i) const = 0; + virtual double phase_shift() const = 0; // shift theta_from - theta_to + + template + BranchOutput get_output(BranchSolverOutput const& edge_solver_output) const { + // result object + BranchOutput output{}; + static_cast(output) = base_output(true); + // calculate result + output.p_from = base_power * real(edge_solver_output.s_f); + output.q_from = base_power * imag(edge_solver_output.s_f); + output.i_from = base_i_from() * cabs(edge_solver_output.i_f); + output.s_from = base_power * cabs(edge_solver_output.s_f); + output.p_to = base_power * real(edge_solver_output.s_t); + output.q_to = base_power * imag(edge_solver_output.s_t); + output.i_to = base_i_to() * cabs(edge_solver_output.i_t); + output.s_to = base_power * cabs(edge_solver_output.s_t); + double const max_s = std::max(sum_val(output.s_from), sum_val(output.s_to)); + double const max_i = std::max(max_val(output.i_from), max_val(output.i_to)); + output.loading = loading(max_s, max_i); + return output; + } + + BranchShortCircuitOutput get_sc_output(ComplexValue const& i_f, + ComplexValue const& i_t) const { + return get_sc_output(BranchShortCircuitSolverOutput{.i_f = i_f, .i_t = i_t}); + } + BranchShortCircuitOutput get_sc_output(ComplexValue const& i_f, + ComplexValue const& i_t) const { + return get_sc_output(BranchShortCircuitSolverOutput{.i_f = i_f, .i_t = i_t}); + } + + BranchShortCircuitOutput + get_sc_output(BranchShortCircuitSolverOutput const& edge_solver_output) const { + BranchShortCircuitOutput output{}; + static_cast(output) = base_output(true); + // calculate result + output.i_from = base_i_from() * cabs(edge_solver_output.i_f); + output.i_to = base_i_to() * cabs(edge_solver_output.i_t); + output.i_from_angle = arg(edge_solver_output.i_f); + output.i_to_angle = arg(edge_solver_output.i_t); + return output; + } + + BranchShortCircuitOutput + get_sc_output(BranchShortCircuitSolverOutput const& edge_solver_output) const { + return get_sc_output( + BranchShortCircuitSolverOutput{.i_f = ComplexValue{edge_solver_output.i_f}, + .i_t = ComplexValue{edge_solver_output.i_t}}); + } + + template BranchOutput get_null_output() const { + BranchOutput output{.loading = {}, + .p_from = {}, + .q_from = {}, + .i_from = {}, + .s_from = {}, + .p_to = {}, + .q_to = {}, + .i_to = {}, + .s_to = {}}; + static_cast(output) = base_output(false); + return output; + } + + BranchShortCircuitOutput get_null_sc_output() const { + BranchShortCircuitOutput output{.i_from = {}, .i_from_angle = {}, .i_to = {}, .i_to_angle = {}}; + static_cast(output) = base_output(false); + return output; + } + + // setter + bool set_status(IntS new_from_status, IntS new_to_status) { + bool const set_from = new_from_status != na_IntS; + bool const set_to = new_to_status != na_IntS; + bool changed = false; + if (set_from) { + changed = changed || (from_status_ != static_cast(new_from_status)); + from_status_ = static_cast(new_from_status); + } + if (set_to) { + changed = changed || (to_status_ != static_cast(new_to_status)); + to_status_ = static_cast(new_to_status); + } + return changed; + } + + // default update for edge, will be hidden for transformer + UpdateChange update(BranchUpdate const& update_data) { + assert(update_data.id == this->id() || is_nan(update_data.id)); + bool const changed = set_status(update_data.from_status, update_data.to_status); + // change edge connection will change both topo and param + return {.topo = changed, .param = changed}; + } + + auto inverse(std::convertible_to auto update_data) const { + assert(update_data.id == this->id() || is_nan(update_data.id)); + + set_if_not_nan(update_data.from_status, status_to_int(from_status_)); + set_if_not_nan(update_data.to_status, status_to_int(to_status_)); + + return update_data; + } + + protected: + // calculate edge param based on symmetric component + BranchCalcParam + calc_param_y_sym(DoubleComplex const& y_series, // y_series must be converted to the "to" side of the edge + DoubleComplex const& y_shunt, // y_shunt must be converted to the "to" side of the edge + DoubleComplex const& tap_ratio) const { + double const tap = cabs(tap_ratio); + BranchCalcParam param{}; + // not both connected + if (!edge_status()) { + // single connected + if (from_status() || to_status()) { + DoubleComplex edge_shunt; + // shunt value + if (cabs(y_shunt) < numerical_tolerance) { + edge_shunt = 0.0; + } else { + // edge_shunt = y_shunt/2 + 1/(1/y_series + 2/y_shunt) // NOSONAR(S125) + edge_shunt = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); + } + // from or to connected + param.yff() = from_status() ? (1.0 / tap / tap) * edge_shunt : 0.0; + param.ytt() = to_status() ? edge_shunt : 0.0; + } + } + // both connected + else { + param.ytt() = y_series + 0.5 * y_shunt; + param.yff() = (1.0 / tap / tap) * param.ytt(); + param.yft() = (-1.0 / conj(tap_ratio)) * y_series; + param.ytf() = (-1.0 / tap_ratio) * y_series; + } + return param; + } + // calculate edge param for asymmetric + BranchCalcParam calc_param_y_asym(DoubleComplex const& y1_series, DoubleComplex const& y1_shunt, + DoubleComplex const& y0_series, DoubleComplex const& y0_shunt, + DoubleComplex const& tap_ratio) const { + BranchCalcParam const param1 = calc_param_y_sym(y1_series, y1_shunt, tap_ratio); + BranchCalcParam const param0 = calc_param_y_sym(y0_series, y0_shunt, tap_ratio); + // abc matrix + // 1/3 * + // [[2y1+y0, y0-y1, y0-y1], + // [y0-y1, 2y1+y0, y0-y1], + // [y0-y1, y0-y1, 2y1+y0]] + BranchCalcParam param{}; + for (size_t i = 0; i < 4; ++i) { + param.value[i] = ComplexTensor{(2.0 * param1.value[i] + param0.value[i]) / 3.0, + (param0.value[i] - param1.value[i]) / 3.0}; + } + return param; + } + + private: + ID from_node_; + ID to_node_; + bool from_status_; + bool to_status_; + + virtual BranchCalcParam sym_calc_param() const = 0; + virtual BranchCalcParam asym_calc_param() const = 0; +}; + +} // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/generic_branch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/generic_branch.hpp index 82fb0b34f4..904c79a1e0 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/generic_branch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/generic_branch.hpp @@ -58,7 +58,6 @@ class GenericBranch final : public Branch { double base_i_to() const override { return base_i_to_; } double loading(double max_s, double /*max_i*/) const override { return std::isnan(sn_) ? 0.0 : (max_s / sn_); }; double phase_shift() const override { return theta_; } - bool is_param_mutable() const override { return false; } private: double sn_; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/line.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/line.hpp index 2e9ba93957..2a76c0d9cd 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/line.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/line.hpp @@ -40,7 +40,6 @@ class Line final : public Branch { 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_; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp index abd9e645b8..b5bf0b840d 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp @@ -4,7 +4,7 @@ #pragma once -#include "branch.hpp" +#include "edge.hpp" #include "../auxiliary/input.hpp" #include "../auxiliary/update.hpp" @@ -13,21 +13,22 @@ namespace power_grid_model { -class Link final : public Branch { +class Link final : public Edge { public: using InputType = LinkInput; using UpdateType = BranchUpdate; static constexpr char const* name = "link"; + ComponentType math_model_type() const final { return ComponentType::link; } + explicit Link(LinkInput const& link_input, double u1, double u2) - : Branch{link_input}, base_i_from_{base_power_3p / u1 / sqrt3}, base_i_to_{base_power_3p / u2 / sqrt3} {} + : Edge{link_input}, base_i_from_{base_power_3p / u1 / sqrt3}, base_i_to_{base_power_3p / u2 / sqrt3} {} // override getter double base_i_from() const override { return base_i_from_; } double base_i_to() const override { return base_i_to_; } double loading(double /* max_s */, double /* max_i */) const override { return 0.0; }; double phase_shift() const override { return 0.0; } - bool is_param_mutable() const override { return false; } private: double base_i_from_; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp index ebd8d92196..8d421ab1ca 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/transformer.hpp @@ -95,7 +95,6 @@ class Transformer : public Branch { double loading(double max_s, double /* max_i */) const final { return max_s / sn_; }; // phase shift is theta_from - theta_to double phase_shift() const final { return clock_ * deg_30; } - bool is_param_mutable() const final { return true; } // getters constexpr IntS tap_pos() const { return tap_pos_; } constexpr BranchSide tap_side() const { return tap_side_; } 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 142b7ecd2b..d9ec34926b 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 @@ -15,6 +15,7 @@ #include "../component/branch.hpp" #include "../component/branch3.hpp" #include "../component/current_sensor.hpp" +#include "../component/edge.hpp" #include "../component/fault.hpp" #include "../component/line.hpp" #include "../component/link.hpp" diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/output.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/output.hpp index 34b33cc13f..32cc803bf1 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/output.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/output.hpp @@ -16,6 +16,7 @@ #include "../component/branch.hpp" #include "../component/branch3.hpp" #include "../component/current_sensor.hpp" +#include "../component/edge.hpp" #include "../component/fault.hpp" #include "../component/load_gen.hpp" #include "../component/node.hpp" @@ -85,7 +86,7 @@ constexpr auto output_result(Component const& node, MainModelState Component, steady_state_solver_output_type SolverOutputType> +template Component, steady_state_solver_output_type SolverOutputType> constexpr auto output_result(Component const& branch, std::vector const& solver_output, Idx2D math_id) { using sym = decode_symmetry_v; @@ -95,7 +96,7 @@ constexpr auto output_result(Component const& branch, std::vector(solver_output[math_id.group].branch[math_id.pos]); } -template Component, short_circuit_solver_output_type SolverOutputType> +template Component, short_circuit_solver_output_type SolverOutputType> inline auto output_result(Component const& branch, std::vector const& solver_output, Idx2D math_id) { if (math_id.group == disconnected) { return branch.get_null_sc_output(); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/state_queries.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/state_queries.hpp index 8483d99994..f6529e5eac 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/state_queries.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/state_queries.hpp @@ -11,6 +11,7 @@ #include "../common/enum.hpp" #include "../component/branch.hpp" #include "../component/branch3.hpp" +#include "../component/edge.hpp" #include "../component/node.hpp" #include "../component/regulator.hpp" #include "../component/shunt.hpp" @@ -21,7 +22,7 @@ #include namespace power_grid_model::main_core { -template ComponentType, class ComponentContainer> +template ComponentType, class ComponentContainer> requires model_component_state_c constexpr auto get_branch_nodes(MainModelState const& state, Idx topology_sequence_idx) { return state.comp_topo->branch_node_idx[topology_sequence_idx]; @@ -55,7 +56,7 @@ constexpr auto get_math_id(MainModelState const& state, Idx return state.topo_comp_coup->node[topology_sequence_idx]; } -template ComponentType, class ComponentContainer> +template ComponentType, class ComponentContainer> requires model_component_state_c constexpr auto get_math_id(MainModelState const& state, Idx topology_sequence_idx) { return state.topo_comp_coup->branch[topology_sequence_idx]; @@ -91,10 +92,10 @@ constexpr auto comp_base_sequence_cbegin(MainModelState cons return state.reduced_topology->topo_node_coup.coupling.user_nodes_to_topo_nodes.cbegin(); } -template Component, class ComponentContainer> +template Component, class ComponentContainer> requires model_component_state_c constexpr auto comp_base_sequence_cbegin(MainModelState const& state) { - return state.topo_comp_coup->branch.cbegin() + get_component_sequence_offset(state.components); + return state.topo_comp_coup->branch.cbegin() + get_component_sequence_offset(state.components); } template Component, class ComponentContainer> diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp index c270d1f03e..3759f8142e 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp @@ -13,6 +13,8 @@ #include "../component/branch.hpp" #include "../component/branch3.hpp" #include "../component/current_sensor.hpp" +#include "../component/edge.hpp" +#include "../component/link.hpp" #include "../component/load_gen.hpp" #include "../component/node.hpp" #include "../component/power_sensor.hpp" @@ -52,9 +54,19 @@ constexpr void register_topology_components(ComponentContainer const& components template Component, class ComponentContainer> requires common::component_container_c constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { - apply_registration(components, comp_topo.branch_node_idx, [&components](Branch const& branch) { - return BranchIdx{get_component_sequence_idx(components, branch.from_node()), - get_component_sequence_idx(components, branch.to_node())}; + apply_registration(components, comp_topo.branch_node_idx, + [&components](Branch const& edge) { + return BranchIdx{get_component_sequence_idx(components, edge.from_node()), + get_component_sequence_idx(components, edge.to_node())}; + }); +} + +template Component, class ComponentContainer> + requires common::component_container_c +constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { + apply_registration(components, comp_topo.link_node_idx, [&components](Link const& edge) { + return BranchIdx{get_component_sequence_idx(components, edge.from_node()), + get_component_sequence_idx(components, edge.to_node())}; }); } @@ -208,6 +220,14 @@ constexpr void register_connections_components(ComponentContainer const& compone apply_registration(components, comp_conn.branch_phase_shift, [](Branch const& branch) { return branch.phase_shift(); }); } + +template Component, class ComponentContainer> + requires common::component_container_c +constexpr void register_connections_components(ComponentContainer const& components, ComponentConnections& comp_conn) { + apply_registration(components, comp_conn.link_connected, [](Link const& link) { + return BranchConnected{status_to_int(link.from_status()), status_to_int(link.to_status())}; + }); +} template Component, class ComponentContainer> requires common::component_container_c constexpr void register_connections_components(ComponentContainer const& components, ComponentConnections& comp_conn) { @@ -229,9 +249,8 @@ constexpr void register_connections_components(ComponentContainer const& compone } // namespace detail template - requires common::component_container_c + requires common::component_container_c ComponentTopology construct_topology(typename ModelType::ComponentContainer const& components) { ComponentTopology comp_topo; using TopologyTypesTuple = ModelType::TopologyTypesTuple; @@ -243,7 +262,7 @@ ComponentTopology construct_topology(typename ModelType::ComponentContainer cons } template - requires common::component_container_c + requires common::component_container_c ComponentConnections construct_components_connections(typename ModelType::ComponentContainer const& components) { ComponentConnections comp_conn; using TopologyConnectionTypesTuple = ModelType::TopologyConnectionTypesTuple; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index 142841c2ba..fb92d89585 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -207,6 +207,7 @@ class MainModelImpl { construction_complete_ = true; #endif // !NDEBUG state_.components.set_construction_complete(); + state_.comp_topo = std::make_shared(main_core::construct_topology(state_.components)); } @@ -423,6 +424,7 @@ class MainModelImpl { } void check_no_future_deprecations(Options const& /*options*/, ConstDataset const* /*batch_dataset*/) const { + // TODO(mgovers): cleanup v2: remove this function, as power sensor creation itself should always throw after node injection sensors removal ModelType::run_functor_with_all_component_types_return_void([this]() { // only flow sensors have get_terminal_type() so we can filter on it if constexpr (requires(CT c) { @@ -438,6 +440,7 @@ class MainModelImpl { } private: + template void output_result(MathOutput> math_output, MutableDataset const& result_data, Logger& logger) const { diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp index 87b0951cbb..820271a1fc 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/optimizer/tap_position_optimizer.hpp @@ -16,6 +16,7 @@ #include "../component/branch.hpp" #include "../component/branch3.hpp" #include "../component/component.hpp" +#include "../component/edge.hpp" #include "../component/line.hpp" #include "../component/link.hpp" #include "../component/node.hpp" @@ -233,7 +234,7 @@ constexpr void add_edge(main_core::MainModelState const& sta } } -template Component, class ComponentContainer> +template Component, class ComponentContainer> requires main_core::model_component_state_c && (!transformer_c) constexpr void add_edge(main_core::MainModelState const& state, @@ -625,7 +626,7 @@ inline auto regulator_mapping(State const& state, RankedTransformerGroups const& return result; } -template ComponentType, steady_state_solver_output_type SolverOutputType> +template ComponentType, steady_state_solver_output_type SolverOutputType> inline auto i_pu(std::vector const& solver_output, Idx2D const& math_id, ControlSide control_side) { using enum ControlSide; 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 4cc1c90263..8da75c3881 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 @@ -354,20 +354,6 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_u; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_u_angle; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_p; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_q; -// component line -PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_line; -// attributes of sym_output line -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_id; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_energized; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_loading; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_p_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_q_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_i_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_s_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_p_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_q_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_i_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_s_to; // component link PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_link; // attributes of sym_output link @@ -382,6 +368,20 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_p_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_q_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_s_to; +// component line +PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_line; +// attributes of sym_output line +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_loading; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_p_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_q_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_s_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_p_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_q_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_s_to; // component transformer PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_transformer; // attributes of sym_output transformer @@ -577,20 +577,6 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_u; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_u_angle; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_p; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_q; -// component line -PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_line; -// attributes of asym_output line -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_id; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_energized; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_loading; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_p_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_q_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_i_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_s_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_p_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_q_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_i_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_s_to; // component link PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_link; // attributes of asym_output link @@ -605,6 +591,20 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_p_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_q_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_s_to; +// component line +PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_line; +// attributes of asym_output line +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_loading; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_p_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_q_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_s_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_p_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_q_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_s_to; // component transformer PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_transformer; // attributes of asym_output 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 e53239de05..deb18ce6cc 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 @@ -343,20 +343,6 @@ PGM_MetaAttribute const* const PGM_def_sym_output_node_u = PGM_meta_get_attribut PGM_MetaAttribute const* const PGM_def_sym_output_node_u_angle = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "node", "u_angle"); PGM_MetaAttribute const* const PGM_def_sym_output_node_p = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "node", "p"); PGM_MetaAttribute const* const PGM_def_sym_output_node_q = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "node", "q"); -// component line -PGM_MetaComponent const* const PGM_def_sym_output_line = PGM_meta_get_component_by_name(nullptr, "sym_output", "line"); -// attributes of sym_output line -PGM_MetaAttribute const* const PGM_def_sym_output_line_id = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "id"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_energized = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "energized"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_loading = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "loading"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_p_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "p_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_q_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "q_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "i_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_s_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "s_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_p_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "p_to"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "q_to"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "i_to"); -PGM_MetaAttribute const* const PGM_def_sym_output_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "s_to"); // component link PGM_MetaComponent const* const PGM_def_sym_output_link = PGM_meta_get_component_by_name(nullptr, "sym_output", "link"); // attributes of sym_output link @@ -371,6 +357,20 @@ PGM_MetaAttribute const* const PGM_def_sym_output_link_p_to = PGM_meta_get_attri PGM_MetaAttribute const* const PGM_def_sym_output_link_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "q_to"); PGM_MetaAttribute const* const PGM_def_sym_output_link_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "i_to"); PGM_MetaAttribute const* const PGM_def_sym_output_link_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "s_to"); +// component line +PGM_MetaComponent const* const PGM_def_sym_output_line = PGM_meta_get_component_by_name(nullptr, "sym_output", "line"); +// attributes of sym_output line +PGM_MetaAttribute const* const PGM_def_sym_output_line_id = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "id"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_energized = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "energized"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_loading = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "loading"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_p_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "p_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_q_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "q_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "i_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_s_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "s_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_p_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "p_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "q_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "i_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "s_to"); // component transformer PGM_MetaComponent const* const PGM_def_sym_output_transformer = PGM_meta_get_component_by_name(nullptr, "sym_output", "transformer"); // attributes of sym_output transformer @@ -566,20 +566,6 @@ PGM_MetaAttribute const* const PGM_def_asym_output_node_u = PGM_meta_get_attribu PGM_MetaAttribute const* const PGM_def_asym_output_node_u_angle = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "node", "u_angle"); PGM_MetaAttribute const* const PGM_def_asym_output_node_p = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "node", "p"); PGM_MetaAttribute const* const PGM_def_asym_output_node_q = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "node", "q"); -// component line -PGM_MetaComponent const* const PGM_def_asym_output_line = PGM_meta_get_component_by_name(nullptr, "asym_output", "line"); -// attributes of asym_output line -PGM_MetaAttribute const* const PGM_def_asym_output_line_id = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "id"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_energized = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "energized"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_loading = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "loading"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_p_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "p_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_q_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "q_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "i_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_s_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "s_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_p_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "p_to"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "q_to"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "i_to"); -PGM_MetaAttribute const* const PGM_def_asym_output_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "s_to"); // component link PGM_MetaComponent const* const PGM_def_asym_output_link = PGM_meta_get_component_by_name(nullptr, "asym_output", "link"); // attributes of asym_output link @@ -594,6 +580,20 @@ PGM_MetaAttribute const* const PGM_def_asym_output_link_p_to = PGM_meta_get_attr PGM_MetaAttribute const* const PGM_def_asym_output_link_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "q_to"); PGM_MetaAttribute const* const PGM_def_asym_output_link_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "i_to"); PGM_MetaAttribute const* const PGM_def_asym_output_link_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "s_to"); +// component line +PGM_MetaComponent const* const PGM_def_asym_output_line = PGM_meta_get_component_by_name(nullptr, "asym_output", "line"); +// attributes of asym_output line +PGM_MetaAttribute const* const PGM_def_asym_output_line_id = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "id"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_energized = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "energized"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_loading = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "loading"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_p_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "p_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_q_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "q_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_i_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "i_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_s_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "s_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_p_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "p_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "q_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "i_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "s_to"); // component transformer PGM_MetaComponent const* const PGM_def_asym_output_transformer = PGM_meta_get_component_by_name(nullptr, "asym_output", "transformer"); // attributes of asym_output transformer diff --git a/tests/cpp_unit_tests/component/test_asym_line.cpp b/tests/cpp_unit_tests/component/test_asym_line.cpp index aaf983020f..9cd0a63a7c 100644 --- a/tests/cpp_unit_tests/component/test_asym_line.cpp +++ b/tests/cpp_unit_tests/component/test_asym_line.cpp @@ -68,13 +68,12 @@ void execute_subcases(const AsymLineInput& input, const ComplexTensor(); diff --git a/tests/cpp_unit_tests/component/test_link.cpp b/tests/cpp_unit_tests/component/test_link.cpp index ff353bc2e8..b25bb65e45 100644 --- a/tests/cpp_unit_tests/component/test_link.cpp +++ b/tests/cpp_unit_tests/component/test_link.cpp @@ -25,7 +25,7 @@ using namespace std::complex_literals; TEST_CASE("Test link") { LinkInput input{.id = 1, .from_node = 2, .to_node = 3, .from_status = 1, .to_status = 1}; Link link{input, 10e3, 50e3}; - Branch& branch = link; + Edge& branch = link; double const base_i_from = base_power_1p / (10.0e3 / sqrt3); double const base_i_to = base_power_1p / (50.0e3 / sqrt3); ComplexValue const uaf{1.0}; @@ -37,14 +37,13 @@ TEST_CASE("Test link") { ComplexValue const if_sc_asym{1.0 + 1.0i}; ComplexValue const it_sc_asym{2.0 + (2.0i * sqrt3)}; - CHECK(link.math_model_type() == ComponentType::branch); + CHECK(link.math_model_type() == ComponentType::link); SUBCASE("General") { 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_from)); CHECK(branch.base_i_to() == doctest::Approx(base_i_to)); - CHECK(!branch.is_param_mutable()); CHECK(branch.phase_shift() == 0.0); } diff --git a/tests/cpp_unit_tests/component/test_transformer.cpp b/tests/cpp_unit_tests/component/test_transformer.cpp index 1139bda8cb..f97ffcb95a 100644 --- a/tests/cpp_unit_tests/component/test_transformer.cpp +++ b/tests/cpp_unit_tests/component/test_transformer.cpp @@ -406,8 +406,6 @@ TEST_CASE("Test Transfomer - Test 0 YNyn12") { CHECK((cabs(param.value[2] - y_tf) < numerical_tolerance).all()); CHECK((cabs(param.value[3] - y_tt) < numerical_tolerance).all()); - SUBCASE("Test transformer is_param_mutable") { CHECK(YNyn12.is_param_mutable() == true); } - SUBCASE("Test transformer phase shift") { CHECK(YNyn12.phase_shift() == doctest::Approx(0.0)); } SUBCASE("Test transformer loading") { CHECK(YNyn12.loading(60.0e6, 0.0) == doctest::Approx(2.0)); } From 0afae726add8256f7b0574a6f4025eb4aaad8bc9 Mon Sep 17 00:00:00 2001 From: Jerry Jinfeng Guo Date: Fri, 21 Aug 2026 20:38:23 +0200 Subject: [PATCH 02/15] updated places Branch was used to initialize container, adding component and output etc Signed-off-by: Jerry Jinfeng Guo --- .../power_grid_model/component/edge.hpp | 1 + .../main_core/container_queries.hpp | 4 ++-- .../power_grid_model/main_core/input.hpp | 4 ++++ .../power_grid_model/main_core/topology.hpp | 22 +++++++++---------- .../power_grid_model/main_core/y_bus.hpp | 10 ++++----- .../optimizer/test_optimizer.hpp | 4 ++-- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp index 16d55c74ee..94da1e90ef 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp @@ -34,6 +34,7 @@ class Edge : public Base { using SideType = BranchSide; static constexpr char const* name = "edge"; + // ComponentType math_model_type() const { return ComponentType::edge; } explicit Edge(BranchInput const& edge_input) : Base{edge_input}, diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/container_queries.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/container_queries.hpp index 1a9b51ae1c..188b0af82b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/container_queries.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/container_queries.hpp @@ -100,8 +100,8 @@ constexpr auto get_component_citer(ComponentContainer const& components) { namespace detail { template struct topology_base_type; -template Component> struct topology_base_type { - using type = Branch; +template Component> struct topology_base_type { + using type = Edge; }; template Component> struct topology_base_type { using type = Branch3; 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 d9ec34926b..81352f97fd 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 @@ -75,6 +75,10 @@ inline void add_component(ComponentContainer& components, Inputs component_input } else { emplace_component(components, id, input, u1, u2); } + } else if constexpr (std::derived_from) { + double const u1 = get_component(components, input.from_node).u_rated(); + double const u2 = get_component(components, input.to_node).u_rated(); + emplace_component(components, id, input, u1, u2); } else if constexpr (std::derived_from) { double const u1 = get_component(components, input.node_1).u_rated(); double const u2 = get_component(components, input.node_2).u_rated(); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp index 3759f8142e..a3b5fc2caa 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp @@ -52,13 +52,13 @@ constexpr void register_topology_components(ComponentContainer const& components } template Component, class ComponentContainer> - requires common::component_container_c + requires common::component_container_c constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { - apply_registration(components, comp_topo.branch_node_idx, - [&components](Branch const& edge) { - return BranchIdx{get_component_sequence_idx(components, edge.from_node()), - get_component_sequence_idx(components, edge.to_node())}; - }); + apply_registration(components, comp_topo.branch_node_idx, + [&components](Edge const& edge) { + return BranchIdx{get_component_sequence_idx(components, edge.from_node()), + get_component_sequence_idx(components, edge.to_node())}; + }); } template Component, class ComponentContainer> @@ -212,13 +212,13 @@ constexpr void register_topology_components(ComponentContainer const& components } template Component, class ComponentContainer> - requires common::component_container_c + requires common::component_container_c constexpr void register_connections_components(ComponentContainer const& components, ComponentConnections& comp_conn) { - apply_registration(components, comp_conn.branch_connected, [](Branch const& branch) { - return BranchConnected{status_to_int(branch.from_status()), status_to_int(branch.to_status())}; + apply_registration(components, comp_conn.branch_connected, [](Edge const& edge) { + return BranchConnected{status_to_int(edge.from_status()), status_to_int(edge.to_status())}; }); - apply_registration(components, comp_conn.branch_phase_shift, - [](Branch const& branch) { return branch.phase_shift(); }); + apply_registration(components, comp_conn.branch_phase_shift, + [](Edge const& edge) { return edge.phase_shift(); }); } template Component, class ComponentContainer> diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/y_bus.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/y_bus.hpp index c784fff379..47705b24a4 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/y_bus.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/y_bus.hpp @@ -24,17 +24,17 @@ constexpr Idx isolated_component{-1}; namespace detail { -template ComponentType, math_model_param_c MathModelParamType, typename ComponentContainer> +template ComponentType, math_model_param_c MathModelParamType, typename ComponentContainer> constexpr void add_to_math_model_params(std::vector& math_model_param, MainModelState const& state, Idx const topology_sequence_idx) { - Idx2D const math_idx = get_math_id(state, topology_sequence_idx); + Idx2D const math_idx = get_math_id(state, topology_sequence_idx); if (math_idx.group == isolated_component) { return; } // assign parameters auto& model_params = math_model_param[math_idx.group]; - auto branch_params = state.components.template get_item_by_seq(topology_sequence_idx) + auto branch_params = state.components.template get_item_by_seq(topology_sequence_idx) .template calc_param(); if constexpr (std::derived_from>) { @@ -123,7 +123,7 @@ constexpr void add_to_math_model_params(std::vector const& / } template - requires std::derived_from || std::derived_from || + requires std::derived_from || std::derived_from || std::derived_from || std::derived_from constexpr void add_to_increment(std::vector>& increments, MainModelState const& state, Idx2D const& changed_component_idx) { @@ -193,7 +193,7 @@ inline std::vector> get_math_param(main_model_state_c auto c } // loop all branch for (Idx const i : IdxRange{std::ssize(state.comp_topo->branch_node_idx)}) { - detail::add_to_math_model_params(math_param, state, i); + detail::add_to_math_model_params(math_param, state, i); } // loop all branch3 for (Idx const i : IdxRange{std::ssize(state.comp_topo->branch3_node_idx)}) { diff --git a/tests/cpp_unit_tests/optimizer/test_optimizer.hpp b/tests/cpp_unit_tests/optimizer/test_optimizer.hpp index e7f410be98..8ede89e0b9 100644 --- a/tests/cpp_unit_tests/optimizer/test_optimizer.hpp +++ b/tests/cpp_unit_tests/optimizer/test_optimizer.hpp @@ -84,8 +84,8 @@ inline auto u_pu(State const& /* state */, std::vector const& // using StubComponentContainer = Container, StubComponent, StubTransformerA, // TransformerTapRegulator, StubTransformerB>; using StubComponentContainer = - Container, Line, Link, Node, Transformer, - ThreeWindingTransformer, TransformerTapRegulator, Source>; + Container, Line, Link, Node, + Transformer, ThreeWindingTransformer, TransformerTapRegulator, Source>; using StubState = main_core::MainModelState; static_assert(main_core::main_model_state_c); From a6a63551da1da5e1e415cd0482b6e9787c2df0f1 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 12:01:47 +0200 Subject: [PATCH 03/15] Unit test for Edge with TestEdge Signed-off-by: Jerry Guo --- .../power_grid_model/component/branch.hpp | 2 +- .../power_grid_model/component/edge.hpp | 3 +- .../power_grid_model/main_core/topology.hpp | 14 +- .../power_grid_model/main_model_impl.hpp | 4 +- tests/cpp_unit_tests/component/CMakeLists.txt | 1 + tests/cpp_unit_tests/component/test_edge.cpp | 261 ++++++++++++++++++ 6 files changed, 273 insertions(+), 12 deletions(-) create mode 100644 tests/cpp_unit_tests/component/test_edge.cpp diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp index a3b8438174..e71db01000 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp @@ -35,7 +35,7 @@ class Branch : public Edge { static constexpr char const* name = "branch"; ComponentType math_model_type() const final { return ComponentType::branch; } - explicit Branch(BranchInput const& branch_input): Edge{branch_input} {} + explicit Branch(BranchInput const& branch_input) : Edge{branch_input} {} }; } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp index 94da1e90ef..4a497858d6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp @@ -90,8 +90,7 @@ class Edge : public Base { virtual double loading(double max_s, double max_i) const = 0; virtual double phase_shift() const = 0; // shift theta_from - theta_to - template - BranchOutput get_output(BranchSolverOutput const& edge_solver_output) const { + template BranchOutput get_output(BranchSolverOutput const& edge_solver_output) const { // result object BranchOutput output{}; static_cast(output) = base_output(true); diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp index a3b5fc2caa..d6a0121d28 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp @@ -54,11 +54,10 @@ constexpr void register_topology_components(ComponentContainer const& components template Component, class ComponentContainer> requires common::component_container_c constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { - apply_registration(components, comp_topo.branch_node_idx, - [&components](Edge const& edge) { - return BranchIdx{get_component_sequence_idx(components, edge.from_node()), - get_component_sequence_idx(components, edge.to_node())}; - }); + apply_registration(components, comp_topo.branch_node_idx, [&components](Edge const& edge) { + return BranchIdx{get_component_sequence_idx(components, edge.from_node()), + get_component_sequence_idx(components, edge.to_node())}; + }); } template Component, class ComponentContainer> @@ -249,8 +248,9 @@ constexpr void register_connections_components(ComponentContainer const& compone } // namespace detail template - requires common::component_container_c + requires common::component_container_c ComponentTopology construct_topology(typename ModelType::ComponentContainer const& components) { ComponentTopology comp_topo; using TopologyTypesTuple = ModelType::TopologyTypesTuple; diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp index fb92d89585..22f1f6ef1c 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_model_impl.hpp @@ -424,7 +424,8 @@ class MainModelImpl { } void check_no_future_deprecations(Options const& /*options*/, ConstDataset const* /*batch_dataset*/) const { - // TODO(mgovers): cleanup v2: remove this function, as power sensor creation itself should always throw after node injection sensors removal + // TODO(mgovers): cleanup v2: remove this function, as power sensor creation itself should always throw after + // node injection sensors removal ModelType::run_functor_with_all_component_types_return_void([this]() { // only flow sensors have get_terminal_type() so we can filter on it if constexpr (requires(CT c) { @@ -440,7 +441,6 @@ class MainModelImpl { } private: - template void output_result(MathOutput> math_output, MutableDataset const& result_data, Logger& logger) const { diff --git a/tests/cpp_unit_tests/component/CMakeLists.txt b/tests/cpp_unit_tests/component/CMakeLists.txt index 649ce60f2e..56723f3702 100644 --- a/tests/cpp_unit_tests/component/CMakeLists.txt +++ b/tests/cpp_unit_tests/component/CMakeLists.txt @@ -7,6 +7,7 @@ add_executable( "../test_entry_point.cpp" "test_all_components.cpp" "test_node.cpp" + "test_edge.cpp" "test_asym_line.cpp" "test_line.cpp" "test_generic_branch.cpp" diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp new file mode 100644 index 0000000000..cd6f052492 --- /dev/null +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -0,0 +1,261 @@ +// SPDX-FileCopyrightText: Contributors to the Power Grid Model project +// +// SPDX-License-Identifier: MPL-2.0 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace power_grid_model { + +using namespace std::complex_literals; + +namespace { +// Concrete test implementation of Edge for testing purposes +class TestEdge : public Edge { + public: + explicit TestEdge(BranchInput const& edge_input, double u_rated, DoubleComplex const& y_series, + DoubleComplex const& y_shunt, DoubleComplex const& tap_ratio = 1.0, + DoubleComplex const& y0_series = 0.0, DoubleComplex const& y0_shunt = 0.0) + : Edge{edge_input}, + base_i_{base_power_3p / u_rated / sqrt3}, + y_series_{y_series}, + y_shunt_{y_shunt}, + tap_ratio_{tap_ratio}, + y0_series_{y0_series}, + y0_shunt_{y0_shunt} {} + + ComponentType math_model_type() const override { return ComponentType::branch; } + + 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_s / base_power_3p; } + double phase_shift() const override { return arg(tap_ratio_); } + + private: + double base_i_; + DoubleComplex y_series_; + DoubleComplex y_shunt_; + DoubleComplex tap_ratio_; + DoubleComplex y0_series_; + DoubleComplex y0_shunt_; + + BranchCalcParam sym_calc_param() const override { + return calc_param_y_sym(y_series_, y_shunt_, tap_ratio_); + } + + BranchCalcParam asym_calc_param() const override { + return calc_param_y_asym(y_series_, y_shunt_, y0_series_, y0_shunt_, tap_ratio_); + } +}; +} // namespace + +TEST_CASE("Test Edge") { + BranchInput const input{.id = 1, .from_node = 2, .to_node = 3, .from_status = 1, .to_status = 1}; + + double const u_rated = 10.0e3; + double const base_i = base_power_3p / u_rated / sqrt3; + double const base_y = base_i * base_i / base_power_1p; + + DoubleComplex const y_series = (1.0 / (0.3 + 0.4i)) / base_y; + DoubleComplex const y_shunt = (50.0 * 2 * pi * 2e-4) * (0.1 + 1.0i) / base_y; + DoubleComplex const tap_ratio = 1.0 + 0.0i; + + // For asymmetric + DoubleComplex const y0_series = (1.0 / (0.1 + 0.2i)) / base_y; + DoubleComplex const y0_shunt = (50.0 * 2 * pi * 1e-4) * (0.2 + 1.0i) / base_y; + + TestEdge edge{input, u_rated, y_series, y_shunt, tap_ratio, y0_series, y0_shunt}; + Edge& edge_ref = edge; + + // Expected symmetric values + DoubleComplex const yff1 = y_series + 0.5 * y_shunt; + DoubleComplex const yft1 = -y_series; + DoubleComplex const ys1 = 0.5 * y_shunt + 1.0 / (1.0 / y_series + 2.0 / y_shunt); + + // Expected asymmetric values + DoubleComplex const yff0 = y0_series + 0.5 * y0_shunt; + DoubleComplex const yft0 = -y0_series; + DoubleComplex const ys0 = 0.5 * y0_shunt + 1.0 / (1.0 / y0_series + 2.0 / y0_shunt); + 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}; + + SUBCASE("Property Mapping") { + CHECK(edge_ref.id() == 1); + CHECK(edge_ref.from_node() == 2); + CHECK(edge_ref.to_node() == 3); + CHECK(edge_ref.from_status() == true); + CHECK(edge_ref.to_status() == true); + CHECK(Edge::name == std::string{"edge"}); + } + + SUBCASE("Status Flags") { + CHECK(edge_ref.from_status() == true); + CHECK(edge_ref.to_status() == true); + CHECK(edge_ref.edge_status() == true); + + edge_ref.set_status(true, false); + CHECK(edge_ref.edge_status() == false); + + edge_ref.set_status(false, true); + CHECK(edge_ref.edge_status() == false); + + edge_ref.set_status(false, false); + CHECK(edge_ref.edge_status() == false); + + edge_ref.set_status(true, true); + } + + SUBCASE("Status Updates") { + // Reset to known state + edge_ref.set_status(true, true); + + CHECK(!edge_ref.set_status(na_IntS, na_IntS)); + CHECK(edge_ref.from_status() == true); + CHECK(edge_ref.to_status() == true); + + CHECK(edge_ref.set_status(false, na_IntS)); + CHECK(edge_ref.from_status() == false); + + CHECK(!edge_ref.set_status(false, na_IntS)); + + BranchUpdate update{.id = 1, .from_status = 1, .to_status = na_IntS}; + UpdateChange change = edge_ref.update(update); + CHECK(change.topo == true); + CHECK(change.param == true); + } + + SUBCASE("Inverse State") { + // Reset to known state + edge_ref.set_status(true, true); + + BranchUpdate update{.id = 1, .from_status = 0, .to_status = 0}; + auto const inv = edge_ref.inverse(update); + CHECK(inv.from_status == status_to_int(true)); + CHECK(inv.to_status == status_to_int(true)); + } + + SUBCASE("Energization") { + edge_ref.set_status(true, true); + CHECK(edge_ref.energized(false) == false); + CHECK(edge_ref.energized(true) == true); + + edge_ref.set_status(false, true); + CHECK(edge_ref.energized(true) == true); + + edge_ref.set_status(false, false); + CHECK(edge_ref.energized(true) == false); + + edge_ref.set_status(true, true); + } + + SUBCASE("Symmetric Parameters") { + edge_ref.set_status(true, true); + + // Not energized + BranchCalcParam param = edge_ref.calc_param(false); + CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); + + // Both disconnected + edge_ref.set_status(false, false); + param = edge_ref.calc_param(true); + CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); + CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); + + // From connected only + edge_ref.set_status(true, false); + param = edge_ref.calc_param(true); + CHECK(cabs(param.yff() - ys1) < numerical_tolerance); + CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); + + // To connected only + edge_ref.set_status(false, true); + param = edge_ref.calc_param(true); + CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); + CHECK(cabs(param.ytt() - ys1) < numerical_tolerance); + + // Both connected + edge_ref.set_status(true, true); + param = edge_ref.calc_param(true); + 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); + } + + SUBCASE("Asymmetric Parameters") { + edge_ref.set_status(true, true); + BranchCalcParam param = edge_ref.calc_param(true); + + 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()); + + edge_ref.set_status(true, false); + param = edge_ref.calc_param(true); + CHECK((cabs(param.yff() - ysa) < numerical_tolerance).all()); + CHECK((cabs(param.ytt() - 0.0) < numerical_tolerance).all()); + } + + SUBCASE("Output Generation") { + edge_ref.set_status(true, true); + BranchSolverOutput const solver_output{ + .s_f = 1.0 - 1.5i, .s_t = 1.5 - 1.5i, .i_f = 1.0 - 2.0i, .i_t = 2.0 - 1.0i}; + + BranchOutput output = edge_ref.get_output(solver_output); + + CHECK(output.id == 1); + CHECK(output.energized == 1); + CHECK(output.p_from == doctest::Approx(1.0 * base_power)); + CHECK(output.q_from == doctest::Approx(-1.5 * base_power)); + 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)); + } + + SUBCASE("Short Circuit Output") { + edge_ref.set_status(true, true); + DoubleComplex const if_sc{1.0, 1.0}; + DoubleComplex const it_sc{2.0, 2.0 * sqrt3}; + + BranchShortCircuitOutput sc_output = edge_ref.get_sc_output(if_sc, it_sc); + CHECK(sc_output.id == 1); + CHECK(sc_output.energized == 1); + CHECK(sc_output.i_from(0) == doctest::Approx(cabs(if_sc) * base_i)); + CHECK(sc_output.i_to(0) == doctest::Approx(cabs(it_sc) * base_i)); + CHECK(sc_output.i_from_angle(0) == doctest::Approx(pi / 4)); + CHECK(sc_output.i_to_angle(0) == doctest::Approx(pi / 3)); + } + + SUBCASE("Null Outputs") { + BranchOutput null_output = edge_ref.get_null_output(); + CHECK(null_output.id == 1); + CHECK(null_output.energized == 0); + CHECK(null_output.loading == 0.0); + CHECK(null_output.i_from == 0.0); + + BranchShortCircuitOutput null_sc_output = edge_ref.get_null_sc_output(); + CHECK(null_sc_output.energized == 0); + CHECK(null_sc_output.i_from(0) == 0.0); + } + + SUBCASE("Enum Violations") { + CHECK_THROWS_AS(edge_ref.node(static_cast(99)), MissingCaseForEnumError); + CHECK_THROWS_AS(edge_ref.status(static_cast(99)), MissingCaseForEnumError); + } +} + +} // namespace power_grid_model From 3a6056b2f491b42088c3b4f6d162dfc68676bc93 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 12:07:15 +0200 Subject: [PATCH 04/15] DCO Remediation Commit for Jerry Guo I, Jerry Guo , hereby add my Signed-off-by to this commit: a6a63551da1da5e1e415cd0482b6e9787c2df0f1 Signed-off-by: Jerry Guo --- .../include/power_grid_model/component/branch.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp index e71db01000..52f4c7a08b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp @@ -26,7 +26,7 @@ namespace power_grid_model { -class Branch : public Edge { +class Branch : public Edge { // TODO: not yet unit tested public: using InputType = BranchInput; using UpdateType = BranchUpdate; From 9d5604d2af3c05749dfe8bdcb305624eadba6b61 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 13:36:01 +0200 Subject: [PATCH 05/15] Sonar cloud and code quality Signed-off-by: Jerry Guo --- .../power_grid_model/component/branch.hpp | 2 +- .../power_grid_model/component/edge.hpp | 3 +- .../power_grid_model/component/link.hpp | 2 +- .../power_grid_model_c/dataset_definitions.h | 56 +++++++++---------- .../src/dataset_definitions.cpp | 56 +++++++++---------- 5 files changed, 59 insertions(+), 60 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp index 52f4c7a08b..77377625bd 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/branch.hpp @@ -35,7 +35,7 @@ class Branch : public Edge { // TODO: not yet unit tested static constexpr char const* name = "branch"; ComponentType math_model_type() const final { return ComponentType::branch; } - explicit Branch(BranchInput const& branch_input) : Edge{branch_input} {} + using Edge::Edge; // inherit constructor }; } // namespace power_grid_model diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp index 4a497858d6..2d514f11c2 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/edge.hpp @@ -33,8 +33,7 @@ class Edge : public Base { using ShortCircuitOutputType = BranchShortCircuitOutput; using SideType = BranchSide; - static constexpr char const* name = "edge"; - // ComponentType math_model_type() const { return ComponentType::edge; } + static constexpr char const* name = "edge"; // possibly redundant explicit Edge(BranchInput const& edge_input) : Base{edge_input}, diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp index b5bf0b840d..7cdbfc4900 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/component/link.hpp @@ -19,7 +19,7 @@ class Link final : public Edge { using UpdateType = BranchUpdate; static constexpr char const* name = "link"; - ComponentType math_model_type() const final { return ComponentType::link; } + ComponentType math_model_type() const override { return ComponentType::link; } explicit Link(LinkInput const& link_input, double u1, double u2) : Edge{link_input}, base_i_from_{base_power_3p / u1 / sqrt3}, base_i_to_{base_power_3p / u2 / sqrt3} {} 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 8da75c3881..4cc1c90263 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 @@ -354,20 +354,6 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_u; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_u_angle; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_p; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_node_q; -// component link -PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_link; -// attributes of sym_output link -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_id; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_energized; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_loading; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_p_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_q_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_i_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_s_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_p_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_q_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_i_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_s_to; // component line PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_line; // attributes of sym_output line @@ -382,6 +368,20 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_p_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_q_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_line_s_to; +// component link +PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_link; +// attributes of sym_output link +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_loading; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_p_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_q_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_s_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_p_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_q_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_sym_output_link_s_to; // component transformer PGM_API extern PGM_MetaComponent const* const PGM_def_sym_output_transformer; // attributes of sym_output transformer @@ -577,20 +577,6 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_u; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_u_angle; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_p; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_node_q; -// component link -PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_link; -// attributes of asym_output link -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_id; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_energized; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_loading; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_p_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_q_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_i_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_s_from; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_p_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_q_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_i_to; -PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_s_to; // component line PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_line; // attributes of asym_output line @@ -605,6 +591,20 @@ PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_p_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_q_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_i_to; PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_line_s_to; +// component link +PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_link; +// attributes of asym_output link +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_id; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_energized; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_loading; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_p_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_q_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_i_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_s_from; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_p_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_q_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_i_to; +PGM_API extern PGM_MetaAttribute const* const PGM_def_asym_output_link_s_to; // component transformer PGM_API extern PGM_MetaComponent const* const PGM_def_asym_output_transformer; // attributes of asym_output 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 deb18ce6cc..e53239de05 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 @@ -343,20 +343,6 @@ PGM_MetaAttribute const* const PGM_def_sym_output_node_u = PGM_meta_get_attribut PGM_MetaAttribute const* const PGM_def_sym_output_node_u_angle = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "node", "u_angle"); PGM_MetaAttribute const* const PGM_def_sym_output_node_p = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "node", "p"); PGM_MetaAttribute const* const PGM_def_sym_output_node_q = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "node", "q"); -// component link -PGM_MetaComponent const* const PGM_def_sym_output_link = PGM_meta_get_component_by_name(nullptr, "sym_output", "link"); -// attributes of sym_output link -PGM_MetaAttribute const* const PGM_def_sym_output_link_id = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "id"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_energized = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "energized"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_loading = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "loading"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_p_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "p_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_q_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "q_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_i_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "i_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_s_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "s_from"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_p_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "p_to"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "q_to"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "i_to"); -PGM_MetaAttribute const* const PGM_def_sym_output_link_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "s_to"); // component line PGM_MetaComponent const* const PGM_def_sym_output_line = PGM_meta_get_component_by_name(nullptr, "sym_output", "line"); // attributes of sym_output line @@ -371,6 +357,20 @@ PGM_MetaAttribute const* const PGM_def_sym_output_line_p_to = PGM_meta_get_attri PGM_MetaAttribute const* const PGM_def_sym_output_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "q_to"); PGM_MetaAttribute const* const PGM_def_sym_output_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "i_to"); PGM_MetaAttribute const* const PGM_def_sym_output_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "line", "s_to"); +// component link +PGM_MetaComponent const* const PGM_def_sym_output_link = PGM_meta_get_component_by_name(nullptr, "sym_output", "link"); +// attributes of sym_output link +PGM_MetaAttribute const* const PGM_def_sym_output_link_id = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "id"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_energized = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "energized"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_loading = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "loading"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_p_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "p_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_q_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "q_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_i_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "i_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_s_from = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "s_from"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_p_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "p_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_q_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "q_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_i_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "i_to"); +PGM_MetaAttribute const* const PGM_def_sym_output_link_s_to = PGM_meta_get_attribute_by_name(nullptr, "sym_output", "link", "s_to"); // component transformer PGM_MetaComponent const* const PGM_def_sym_output_transformer = PGM_meta_get_component_by_name(nullptr, "sym_output", "transformer"); // attributes of sym_output transformer @@ -566,20 +566,6 @@ PGM_MetaAttribute const* const PGM_def_asym_output_node_u = PGM_meta_get_attribu PGM_MetaAttribute const* const PGM_def_asym_output_node_u_angle = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "node", "u_angle"); PGM_MetaAttribute const* const PGM_def_asym_output_node_p = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "node", "p"); PGM_MetaAttribute const* const PGM_def_asym_output_node_q = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "node", "q"); -// component link -PGM_MetaComponent const* const PGM_def_asym_output_link = PGM_meta_get_component_by_name(nullptr, "asym_output", "link"); -// attributes of asym_output link -PGM_MetaAttribute const* const PGM_def_asym_output_link_id = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "id"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_energized = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "energized"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_loading = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "loading"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_p_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "p_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_q_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "q_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_i_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "i_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_s_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "s_from"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_p_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "p_to"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "q_to"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "i_to"); -PGM_MetaAttribute const* const PGM_def_asym_output_link_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "s_to"); // component line PGM_MetaComponent const* const PGM_def_asym_output_line = PGM_meta_get_component_by_name(nullptr, "asym_output", "line"); // attributes of asym_output line @@ -594,6 +580,20 @@ PGM_MetaAttribute const* const PGM_def_asym_output_line_p_to = PGM_meta_get_attr PGM_MetaAttribute const* const PGM_def_asym_output_line_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "q_to"); PGM_MetaAttribute const* const PGM_def_asym_output_line_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "i_to"); PGM_MetaAttribute const* const PGM_def_asym_output_line_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "line", "s_to"); +// component link +PGM_MetaComponent const* const PGM_def_asym_output_link = PGM_meta_get_component_by_name(nullptr, "asym_output", "link"); +// attributes of asym_output link +PGM_MetaAttribute const* const PGM_def_asym_output_link_id = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "id"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_energized = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "energized"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_loading = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "loading"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_p_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "p_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_q_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "q_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_i_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "i_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_s_from = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "s_from"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_p_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "p_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_q_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "q_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_i_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "i_to"); +PGM_MetaAttribute const* const PGM_def_asym_output_link_s_to = PGM_meta_get_attribute_by_name(nullptr, "asym_output", "link", "s_to"); // component transformer PGM_MetaComponent const* const PGM_def_asym_output_transformer = PGM_meta_get_component_by_name(nullptr, "asym_output", "transformer"); // attributes of asym_output transformer From f15aa1a4da4ea4c71a4dd8363e54290f1d298b8d Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 16:23:38 +0200 Subject: [PATCH 06/15] clang-tidy Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 94 ++++++++++---------- tests/cpp_unit_tests/component/test_link.cpp | 1 - 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index cd6f052492..2325c45fa4 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -97,99 +97,99 @@ TEST_CASE("Test Edge") { CHECK(edge_ref.id() == 1); CHECK(edge_ref.from_node() == 2); CHECK(edge_ref.to_node() == 3); - CHECK(edge_ref.from_status() == true); - CHECK(edge_ref.to_status() == true); + CHECK(edge_ref.from_status() == 1); + CHECK(edge_ref.to_status() == 1); CHECK(Edge::name == std::string{"edge"}); } SUBCASE("Status Flags") { - CHECK(edge_ref.from_status() == true); - CHECK(edge_ref.to_status() == true); - CHECK(edge_ref.edge_status() == true); + CHECK(edge_ref.from_status() == 1); + CHECK(edge_ref.to_status() == 1); + CHECK(edge_ref.edge_status() == 1); - edge_ref.set_status(true, false); - CHECK(edge_ref.edge_status() == false); + edge_ref.set_status(1, 0); + CHECK(edge_ref.edge_status() == 0); - edge_ref.set_status(false, true); - CHECK(edge_ref.edge_status() == false); + edge_ref.set_status(0, 1); + CHECK(edge_ref.edge_status() == 0); - edge_ref.set_status(false, false); - CHECK(edge_ref.edge_status() == false); + edge_ref.set_status(0, 0); + CHECK(edge_ref.edge_status() == 0); - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); } SUBCASE("Status Updates") { // Reset to known state - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); CHECK(!edge_ref.set_status(na_IntS, na_IntS)); - CHECK(edge_ref.from_status() == true); - CHECK(edge_ref.to_status() == true); + CHECK(edge_ref.from_status() == 1); + CHECK(edge_ref.to_status() == 1); - CHECK(edge_ref.set_status(false, na_IntS)); - CHECK(edge_ref.from_status() == false); + CHECK(edge_ref.set_status(0, na_IntS)); + CHECK(edge_ref.from_status() == 0); - CHECK(!edge_ref.set_status(false, na_IntS)); + CHECK(!edge_ref.set_status(0, na_IntS)); BranchUpdate update{.id = 1, .from_status = 1, .to_status = na_IntS}; UpdateChange change = edge_ref.update(update); - CHECK(change.topo == true); - CHECK(change.param == true); + CHECK(change.topo == 1); + CHECK(change.param == 1); } SUBCASE("Inverse State") { // Reset to known state - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); BranchUpdate update{.id = 1, .from_status = 0, .to_status = 0}; auto const inv = edge_ref.inverse(update); - CHECK(inv.from_status == status_to_int(true)); - CHECK(inv.to_status == status_to_int(true)); + CHECK(inv.from_status == status_to_int(1)); + CHECK(inv.to_status == status_to_int(1)); } SUBCASE("Energization") { - edge_ref.set_status(true, true); - CHECK(edge_ref.energized(false) == false); - CHECK(edge_ref.energized(true) == true); + edge_ref.set_status(1, 1); + CHECK(edge_ref.energized(0) == 0); + CHECK(edge_ref.energized(1) == 1); - edge_ref.set_status(false, true); - CHECK(edge_ref.energized(true) == true); + edge_ref.set_status(0, 1); + CHECK(edge_ref.energized(1) == 1); - edge_ref.set_status(false, false); - CHECK(edge_ref.energized(true) == false); + edge_ref.set_status(0, 0); + CHECK(edge_ref.energized(1) == 0); - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); } SUBCASE("Symmetric Parameters") { - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); // Not energized - BranchCalcParam param = edge_ref.calc_param(false); + BranchCalcParam param = edge_ref.calc_param(0); CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); // Both disconnected - edge_ref.set_status(false, false); - param = edge_ref.calc_param(true); + edge_ref.set_status(0, 0); + param = edge_ref.calc_param(1); CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); // From connected only - edge_ref.set_status(true, false); - param = edge_ref.calc_param(true); + edge_ref.set_status(1, 0); + param = edge_ref.calc_param(1); CHECK(cabs(param.yff() - ys1) < numerical_tolerance); CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); // To connected only - edge_ref.set_status(false, true); - param = edge_ref.calc_param(true); + edge_ref.set_status(0, 1); + param = edge_ref.calc_param(1); CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); CHECK(cabs(param.ytt() - ys1) < numerical_tolerance); // Both connected - edge_ref.set_status(true, true); - param = edge_ref.calc_param(true); + edge_ref.set_status(1, 1); + param = edge_ref.calc_param(1); CHECK(cabs(param.yff() - yff1) < numerical_tolerance); CHECK(cabs(param.ytt() - yff1) < numerical_tolerance); CHECK(cabs(param.ytf() - yft1) < numerical_tolerance); @@ -197,22 +197,22 @@ TEST_CASE("Test Edge") { } SUBCASE("Asymmetric Parameters") { - edge_ref.set_status(true, true); - BranchCalcParam param = edge_ref.calc_param(true); + edge_ref.set_status(1, 1); + BranchCalcParam param = edge_ref.calc_param(1); 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()); - edge_ref.set_status(true, false); - param = edge_ref.calc_param(true); + edge_ref.set_status(1, 0); + param = edge_ref.calc_param(1); CHECK((cabs(param.yff() - ysa) < numerical_tolerance).all()); CHECK((cabs(param.ytt() - 0.0) < numerical_tolerance).all()); } SUBCASE("Output Generation") { - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); BranchSolverOutput const solver_output{ .s_f = 1.0 - 1.5i, .s_t = 1.5 - 1.5i, .i_f = 1.0 - 2.0i, .i_t = 2.0 - 1.0i}; @@ -227,7 +227,7 @@ TEST_CASE("Test Edge") { } SUBCASE("Short Circuit Output") { - edge_ref.set_status(true, true); + edge_ref.set_status(1, 1); DoubleComplex const if_sc{1.0, 1.0}; DoubleComplex const it_sc{2.0, 2.0 * sqrt3}; diff --git a/tests/cpp_unit_tests/component/test_link.cpp b/tests/cpp_unit_tests/component/test_link.cpp index b25bb65e45..6421fead5f 100644 --- a/tests/cpp_unit_tests/component/test_link.cpp +++ b/tests/cpp_unit_tests/component/test_link.cpp @@ -2,7 +2,6 @@ // // SPDX-License-Identifier: MPL-2.0 -#include #include #include From 527d61fee3c9303e739f6da734066fe7173c95cf Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 20:26:46 +0200 Subject: [PATCH 07/15] clang-tidy 2.0 Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 23 ++++++++++---------- tests/cpp_unit_tests/component/test_link.cpp | 1 + 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index 2325c45fa4..f43f8c4f1d 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -62,7 +63,7 @@ class TestEdge : public Edge { }; } // namespace -TEST_CASE("Test Edge") { +TEST_CASE("Test edge") { BranchInput const input{.id = 1, .from_node = 2, .to_node = 3, .from_status = 1, .to_status = 1}; double const u_rated = 10.0e3; @@ -132,8 +133,8 @@ TEST_CASE("Test Edge") { CHECK(!edge_ref.set_status(0, na_IntS)); - BranchUpdate update{.id = 1, .from_status = 1, .to_status = na_IntS}; - UpdateChange change = edge_ref.update(update); + BranchUpdate const update{.id = 1, .from_status = 1, .to_status = na_IntS}; + UpdateChange const change = edge_ref.update(update); CHECK(change.topo == 1); CHECK(change.param == 1); } @@ -142,7 +143,7 @@ TEST_CASE("Test Edge") { // Reset to known state edge_ref.set_status(1, 1); - BranchUpdate update{.id = 1, .from_status = 0, .to_status = 0}; + BranchUpdate const update{.id = 1, .from_status = 0, .to_status = 0}; auto const inv = edge_ref.inverse(update); CHECK(inv.from_status == status_to_int(1)); CHECK(inv.to_status == status_to_int(1)); @@ -166,30 +167,30 @@ TEST_CASE("Test Edge") { edge_ref.set_status(1, 1); // Not energized - BranchCalcParam param = edge_ref.calc_param(0); + BranchCalcParam param = edge_ref.calc_param(false); CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); // Both disconnected edge_ref.set_status(0, 0); - param = edge_ref.calc_param(1); + param = edge_ref.calc_param(true); CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); // From connected only edge_ref.set_status(1, 0); - param = edge_ref.calc_param(1); + param = edge_ref.calc_param(true); CHECK(cabs(param.yff() - ys1) < numerical_tolerance); CHECK(cabs(param.ytt() - 0.0) < numerical_tolerance); // To connected only edge_ref.set_status(0, 1); - param = edge_ref.calc_param(1); + param = edge_ref.calc_param(true); CHECK(cabs(param.yff() - 0.0) < numerical_tolerance); CHECK(cabs(param.ytt() - ys1) < numerical_tolerance); // Both connected edge_ref.set_status(1, 1); - param = edge_ref.calc_param(1); + param = edge_ref.calc_param(true); CHECK(cabs(param.yff() - yff1) < numerical_tolerance); CHECK(cabs(param.ytt() - yff1) < numerical_tolerance); CHECK(cabs(param.ytf() - yft1) < numerical_tolerance); @@ -198,7 +199,7 @@ TEST_CASE("Test Edge") { SUBCASE("Asymmetric Parameters") { edge_ref.set_status(1, 1); - BranchCalcParam param = edge_ref.calc_param(1); + BranchCalcParam param = edge_ref.calc_param(true); CHECK((cabs(param.yff() - yffa) < numerical_tolerance).all()); CHECK((cabs(param.ytt() - yffa) < numerical_tolerance).all()); @@ -206,7 +207,7 @@ TEST_CASE("Test Edge") { CHECK((cabs(param.yft() - yfta) < numerical_tolerance).all()); edge_ref.set_status(1, 0); - param = edge_ref.calc_param(1); + param = edge_ref.calc_param(true); CHECK((cabs(param.yff() - ysa) < numerical_tolerance).all()); CHECK((cabs(param.ytt() - 0.0) < numerical_tolerance).all()); } diff --git a/tests/cpp_unit_tests/component/test_link.cpp b/tests/cpp_unit_tests/component/test_link.cpp index 6421fead5f..5afabe08ad 100644 --- a/tests/cpp_unit_tests/component/test_link.cpp +++ b/tests/cpp_unit_tests/component/test_link.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include From 3224e473c3fddc2909dfcf7280fe62e43c8e8c30 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 21:16:46 +0200 Subject: [PATCH 08/15] clang-tidy 3.0 Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index f43f8c4f1d..5c6c95715f 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -217,7 +217,7 @@ TEST_CASE("Test edge") { BranchSolverOutput const solver_output{ .s_f = 1.0 - 1.5i, .s_t = 1.5 - 1.5i, .i_f = 1.0 - 2.0i, .i_t = 2.0 - 1.0i}; - BranchOutput output = edge_ref.get_output(solver_output); + BranchOutput const output = edge_ref.get_output(solver_output); CHECK(output.id == 1); CHECK(output.energized == 1); @@ -232,7 +232,7 @@ TEST_CASE("Test edge") { DoubleComplex const if_sc{1.0, 1.0}; DoubleComplex const it_sc{2.0, 2.0 * sqrt3}; - BranchShortCircuitOutput sc_output = edge_ref.get_sc_output(if_sc, it_sc); + BranchShortCircuitOutput const sc_output = edge_ref.get_sc_output(if_sc, it_sc); CHECK(sc_output.id == 1); CHECK(sc_output.energized == 1); CHECK(sc_output.i_from(0) == doctest::Approx(cabs(if_sc) * base_i)); @@ -242,20 +242,20 @@ TEST_CASE("Test edge") { } SUBCASE("Null Outputs") { - BranchOutput null_output = edge_ref.get_null_output(); + BranchOutput const null_output = edge_ref.get_null_output(); CHECK(null_output.id == 1); CHECK(null_output.energized == 0); CHECK(null_output.loading == 0.0); CHECK(null_output.i_from == 0.0); - BranchShortCircuitOutput null_sc_output = edge_ref.get_null_sc_output(); + BranchShortCircuitOutput const null_sc_output = edge_ref.get_null_sc_output(); CHECK(null_sc_output.energized == 0); CHECK(null_sc_output.i_from(0) == 0.0); } SUBCASE("Enum Violations") { - CHECK_THROWS_AS(edge_ref.node(static_cast(99)), MissingCaseForEnumError); - CHECK_THROWS_AS(edge_ref.status(static_cast(99)), MissingCaseForEnumError); + CHECK_THROWS_AS(edge_ref.node(static_cast(2)), MissingCaseForEnumError); + CHECK_THROWS_AS(edge_ref.status(static_cast(2)), MissingCaseForEnumError); } } From 166059aaaeba250c7f2a7c6f95be8ff73cf8c607 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sat, 22 Aug 2026 21:52:57 +0200 Subject: [PATCH 09/15] clang-tody n.0 Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index 5c6c95715f..d458072058 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -254,8 +254,9 @@ TEST_CASE("Test edge") { } SUBCASE("Enum Violations") { - CHECK_THROWS_AS(edge_ref.node(static_cast(2)), MissingCaseForEnumError); - CHECK_THROWS_AS(edge_ref.status(static_cast(2)), MissingCaseForEnumError); + IntS const invalid_side = 2; + CHECK_THROWS_AS(edge_ref.node(static_cast(invalid_side)), MissingCaseForEnumError); + CHECK_THROWS_AS(edge_ref.status(static_cast(invalid_side)), MissingCaseForEnumError); } } From f04ffc98f1869e539ceec9704f6a04c182395cee Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sun, 23 Aug 2026 09:19:16 +0200 Subject: [PATCH 10/15] made invalid branch side from const to volatile Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index d458072058..02632654d3 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -254,7 +254,7 @@ TEST_CASE("Test edge") { } SUBCASE("Enum Violations") { - IntS const invalid_side = 2; + IntS volatile invalid_side = 2; CHECK_THROWS_AS(edge_ref.node(static_cast(invalid_side)), MissingCaseForEnumError); CHECK_THROWS_AS(edge_ref.status(static_cast(invalid_side)), MissingCaseForEnumError); } From dcc07f2601c7f016327c714f001155745396a909 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sun, 23 Aug 2026 12:36:25 +0200 Subject: [PATCH 11/15] ecception test temporarily removed Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index 02632654d3..d7d1756fbd 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -252,12 +252,6 @@ TEST_CASE("Test edge") { CHECK(null_sc_output.energized == 0); CHECK(null_sc_output.i_from(0) == 0.0); } - - SUBCASE("Enum Violations") { - IntS volatile invalid_side = 2; - CHECK_THROWS_AS(edge_ref.node(static_cast(invalid_side)), MissingCaseForEnumError); - CHECK_THROWS_AS(edge_ref.status(static_cast(invalid_side)), MissingCaseForEnumError); - } } } // namespace power_grid_model From 0f830439d5298fe7d9ac3169a39684ba6057b81c Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Sun, 23 Aug 2026 14:55:02 +0200 Subject: [PATCH 12/15] clang-tidy 4.0 Signed-off-by: Jerry Guo --- tests/cpp_unit_tests/component/test_edge.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/cpp_unit_tests/component/test_edge.cpp b/tests/cpp_unit_tests/component/test_edge.cpp index d7d1756fbd..bd17fd8c6d 100644 --- a/tests/cpp_unit_tests/component/test_edge.cpp +++ b/tests/cpp_unit_tests/component/test_edge.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include From 97b1a4541bf578fbf3ac09db44112fc1229abe68 Mon Sep 17 00:00:00 2001 From: Jerry Jinfeng Guo Date: Mon, 24 Aug 2026 16:13:28 +0200 Subject: [PATCH 13/15] simplify registration of branch and link to both use edge Signed-off-by: Jerry Jinfeng Guo --- .../main_core/main_model_type.hpp | 4 ++-- .../power_grid_model/main_core/topology.hpp | 24 ++++--------------- .../main_core/test_main_model_type.cpp | 20 ++++++++-------- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/main_model_type.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/main_model_type.hpp index 04d61367a0..b72a626fa6 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/main_model_type.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/main_model_type.hpp @@ -94,13 +94,13 @@ class MainModelType, ComponentLis std::tuple..., std::type_identity...>{}; static constexpr auto topology_types_tuple_v_ = - std::tuple, std::type_identity, std::type_identity, + std::tuple, std::type_identity, std::type_identity, std::type_identity, std::type_identity, std::type_identity, std::type_identity, std::type_identity, std::type_identity, std::type_identity>{}; static constexpr auto topology_connection_types_tuple_v_ = - std::tuple, std::type_identity, std::type_identity>{}; + std::tuple, std::type_identity, std::type_identity>{}; public: using TopologyTypesTuple = detail::tuple_type_identities_to_tuple_types_t(components); } -template Component, class ComponentContainer> +template Component, class ComponentContainer> requires common::component_container_c constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { apply_registration(components, comp_topo.branch_node_idx, [&components](Edge const& edge) { @@ -60,15 +60,6 @@ constexpr void register_topology_components(ComponentContainer const& components }); } -template Component, class ComponentContainer> - requires common::component_container_c -constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { - apply_registration(components, comp_topo.link_node_idx, [&components](Link const& edge) { - return BranchIdx{get_component_sequence_idx(components, edge.from_node()), - get_component_sequence_idx(components, edge.to_node())}; - }); -} - template Component, class ComponentContainer> requires common::component_container_c constexpr void register_topology_components(ComponentContainer const& components, ComponentTopology& comp_topo) { @@ -210,7 +201,7 @@ constexpr void register_topology_components(ComponentContainer const& components [](Regulator const& regulator) { return regulator.regulated_object_type(); }); } -template Component, class ComponentContainer> +template Component, class ComponentContainer> requires common::component_container_c constexpr void register_connections_components(ComponentContainer const& components, ComponentConnections& comp_conn) { apply_registration(components, comp_conn.branch_connected, [](Edge const& edge) { @@ -220,13 +211,6 @@ constexpr void register_connections_components(ComponentContainer const& compone [](Edge const& edge) { return edge.phase_shift(); }); } -template Component, class ComponentContainer> - requires common::component_container_c -constexpr void register_connections_components(ComponentContainer const& components, ComponentConnections& comp_conn) { - apply_registration(components, comp_conn.link_connected, [](Link const& link) { - return BranchConnected{status_to_int(link.from_status()), status_to_int(link.to_status())}; - }); -} template Component, class ComponentContainer> requires common::component_container_c constexpr void register_connections_components(ComponentContainer const& components, ComponentConnections& comp_conn) { @@ -248,7 +232,7 @@ constexpr void register_connections_components(ComponentContainer const& compone } // namespace detail template - requires common::component_container_c ComponentTopology construct_topology(typename ModelType::ComponentContainer const& components) { @@ -262,7 +246,7 @@ ComponentTopology construct_topology(typename ModelType::ComponentContainer cons } template - requires common::component_container_c + requires common::component_container_c ComponentConnections construct_components_connections(typename ModelType::ComponentContainer const& components) { ComponentConnections comp_conn; using TopologyConnectionTypesTuple = ModelType::TopologyConnectionTypesTuple; diff --git a/tests/cpp_unit_tests/main_core/test_main_model_type.cpp b/tests/cpp_unit_tests/main_core/test_main_model_type.cpp index 62a9292fe4..3da239277c 100644 --- a/tests/cpp_unit_tests/main_core/test_main_model_type.cpp +++ b/tests/cpp_unit_tests/main_core/test_main_model_type.cpp @@ -87,14 +87,14 @@ TEST_CASE("MainModelType") { } SUBCASE("Node Line Source") { using ModelType = - MainModelType, ComponentList>; + MainModelType, ComponentList>; static_assert( std::is_same_v, Node, Line, Source>>); + Container, Node, Line, Source>>); static_assert(std::is_same_v>); - static_assert(std::is_same_v>); - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); static_assert(ModelType::index_of_component == 0); static_assert(ModelType::index_of_component == 1); static_assert(ModelType::index_of_component == 2); @@ -115,18 +115,18 @@ TEST_CASE("MainModelType") { utils::run_functor_with_tuple_return_void( [&calls]() { calls.push_back(std::string_view(CompType::name)); }); - CHECK(calls == std::vector{"node", "branch", "source"}); + CHECK(calls == std::vector{"node", "edge", "source"}); } SUBCASE("Different component order: Line Source Node") { using ModelType = - MainModelType, ComponentList>; + MainModelType, ComponentList>; static_assert( std::is_same_v, Line, Source, Node>>); + Container, Line, Source, Node>>); static_assert(std::is_same_v>); - static_assert(std::is_same_v>); - static_assert(std::is_same_v>); + static_assert(std::is_same_v>); + static_assert(std::is_same_v>); static_assert(ModelType::index_of_component == 0); static_assert(ModelType::index_of_component == 1); static_assert(ModelType::index_of_component == 2); @@ -148,7 +148,7 @@ TEST_CASE("MainModelType") { utils::run_functor_with_tuple_return_void( [&calls]() { calls.push_back(std::string_view(CompType::name)); }); - CHECK(calls == std::vector{"node", "branch", "source"}); + CHECK(calls == std::vector{"node", "edge", "source"}); } SUBCASE("Node AComponent Source") { From 8e0e8a2e2a148ba6f154ef808d3ea18f6ff25785 Mon Sep 17 00:00:00 2001 From: Jerry Guo Date: Mon, 24 Aug 2026 16:21:11 +0200 Subject: [PATCH 14/15] clang-format Signed-off-by: Jerry Guo --- .../include/power_grid_model/main_core/topology.hpp | 4 ++-- tests/cpp_unit_tests/main_core/test_main_model_type.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp index 9bae8888ab..f2dca1df70 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/main_core/topology.hpp @@ -232,8 +232,8 @@ constexpr void register_connections_components(ComponentContainer const& compone } // namespace detail template - requires common::component_container_c ComponentTopology construct_topology(typename ModelType::ComponentContainer const& components) { ComponentTopology comp_topo; diff --git a/tests/cpp_unit_tests/main_core/test_main_model_type.cpp b/tests/cpp_unit_tests/main_core/test_main_model_type.cpp index 3da239277c..0b8bd2a57f 100644 --- a/tests/cpp_unit_tests/main_core/test_main_model_type.cpp +++ b/tests/cpp_unit_tests/main_core/test_main_model_type.cpp @@ -86,8 +86,8 @@ TEST_CASE("MainModelType") { CHECK(calls == std::vector{"node", "source"}); } SUBCASE("Node Line Source") { - using ModelType = - MainModelType, ComponentList>; + using ModelType = MainModelType, + ComponentList>; static_assert( std::is_same_v{"node", "edge", "source"}); } SUBCASE("Different component order: Line Source Node") { - using ModelType = - MainModelType, ComponentList>; + using ModelType = MainModelType, + ComponentList>; static_assert( std::is_same_v Date: Tue, 25 Aug 2026 06:40:30 +0200 Subject: [PATCH 15/15] resolve comment Signed-off-by: Jerry Guo --- docs/user_manual/components.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user_manual/components.md b/docs/user_manual/components.md index 08fa9bd561..b3fd62ad8f 100644 --- a/docs/user_manual/components.md +++ b/docs/user_manual/components.md @@ -185,8 +185,8 @@ Because of this, the power-grid-model choses to model this accordingly: to 10e6 siemens for a 10kV network. ```{note} -New in version `v1.13.142`: links may be modeled as infinite (but equal) admittance connections. -In the old behavior, link admittences are always modeled with the same fixed per-unit value. +New in version [`v1.13.142`](https://github.com/PowerGridModel/power-grid-model/releases/tag/v1.13.142): links may be modeled as infinite (but equal) admittance connections. +In the old behavior, link admittances were always modeled with the same fixed per-unit value. Starting with version `v2.0.0`, link admittances are always modeled as infinite-admittance connections. ```