diff --git a/src/scippnexus/nxdata.py b/src/scippnexus/nxdata.py index 38d58550..feaa22a3 100644 --- a/src/scippnexus/nxdata.py +++ b/src/scippnexus/nxdata.py @@ -110,6 +110,10 @@ def _init_field_dims(self, name: str, field: Field | Group) -> None: # len(dims). shape = _squeeze_trailing(dims, field.dataset.shape) field.sizes = dict(zip(dims, shape, strict=False)) + elif name in self._aux_signals: + # Auxiliary signals are allowed to have dimensions unrelated to the + # primary signal. Keep the field's fallback dimensions in that case. + return elif self._valid: s1 = self._signal.sizes s2 = field.sizes @@ -376,7 +380,13 @@ def _assemble_as_data( signals = {self._signal_name: da} signals.update(aux) if all(isinstance(v, sc.Variable | sc.DataArray) for v in signals.values()): - return sc.Dataset(signals) + try: + return sc.Dataset(signals) + except sc.DimensionError: + # A Dataset requires matching item dimensionality. NeXus permits + # auxiliary signals on unrelated dimensions, so retain those as + # separate DataGroup entries instead. + pass return sc.DataGroup(signals) return da diff --git a/tests/nxdata_test.py b/tests/nxdata_test.py index 2567f699..5621fb69 100644 --- a/tests/nxdata_test.py +++ b/tests/nxdata_test.py @@ -276,6 +276,26 @@ def test_auxiliary_signal_causes_load_as_dataset(h5root) -> None: assert_identical(data[...], sc.Dataset({'signal': signal, 'xx': aux})) +def test_auxiliary_signal_with_different_dims_loads_as_data_group(h5root) -> None: + signal = sc.array(dims=['tof'], unit='counts', values=[1, 2, 3]) + frame_total = sc.array(dims=['frame'], unit='counts', values=[4, 5]) + data = snx.create_class(h5root, 'data1', NXdata) + data.attrs['axes'] = signal.dims + data.attrs['signal'] = 'signal' + data.attrs['auxiliary_signals'] = ['frame_total'] + snx.create_field(data, 'signal', signal) + snx.create_field(data, 'frame_total', frame_total) + + loaded = snx.Group(data, definitions=snx.base_definitions())[...] + + assert isinstance(loaded, sc.DataGroup) + assert_identical(loaded['signal'], sc.DataArray(signal)) + assert_identical( + loaded['frame_total'], + sc.array(dims=['dim_0'], unit='counts', values=[4, 5]), + ) + + def test_NXlog_data_is_loaded_as_time_dependent_data_array(nxroot) -> None: da = sc.DataArray( data=sc.array(dims=['time'], unit='K', values=[1, 2, 3]),