Skip to content

Conversation

@nvaytet
Copy link
Member

@nvaytet nvaytet commented Nov 11, 2025

Example (from the tests):

class UserAffiliation(sl.Scope[RunType, str], str):
    """User affiliation."""

def load_user_affiliation(
    file: NeXusFileSpec[RunType],
    path: NeXusName[UserAffiliation[RunType]],
) -> UserAffiliation[RunType]:
    return UserAffiliation[RunType](load_field(file, path))

wf = GenericNeXusWorkflow(run_types=[SampleRun], monitor_types=[])
wf.insert(load_user_affiliation)
wf[Filename[SampleRun]] = loki_tutorial_sample_run_60250
wf[NeXusName[UserAffiliation[SampleRun]]] = '/entry/user_0/affiliation'
affiliation = wf.compute(UserAffiliation[SampleRun])
assert affiliation == 'ESS'

location: NeXusComponentLocationSpec[UserAffiliation, RunType],
) -> UserAffiliation[RunType]:
return UserAffiliation[RunType](
load_component(location, nx_class=snx.NXuser)['affiliation']
Copy link
Member Author

@nvaytet nvaytet Nov 11, 2025

Choose a reason for hiding this comment

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

I could not figure out how to just have load_component(location, nx_class=None) and (below) wf[NeXusName[UserAffiliation]] = '/entry/user_0/affiliation'...

I'm running into the error ValueError: Expected a NeXus group as item '/entry/title' but got a field.
Help welcome!

Copy link
Member

Choose a reason for hiding this comment

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

I am not sure I understand the approach at all: If we anyway add a custom "load" provider, why was the generic NeXus workflow modified? What role does it still play? Is it the location-spec mechanism?

Regarding the error, could it be related that load_component looks only within NXinstrument (except for the sample)? Is there some search logic that needs to be generalized?

Copy link
Member Author

Choose a reason for hiding this comment

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

Is it the location-spec mechanism

Yes, I thought we needed to do things this way to re-use the load_component properly.
If there is a less invasive way to just add a provider and not modify the generic workflow, then it would be great if you can show me?
thanks

Copy link
Member

Choose a reason for hiding this comment

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

No that's fine... provided we can actually re-use load_component?

Copy link
Member Author

Choose a reason for hiding this comment

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

Regarding the error, could it be related that load_component looks only within NXinstrument (except for the sample)?

Sorry, the error message was confusing. I copied the wrong message (from a previous iteration).
The error is actually
ValueError: Expected a NeXus group as item '/entry/user_0/affiliation' but got a field.

So it is because load_component expects to load a group and not a field.

Copy link
Member

Choose a reason for hiding this comment

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

load_component was made for any "physical component" (it handles positions, etc.). Say maybe it is reasonable and by design that it fails? Which brings us back to the question of what you gain by trying to uses the existing machinery instead of having a simple load provider?

Copy link
Member Author

Choose a reason for hiding this comment

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

I really don't mind either way, I could not figure out how to properly just add a simple load provider which would hook into the part of the workflow that opens the file for reading.

I thought that using the Filename[SampleRun] as input to the provider would mean we open the file multiple times, and I wanted to avoid that.
So I would welcome some pointers as to what the provider would take in as input so it can load a custom field. Thanks in advance 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Why not use the same inputs that load_component does, but in a reusable provider (load_field or load_group?)?

def LoadDetectorWorkflow(
*,
run_types: Iterable[sciline.typing.Key],
monitor_types: Iterable[sciline.typing.Key],
Copy link
Member Author

@nvaytet nvaytet Nov 11, 2025

Choose a reason for hiding this comment

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

Not sure why we needed to have the monitor_types here, when we are loading detectors?
So I removed it.

@nvaytet nvaytet marked this pull request as draft November 14, 2025 12:02
@nvaytet nvaytet changed the title Add component types contraints to allow loading custom component in a nexus file Add load_field and load_group to make it simpler to load custom entries using GenericNeXusWorkflow Nov 14, 2025
def load_field(
filename: NeXusFileSpec,
field_path: str,
selection: snx.typing.ScippIndex | slice = (),
Copy link
Member Author

Choose a reason for hiding this comment

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

I decided to add the selection as an arg here instead of going the NeXusComponentLocationSpec way as it would have required creating a new TypeVar which was not only for Component, and then creating new types like NeXusEntryLocationSpec and also some new

def entry_spec_by_name(
    filename: NeXusFileSpec[RunType], name: NeXusName[EntryTypeVar]
) -> NeXusEntryLocationSpec[EntryTypeVar, RunType]:

(the analog to component_spec_by_name: https://github.com/scipp/essreduce/blob/main/src/ess/reduce/nexus/workflow.py#L89).

The current approach is less invasive.
But I don't mind implementing the above if there would be a use for it?

Right now, since the load_field would be called inside a custom providers, and selection parameters could simple be added to that provider, e.g.

def load_custom_entry(
    file: NeXusFileSpec[RunType],
    path: NeXusName[MyEntry[RunType]],
    start: MyEntryRangeStart[RunType],
    end: MyEntryRangeEnd[RunType]
) -> MyEntry[RunType]:
    return MyEntry[RunType](load_field(file, path, selection=slice(start, end)))

Not sure what other cases could be needed?

@nvaytet nvaytet marked this pull request as ready for review November 14, 2025 14:53
@nvaytet nvaytet changed the title Add load_field and load_group to make it simpler to load custom entries using GenericNeXusWorkflow Add load_field and load_group to allow loading custom entries using GenericNeXusWorkflow Nov 14, 2025
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.

3 participants