Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workflow widget interface #171

Merged
merged 11 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/user-guide/loki/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ maxdepth: 1

loki-direct-beam
loki-iofq
workflow-widget-loki
```
132 changes: 132 additions & 0 deletions docs/user-guide/loki/workflow-widget-loki.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "0",
"metadata": {},
"source": [
"# Workflow widgets example\n",
"\n",
"This notebook illustrates how we can use `essreduce`'s [workflow widgets](https://scipp.github.io/essreduce/user-guide/widget.html)\n",
"to generate a graphical interface for running the LoKI tutorial workflow.\n",
"\n",
"## Initializing the GUI\n",
"\n",
"It is as simple as importing the loki submodule and generating a GUI using `workflow_widget`\n",
"(the workflow automatically registers itself to a library of workflows when imported)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1",
"metadata": {},
"outputs": [],
"source": [
"# Import loki submodule to register workflow\n",
"from ess import loki # noqa: F401\n",
"from ess.reduce import ui\n",
"\n",
"# Prepare a container for accessing the results computed by the GUI\n",
"results = {}\n",
"\n",
"# Initialize the GUI widget\n",
"widget = ui.workflow_widget(result_registry=results)\n",
"widget"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2",
"metadata": {
"nbsphinx": "hidden"
},
"outputs": [],
"source": [
"from ess.sans.types import DirectBeam, QBins\n",
"\n",
"select = widget.children[0].children[0]\n",
"keys, values = zip(*select.options, strict=True)\n",
"ind = keys.index(\"LokiAtLarmorTutorialWorkflow\")\n",
"select.value = values[ind]\n",
"# Select IofQ[SampleRun] output\n",
"wfw = widget.children[1].children[0]\n",
"outputs = wfw.output_selection_box.typical_outputs_widget\n",
"keys, values = zip(*outputs.options, strict=True)\n",
"ind = keys.index(\"IofQ[SampleRun]\")\n",
"outputs.value = (values[ind],)\n",
"# Refresh parameters\n",
"pbox = wfw.parameter_box\n",
"pbox.parameter_refresh_button.click()\n",
"# Enable DirectBeam input\n",
"pbox._input_widgets[DirectBeam].children[0].enabled = True\n",
"pbox._input_widgets[DirectBeam].children[0].wrapped._option_box.value = None\n",
"# Adjust Q range\n",
"pbox._input_widgets[QBins].children[0].fields[\"start\"].value = 0.01\n",
"# Run the workflow\n",
"rbox = wfw.result_box\n",
"rbox.run_button.click()"
]
},
{
"cell_type": "markdown",
"id": "3",
"metadata": {},
"source": [
"## Accessing the results\n",
"\n",
"We can now access the computed result in the `results` dictionary:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4",
"metadata": {},
"outputs": [],
"source": [
"results"
]
},
{
"cell_type": "markdown",
"id": "5",
"metadata": {},
"source": [
"The result can be plotted using"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6",
"metadata": {},
"outputs": [],
"source": [
"(da,) = results.values()\n",
"da.plot(norm=\"log\")"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
5 changes: 5 additions & 0 deletions src/ess/isissans/sans2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
import scipp as sc

from ess.reduce.nexus.workflow import GenericNeXusWorkflow
from ess.reduce.workflow import register_workflow
from ess.sans import providers as sans_providers
from ess.sans.parameters import typical_outputs
from ess.sans.types import BeamCenter, CalibratedDetector, DetectorMasks, SampleRun

from .general import default_parameters
Expand Down Expand Up @@ -82,6 +84,7 @@ def to_detector_masks(
providers = (detector_edge_mask, sample_holder_mask, to_detector_masks)


@register_workflow
def Sans2dWorkflow() -> sciline.Pipeline:
"""Create Sans2d workflow with default parameters."""
from . import providers as isis_providers
Expand All @@ -93,9 +96,11 @@ def Sans2dWorkflow() -> sciline.Pipeline:
workflow.insert(provider)
for key, param in default_parameters().items():
workflow[key] = param
workflow.typical_outputs = typical_outputs
return workflow


@register_workflow
def Sans2dTutorialWorkflow() -> sciline.Pipeline:
"""
Create Sans2d tutorial workflow.
Expand Down
5 changes: 5 additions & 0 deletions src/ess/isissans/zoom.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import sciline

from ess.reduce.nexus.workflow import GenericNeXusWorkflow
from ess.reduce.workflow import register_workflow
from ess.sans import providers as sans_providers
from ess.sans.io import read_xml_detector_masking
from ess.sans.parameters import typical_outputs

from .general import default_parameters
from .io import load_tutorial_direct_beam, load_tutorial_run
Expand All @@ -21,6 +23,7 @@ def set_mantid_log_level(level: int = 3):
pass


@register_workflow
def ZoomWorkflow() -> sciline.Pipeline:
"""Create Zoom workflow with default parameters."""
from . import providers as isis_providers
Expand All @@ -35,9 +38,11 @@ def ZoomWorkflow() -> sciline.Pipeline:
for key, param in default_parameters().items():
workflow[key] = param
workflow.insert(read_xml_detector_masking)
workflow.typical_outputs = typical_outputs
return workflow


@register_workflow
def ZoomTutorialWorkflow() -> sciline.Pipeline:
"""
Create Zoom tutorial workflow.
Expand Down
38 changes: 38 additions & 0 deletions src/ess/loki/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
import sciline
import scipp as sc

from ess import sans
from ess.reduce.nexus.workflow import GenericNeXusWorkflow
from ess.reduce.workflow import register_workflow
from ess.sans import providers as sans_providers
from ess.sans.io import read_xml_detector_masking
from ess.sans.parameters import typical_outputs

from ..sans.types import (
CorrectForGravity,
Expand Down Expand Up @@ -104,6 +107,7 @@ def load_direct_beam(filename: DirectBeamFilename) -> DirectBeam:
)


@register_workflow
def LokiAtLarmorWorkflow() -> sciline.Pipeline:
"""
Workflow with default parameters for Loki test at Larmor.
Expand All @@ -124,4 +128,38 @@ def LokiAtLarmorWorkflow() -> sciline.Pipeline:
for key, param in default_parameters().items():
workflow[key] = param
workflow.insert(read_xml_detector_masking)
workflow[sans.types.NeXusDetectorName] = 'larmor_detector'
workflow.typical_outputs = typical_outputs
return workflow


@register_workflow
def LokiAtLarmorTutorialWorkflow() -> sciline.Pipeline:
from ess.loki import data

workflow = LokiAtLarmorWorkflow()
workflow[sans.types.Filename[sans.types.SampleRun]] = (
data.loki_tutorial_sample_run_60339()
)
# TODO This does not work with multiple
workflow[sans.types.PixelMaskFilename] = data.loki_tutorial_mask_filenames()[0]

workflow[sans.types.Filename[sans.types.SampleRun]] = (
data.loki_tutorial_sample_run_60339()
)
workflow[sans.types.Filename[sans.types.BackgroundRun]] = (
data.loki_tutorial_background_run_60393()
)
workflow[sans.types.Filename[sans.types.TransmissionRun[sans.types.SampleRun]]] = (
data.loki_tutorial_sample_transmission_run()
)
workflow[
sans.types.Filename[sans.types.TransmissionRun[sans.types.BackgroundRun]]
] = data.loki_tutorial_run_60392()
workflow[sans.types.Filename[sans.types.EmptyBeamRun]] = (
data.loki_tutorial_run_60392()
)
workflow[sans.types.BeamCenter] = sc.vector(
value=[-0.02914868, -0.01816138, 0.0], unit='m'
)
return workflow
129 changes: 129 additions & 0 deletions src/ess/sans/parameters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2024 Scipp contributors (https://github.com/scipp)
"""
Default parameters, providers and utility functions for the loki workflow.
"""

from __future__ import annotations

import scipp as sc

from ess.reduce.parameter import (
BinEdgesParameter,
BooleanParameter,
FilenameParameter,
MultiFilenameParameter,
ParamWithOptions,
StringParameter,
Vector2dParameter,
parameter_registry,
)

from ..sans.types import (
BackgroundRun,
BackgroundSubtractedIofQ,
BackgroundSubtractedIofQxy,
BeamCenter,
CorrectForGravity,
DirectBeam,
DirectBeamFilename,
EmptyBeamRun,
Filename,
Incident,
IofQ,
IofQxy,
MaskedData,
NeXusDetectorName,
NeXusMonitorName,
PixelMaskFilename,
PixelShapePath,
QBins,
QxBins,
QyBins,
ReturnEvents,
SampleRun,
TransformationPath,
Transmission,
TransmissionRun,
UncertaintyBroadcastMode,
WavelengthBins,
WavelengthMonitor,
)

parameter_registry[CorrectForGravity] = BooleanParameter.from_type(
CorrectForGravity, default=False
)
parameter_registry[NeXusDetectorName] = StringParameter.from_type(NeXusDetectorName)
parameter_registry[NeXusMonitorName[Incident]] = StringParameter.from_type(
NeXusMonitorName[Incident], default=''
)
parameter_registry[NeXusMonitorName[Transmission]] = StringParameter.from_type(
NeXusMonitorName[Transmission], default=''
)
parameter_registry[TransformationPath] = StringParameter.from_type(
TransformationPath, default=''
)
parameter_registry[PixelMaskFilename] = MultiFilenameParameter.from_type(
PixelMaskFilename
)
parameter_registry[PixelShapePath] = StringParameter.from_type(
PixelShapePath, default=''
)
# Should this be ReductionMode (EventMode/HistogramMode)?
parameter_registry[ReturnEvents] = BooleanParameter.from_type(
ReturnEvents, default=False
)
parameter_registry[UncertaintyBroadcastMode] = ParamWithOptions.from_enum(
UncertaintyBroadcastMode, default=UncertaintyBroadcastMode.upper_bound
)
parameter_registry[Filename[SampleRun]] = FilenameParameter.from_type(
Filename[SampleRun]
)
parameter_registry[Filename[BackgroundRun]] = FilenameParameter.from_type(
Filename[BackgroundRun]
)
parameter_registry[Filename[TransmissionRun[SampleRun]]] = FilenameParameter.from_type(
Filename[TransmissionRun[SampleRun]]
)
parameter_registry[Filename[TransmissionRun[BackgroundRun]]] = (
FilenameParameter.from_type(Filename[TransmissionRun[BackgroundRun]])
)
parameter_registry[Filename[EmptyBeamRun]] = FilenameParameter.from_type(
Filename[EmptyBeamRun]
)
parameter_registry[WavelengthBins] = BinEdgesParameter(
WavelengthBins, dim='wavelength', start=2, stop=12.0, nbins=300, log=False
)
parameter_registry[QBins] = BinEdgesParameter(
QBins, dim='Q', start=0.1, stop=0.3, nbins=100, log=False
)
parameter_registry[QxBins] = BinEdgesParameter(
QxBins, dim='Qx', start=-0.5, stop=0.5, nbins=100
)
parameter_registry[QyBins] = BinEdgesParameter(
QyBins, dim='Qy', start=-0.5, stop=0.5, nbins=100
)
parameter_registry[DirectBeam] = StringParameter.from_type(
DirectBeam, switchable=True, optional=True, default=None
)
parameter_registry[DirectBeamFilename] = FilenameParameter.from_type(
DirectBeamFilename, switchable=True
)
parameter_registry[BeamCenter] = Vector2dParameter.from_type(
BeamCenter, default=sc.vector([0, 0, 0], unit='m')
)

typical_outputs = (
BackgroundSubtractedIofQ,
BackgroundSubtractedIofQxy,
IofQ[SampleRun],
IofQxy[SampleRun],
IofQ[BackgroundRun],
IofQxy[BackgroundRun],
MaskedData[BackgroundRun],
MaskedData[SampleRun],
WavelengthMonitor[SampleRun, Incident],
WavelengthMonitor[SampleRun, Transmission],
WavelengthMonitor[BackgroundRun, Incident],
WavelengthMonitor[BackgroundRun, Transmission],
)
Loading