essreduce 24.11.1__py3-none-any.whl → 24.11.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ess/reduce/__init__.py +1 -1
- ess/reduce/data.py +20 -6
- ess/reduce/nexus/__init__.py +2 -0
- ess/reduce/nexus/_nexus_loader.py +53 -14
- ess/reduce/nexus/types.py +45 -4
- ess/reduce/nexus/workflow.py +76 -1
- ess/reduce/parameter.py +5 -0
- ess/reduce/widgets/__init__.py +25 -22
- ess/reduce/widgets/_filename_widget.py +10 -0
- ess/reduce/widgets/_string_widget.py +39 -0
- ess/reduce/workflow.py +1 -4
- {essreduce-24.11.1.dist-info → essreduce-24.11.3.dist-info}/METADATA +9 -7
- {essreduce-24.11.1.dist-info → essreduce-24.11.3.dist-info}/RECORD +17 -15
- {essreduce-24.11.1.dist-info → essreduce-24.11.3.dist-info}/WHEEL +1 -1
- {essreduce-24.11.1.dist-info → essreduce-24.11.3.dist-info}/LICENSE +0 -0
- {essreduce-24.11.1.dist-info → essreduce-24.11.3.dist-info}/entry_points.txt +0 -0
- {essreduce-24.11.1.dist-info → essreduce-24.11.3.dist-info}/top_level.txt +0 -0
ess/reduce/__init__.py
CHANGED
|
@@ -7,7 +7,7 @@ import importlib.metadata
|
|
|
7
7
|
from . import nexus, uncertainty
|
|
8
8
|
|
|
9
9
|
try:
|
|
10
|
-
__version__ = importlib.metadata.version(
|
|
10
|
+
__version__ = importlib.metadata.version("essreduce")
|
|
11
11
|
except importlib.metadata.PackageNotFoundError:
|
|
12
12
|
__version__ = "0.0.0"
|
|
13
13
|
|
ess/reduce/data.py
CHANGED
|
@@ -31,7 +31,16 @@ class Registry:
|
|
|
31
31
|
return self._registry.fetch(name, processor=pooch.Unzip() if unzip else None)
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
_bifrost_registry = Registry(
|
|
35
|
+
instrument='bifrost',
|
|
36
|
+
files={
|
|
37
|
+
"BIFROST_20240914T053723.h5": "md5:0f2fa5c9a851f8e3a4fa61defaa3752e",
|
|
38
|
+
},
|
|
39
|
+
version='1',
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
_loki_registry = Registry(
|
|
35
44
|
instrument='loki',
|
|
36
45
|
files={
|
|
37
46
|
# Files from LoKI@Larmor detector test experiment
|
|
@@ -57,26 +66,31 @@ _registry = Registry(
|
|
|
57
66
|
)
|
|
58
67
|
|
|
59
68
|
|
|
69
|
+
def bifrost_simulated_elastic() -> str:
|
|
70
|
+
"""McStas simulation with elastic incoherent scattering + phonon."""
|
|
71
|
+
return _bifrost_registry.get_path('BIFROST_20240914T053723.h5')
|
|
72
|
+
|
|
73
|
+
|
|
60
74
|
def loki_tutorial_sample_run_60250() -> str:
|
|
61
75
|
"""Sample run with sample and sample holder/can, no transmission monitor in beam."""
|
|
62
|
-
return
|
|
76
|
+
return _loki_registry.get_path('60250-2022-02-28_2215.nxs')
|
|
63
77
|
|
|
64
78
|
|
|
65
79
|
def loki_tutorial_sample_run_60339() -> str:
|
|
66
80
|
"""Sample run with sample and sample holder/can, no transmission monitor in beam."""
|
|
67
|
-
return
|
|
81
|
+
return _loki_registry.get_path('60339-2022-02-28_2215.nxs')
|
|
68
82
|
|
|
69
83
|
|
|
70
84
|
def loki_tutorial_background_run_60248() -> str:
|
|
71
85
|
"""Background run with sample holder/can only, no transmission monitor."""
|
|
72
|
-
return
|
|
86
|
+
return _loki_registry.get_path('60248-2022-02-28_2215.nxs')
|
|
73
87
|
|
|
74
88
|
|
|
75
89
|
def loki_tutorial_background_run_60393() -> str:
|
|
76
90
|
"""Background run with sample holder/can only, no transmission monitor."""
|
|
77
|
-
return
|
|
91
|
+
return _loki_registry.get_path('60393-2022-02-28_2215.nxs')
|
|
78
92
|
|
|
79
93
|
|
|
80
94
|
def loki_tutorial_sample_transmission_run() -> str:
|
|
81
95
|
"""Sample transmission run (sample + sample holder/can + transmission monitor)."""
|
|
82
|
-
return
|
|
96
|
+
return _loki_registry.get_path('60394-2022-02-28_2215.nxs')
|
ess/reduce/nexus/__init__.py
CHANGED
|
@@ -18,6 +18,7 @@ from ._nexus_loader import (
|
|
|
18
18
|
load_data,
|
|
19
19
|
group_event_data,
|
|
20
20
|
load_component,
|
|
21
|
+
load_all_components,
|
|
21
22
|
compute_component_position,
|
|
22
23
|
extract_signal_data_array,
|
|
23
24
|
)
|
|
@@ -25,6 +26,7 @@ from ._nexus_loader import (
|
|
|
25
26
|
__all__ = [
|
|
26
27
|
'types',
|
|
27
28
|
'group_event_data',
|
|
29
|
+
'load_all_components',
|
|
28
30
|
'load_data',
|
|
29
31
|
'load_component',
|
|
30
32
|
'compute_component_position',
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
"""NeXus loaders."""
|
|
5
5
|
|
|
6
|
-
from collections.abc import Mapping
|
|
7
|
-
from contextlib import AbstractContextManager, nullcontext
|
|
6
|
+
from collections.abc import Generator, Mapping
|
|
7
|
+
from contextlib import AbstractContextManager, contextmanager, nullcontext
|
|
8
8
|
from dataclasses import dataclass
|
|
9
9
|
from math import prod
|
|
10
10
|
from typing import cast
|
|
@@ -13,7 +13,14 @@ import scipp as sc
|
|
|
13
13
|
import scippnexus as snx
|
|
14
14
|
|
|
15
15
|
from ..logging import get_logger
|
|
16
|
-
from .types import
|
|
16
|
+
from .types import (
|
|
17
|
+
FilePath,
|
|
18
|
+
NeXusAllLocationSpec,
|
|
19
|
+
NeXusEntryName,
|
|
20
|
+
NeXusFile,
|
|
21
|
+
NeXusGroup,
|
|
22
|
+
NeXusLocationSpec,
|
|
23
|
+
)
|
|
17
24
|
|
|
18
25
|
|
|
19
26
|
class NoNewDefinitionsType: ...
|
|
@@ -28,22 +35,36 @@ def load_component(
|
|
|
28
35
|
nx_class: type[snx.NXobject],
|
|
29
36
|
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
30
37
|
) -> sc.DataGroup:
|
|
31
|
-
|
|
38
|
+
"""Load a single component of a given class from NeXus."""
|
|
32
39
|
selection = location.selection
|
|
33
|
-
entry_name = location.entry_name
|
|
34
40
|
group_name = location.component_name
|
|
35
|
-
with
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
else:
|
|
40
|
-
instrument = _unique_child_group(entry, snx.NXinstrument, None)
|
|
41
|
-
component = _unique_child_group(instrument, nx_class, group_name)
|
|
41
|
+
with _open_component_parent(
|
|
42
|
+
location, nx_class=nx_class, definitions=definitions
|
|
43
|
+
) as parent:
|
|
44
|
+
component = _unique_child_group(parent, nx_class, group_name)
|
|
42
45
|
loaded = cast(sc.DataGroup, component[selection])
|
|
43
|
-
loaded['nexus_component_name'] = component.name.
|
|
46
|
+
loaded['nexus_component_name'] = component.name.rsplit('/', 1)[-1]
|
|
44
47
|
return loaded
|
|
45
48
|
|
|
46
49
|
|
|
50
|
+
def load_all_components(
|
|
51
|
+
location: NeXusAllLocationSpec,
|
|
52
|
+
*,
|
|
53
|
+
nx_class: type[snx.NXobject],
|
|
54
|
+
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
55
|
+
) -> sc.DataGroup:
|
|
56
|
+
"""Load all components of a given class from NeXus."""
|
|
57
|
+
with _open_component_parent(
|
|
58
|
+
location, nx_class=nx_class, definitions=definitions
|
|
59
|
+
) as parent:
|
|
60
|
+
components = sc.DataGroup()
|
|
61
|
+
for name, component in parent[nx_class].items():
|
|
62
|
+
loaded = component[location.selection]
|
|
63
|
+
loaded['nexus_component_name'] = name
|
|
64
|
+
components[name] = loaded
|
|
65
|
+
return components
|
|
66
|
+
|
|
67
|
+
|
|
47
68
|
def compute_component_position(dg: sc.DataGroup) -> sc.DataGroup:
|
|
48
69
|
# In some downstream packages we use some of the Nexus components which attempt
|
|
49
70
|
# to compute positions without having actual Nexus data defining depends_on chains.
|
|
@@ -70,7 +91,7 @@ def compute_component_position(dg: sc.DataGroup) -> sc.DataGroup:
|
|
|
70
91
|
def _open_nexus_file(
|
|
71
92
|
file_path: FilePath | NeXusFile | NeXusGroup,
|
|
72
93
|
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
73
|
-
) -> AbstractContextManager:
|
|
94
|
+
) -> AbstractContextManager[snx.Group]:
|
|
74
95
|
if isinstance(file_path, getattr(NeXusGroup, '__supertype__', type(None))):
|
|
75
96
|
if (
|
|
76
97
|
definitions is not NoNewDefinitions
|
|
@@ -85,6 +106,24 @@ def _open_nexus_file(
|
|
|
85
106
|
return snx.File(file_path, definitions=definitions)
|
|
86
107
|
|
|
87
108
|
|
|
109
|
+
@contextmanager
|
|
110
|
+
def _open_component_parent(
|
|
111
|
+
location: NeXusLocationSpec,
|
|
112
|
+
*,
|
|
113
|
+
nx_class: type[snx.NXobject],
|
|
114
|
+
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
115
|
+
) -> Generator[snx.Group, None, None]:
|
|
116
|
+
"""Locate the parent group of a NeXus component."""
|
|
117
|
+
file_path = location.filename
|
|
118
|
+
entry_name = location.entry_name
|
|
119
|
+
with _open_nexus_file(file_path, definitions=definitions) as f:
|
|
120
|
+
entry = _unique_child_group(f, snx.NXentry, entry_name)
|
|
121
|
+
if nx_class is snx.NXsample:
|
|
122
|
+
yield entry
|
|
123
|
+
else:
|
|
124
|
+
yield _unique_child_group(entry, snx.NXinstrument, None)
|
|
125
|
+
|
|
126
|
+
|
|
88
127
|
def _unique_child_group(
|
|
89
128
|
group: snx.Group, nx_class: type[snx.NXobject], name: str | None
|
|
90
129
|
) -> snx.Group:
|
ess/reduce/nexus/types.py
CHANGED
|
@@ -91,6 +91,8 @@ Monitor4 = NewType('Monitor4', int)
|
|
|
91
91
|
"""Identifier for an arbitrary monitor"""
|
|
92
92
|
Monitor5 = NewType('Monitor5', int)
|
|
93
93
|
"""Identifier for an arbitrary monitor"""
|
|
94
|
+
Monitor6 = NewType('Monitor6', int)
|
|
95
|
+
"""Identifier for an arbitrary monitor"""
|
|
94
96
|
IncidentMonitor = NewType('IncidentMonitor', int)
|
|
95
97
|
"""Incident monitor"""
|
|
96
98
|
TransmissionMonitor = NewType('TransmissionMonitor', int)
|
|
@@ -102,6 +104,7 @@ MonitorType = TypeVar(
|
|
|
102
104
|
Monitor3,
|
|
103
105
|
Monitor4,
|
|
104
106
|
Monitor5,
|
|
107
|
+
Monitor6,
|
|
105
108
|
IncidentMonitor,
|
|
106
109
|
TransmissionMonitor,
|
|
107
110
|
)
|
|
@@ -112,11 +115,14 @@ Component = TypeVar(
|
|
|
112
115
|
snx.NXdetector,
|
|
113
116
|
snx.NXsample,
|
|
114
117
|
snx.NXsource,
|
|
118
|
+
snx.NXdisk_chopper,
|
|
119
|
+
snx.NXcrystal,
|
|
115
120
|
Monitor1,
|
|
116
121
|
Monitor2,
|
|
117
122
|
Monitor3,
|
|
118
123
|
Monitor4,
|
|
119
124
|
Monitor5,
|
|
125
|
+
Monitor6,
|
|
120
126
|
IncidentMonitor,
|
|
121
127
|
TransmissionMonitor,
|
|
122
128
|
)
|
|
@@ -128,7 +134,7 @@ class NeXusName(sciline.Scope[Component, str], str):
|
|
|
128
134
|
"""Name of a component in a NeXus file."""
|
|
129
135
|
|
|
130
136
|
|
|
131
|
-
class NeXusClass(sciline.Scope[Component,
|
|
137
|
+
class NeXusClass(sciline.Scope[Component, type], type):
|
|
132
138
|
"""NX_class of a component in a NeXus file."""
|
|
133
139
|
|
|
134
140
|
|
|
@@ -142,6 +148,12 @@ class NeXusComponent(
|
|
|
142
148
|
"""Raw data from a NeXus component."""
|
|
143
149
|
|
|
144
150
|
|
|
151
|
+
class AllNeXusComponents(
|
|
152
|
+
sciline.ScopeTwoParams[Component, RunType, sc.DataGroup], sc.DataGroup
|
|
153
|
+
):
|
|
154
|
+
"""Raw data from all NeXus components of one class."""
|
|
155
|
+
|
|
156
|
+
|
|
145
157
|
class NeXusData(sciline.ScopeTwoParams[Component, RunType, sc.DataArray], sc.DataArray):
|
|
146
158
|
"""
|
|
147
159
|
Data array loaded from an NXevent_data or NXdata group.
|
|
@@ -223,11 +235,26 @@ class NeXusComponentLocationSpec(NeXusLocationSpec, Generic[Component, RunType])
|
|
|
223
235
|
|
|
224
236
|
|
|
225
237
|
@dataclass
|
|
226
|
-
class
|
|
227
|
-
"""
|
|
238
|
+
class NeXusAllLocationSpec:
|
|
239
|
+
"""
|
|
240
|
+
NeXus parameters to identify all components of a class to load.
|
|
241
|
+
"""
|
|
228
242
|
|
|
243
|
+
filename: FilePath | NeXusFile | NeXusGroup
|
|
244
|
+
entry_name: NeXusEntryName | None = None
|
|
245
|
+
selection: snx.typing.ScippIndex | slice = ()
|
|
229
246
|
|
|
230
|
-
|
|
247
|
+
|
|
248
|
+
@dataclass
|
|
249
|
+
class NeXusAllComponentLocationSpec(NeXusAllLocationSpec, Generic[Component, RunType]):
|
|
250
|
+
"""
|
|
251
|
+
NeXus parameters to identify all components of a class to load.
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@dataclass
|
|
256
|
+
class NeXusDataLocationSpec(NeXusLocationSpec, Generic[Component, RunType]):
|
|
257
|
+
"""NeXus filename and parameters to identify (parts of) detector data to load."""
|
|
231
258
|
|
|
232
259
|
|
|
233
260
|
class NeXusTransformationChain(
|
|
@@ -257,3 +284,17 @@ class NeXusTransformation(Generic[Component, RunType]):
|
|
|
257
284
|
raise ValueError(f"Expected scalar transformation, got {chain}")
|
|
258
285
|
transform = chain.compute()
|
|
259
286
|
return NeXusTransformation(value=transform)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class Choppers(
|
|
290
|
+
sciline.Scope[RunType, sc.DataGroup[sc.DataGroup[Any]]],
|
|
291
|
+
sc.DataGroup[sc.DataGroup[Any]],
|
|
292
|
+
):
|
|
293
|
+
"""All choppers in a NeXus file."""
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class Analyzers(
|
|
297
|
+
sciline.Scope[RunType, sc.DataGroup[sc.DataGroup[Any]]],
|
|
298
|
+
sc.DataGroup[sc.DataGroup[Any]],
|
|
299
|
+
):
|
|
300
|
+
"""All analyzers in a NeXus file."""
|
ess/reduce/nexus/workflow.py
CHANGED
|
@@ -13,12 +13,16 @@ import scipp as sc
|
|
|
13
13
|
import scippnexus as snx
|
|
14
14
|
from scipp.constants import g
|
|
15
15
|
from scipp.core import label_based_index_to_positional_index
|
|
16
|
+
from scippneutron.chopper import extract_chopper_from_nexus
|
|
16
17
|
|
|
17
18
|
from . import _nexus_loader as nexus
|
|
18
19
|
from .types import (
|
|
20
|
+
AllNeXusComponents,
|
|
21
|
+
Analyzers,
|
|
19
22
|
CalibratedBeamline,
|
|
20
23
|
CalibratedDetector,
|
|
21
24
|
CalibratedMonitor,
|
|
25
|
+
Choppers,
|
|
22
26
|
Component,
|
|
23
27
|
DetectorBankSizes,
|
|
24
28
|
DetectorData,
|
|
@@ -28,6 +32,7 @@ from .types import (
|
|
|
28
32
|
MonitorData,
|
|
29
33
|
MonitorPositionOffset,
|
|
30
34
|
MonitorType,
|
|
35
|
+
NeXusAllComponentLocationSpec,
|
|
31
36
|
NeXusClass,
|
|
32
37
|
NeXusComponent,
|
|
33
38
|
NeXusComponentLocationSpec,
|
|
@@ -96,6 +101,13 @@ def component_spec_by_name(
|
|
|
96
101
|
)
|
|
97
102
|
|
|
98
103
|
|
|
104
|
+
def all_component_spec(
|
|
105
|
+
filename: NeXusFileSpec[RunType],
|
|
106
|
+
) -> NeXusAllComponentLocationSpec[Component, RunType]:
|
|
107
|
+
"""Create a location spec for all components of a class in a NeXus file."""
|
|
108
|
+
return NeXusAllComponentLocationSpec[Component, RunType](filename=filename.value)
|
|
109
|
+
|
|
110
|
+
|
|
99
111
|
def unique_component_spec(
|
|
100
112
|
filename: NeXusFileSpec[RunType],
|
|
101
113
|
) -> NeXusComponentLocationSpec[UniqueComponent, RunType]:
|
|
@@ -173,6 +185,14 @@ def nx_class_for_sample() -> NeXusClass[snx.NXsample]:
|
|
|
173
185
|
return NeXusClass[snx.NXsample](snx.NXsample)
|
|
174
186
|
|
|
175
187
|
|
|
188
|
+
def nx_class_for_disk_chopper() -> NeXusClass[snx.NXdisk_chopper]:
|
|
189
|
+
return NeXusClass[snx.NXdisk_chopper](snx.NXdisk_chopper)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def nx_class_for_crystal() -> NeXusClass[snx.NXcrystal]:
|
|
193
|
+
return NeXusClass[snx.NXcrystal](snx.NXcrystal)
|
|
194
|
+
|
|
195
|
+
|
|
176
196
|
def load_nexus_component(
|
|
177
197
|
location: NeXusComponentLocationSpec[Component, RunType],
|
|
178
198
|
nx_class: NeXusClass[Component],
|
|
@@ -206,6 +226,27 @@ def load_nexus_component(
|
|
|
206
226
|
)
|
|
207
227
|
|
|
208
228
|
|
|
229
|
+
def load_all_nexus_components(
|
|
230
|
+
location: NeXusAllComponentLocationSpec[Component, RunType],
|
|
231
|
+
nx_class: NeXusClass[Component],
|
|
232
|
+
) -> AllNeXusComponents[Component, RunType]:
|
|
233
|
+
"""
|
|
234
|
+
Load all NeXus components of one class from one entry a file.
|
|
235
|
+
|
|
236
|
+
This is equivalent to calling :func:`load_nexus_component` for every component.
|
|
237
|
+
|
|
238
|
+
Parameters
|
|
239
|
+
----------
|
|
240
|
+
location:
|
|
241
|
+
Location spec for the source group.
|
|
242
|
+
nx_class:
|
|
243
|
+
NX_class to identify the components.
|
|
244
|
+
"""
|
|
245
|
+
return AllNeXusComponents[Component, RunType](
|
|
246
|
+
nexus.load_all_components(location, nx_class=nx_class, definitions=definitions)
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
|
|
209
250
|
def load_nexus_data(
|
|
210
251
|
location: NeXusDataLocationSpec[Component, RunType],
|
|
211
252
|
) -> NeXusData[Component, RunType]:
|
|
@@ -465,6 +506,26 @@ def assemble_monitor_data(
|
|
|
465
506
|
return MonitorData[RunType, MonitorType](_add_variances(da))
|
|
466
507
|
|
|
467
508
|
|
|
509
|
+
def parse_disk_choppers(
|
|
510
|
+
choppers: AllNeXusComponents[snx.NXdisk_chopper, RunType],
|
|
511
|
+
) -> Choppers[RunType]:
|
|
512
|
+
"""Convert the NeXus representation of a chopper to ours."""
|
|
513
|
+
return Choppers[RunType](
|
|
514
|
+
choppers.apply(
|
|
515
|
+
lambda chopper: extract_chopper_from_nexus(
|
|
516
|
+
nexus.compute_component_position(chopper)
|
|
517
|
+
)
|
|
518
|
+
)
|
|
519
|
+
)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def parse_analyzers(
|
|
523
|
+
analyzers: AllNeXusComponents[snx.NXcrystal, RunType],
|
|
524
|
+
) -> Analyzers[RunType]:
|
|
525
|
+
"""Convert the NeXus representation of an analyzer to ours."""
|
|
526
|
+
return Analyzers[RunType](analyzers.apply(nexus.compute_component_position))
|
|
527
|
+
|
|
528
|
+
|
|
468
529
|
def _drop(
|
|
469
530
|
children: dict[str, snx.Field | snx.Group], classes: tuple[snx.NXobject, ...]
|
|
470
531
|
) -> dict[str, snx.Field | snx.Group]:
|
|
@@ -536,16 +597,20 @@ _common_providers = (
|
|
|
536
597
|
full_time_interval,
|
|
537
598
|
component_spec_by_name,
|
|
538
599
|
unique_component_spec, # after component_spec_by_name, partially overrides
|
|
600
|
+
all_component_spec,
|
|
539
601
|
get_transformation_chain,
|
|
540
602
|
to_transformation,
|
|
541
603
|
compute_position,
|
|
542
604
|
load_nexus_data,
|
|
543
605
|
load_nexus_component,
|
|
606
|
+
load_all_nexus_components,
|
|
544
607
|
data_by_name,
|
|
545
608
|
nx_class_for_detector,
|
|
546
609
|
nx_class_for_monitor,
|
|
547
610
|
nx_class_for_source,
|
|
548
611
|
nx_class_for_sample,
|
|
612
|
+
nx_class_for_disk_chopper,
|
|
613
|
+
nx_class_for_crystal,
|
|
549
614
|
)
|
|
550
615
|
|
|
551
616
|
_monitor_providers = (
|
|
@@ -562,6 +627,10 @@ _detector_providers = (
|
|
|
562
627
|
assemble_detector_data,
|
|
563
628
|
)
|
|
564
629
|
|
|
630
|
+
_chopper_providers = (parse_disk_choppers,)
|
|
631
|
+
|
|
632
|
+
_analyzer_providers = (parse_analyzers,)
|
|
633
|
+
|
|
565
634
|
|
|
566
635
|
def LoadMonitorWorkflow() -> sciline.Pipeline:
|
|
567
636
|
"""Generic workflow for loading monitor data from a NeXus file."""
|
|
@@ -605,7 +674,13 @@ def GenericNeXusWorkflow(
|
|
|
605
674
|
if monitor_types is not None and run_types is None:
|
|
606
675
|
raise ValueError("run_types must be specified if monitor_types is specified")
|
|
607
676
|
wf = sciline.Pipeline(
|
|
608
|
-
(
|
|
677
|
+
(
|
|
678
|
+
*_common_providers,
|
|
679
|
+
*_monitor_providers,
|
|
680
|
+
*_detector_providers,
|
|
681
|
+
*_chopper_providers,
|
|
682
|
+
*_analyzer_providers,
|
|
683
|
+
)
|
|
609
684
|
)
|
|
610
685
|
wf[DetectorBankSizes] = DetectorBankSizes({})
|
|
611
686
|
wf[PreopenNeXusFile] = PreopenNeXusFile(False)
|
ess/reduce/parameter.py
CHANGED
|
@@ -126,6 +126,11 @@ class StringParameter(Parameter[str]):
|
|
|
126
126
|
pass
|
|
127
127
|
|
|
128
128
|
|
|
129
|
+
@dataclass
|
|
130
|
+
class MultiStringParameter(Parameter[tuple[str, ...]]):
|
|
131
|
+
"""Widget for entering multiple strings."""
|
|
132
|
+
|
|
133
|
+
|
|
129
134
|
@dataclass(kw_only=True)
|
|
130
135
|
class ParamWithBounds(Parameter[T]):
|
|
131
136
|
bounds: tuple[T, T]
|
ess/reduce/widgets/__init__.py
CHANGED
|
@@ -10,6 +10,7 @@ from ..parameter import (
|
|
|
10
10
|
BooleanParameter,
|
|
11
11
|
FilenameParameter,
|
|
12
12
|
MultiFilenameParameter,
|
|
13
|
+
MultiStringParameter,
|
|
13
14
|
ParamWithOptions,
|
|
14
15
|
StringParameter,
|
|
15
16
|
Parameter,
|
|
@@ -21,9 +22,11 @@ from ..parameter import (
|
|
|
21
22
|
from ._config import default_layout, default_style
|
|
22
23
|
|
|
23
24
|
from ._binedges_widget import BinEdgesWidget
|
|
25
|
+
from ._filename_widget import FilenameWidget, MultiFilenameWidget
|
|
24
26
|
from ._linspace_widget import LinspaceWidget
|
|
25
27
|
from ._vector_widget import VectorWidget
|
|
26
28
|
from ._bounds_widget import BoundsWidget
|
|
29
|
+
from ._string_widget import MultiStringWidget, StringWidget
|
|
27
30
|
from ._switchable_widget import SwitchWidget
|
|
28
31
|
from ._optional_widget import OptionalWidget
|
|
29
32
|
|
|
@@ -33,7 +36,6 @@ class EssWidget(Protocol):
|
|
|
33
36
|
|
|
34
37
|
All widgets should have a `value` property that returns the value of the widget.
|
|
35
38
|
It can be composed from multiple widgets.
|
|
36
|
-
```
|
|
37
39
|
"""
|
|
38
40
|
|
|
39
41
|
@property
|
|
@@ -102,42 +104,41 @@ def boolean_parameter_widget(param: BooleanParameter):
|
|
|
102
104
|
|
|
103
105
|
@create_parameter_widget.register(StringParameter)
|
|
104
106
|
def string_parameter_widget(param: StringParameter):
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
)
|
|
107
|
+
return StringWidget(
|
|
108
|
+
description=param.name,
|
|
109
|
+
value=param.default,
|
|
110
|
+
layout=default_layout,
|
|
111
|
+
style=default_style,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
@create_parameter_widget.register(MultiStringParameter)
|
|
116
|
+
def multi_string_parameter_widget(param: MultiStringParameter):
|
|
117
|
+
return MultiStringWidget(
|
|
118
|
+
description=param.name,
|
|
119
|
+
value=param.default,
|
|
120
|
+
layout=default_layout,
|
|
121
|
+
style=default_style,
|
|
122
|
+
)
|
|
122
123
|
|
|
123
124
|
|
|
124
125
|
@create_parameter_widget.register(FilenameParameter)
|
|
125
126
|
def filename_parameter_widget(param: FilenameParameter):
|
|
126
|
-
return
|
|
127
|
+
return FilenameWidget(
|
|
127
128
|
description=param.name,
|
|
129
|
+
value=param.default,
|
|
128
130
|
layout=default_layout,
|
|
129
131
|
style=default_style,
|
|
130
|
-
value=param.default,
|
|
131
132
|
)
|
|
132
133
|
|
|
133
134
|
|
|
134
135
|
@create_parameter_widget.register(MultiFilenameParameter)
|
|
135
136
|
def multi_filename_parameter_widget(param: MultiFilenameParameter):
|
|
136
|
-
return
|
|
137
|
+
return MultiFilenameWidget(
|
|
137
138
|
description=param.name,
|
|
139
|
+
value=param.default,
|
|
138
140
|
layout=default_layout,
|
|
139
141
|
style=default_style,
|
|
140
|
-
value=param.default,
|
|
141
142
|
)
|
|
142
143
|
|
|
143
144
|
|
|
@@ -183,7 +184,9 @@ __all__ = [
|
|
|
183
184
|
'BinEdgesWidget',
|
|
184
185
|
'BoundsWidget',
|
|
185
186
|
'EssWidget',
|
|
187
|
+
'FilenameWidget',
|
|
186
188
|
'LinspaceWidget',
|
|
189
|
+
'MultiFilenameWidget',
|
|
187
190
|
'OptionalWidget',
|
|
188
191
|
'SwitchWidget',
|
|
189
192
|
'VectorWidget',
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
# Copyright (c) 2024 Scipp contributors (https://github.com/scipp)
|
|
3
|
+
|
|
4
|
+
from ._string_widget import MultiStringWidget, StringWidget
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FilenameWidget(StringWidget): ...
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MultiFilenameWidget(MultiStringWidget): ...
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# SPDX-License-Identifier: BSD-3-Clause
|
|
2
|
+
# Copyright (c) 2024 Scipp contributors (https://github.com/scipp)
|
|
3
|
+
from ipywidgets import HBox, Text, ValueWidget
|
|
4
|
+
|
|
5
|
+
from ._config import default_layout
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class StringWidget(HBox, ValueWidget):
|
|
9
|
+
def __init__(self, description: str, value: str | None = None, **kwargs):
|
|
10
|
+
super().__init__(layout=default_layout)
|
|
11
|
+
self.text_widget = Text(description=description, value=value, **kwargs)
|
|
12
|
+
self.children = [self.text_widget]
|
|
13
|
+
|
|
14
|
+
@property
|
|
15
|
+
def value(self) -> str | None:
|
|
16
|
+
v = self.text_widget.value.strip()
|
|
17
|
+
if not v:
|
|
18
|
+
return None
|
|
19
|
+
return v
|
|
20
|
+
|
|
21
|
+
@value.setter
|
|
22
|
+
def value(self, value: str | None):
|
|
23
|
+
if value is None:
|
|
24
|
+
self.text_widget.value = ''
|
|
25
|
+
else:
|
|
26
|
+
self.text_widget.value = value
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MultiStringWidget(StringWidget):
|
|
30
|
+
@property
|
|
31
|
+
def value(self) -> tuple[str, ...]:
|
|
32
|
+
v = super().value
|
|
33
|
+
if v is None:
|
|
34
|
+
return ()
|
|
35
|
+
return tuple(s.strip() for s in v.split(','))
|
|
36
|
+
|
|
37
|
+
@value.setter
|
|
38
|
+
def value(self, value: tuple[str, ...]):
|
|
39
|
+
self.text_widget.value = ', '.join(value)
|
ess/reduce/workflow.py
CHANGED
|
@@ -86,10 +86,7 @@ def assign_parameter_values(pipeline: Pipeline, values: dict[Key, Any]) -> Pipel
|
|
|
86
86
|
"""Set a value for a parameter in the pipeline."""
|
|
87
87
|
pipeline = pipeline.copy()
|
|
88
88
|
for key, value in values.items():
|
|
89
|
-
if (
|
|
90
|
-
isinstance(value, tuple)
|
|
91
|
-
and (mapper := parameter_mappers.get(key)) is not None
|
|
92
|
-
):
|
|
89
|
+
if (mapper := parameter_mappers.get(key)) is not None:
|
|
93
90
|
pipeline = mapper(pipeline, value)
|
|
94
91
|
else:
|
|
95
92
|
pipeline[key] = value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: essreduce
|
|
3
|
-
Version: 24.11.
|
|
3
|
+
Version: 24.11.3
|
|
4
4
|
Summary: Common data reduction tools for the ESS facility
|
|
5
5
|
Author: Scipp contributors
|
|
6
6
|
License: BSD 3-Clause License
|
|
@@ -45,18 +45,20 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
45
45
|
Classifier: Programming Language :: Python :: 3.10
|
|
46
46
|
Classifier: Programming Language :: Python :: 3.11
|
|
47
47
|
Classifier: Programming Language :: Python :: 3.12
|
|
48
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
48
49
|
Classifier: Topic :: Scientific/Engineering
|
|
49
50
|
Classifier: Typing :: Typed
|
|
50
51
|
Requires-Python: >=3.10
|
|
51
52
|
Description-Content-Type: text/markdown
|
|
52
53
|
License-File: LICENSE
|
|
53
|
-
Requires-Dist: sciline
|
|
54
|
-
Requires-Dist: scipp
|
|
55
|
-
Requires-Dist:
|
|
54
|
+
Requires-Dist: sciline>=24.06.2
|
|
55
|
+
Requires-Dist: scipp>=24.02.0
|
|
56
|
+
Requires-Dist: scippneutron>=24.11.0
|
|
57
|
+
Requires-Dist: scippnexus>=24.11.0
|
|
56
58
|
Provides-Extra: test
|
|
57
|
-
Requires-Dist: ipywidgets
|
|
58
|
-
Requires-Dist: pooch
|
|
59
|
-
Requires-Dist: pytest
|
|
59
|
+
Requires-Dist: ipywidgets; extra == "test"
|
|
60
|
+
Requires-Dist: pooch; extra == "test"
|
|
61
|
+
Requires-Dist: pytest; extra == "test"
|
|
60
62
|
|
|
61
63
|
[](CODE_OF_CONDUCT.md)
|
|
62
64
|
[](https://pypi.python.org/pypi/essreduce)
|
|
@@ -1,33 +1,35 @@
|
|
|
1
|
-
ess/reduce/__init__.py,sha256
|
|
2
|
-
ess/reduce/data.py,sha256=
|
|
1
|
+
ess/reduce/__init__.py,sha256=-8a2I4mbJdBgNqKxZJe0lAEQJb-lRjX1xmZvGUWCmmU,382
|
|
2
|
+
ess/reduce/data.py,sha256=vaoeAJ6EpK1YghOiAALLdWiW17TgUnnnt0H-RGiGzXk,3756
|
|
3
3
|
ess/reduce/logging.py,sha256=6n8Czq4LZ3OK9ENlKsWSI1M3KvKv6_HSoUiV4__IUlU,357
|
|
4
|
-
ess/reduce/parameter.py,sha256=
|
|
4
|
+
ess/reduce/parameter.py,sha256=R3y2SMk9EIHWfT7_89Sx6Km2mtni5qCWLVGRi8hVO7A,4560
|
|
5
5
|
ess/reduce/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
ess/reduce/streaming.py,sha256=nEO1Xg6LbQ36F44UaVmSNe2MSWmpwz97y9tnlc-z0zA,7493
|
|
7
7
|
ess/reduce/ui.py,sha256=EjzyMUODHn-5-aHRXE3DDWUsaPbsQRiUP2F4o1Hq260,8427
|
|
8
8
|
ess/reduce/uncertainty.py,sha256=UrS7wB2aK8QoLD3qG2Ud-XmjDl7Y9dANY31k83-cZKs,6982
|
|
9
|
-
ess/reduce/workflow.py,sha256=
|
|
9
|
+
ess/reduce/workflow.py,sha256=sL34T_2Cjl_8iFlegujxI9VyOUwo6erVC8pOXnfWgYw,3060
|
|
10
10
|
ess/reduce/live/__init__.py,sha256=jPQVhihRVNtEDrE20PoKkclKV2aBF1lS7cCHootgFgI,204
|
|
11
11
|
ess/reduce/live/raw.py,sha256=w-h-G-rXIFxwJ9rxIlCLQepGxLmUjtF2rbXtAUxDgZs,18849
|
|
12
12
|
ess/reduce/live/workflow.py,sha256=bsbwvTqPhRO6mC__3b7MgU7DWwAnOvGvG-t2n22EKq8,4285
|
|
13
|
-
ess/reduce/nexus/__init__.py,sha256=
|
|
14
|
-
ess/reduce/nexus/_nexus_loader.py,sha256
|
|
13
|
+
ess/reduce/nexus/__init__.py,sha256=PxJkhlGcFRzVU4SICBhymK5_5FjM5oXPZ8YUpd0v1pE,967
|
|
14
|
+
ess/reduce/nexus/_nexus_loader.py,sha256=-chpzKcZGr2cXmvSYlGiKdKV591mMG-0BsBusGWTer4,16119
|
|
15
15
|
ess/reduce/nexus/json_generator.py,sha256=ME2Xn8L7Oi3uHJk9ZZdCRQTRX-OV_wh9-DJn07Alplk,2529
|
|
16
16
|
ess/reduce/nexus/json_nexus.py,sha256=QrVc0p424nZ5dHX9gebAJppTw6lGZq9404P_OFl1giA,10282
|
|
17
|
-
ess/reduce/nexus/types.py,sha256=
|
|
18
|
-
ess/reduce/nexus/workflow.py,sha256=
|
|
17
|
+
ess/reduce/nexus/types.py,sha256=YIXECk-bctwexCvimLrlv97GMLj1UnGHLV3C95IcBOw,8677
|
|
18
|
+
ess/reduce/nexus/workflow.py,sha256=xcOjfJRECQ_CAxPbc0nr-BbGXe3rUISEDcu3g7D87Nk,22868
|
|
19
19
|
ess/reduce/scripts/grow_nexus.py,sha256=hET3h06M0xlJd62E3palNLFvJMyNax2kK4XyJcOhl-I,3387
|
|
20
|
-
ess/reduce/widgets/__init__.py,sha256=
|
|
20
|
+
ess/reduce/widgets/__init__.py,sha256=cjRJp4qhzCQgXZFtiZgHNmHFJVLo2Z2MozVG_LZYKlI,5281
|
|
21
21
|
ess/reduce/widgets/_binedges_widget.py,sha256=09VXYAWJammkzyRYvfFpjzn0E2-BSaDco3osnTUuv8c,2720
|
|
22
22
|
ess/reduce/widgets/_bounds_widget.py,sha256=p5hADiSGfHKMfvEILQqpcqggu_G3bLf5vNrW5rYTA0s,1020
|
|
23
23
|
ess/reduce/widgets/_config.py,sha256=LywjxYau1hsBZ-c2W1_DQ4CRMaaai3anjA8Q8Hn0Y6Y,222
|
|
24
|
+
ess/reduce/widgets/_filename_widget.py,sha256=jlDZOvECJBBjsmfBHjhn8-ig_DQxp3C-Uy07DITs_nI,262
|
|
24
25
|
ess/reduce/widgets/_linspace_widget.py,sha256=73nPfNSinxfuHN5-kkBoo2oTuGygbLVXPvxaw35xsaU,1175
|
|
25
26
|
ess/reduce/widgets/_optional_widget.py,sha256=A7vwcVwykj7CIyHSPVh6XL5o-8Z1uJTuzha8TR09Zlc,2216
|
|
27
|
+
ess/reduce/widgets/_string_widget.py,sha256=r0PrFP4OOU_UTmwlHYDWcaFMlnYS_NUp7iCic9ehBAU,1148
|
|
26
28
|
ess/reduce/widgets/_switchable_widget.py,sha256=SZi65C1iShTi5Xhh7W0A7uwA-12AVaH5xmiIWOkc27o,1726
|
|
27
29
|
ess/reduce/widgets/_vector_widget.py,sha256=BvuTtc-NGFTkMKIiZS0Elnl34Hi_3A4rthdNLoDI5fM,1138
|
|
28
|
-
essreduce-24.11.
|
|
29
|
-
essreduce-24.11.
|
|
30
|
-
essreduce-24.11.
|
|
31
|
-
essreduce-24.11.
|
|
32
|
-
essreduce-24.11.
|
|
33
|
-
essreduce-24.11.
|
|
30
|
+
essreduce-24.11.3.dist-info/LICENSE,sha256=nVEiume4Qj6jMYfSRjHTM2jtJ4FGu0g-5Sdh7osfEYw,1553
|
|
31
|
+
essreduce-24.11.3.dist-info/METADATA,sha256=wpqZdOA7tOrAlGWLiDPzN3E9Nh8-6B6Pk3CFOSSdr-Y,3619
|
|
32
|
+
essreduce-24.11.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
|
33
|
+
essreduce-24.11.3.dist-info/entry_points.txt,sha256=PMZOIYzCifHMTe4pK3HbhxUwxjFaZizYlLD0td4Isb0,66
|
|
34
|
+
essreduce-24.11.3.dist-info/top_level.txt,sha256=0JxTCgMKPLKtp14wb1-RKisQPQWX7i96innZNvHBr-s,4
|
|
35
|
+
essreduce-24.11.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|