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 820271a1fc..6629a218e7 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 @@ -893,13 +893,21 @@ class TapPositionOptimizerImpl, StateCalculator, IntS search(bool prefer_higher_) const { // This logic is used to determine which of the middle points could be of interest // given strategy used in optimization: - // Since in BinarySearch we insist on absolute upper and lower bounds, we only need to - // find the corresponding mid point. std::midpoint returns always the lower mid point + // In BinarySearch we rely on upper and lower bounds to find the corresponding mid point. + // std::midpoint returns always the relative 'lower' mid point // if the range is of even length. This is why we need to adjust bounds accordingly. // Not because upper bound and lower bound might be reversed, which is not possible. + // In the case the optimization target is beyond the range, both boundaries should be + // considered, especially in the final iteration of the binary search. bool const prefer_higher = control_at_tap_side_ != prefer_higher_; auto const primary_bound = prefer_higher ? upper_bound_ : lower_bound_; auto const secondary_bound = prefer_higher ? lower_bound_ : upper_bound_; + auto const current_at_bound = current_ == primary_bound || current_ == secondary_bound; + bool const is_one_apart = std::abs(static_cast(primary_bound) - secondary_bound) == 1; + // Handle edge case: 1 off and current already not satisfying + if (is_one_apart && current_at_bound) { + return current_ == primary_bound ? secondary_bound : primary_bound; + } return std::midpoint(primary_bound, secondary_bound); } diff --git a/tests/data/power_flow/automatic-tap-regulator/achievable-voltage-above-band-fast-any/params.json b/tests/data/power_flow/automatic-tap-regulator/achievable-voltage-above-band-fast-any/params.json index 799ff822cc..db835303c1 100644 --- a/tests/data/power_flow/automatic-tap-regulator/achievable-voltage-above-band-fast-any/params.json +++ b/tests/data/power_flow/automatic-tap-regulator/achievable-voltage-above-band-fast-any/params.json @@ -5,9 +5,5 @@ "atol": { "default": 1e-5, "u": 100.0 - }, - "xfail": { - "raises": "MaxIterationReached", - "reason": "Bug in fast any tap changing strategy in this edge case: https://github.com/PowerGridModel/power-grid-model/issues/1215" } } diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-fast-any-max-iter/params.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-fast-any-max-iter/params.json index 703a6403b4..b3f76100fa 100644 --- a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-fast-any-max-iter/params.json +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-meshed-fast-any-max-iter/params.json @@ -2,9 +2,5 @@ "calculation_method": "newton_raphson", "tap_changing_strategy": "fast_any_tap", "rtol": 1e-5, - "atol": 1e-5, - "raises": { - "raises": "MaxIterationReached", - "reason": "TapPositionOptimizer::iterate" - } + "atol": 1e-5 } diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/params.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/params.json index d137faeb48..b3f76100fa 100644 --- a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/params.json +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/params.json @@ -2,9 +2,5 @@ "calculation_method": "newton_raphson", "tap_changing_strategy": "fast_any_tap", "rtol": 1e-5, - "atol": 1e-5, - "raises": { - "raises": "MaxIterationReached", - "reason": "TapPositionOptimizer::binary_search" - } + "atol": 1e-5 } diff --git a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/sym_output.json b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/sym_output.json index 021aa4b297..f08a846aa4 100644 --- a/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/sym_output.json +++ b/tests/data/power_flow/automatic-tap-regulator/auto-tap-changer-small-u-band-max-iter-fast-any/sym_output.json @@ -6,10 +6,10 @@ "data": { "node": [ {"id": 1, "u_pu": 1, "u": 9999.9}, - {"id": 2, "u_pu": 1.02456, "u": 409.8260092982474} + {"id": 2, "u_pu": 0.9989, "u": 399.5626} ], "transformer_tap_regulator": [ - {"id": 6, "tap_pos": 2} + {"id": 6, "tap_pos": 3} ] } } \ No newline at end of file