diff --git a/src/power_grid_model/validation/rules.py b/src/power_grid_model/validation/rules.py index 721b43b8b..0b197fbc2 100644 --- a/src/power_grid_model/validation/rules.py +++ b/src/power_grid_model/validation/rules.py @@ -917,10 +917,11 @@ def all_supported_tap_control_side( # pylint: disable=too-many-arguments invalid = np.zeros_like(mask) for ref_component, ref_field in tap_side_fields: - indices = get_indexer(data[ref_component]["id"], data[component][regulated_object_field], default_value=-1) - found = indices != -1 - ref_comp_values = data[ref_component][ref_field][indices[found]] - invalid[found] = np.logical_or(invalid[found], values[found] == ref_comp_values) + if ref_component in data: + indices = get_indexer(data[ref_component]["id"], data[component][regulated_object_field], default_value=-1) + found = indices != -1 + ref_comp_values = data[ref_component][ref_field][indices[found]] + invalid[found] = np.logical_or(invalid[found], values[found] == ref_comp_values) if invalid.any(): return [ diff --git a/src/power_grid_model/validation/utils.py b/src/power_grid_model/validation/utils.py index e8dd226aa..ed2a0347e 100644 --- a/src/power_grid_model/validation/utils.py +++ b/src/power_grid_model/validation/utils.py @@ -196,12 +196,16 @@ def get_indexer(source: np.ndarray, target: np.ndarray, default_value: Optional[ Raises: IndexError: if default_value is None and there were values in target that were not in source """ + permutation_sort = np.argsort(source) # complexity O(N_input * logN_input) indices = np.searchsorted(source, target, sorter=permutation_sort) # complexity O(N_update * logN_input) if default_value is None: return permutation_sort[indices] + if len(source) == 0: + return np.full_like(target, fill_value=default_value) + clipped_indices = np.take(permutation_sort, indices, mode="clip") return np.where(source[clipped_indices] == target, permutation_sort[clipped_indices], default_value) diff --git a/tests/unit/validation/test_rules.py b/tests/unit/validation/test_rules.py index c21ee785f..6f258826e 100644 --- a/tests/unit/validation/test_rules.py +++ b/tests/unit/validation/test_rules.py @@ -27,6 +27,7 @@ NotUniqueError, SameValueError, TwoValuesZeroError, + UnsupportedTransformerRegulationError, ) from power_grid_model.validation.rules import ( all_between, @@ -44,6 +45,7 @@ all_less_than, all_not_two_values_equal, all_not_two_values_zero, + all_supported_tap_control_side, all_unique, all_valid_clocks, all_valid_enum_values, @@ -545,3 +547,35 @@ def test_all_valid_fault_phases(): errors = all_valid_fault_phases(invalid, "fault", "foo", "bar") assert len(errors) == 1 assert FaultPhaseError("fault", fields=["foo", "bar"], ids=list(range(26))) in errors + + +def test_supported_tap_control_side(): + valid = { + "foo": np.array([(0, 4)], dtype=[("id", "i4"), ("foofoo", "i1")]), + "bar": np.array([(1, 5)], dtype=[("id", "i4"), ("barbar", "i1")]), + "baz": np.array([], dtype=[("id", "i4"), ("bazbaz", "i1")]), + "regulator": np.array([(2, 0, 6), (3, 1, 7)], dtype=[("id", "i4"), ("regulated", "i4"), ("control", "i1")]), + } + errors = all_supported_tap_control_side( + valid, + "regulator", + "control", + "regulated", + [("foo", "foofoo"), ("bar", "barbar"), ("baz", "bazbaz"), ("bla", "blabla")], + ) + assert not errors + + invalid = { + "foo": np.array([(0, 4)], dtype=[("id", "i4"), ("foofoo", "i1")]), + "bar": np.array([(1, 5)], dtype=[("id", "i4"), ("barbar", "i1")]), + "regulator": np.array([(2, 0, 4), (3, 1, 5)], dtype=[("id", "i4"), ("regulated", "i4"), ("control", "i1")]), + } + errors = all_supported_tap_control_side( + invalid, + "regulator", + "control", + "regulated", + [("foo", "foofoo"), ("bar", "barbar"), ("baz", "bazbaz")], + ) + assert len(errors) == 1 + assert UnsupportedTransformerRegulationError(component="regulator", fields=["control", "regulated"], ids=[2, 3])