diff --git a/src/chexus/validators.py b/src/chexus/validators.py index c346769..8c819db 100644 --- a/src/chexus/validators.py +++ b/src/chexus/validators.py @@ -284,6 +284,31 @@ def validate(self, node: Dataset | Group) -> Violation | None: ) +class event_id_subset_of_detector_number(Validator): + def __init__(self) -> None: + super().__init__( + "event_id is not subset of associated detector_numbers", + "The values in the event_id field in NXevent_data should be " + "a subset of the values in the detector_number dataset on the " + "associated NXdetector.", + ) + + def applies_to(self, node: Dataset | Group) -> bool: + return ( + isinstance(node, Group) + and node.attrs.get('NX_class') == 'NXevent_data' + and 'event_id' in node.children + and 'detector_number' in node.parent.children + ) + + def validate(self, node: Dataset | Group) -> Violation | None: + if not np.isin( + node.children['event_id'].value, + node.parent.children['detector_number'].value, + ).all(): + return Violation(node.name) + + physical_components = [ "NXaperture", "NXattenuator", @@ -374,6 +399,7 @@ def base_validators(*, has_scipp=True): units_invalid(), NXlog_has_value(), detector_numbers_unique_in_all_detectors(), + event_id_subset_of_detector_number(), ] if has_scipp: validators += [ diff --git a/tests/validators_test.py b/tests/validators_test.py index 4c9a74b..2c0796d 100644 --- a/tests/validators_test.py +++ b/tests/validators_test.py @@ -505,3 +505,54 @@ def test_duplicate_detector_number(value): assert validator.validate(det2) is None # Second time the same detector numbers are seen, we expect a violation assert validator.validate(det) is not None + + +def test_event_id_not_in_detector_number(): + det = chexus.Group(name="detector1", attrs={"NX_class": "NXdetector"}) + det.children = { + 'data_good': chexus.Group( + name="data_good", attrs={"NX_class": "NXevent_data"}, parent=det + ), + 'data_bad': chexus.Group( + name="data_bad", attrs={"NX_class": "NXevent_data"}, parent=det + ), + 'detector_number': chexus.Dataset( + name="detector_number", value=[1, 2, 3], shape=(3,), dtype=int, parent=det + ), + } + det.children['data_good'].children = { + 'event_id': chexus.Dataset( + name='event_id', + value=[1, 2, 3], + shape=(3,), + dtype=int, + parent=det.children['data_good'], + ) + } + det.children['data_bad'].children = { + 'event_id': chexus.Dataset( + name='event_id', + value=[1, 4], + shape=(2,), + dtype=int, + parent=det.children['data_bad'], + ) + } + assert chexus.validators.event_id_subset_of_detector_number().applies_to( + det.children['data_good'] + ) + assert chexus.validators.event_id_subset_of_detector_number().applies_to( + det.children['data_bad'] + ) + assert ( + chexus.validators.event_id_subset_of_detector_number().validate( + det.children['data_good'] + ) + is None + ) + assert ( + chexus.validators.event_id_subset_of_detector_number().validate( + det.children['data_bad'] + ) + is not None + )