Skip to content

Load NXdata auxiliary signals with distinct dimensions - #306

Open
CAOShurong wants to merge 1 commit into
scipp:mainfrom
CAOShurong:codex/304-aux-signals-different-dims
Open

CAOShurong wants to merge 1 commit into
scipp:mainfrom
CAOShurong:codex/304-aux-signals-different-dims

Conversation

@CAOShurong

Copy link
Copy Markdown

Summary

  • keep NXdata valid when an auxiliary signal has dimensions unrelated to the primary signal
  • return a scipp.DataGroup when those signals cannot share a scipp.Dataset
  • preserve the existing Dataset result for dimension-compatible auxiliary signals

Why

NeXus permits auxiliary signals such as ESS frame_total to use dimensions that are unrelated to the primary signal. ScippNexus currently marks the whole NXdata invalid when it cannot infer the auxiliary signal's dimensions from the primary signal. Loading then emits a fallback warning and returns raw fields, so the primary signal also loses its assembled DataArray semantics.

The new path keeps the auxiliary field's fallback dimensions and only falls back from Dataset to DataGroup when Scipp rejects the mixed dimensionality. The primary signal is still assembled as a DataArray, including its coordinates, while auxiliary signals remain independently accessible.

Fixes #304.

Validation

  • new regression is RED on main with the fallback warning and a raw Variable primary signal
  • focused auxiliary-signal cases: 2 passed
  • complete NXdata module: 89 passed
  • full suite: 336 passed, 3 skipped
  • Mypy: no issues in 10 source files
  • all changed-file pre-commit hooks
  • sdist and wheel built from commit eaf7f84a
  • clean Python 3.13 wheel install: different-dimension signals load as DataGroup, compatible signals remain a Dataset, no warning is emitted, and pip check passes

This pull request was developed with OpenAI Codex assistance; I reviewed the implementation and validation results.

Keep NXdata valid when an auxiliary signal uses dimensions unrelated to the primary signal, and fall back from Dataset to DataGroup while preserving assembled signal semantics. Add a focused regression for the ESS frame-total layout. Developed with OpenAI Codex assistance.

@SimonHeybrock SimonHeybrock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for picking this up, and for the thorough validation notes.

However, I think we should probably close this PR for now. The main reason is that #304 has not settled on an approach yet. The issue lists three options, and the discussion so far leans towards not changing the default loader at all: filter auxiliary signals with an application definition instead, defined downstream. essreduce already does this as a workaround (it drops frame_total and reference_time via a custom NXdata definition), so there is no urgent need for a change here.

The approach in this PR also has a drawback for users. The return type of loading an NXdata now depends on the shapes in the file: a Dataset if the auxiliary signals are compatible with the signal, a DataGroup otherwise. Code consuming the result then has to handle both. Maybe we should always returns a DataGroup, similar to what we decided to do for some other classes that had similar issues?

Apart from the design question, I found a few correctness problems, see the inline comments. If we decide on the DataGroup route in the issue, these would need to be addressed. We would be happy to continue there.

Comment thread src/scippnexus/nxdata.py
# len(dims).
shape = _squeeze_trailing(dims, field.dataset.shape)
field.sizes = dict(zip(dims, shape, strict=False))
elif name in self._aux_signals:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skipping the consistency check means the auxiliary signal keeps a generated dim label such as dim_0, and NXdata.sizes merges these into the group sizes. This can silently collide with the signal's dims. Example: signal with axes=['.'] (so its dim is dim_0, length 3) and frame_total with length 2:

  • group.sizes reports {'dim_0': 2}
  • group['dim_0', 2] raises IndexError, although it is a valid index for the signal
  • group['dim_0', 1] slices signal and frame_total with the same index, returning wrong data

On main this file is rejected with a fallback warning, which is the safer outcome.

Comment thread src/scippnexus/nxdata.py
return sc.Dataset(signals)
try:
return sc.Dataset(signals)
except sc.DimensionError:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Catching DimensionError here also hides genuine inconsistencies that are unrelated to "auxiliary signal on different dims", for example *_indices attributes that assign the same dim label with a different length. Previously these produced the fallback warning, now they load silently as a DataGroup.

Comment thread tests/nxdata_test.py
assert_identical(data[...], sc.Dataset({'signal': signal, 'xx': aux}))


def test_auxiliary_signal_with_different_dims_loads_as_data_group(h5root) -> None:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This covers a bare NXdata with only frame_total. Two cases from the issue are not covered:

  • The group also contains a non-signal field on the frame dimension, such as reference_time (essreduce drops it for the same reason). With this PR such a group is still marked invalid and falls back with a warning, so the ESS monitor case would likely still fail.
  • An NXmonitor, which goes through _assemble_as_physical_component rather than _assemble_as_data.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Load NXdata with auxiliary signals with different dims

2 participants