diff --git a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp index e0db9e154..14218306b 100644 --- a/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp +++ b/power_grid_model_c/power_grid_model/include/power_grid_model/common/exception.hpp @@ -135,7 +135,7 @@ class IterationDiverge : public PowerGridError { class MaxIterationReached : public IterationDiverge { public: MaxIterationReached(std::string const& msg = "") { - append_msg("Maximum iterations reached, no solution. " + msg + "\n"); + append_msg("Maximum number of iterations reached" + msg + "\n"); } }; 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 3bbcce84e..1da69591c 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 @@ -899,13 +899,14 @@ class TapPositionOptimizerImpl, StateCalculator, adjust_transformer(regulator, state, result, update_data, search, options) || tap_changed; } if (tap_changed) { + iterations_per_rank[rank_index + 1] = 0; + ++iterations_per_rank[rank_index]; break; } - iterations_per_rank[++rank_index] = 0; // NOSONAR + ++rank_index; } if (tap_changed) { - if (static_cast(++iterations_per_rank[rank_index]) > - 2 * max_tap_ranges_per_rank[rank_index]) { + if (static_cast(iterations_per_rank[rank_index]) > 2 * max_tap_ranges_per_rank[rank_index]) { throw MaxIterationReached{"TapPositionOptimizer::iterate"}; } update_state(update_data); diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json new file mode 100644 index 000000000..3b748a1cc --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json @@ -0,0 +1,59 @@ +{ + "version": "1.0", + "type": "input", + "is_batch": false, + "attributes": {}, + "data": { + "node": [ + {"id": 0, "u_rated": 10000}, + {"id": 1, "u_rated": 10000}, + {"id": 2, "u_rated": 10000}, + {"id": 3, "u_rated": 10000}, + {"id": 4, "u_rated": 10000}, + {"id": 5, "u_rated": 10000}, + {"id": 6, "u_rated": 10000}, + {"id": 7, "u_rated": 400}, + {"id": 8, "u_rated": 400}, + {"id": 9, "u_rated": 400}, + {"id": 10, "u_rated": 400} + ], + "line": [ + {"id": 11, "from_node": 0, "to_node": 1, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.5, "c1": 0, "tan1": 0}, + {"id": 12, "from_node": 0, "to_node": 2, "from_status": 1, "to_status": 1, "r1": 0.1, "x1": 0.6, "c1": 0, "tan1": 0}, + {"id": 13, "from_node": 3, "to_node": 5, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.5, "c1": 0, "tan1": 0}, + {"id": 14, "from_node": 4, "to_node": 6, "from_status": 1, "to_status": 1, "r1": 0.003, "x1": 0.3, "c1": 0, "tan1": 0}, + {"id": 15, "from_node": 7, "to_node": 9, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.5, "c1": 0, "tan1": 0}, + {"id": 16, "from_node": 8, "to_node": 9, "from_status": 1, "to_status": 1, "r1": 0.005, "x1": 0.6, "c1": 0, "tan1": 0} + ], + "transformer": [ + {"id": 17, "from_node": 1, "to_node": 3, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 100}, + {"id": 18, "from_node": 2, "to_node": 4, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 10000, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 100}, + {"id": 19, "from_node": 5, "to_node": 7, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 20}, + {"id": 20, "from_node": 6, "to_node": 8, "from_status": 1, "to_status": 1, "u1": 10000, "u2": 400, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 20}, + {"id": 21, "from_node": 9, "to_node": 10, "from_status": 1, "to_status": 1, "u1": 400, "u2": 400, "sn": 300000, "uk": 0.0005, "pk": 1000, "i0": 0, "p0": 0, "winding_from": 2, "winding_to": 1, "clock": 5, "tap_side": 0, "tap_pos": 0, "tap_min": -10, "tap_max": 10, "tap_size": 20} + ], + "source": [ + {"id": 22, "node": 0, "status": 1, "u_ref": 1} + ], + "sym_load": [ + {"id": 23, "node": 0, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 24, "node": 1, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 25, "node": 2, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 26, "node": 3, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 27, "node": 4, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 28, "node": 5, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 29, "node": 6, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 30, "node": 7, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 31, "node": 8, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 32, "node": 9, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000}, + {"id": 33, "node": 10, "status": 1, "type": 0, "p_specified": 100000, "q_specified": 10000} + ], + "transformer_tap_regulator": [ + {"id": 34, "regulated_object": 17, "status": 1, "control_side": 1, "u_set": 10000, "u_band": 300}, + {"id": 35, "regulated_object": 18, "status": 1, "control_side": 1, "u_set": 10000, "u_band": 300}, + {"id": 36, "regulated_object": 19, "status": 1, "control_side": 1, "u_set": 400, "u_band": 5}, + {"id": 37, "regulated_object": 20, "status": 1, "control_side": 1, "u_set": 400, "u_band": 5}, + {"id": 38, "regulated_object": 21, "status": 1, "control_side": 1, "u_set": 400, "u_band": 5} + ] + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json.license b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json.license new file mode 100644 index 000000000..2fcbfaeb5 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/input.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json new file mode 100644 index 000000000..c3482bcef --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json @@ -0,0 +1,10 @@ +{ + "calculation_method": "newton_raphson", + "tap_changing_strategy": "any_valid_tap", + "rtol": 1e-05, + "atol": 1e-05, + "fail": { + "raises": "MaxIterationReached", + "reason": "TapPositionOptimizer::iterate" + } +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json.license b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json.license new file mode 100644 index 000000000..2fcbfaeb5 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/params.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json new file mode 100644 index 000000000..682b959f0 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json @@ -0,0 +1,7 @@ +{ + "version": "1.0", + "type": "sym_output", + "is_batch": false, + "attributes": {}, + "data": {} +} \ No newline at end of file diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json.license b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json.license new file mode 100644 index 000000000..2fcbfaeb5 --- /dev/null +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-any-max-iter/sym_output.json.license @@ -0,0 +1,3 @@ +SPDX-FileCopyrightText: 2023 Contributors to the Power Grid Model project + +SPDX-License-Identifier: MPL-2.0 \ No newline at end of file diff --git a/tests/unit/utils.py b/tests/unit/utils.py index 7d246e3fd..3c9ef8a92 100644 --- a/tests/unit/utils.py +++ b/tests/unit/utils.py @@ -25,6 +25,7 @@ InvalidMeasuredObject, InvalidRegulatedObject, InvalidTransformerClock, + MaxIterationReached, NotObservableError, PowerGridBatchError, PowerGridError, @@ -60,6 +61,7 @@ PowerGridSerializationError, AssertionError, OSError, + MaxIterationReached, ) }