Skip to content

Commit

Permalink
updated validations test; marked invalid grid; added error interfacing
Browse files Browse the repository at this point in the history
Signed-off-by: Jerry Guo <Jerry.Jinfeng.Guo@alliander.com>
  • Loading branch information
Jerry-Jinfeng-Guo committed Nov 19, 2024
1 parent bd59bf5 commit b642c97
Show file tree
Hide file tree
Showing 9 changed files with 99 additions and 1,068 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,9 @@ class AutomaticTapCalculationError : public PowerGridError {
class AutomaticTapInputError : public PowerGridError {
public:
AutomaticTapInputError(std::string const& msg) {
append_msg(msg); // NOSONAR
append_msg(
"Automatic tap changer has invalid configuration that does not meet the transformer ranking criteria. " +
msg); // NOSONAR
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,30 +137,31 @@ inline void add_component(MainModelState<ComponentContainer>& state, ForwardIter
}
}();
// (TODO: jguo) This validation still needs to be updated
if (regulated_object_idx.group == get_component_type_index<Transformer>(state)) {
auto const& regulated_object = get_component<Transformer>(state, regulated_object_idx);

auto const non_tap_side =
regulated_object.tap_side() == BranchSide::from ? BranchSide::to : BranchSide::from;
if (get_component<Node>(state, regulated_object.node(regulated_object.tap_side())).u_rated() <
get_component<Node>(state, regulated_object.node(non_tap_side)).u_rated()) {
throw AutomaticTapCalculationError(id);
}
} else if (regulated_object_idx.group == get_component_type_index<ThreeWindingTransformer>(state)) {
auto const& regulated_object = get_component<ThreeWindingTransformer>(state, regulated_object_idx);
auto const tap_side_u_rated =
get_component<Node>(state, regulated_object.node(regulated_object.tap_side())).u_rated();
for (auto const side : branch3_sides) {
if (side == regulated_object.tap_side()) {
continue;
}
if (tap_side_u_rated < get_component<Node>(state, regulated_object.node(side)).u_rated()) {
throw AutomaticTapCalculationError(id);
}
}
} else {
throw InvalidRegulatedObject(input.regulated_object, Component::name);
}
// check and forbid for step-up transformer logic to be removed
// if (regulated_object_idx.group == get_component_type_index<Transformer>(state)) {
// auto const& regulated_object = get_component<Transformer>(state, regulated_object_idx);

// auto const non_tap_side =
// regulated_object.tap_side() == BranchSide::from ? BranchSide::to : BranchSide::from;
// if (get_component<Node>(state, regulated_object.node(regulated_object.tap_side())).u_rated() <
// get_component<Node>(state, regulated_object.node(non_tap_side)).u_rated()) {
// throw AutomaticTapCalculationError(id);
// }
// } else if (regulated_object_idx.group == get_component_type_index<ThreeWindingTransformer>(state)) {
// auto const& regulated_object = get_component<ThreeWindingTransformer>(state, regulated_object_idx);
// auto const tap_side_u_rated =
// get_component<Node>(state, regulated_object.node(regulated_object.tap_side())).u_rated();
// for (auto const side : branch3_sides) {
// if (side == regulated_object.tap_side()) {
// continue;
// }
// if (tap_side_u_rated < get_component<Node>(state, regulated_object.node(side)).u_rated()) {
// throw AutomaticTapCalculationError(id);
// }
// }
// } else {
// throw InvalidRegulatedObject(input.regulated_object, Component::name);
// }

auto const regulated_object_type = get_component<Base>(state, regulated_object_idx).math_model_type();
double const u_rated = get_component<Node>(state, regulated_terminal).u_rated();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,6 @@ inline void process_trafo3w_edge(main_core::main_model_state_c auto const& state
// add regulated idx only when the first side node is tap side node.
// This is done to add only one directional edge with regulated idx.
auto const edge_value =
// (TODO: jguo) The following commented out logic was a potential bug
// (from_node != tap_side_node)
// ? unregulated_edge_prop
// :
TrafoGraphEdge{trafo3w_idx, 1, branch_3_side_to_tap_side(transformer3w.tap_side()), control_side};
add_to_edge(state, edges, edge_props, edge_from_node, edge_to_node, edge_value);
} else {
Expand Down Expand Up @@ -288,7 +284,7 @@ inline void process_edges_dijkstra(Idx v, std::vector<EdgeWeight>& vertex_distan
auto t = boost::target(e, graph);
const EdgeWeight weight = graph[e].weight;

// We can not use BGL_FORALL_OUTEDGES here because we need information
// We can not use BGL_FORALL_OUTEDGES here because we need information
// regardless of edge direction
if (u == s && vertex_distances[s] + weight < vertex_distances[t]) {
vertex_distances[t] = vertex_distances[s] + weight;
Expand Down Expand Up @@ -322,12 +318,25 @@ inline auto get_edge_weights(TransformerGraph const& graph) -> TrafoGraphEdgePro
auto const edge_tgt_rank = vertex_distances[boost::target(e, graph)];
auto const edge_res = std::min(edge_src_rank, edge_tgt_rank);

// New edge logic for ranking
// | Tap | Control | All edges |
// ---------------------------------------------
// | A | A | [B->A], [C->A], [B<->C] |
// | A | B | [A->B], [A->C], [B<->C] |
// | A | C | [A->B], [A->C], [B<->C] |
// | B | A | [B->A], [C<->A], [B->C] |
// | B | B | [A->B], [C<->A], [C->B] |
// | B | C | [B->A], [C<->A], [B->C] |
// | C | A | [A<->B], [C->A], [C->B] |
// | C | B | [A<->B], [C->A], [C->B] |
// | C | C | [A<->B], [A->C], [A->B] |
// In two winding trafo, the edge is always pointing to the control side; in three winding trafo edges, the
// edges are always pointing parallel to the control side: meaning that for delta configuration ABC, the above
// situations can happen.
if (edge_src_rank != edge_tgt_rank - 1) {
throw AutomaticTapInputError("Transformer is not unrechable: control side rank mismatch");
throw AutomaticTapInputError("Transformer is unrechable: control side rank mismatch");
}
if (!is_unreachable(edge_res)) {
// (TODO: jguo) old way -> broke existing validation tests
// result.push_back({graph[e].regulated_idx, edge_res});
result.push_back({graph[e].regulated_idx, edge_tgt_rank});
}
}
Expand All @@ -349,7 +358,7 @@ inline auto rank_transformers(TrafoGraphEdgeProperties const& w_trafo_list) -> R
previous_weight = trafo.weight;
}
auto& current_group = groups.back(); // avoid duplicates
if (std::find(current_group.begin(), current_group.end(), trafo.regulated_idx) == current_group.end()) {
if (std::ranges::find(current_group, trafo.regulated_idx) == current_group.end()) {
current_group.push_back(trafo.regulated_idx);
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/power_grid_model/_core/error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from power_grid_model._core.power_grid_core import power_grid_core as pgc
from power_grid_model.errors import (
AutomaticTapCalculationError,
AutomaticTapInputError,
ConflictID,
ConflictVoltage,
IDNotFound,
Expand Down Expand Up @@ -71,6 +72,10 @@
_AUTOMATIC_TAP_CALCULATION_ERROR_RE = re.compile(
r"Automatic tap changing regulator with tap_side at LV side is not supported. Found at id (-?\d+)\n"
)
_AUTOMATIC_TAP_INPUT_ERROR_RE = re.compile(
r"Automatic tap changer has invalid configuration that does not meet the transformer ranking criteria. (-?\d+)\n"
)

_ID_WRONG_TYPE_RE = re.compile(r"Wrong type for object with id (-?\d+)\n")
_INVALID_CALCULATION_METHOD_RE = re.compile(r"The calculation method is invalid for this calculation!")
_INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE = re.compile(r"short circuit type") # multiple different flavors
Expand All @@ -95,6 +100,7 @@
_INVALID_MEASURED_OBJECT_RE: InvalidMeasuredObject,
_INVALID_REGULATED_OBJECT_RE: InvalidRegulatedObject,
_AUTOMATIC_TAP_CALCULATION_ERROR_RE: AutomaticTapCalculationError,
_AUTOMATIC_TAP_INPUT_ERROR_RE: AutomaticTapInputError,
_ID_WRONG_TYPE_RE: IDWrongType,
_INVALID_CALCULATION_METHOD_RE: InvalidCalculationMethod,
_INVALID_SHORT_CIRCUIT_PHASE_OR_TYPE_RE: InvalidShortCircuitPhaseOrType,
Expand Down
4 changes: 4 additions & 0 deletions src/power_grid_model/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ class AutomaticTapCalculationError(PowerGridError):
"""Automatic tap changer with tap at LV side is unsupported for automatic tap changing calculation."""


class AutomaticTapInputError(PowerGridError):
"""Automatic tap changer has invalid configuration that does not meet the transformer ranking criteria."""


class InvalidShortCircuitPhaseOrType(PowerGridError):
"""Invalid (combination of) short circuit types and phase(s) provided."""

Expand Down
17 changes: 1 addition & 16 deletions tests/cpp_unit_tests/test_tap_position_optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,22 +258,6 @@ TEST_CASE("Test Transformer ranking") {
CHECK(actual_edges_prop == expected_edges_prop);
}

// (TODO: jguo) old way, to be removed
SUBCASE("Automatic tap unsupported tap side at LV") {
TestState bad_state;
std::vector<NodeInput> bad_nodes{{0, 50e3}, {1, 10e3}};
main_core::add_component<Node>(bad_state, bad_nodes.begin(), bad_nodes.end(), 50.0);

std::vector<TransformerInput> bad_trafo{get_transformer(2, 0, 1, BranchSide::to)};
main_core::add_component<Transformer>(bad_state, bad_trafo.begin(), bad_trafo.end(), 50.0);

std::vector<TransformerTapRegulatorInput> bad_regulators{get_regulator(3, 2, ControlSide::from)};

CHECK_THROWS_AS(main_core::add_component<TransformerTapRegulator>(bad_state, bad_regulators.begin(),
bad_regulators.end(), 50.0),
AutomaticTapCalculationError);
}

SUBCASE("Process edge weights") {
using vertex_iterator = boost::graph_traits<pgm_tap::TransformerGraph>::vertex_iterator;

Expand Down Expand Up @@ -341,6 +325,7 @@ TEST_CASE("Test Transformer ranking") {

SUBCASE("Ranking complete the graph") {
// (TODO: jguo) existing demo grid is not compatible with the updated ranking
// The test grid needs to be updated here to match the new ranking logic
// pgm_tap::RankedTransformerGroups order = pgm_tap::rank_transformers(state);
// pgm_tap::RankedTransformerGroups const ref_order{
// {{Idx2D{3, 0}, Idx2D{3, 1}, Idx2D{4, 0}}, {Idx2D{3, 3}, Idx2D{3, 2}, Idx2D{3, 4}}}};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,18 @@
{"id": 3, "u_rated": 10500},
{"id": 4, "u_rated": 10500},
{"id": 5, "u_rated": 21000},
{"id": 6, "u_rated": 10500},
{"id": 25, "u_rated": 21000},
{"id": 26, "u_rated": 10500}
{"id": 6, "u_rated": 10500}
],
"line": [
{"id": 7, "from_node": 2, "to_node": 3, "from_status": 1, "to_status": 1, "r1": 0.506, "x1": 1.07, "c1": 5.099999999999999e-06, "tan1": 0, "r0": 11.47, "x0": 2.94, "c0": 5.099999999999999e-06, "tan0": 0, "i_n": 604},
{"id": 8, "from_node": 1, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 1.01, "x1": 1.92, "c1": 3.2e-06, "tan1": 0, "r0": 22.36, "x0": 6.11, "c0": 3.2e-06, "tan0": 0, "i_n": 431},
{"id": 27, "from_node": 1, "to_node": 25, "from_status": 0, "to_status": 1, "r1": 1.01, "x1": 1.92, "c1": 3.2e-06, "tan1": 0, "r0": 22.36, "x0": 6.11, "c0": 3.2e-06, "tan0": 0, "i_n": 431}
{"id": 8, "from_node": 1, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 1.01, "x1": 1.92, "c1": 3.2e-06, "tan1": 0, "r0": 22.36, "x0": 6.11, "c0": 3.2e-06, "tan0": 0, "i_n": 431}
],
"transformer": [
{"id": 9, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 12000000, "uk": 0.204, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -11, "tap_max": 9, "tap_nom": 0, "tap_size": 2500, "uk_min": 0.204, "uk_max": 0.204, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0},
{"id": 10, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 11000, "sn": 12000000, "uk": 0.204, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 2, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -11, "tap_max": 9, "tap_nom": 0, "tap_size": 2500, "uk_min": 0.204, "uk_max": 0.204, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0},
{"id": 11, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "u1": 150000, "u2": 21000, "sn": 25000000, "uk": 0.208, "pk": 80000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 2, "clock": 1, "tap_side": 0, "tap_pos": 0, "tap_min": -16, "tap_max": 16, "tap_nom": 0, "tap_size": 1730, "uk_min": 0.208, "uk_max": 0.208, "pk_min": 80000, "pk_max": 80000, "r_grounding_from": 0, "x_grounding_from": 0},
{"id": 12, "from_node": 5, "to_node": 6, "from_status": 1, "to_status": 1, "u1": 21000, "u2": 10000, "sn": 12000000, "uk": 0.08, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 0, "tap_min": -15, "tap_max": 15, "tap_nom": 0, "tap_size": 270, "uk_min": 0.08, "uk_max": 0.08, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0},
{"id": 13, "from_node": 3, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10500, "u2": 10500, "sn": 12000000, "uk": 0.005, "pk": 0, "i0": 0, "p0": 0, "winding_from": 0, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 7, "tap_min": 1, "tap_max": 13, "tap_nom": 7, "tap_size": 150, "uk_min": 0.004500000000000001, "uk_max": 0.006, "pk_min": 0, "pk_max": 0, "r_grounding_from": 0, "x_grounding_from": 0, "r_grounding_to": 0, "x_grounding_to": 0},
{"id": 24, "from_node": 25, "to_node": 26, "from_status": 1, "to_status": 1, "u1": 21000, "u2": 10500, "sn": 12000000, "uk": 0.08, "pk": 60000, "i0": 0, "p0": 0, "winding_from": 1, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 0, "tap_min": -15, "tap_max": 15, "tap_nom": 0, "tap_size": 270, "uk_min": 0.08, "uk_max": 0.08, "pk_min": 60000, "pk_max": 60000, "r_grounding_from": 0, "x_grounding_from": 0}
{"id": 13, "from_node": 3, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10500, "u2": 10500, "sn": 12000000, "uk": 0.005, "pk": 0, "i0": 0, "p0": 0, "winding_from": 0, "winding_to": 0, "clock": 0, "tap_side": 0, "tap_pos": 7, "tap_min": 1, "tap_max": 13, "tap_nom": 7, "tap_size": 150, "uk_min": 0.004500000000000001, "uk_max": 0.006, "pk_min": 0, "pk_max": 0, "r_grounding_from": 0, "x_grounding_from": 0, "r_grounding_to": 0, "x_grounding_to": 0}
],
"source": [
{"id": 14, "node": 0, "status": 1, "u_ref": 1, "sk": 1e+20, "rx_ratio": 0.1, "z01_ratio": 3}
Expand All @@ -42,8 +38,7 @@
{"id": 20, "regulated_object": 10, "status": 1, "control_side": 1, "u_set": 10600, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0},
{"id": 21, "regulated_object": 11, "status": 1, "control_side": 1, "u_set": 21000, "u_band": 2000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0},
{"id": 22, "regulated_object": 12, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0},
{"id": 23, "regulated_object": 13, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0},
{"id": 28, "regulated_object": 24, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0}
{"id": 23, "regulated_object": 13, "status": 1, "control_side": 1, "u_set": 10500, "u_band": 1000, "line_drop_compensation_r": 0, "line_drop_compensation_x": 0}
]
}
}
Loading

0 comments on commit b642c97

Please sign in to comment.