essreduce 25.10.1__py3-none-any.whl → 25.11.0__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/live/raw.py +5 -5
- ess/reduce/nexus/__init__.py +4 -0
- ess/reduce/nexus/_nexus_loader.py +119 -14
- ess/reduce/nexus/types.py +25 -18
- ess/reduce/nexus/workflow.py +20 -58
- ess/reduce/time_of_flight/__init__.py +4 -4
- ess/reduce/time_of_flight/eto_to_tof.py +37 -22
- ess/reduce/time_of_flight/lut.py +2 -2
- ess/reduce/time_of_flight/types.py +2 -2
- {essreduce-25.10.1.dist-info → essreduce-25.11.0.dist-info}/METADATA +3 -3
- {essreduce-25.10.1.dist-info → essreduce-25.11.0.dist-info}/RECORD +15 -15
- {essreduce-25.10.1.dist-info → essreduce-25.11.0.dist-info}/WHEEL +0 -0
- {essreduce-25.10.1.dist-info → essreduce-25.11.0.dist-info}/entry_points.txt +0 -0
- {essreduce-25.10.1.dist-info → essreduce-25.11.0.dist-info}/licenses/LICENSE +0 -0
- {essreduce-25.10.1.dist-info → essreduce-25.11.0.dist-info}/top_level.txt +0 -0
ess/reduce/live/raw.py
CHANGED
|
@@ -29,7 +29,7 @@ import scipp as sc
|
|
|
29
29
|
import scippnexus as snx
|
|
30
30
|
|
|
31
31
|
from ess.reduce.nexus.types import (
|
|
32
|
-
|
|
32
|
+
EmptyDetector,
|
|
33
33
|
Filename,
|
|
34
34
|
NeXusComponent,
|
|
35
35
|
NeXusDetectorName,
|
|
@@ -305,7 +305,7 @@ class RollingDetectorView(Detector):
|
|
|
305
305
|
|
|
306
306
|
@staticmethod
|
|
307
307
|
def from_detector_and_histogrammer(
|
|
308
|
-
detector:
|
|
308
|
+
detector: EmptyDetector[SampleRun],
|
|
309
309
|
window: RollingDetectorViewWindow,
|
|
310
310
|
projection: Histogrammer,
|
|
311
311
|
) -> RollingDetectorView:
|
|
@@ -320,10 +320,10 @@ class RollingDetectorView(Detector):
|
|
|
320
320
|
def from_detector_with_projection(
|
|
321
321
|
projection: Callable[[sc.DataArray], sc.DataArray] | None,
|
|
322
322
|
) -> Callable[
|
|
323
|
-
[
|
|
323
|
+
[EmptyDetector[SampleRun], RollingDetectorViewWindow], RollingDetectorView
|
|
324
324
|
]:
|
|
325
325
|
def factory(
|
|
326
|
-
detector:
|
|
326
|
+
detector: EmptyDetector[SampleRun],
|
|
327
327
|
window: RollingDetectorViewWindow,
|
|
328
328
|
) -> RollingDetectorView:
|
|
329
329
|
"""Helper for constructing via a Sciline workflow."""
|
|
@@ -591,7 +591,7 @@ def gaussian_position_noise(sigma: PositionNoiseSigma) -> PositionNoise:
|
|
|
591
591
|
|
|
592
592
|
def position_with_noisy_replicas(
|
|
593
593
|
*,
|
|
594
|
-
detector:
|
|
594
|
+
detector: EmptyDetector[SampleRun],
|
|
595
595
|
position_noise: PositionNoise,
|
|
596
596
|
replicas: PositionNoiseReplicaCount,
|
|
597
597
|
) -> CalibratedPositionWithNoisyReplicas:
|
ess/reduce/nexus/__init__.py
CHANGED
|
@@ -20,6 +20,8 @@ from ._nexus_loader import (
|
|
|
20
20
|
load_all_components,
|
|
21
21
|
load_component,
|
|
22
22
|
load_data,
|
|
23
|
+
open_component_group,
|
|
24
|
+
open_nexus_file,
|
|
23
25
|
)
|
|
24
26
|
from .workflow import GenericNeXusWorkflow
|
|
25
27
|
|
|
@@ -31,5 +33,7 @@ __all__ = [
|
|
|
31
33
|
'load_all_components',
|
|
32
34
|
'load_component',
|
|
33
35
|
'load_data',
|
|
36
|
+
'open_component_group',
|
|
37
|
+
'open_nexus_file',
|
|
34
38
|
'types',
|
|
35
39
|
]
|
|
@@ -46,17 +46,37 @@ def load_component(
|
|
|
46
46
|
location: NeXusLocationSpec,
|
|
47
47
|
*,
|
|
48
48
|
nx_class: type[snx.NXobject],
|
|
49
|
+
parent_class: type[snx.NXobject] | None = None,
|
|
49
50
|
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
50
51
|
) -> sc.DataGroup:
|
|
51
|
-
"""Load a single component of a given class from NeXus.
|
|
52
|
+
"""Load a single component of a given class from NeXus.
|
|
53
|
+
|
|
54
|
+
Parameters
|
|
55
|
+
----------
|
|
56
|
+
location:
|
|
57
|
+
Specifies (part of) the location of the component to load.
|
|
58
|
+
nx_class:
|
|
59
|
+
NeXus class of the component to load.
|
|
60
|
+
parent_class:
|
|
61
|
+
NeXus class of the parent of the component to load.
|
|
62
|
+
If ``None``, is deduced from ``nx_class`` if possible.
|
|
63
|
+
definitions:
|
|
64
|
+
Application definitions to use for the file.
|
|
65
|
+
|
|
66
|
+
Returns
|
|
67
|
+
-------
|
|
68
|
+
:
|
|
69
|
+
The loaded component as a data group.
|
|
70
|
+
"""
|
|
52
71
|
selection = location.selection
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
loaded
|
|
72
|
+
with open_component_group(
|
|
73
|
+
location,
|
|
74
|
+
nx_class=nx_class,
|
|
75
|
+
parent_class=parent_class,
|
|
76
|
+
definitions=definitions,
|
|
77
|
+
) as group:
|
|
78
|
+
loaded = cast(sc.DataGroup, group[selection])
|
|
79
|
+
loaded['nexus_component_name'] = group.name.rsplit('/', 1)[-1]
|
|
60
80
|
return loaded
|
|
61
81
|
|
|
62
82
|
|
|
@@ -64,11 +84,14 @@ def load_all_components(
|
|
|
64
84
|
location: NeXusAllLocationSpec,
|
|
65
85
|
*,
|
|
66
86
|
nx_class: type[snx.NXobject],
|
|
87
|
+
parent_class: type[snx.NXobject] | None = None,
|
|
67
88
|
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
68
89
|
) -> sc.DataGroup:
|
|
69
90
|
"""Load all components of a given class from NeXus."""
|
|
70
91
|
with _open_component_parent(
|
|
71
|
-
location,
|
|
92
|
+
location,
|
|
93
|
+
parent_class=_deduce_component_parent_class(nx_class, parent_class),
|
|
94
|
+
definitions=definitions,
|
|
72
95
|
) as parent:
|
|
73
96
|
components = sc.DataGroup()
|
|
74
97
|
for name, component in parent[nx_class].items():
|
|
@@ -119,6 +142,29 @@ def open_nexus_file(
|
|
|
119
142
|
*,
|
|
120
143
|
locking: bool | str | None | NoLockingIfNeededType = NoLockingIfNeeded,
|
|
121
144
|
) -> AbstractContextManager[snx.Group]:
|
|
145
|
+
"""Open a NeXus file.
|
|
146
|
+
|
|
147
|
+
Parameters
|
|
148
|
+
----------
|
|
149
|
+
file_path:
|
|
150
|
+
Path of the file to open or a NeXus file or group handle.
|
|
151
|
+
definitions:
|
|
152
|
+
If set, application definitions to use for the file.
|
|
153
|
+
If ``file_path`` is a NeXus file or group, this must be unset or match
|
|
154
|
+
the existing definitions.
|
|
155
|
+
locking:
|
|
156
|
+
This is an advanced feature to work around a limitation of the DMSC file system.
|
|
157
|
+
It may be removed in the future.
|
|
158
|
+
|
|
159
|
+
This flag can disable or force locking the HDF5 file.
|
|
160
|
+
By default, the file is locked if possible but may remain unlocked
|
|
161
|
+
if it is on a read-only filesystem.
|
|
162
|
+
|
|
163
|
+
Returns
|
|
164
|
+
-------
|
|
165
|
+
:
|
|
166
|
+
A context manager for the opened file.
|
|
167
|
+
"""
|
|
122
168
|
if isinstance(file_path, getattr(NeXusGroup, '__supertype__', type(None))):
|
|
123
169
|
if (
|
|
124
170
|
definitions is not NoNewDefinitions
|
|
@@ -203,10 +249,46 @@ def _open_nexus_file_from_path(
|
|
|
203
249
|
|
|
204
250
|
|
|
205
251
|
@contextmanager
|
|
206
|
-
def
|
|
252
|
+
def open_component_group(
|
|
207
253
|
location: NeXusLocationSpec,
|
|
208
254
|
*,
|
|
209
255
|
nx_class: type[snx.NXobject],
|
|
256
|
+
parent_class: type[snx.NXobject] | None = None,
|
|
257
|
+
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
258
|
+
) -> Generator[snx.Group, None, None]:
|
|
259
|
+
"""Open the HDF5 group of a NeXus component.
|
|
260
|
+
|
|
261
|
+
Parameters
|
|
262
|
+
----------
|
|
263
|
+
location:
|
|
264
|
+
Specifies (part of) the location of the component to load.
|
|
265
|
+
nx_class:
|
|
266
|
+
NeXus class of the component to load.
|
|
267
|
+
parent_class:
|
|
268
|
+
NeXus class of the parent of the component to load.
|
|
269
|
+
If ``None``, is deduced from ``nx_class`` if possible.
|
|
270
|
+
definitions:
|
|
271
|
+
Application definitions to use for the file.
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
:
|
|
276
|
+
A context manager for the group of the specified component.
|
|
277
|
+
"""
|
|
278
|
+
group_name = location.component_name
|
|
279
|
+
with _open_component_parent(
|
|
280
|
+
location,
|
|
281
|
+
parent_class=_deduce_component_parent_class(nx_class, parent_class),
|
|
282
|
+
definitions=definitions,
|
|
283
|
+
) as parent:
|
|
284
|
+
yield _unique_child_group(parent, nx_class, group_name)
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@contextmanager
|
|
288
|
+
def _open_component_parent(
|
|
289
|
+
location: NeXusLocationSpec,
|
|
290
|
+
*,
|
|
291
|
+
parent_class: type[snx.NXobject],
|
|
210
292
|
definitions: Mapping | None | NoNewDefinitionsType = NoNewDefinitions,
|
|
211
293
|
) -> Generator[snx.Group, None, None]:
|
|
212
294
|
"""Locate the parent group of a NeXus component."""
|
|
@@ -214,10 +296,30 @@ def _open_component_parent(
|
|
|
214
296
|
entry_name = location.entry_name
|
|
215
297
|
with open_nexus_file(file_path, definitions=definitions) as f:
|
|
216
298
|
entry = _unique_child_group(f, snx.NXentry, entry_name)
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
299
|
+
match parent_class:
|
|
300
|
+
case snx.NXentry:
|
|
301
|
+
yield entry
|
|
302
|
+
case snx.NXinstrument:
|
|
303
|
+
yield _unique_child_group(entry, snx.NXinstrument, None)
|
|
304
|
+
case _:
|
|
305
|
+
raise NotImplementedError(
|
|
306
|
+
f"No support for loading a NeXus component from a {parent_class}."
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _deduce_component_parent_class(
|
|
311
|
+
nx_class: type[snx.NXobject], parent_class: type[snx.NXobject] | None
|
|
312
|
+
) -> type[snx.NXobject]:
|
|
313
|
+
if parent_class is not None:
|
|
314
|
+
return parent_class
|
|
315
|
+
|
|
316
|
+
match nx_class:
|
|
317
|
+
case snx.NXsample:
|
|
318
|
+
return snx.NXentry
|
|
319
|
+
case _:
|
|
320
|
+
# Most components are in the instrument,
|
|
321
|
+
# callers need to override this for specialized components stored elsewhere.
|
|
322
|
+
return snx.NXinstrument
|
|
221
323
|
|
|
222
324
|
|
|
223
325
|
def _unique_child_group(
|
|
@@ -367,6 +469,9 @@ def load_data(
|
|
|
367
469
|
elif _contains_nx_class(component, snx.NXdata):
|
|
368
470
|
data = _unique_child_group(component, snx.NXdata, None)
|
|
369
471
|
sel = _to_snx_selection(selection, for_events=False)
|
|
472
|
+
elif _contains_nx_class(component, snx.NXlog):
|
|
473
|
+
data = _unique_child_group(component, snx.NXlog, "data")
|
|
474
|
+
sel = _to_snx_selection(selection, for_events=False)
|
|
370
475
|
else:
|
|
371
476
|
raise ValueError(
|
|
372
477
|
f"NeXus group '{component.name}' contains neither "
|
ess/reduce/nexus/types.py
CHANGED
|
@@ -40,6 +40,14 @@ PreopenNeXusFile = NewType('PreopenNeXusFile', bool)
|
|
|
40
40
|
# 1 TypeVars used to parametrize the generic parts of the workflow
|
|
41
41
|
|
|
42
42
|
# 1.1 Run types
|
|
43
|
+
|
|
44
|
+
AnyRun = NewType("AnyRun", int)
|
|
45
|
+
"""RunType that does not represent a specific measurement run.
|
|
46
|
+
|
|
47
|
+
This can be used in cases where it makes no sense to use an 'actual' run type
|
|
48
|
+
like ``SampleRun`` or ``BackgroundRun``.
|
|
49
|
+
"""
|
|
50
|
+
|
|
43
51
|
BackgroundRun = NewType('BackgroundRun', int)
|
|
44
52
|
"""Background run such as a run with only a solvent which the sample is placed in."""
|
|
45
53
|
EmptyBeamRun = NewType('EmptyBeamRun', int)
|
|
@@ -136,12 +144,17 @@ This list will be supplemented with monitor types when creating a pipeline.
|
|
|
136
144
|
UniqueComponent = TypeVar('UniqueComponent', snx.NXsample, snx.NXsource)
|
|
137
145
|
"""Components that can be identified by their type as there will only be one."""
|
|
138
146
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
|
|
148
|
+
class Beamline(scn_meta.Beamline, Generic[RunType]):
|
|
149
|
+
"""Beamline metadata."""
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class Measurement(scn_meta.Measurement, Generic[RunType]):
|
|
153
|
+
"""measurement metadata."""
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class Source(scn_meta.Source, Generic[RunType]):
|
|
157
|
+
"""Neutron source metadata."""
|
|
145
158
|
|
|
146
159
|
|
|
147
160
|
class NeXusName(sciline.Scope[Component, str], str):
|
|
@@ -186,25 +199,19 @@ class MonitorPositionOffset(
|
|
|
186
199
|
"""Offset for the monitor position, added to base position."""
|
|
187
200
|
|
|
188
201
|
|
|
189
|
-
class
|
|
190
|
-
"""
|
|
202
|
+
class EmptyDetector(sciline.Scope[RunType, sc.DataArray], sc.DataArray):
|
|
203
|
+
"""Detector without neutron data."""
|
|
191
204
|
|
|
192
205
|
|
|
193
|
-
class
|
|
194
|
-
"""
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class CalibratedMonitor(
|
|
198
|
-
sciline.Scope[RunType, MonitorType, sc.DataArray], sc.DataArray
|
|
199
|
-
):
|
|
200
|
-
"""Calibrated data from a monitor."""
|
|
206
|
+
class EmptyMonitor(sciline.Scope[RunType, MonitorType, sc.DataArray], sc.DataArray):
|
|
207
|
+
"""Monitor without neutron data."""
|
|
201
208
|
|
|
202
209
|
|
|
203
|
-
class
|
|
210
|
+
class RawDetector(sciline.Scope[RunType, sc.DataArray], sc.DataArray):
|
|
204
211
|
"""Calibrated detector merged with neutron event or histogram data."""
|
|
205
212
|
|
|
206
213
|
|
|
207
|
-
class
|
|
214
|
+
class RawMonitor(sciline.Scope[RunType, MonitorType, sc.DataArray], sc.DataArray):
|
|
208
215
|
"""Calibrated monitor merged with neutron event or histogram data."""
|
|
209
216
|
|
|
210
217
|
|
ess/reduce/nexus/workflow.py
CHANGED
|
@@ -20,17 +20,14 @@ from .types import (
|
|
|
20
20
|
COMPONENT_CONSTRAINTS,
|
|
21
21
|
AllNeXusComponents,
|
|
22
22
|
Beamline,
|
|
23
|
-
CalibratedBeamline,
|
|
24
|
-
CalibratedDetector,
|
|
25
|
-
CalibratedMonitor,
|
|
26
23
|
Component,
|
|
27
24
|
DetectorBankSizes,
|
|
28
|
-
DetectorData,
|
|
29
25
|
DetectorPositionOffset,
|
|
26
|
+
EmptyDetector,
|
|
27
|
+
EmptyMonitor,
|
|
30
28
|
Filename,
|
|
31
29
|
GravityVector,
|
|
32
30
|
Measurement,
|
|
33
|
-
MonitorData,
|
|
34
31
|
MonitorPositionOffset,
|
|
35
32
|
MonitorType,
|
|
36
33
|
NeXusAllComponentLocationSpec,
|
|
@@ -46,8 +43,9 @@ from .types import (
|
|
|
46
43
|
Position,
|
|
47
44
|
PreopenNeXusFile,
|
|
48
45
|
RawChoppers,
|
|
46
|
+
RawDetector,
|
|
47
|
+
RawMonitor,
|
|
49
48
|
RunType,
|
|
50
|
-
SampleRun,
|
|
51
49
|
TimeInterval,
|
|
52
50
|
UniqueComponent,
|
|
53
51
|
)
|
|
@@ -361,13 +359,11 @@ def get_calibrated_detector(
|
|
|
361
359
|
# all.
|
|
362
360
|
offset: DetectorPositionOffset[RunType],
|
|
363
361
|
bank_sizes: DetectorBankSizes,
|
|
364
|
-
) ->
|
|
362
|
+
) -> EmptyDetector[RunType]:
|
|
365
363
|
"""
|
|
366
364
|
Extract the data array corresponding to a detector's signal field.
|
|
367
365
|
|
|
368
|
-
The
|
|
369
|
-
signal values array, but not additional information about the detector. The
|
|
370
|
-
data array is reshaped to the logical detector shape, which by folding the data
|
|
366
|
+
The data array is reshaped to the logical detector shape, by folding the data
|
|
371
367
|
array along the detector_number dimension.
|
|
372
368
|
|
|
373
369
|
Parameters
|
|
@@ -396,50 +392,15 @@ def get_calibrated_detector(
|
|
|
396
392
|
else:
|
|
397
393
|
transform_value = transform.value
|
|
398
394
|
position = transform_value * offsets
|
|
399
|
-
return
|
|
395
|
+
return EmptyDetector[RunType](
|
|
400
396
|
da.assign_coords(position=position + offset.to(unit=position.unit))
|
|
401
397
|
)
|
|
402
398
|
|
|
403
399
|
|
|
404
|
-
def assemble_beamline(
|
|
405
|
-
detector: CalibratedDetector[RunType],
|
|
406
|
-
source_position: Position[snx.NXsource, RunType],
|
|
407
|
-
sample_position: Position[snx.NXsample, RunType],
|
|
408
|
-
gravity: GravityVector,
|
|
409
|
-
) -> CalibratedBeamline[RunType]:
|
|
410
|
-
"""
|
|
411
|
-
Add beamline information (gravity vector, source- and sample-position) to detector.
|
|
412
|
-
|
|
413
|
-
This is performed separately and after :py:func:`get_calibrated_detector` to avoid
|
|
414
|
-
as false dependency of, e.g., the reshaped detector numbers on the sample position.
|
|
415
|
-
The latter can change during a run, e.g., for a rotating sample. The detector
|
|
416
|
-
numbers might be used, e.g., to mask certain detector pixels, and should not depend
|
|
417
|
-
on the sample position.
|
|
418
|
-
|
|
419
|
-
Parameters
|
|
420
|
-
----------
|
|
421
|
-
detector:
|
|
422
|
-
NeXus detector group.
|
|
423
|
-
source_position:
|
|
424
|
-
Position of the neutron source.
|
|
425
|
-
sample_position:
|
|
426
|
-
Position of the sample.
|
|
427
|
-
gravity:
|
|
428
|
-
Gravity vector.
|
|
429
|
-
"""
|
|
430
|
-
return CalibratedBeamline[RunType](
|
|
431
|
-
detector.assign_coords(
|
|
432
|
-
source_position=source_position,
|
|
433
|
-
sample_position=sample_position,
|
|
434
|
-
gravity=gravity,
|
|
435
|
-
)
|
|
436
|
-
)
|
|
437
|
-
|
|
438
|
-
|
|
439
400
|
def assemble_detector_data(
|
|
440
|
-
detector:
|
|
401
|
+
detector: EmptyDetector[RunType],
|
|
441
402
|
event_data: NeXusData[snx.NXdetector, RunType],
|
|
442
|
-
) ->
|
|
403
|
+
) -> RawDetector[RunType]:
|
|
443
404
|
"""
|
|
444
405
|
Assemble a detector data array with event data.
|
|
445
406
|
|
|
@@ -455,7 +416,7 @@ def assemble_detector_data(
|
|
|
455
416
|
grouped = nexus.group_event_data(
|
|
456
417
|
event_data=event_data, detector_number=detector.coords['detector_number']
|
|
457
418
|
)
|
|
458
|
-
return
|
|
419
|
+
return RawDetector[RunType](
|
|
459
420
|
_add_variances(grouped)
|
|
460
421
|
.assign_coords(detector.coords)
|
|
461
422
|
.assign_masks(detector.masks)
|
|
@@ -466,7 +427,7 @@ def get_calibrated_monitor(
|
|
|
466
427
|
monitor: NeXusComponent[MonitorType, RunType],
|
|
467
428
|
offset: MonitorPositionOffset[RunType, MonitorType],
|
|
468
429
|
source_position: Position[snx.NXsource, RunType],
|
|
469
|
-
) ->
|
|
430
|
+
) -> EmptyMonitor[RunType, MonitorType]:
|
|
470
431
|
"""
|
|
471
432
|
Extract the data array corresponding to a monitor's signal field.
|
|
472
433
|
|
|
@@ -483,7 +444,7 @@ def get_calibrated_monitor(
|
|
|
483
444
|
Position of the neutron source.
|
|
484
445
|
"""
|
|
485
446
|
monitor = nexus.compute_component_position(monitor)
|
|
486
|
-
return
|
|
447
|
+
return EmptyMonitor[RunType, MonitorType](
|
|
487
448
|
nexus.extract_signal_data_array(monitor).assign_coords(
|
|
488
449
|
position=monitor['position'] + offset.to(unit=monitor['position'].unit),
|
|
489
450
|
source_position=source_position,
|
|
@@ -492,9 +453,9 @@ def get_calibrated_monitor(
|
|
|
492
453
|
|
|
493
454
|
|
|
494
455
|
def assemble_monitor_data(
|
|
495
|
-
monitor:
|
|
456
|
+
monitor: EmptyMonitor[RunType, MonitorType],
|
|
496
457
|
data: NeXusData[MonitorType, RunType],
|
|
497
|
-
) ->
|
|
458
|
+
) -> RawMonitor[RunType, MonitorType]:
|
|
498
459
|
"""
|
|
499
460
|
Assemble a monitor data array with event data.
|
|
500
461
|
|
|
@@ -508,7 +469,7 @@ def assemble_monitor_data(
|
|
|
508
469
|
Data array with neutron counts.
|
|
509
470
|
"""
|
|
510
471
|
da = data.assign_coords(monitor.coords).assign_masks(monitor.masks)
|
|
511
|
-
return
|
|
472
|
+
return RawMonitor[RunType, MonitorType](_add_variances(da))
|
|
512
473
|
|
|
513
474
|
|
|
514
475
|
def parse_disk_choppers(
|
|
@@ -606,14 +567,16 @@ def _assign_values_as_variances(var: sc.Variable) -> sc.Variable:
|
|
|
606
567
|
return var
|
|
607
568
|
|
|
608
569
|
|
|
609
|
-
def load_beamline_metadata_from_nexus(
|
|
570
|
+
def load_beamline_metadata_from_nexus(
|
|
571
|
+
file_spec: NeXusFileSpec[RunType],
|
|
572
|
+
) -> Beamline[RunType]:
|
|
610
573
|
"""Load beamline metadata from a sample NeXus file."""
|
|
611
574
|
return nexus.load_metadata(file_spec.value, Beamline)
|
|
612
575
|
|
|
613
576
|
|
|
614
577
|
def load_measurement_metadata_from_nexus(
|
|
615
|
-
file_spec: NeXusFileSpec[
|
|
616
|
-
) -> Measurement:
|
|
578
|
+
file_spec: NeXusFileSpec[RunType],
|
|
579
|
+
) -> Measurement[RunType]:
|
|
617
580
|
"""Load measurement metadata from a sample NeXus file."""
|
|
618
581
|
return nexus.load_metadata(file_spec.value, Measurement)
|
|
619
582
|
|
|
@@ -654,7 +617,6 @@ _detector_providers = (
|
|
|
654
617
|
no_detector_position_offset,
|
|
655
618
|
load_nexus_sample,
|
|
656
619
|
get_calibrated_detector,
|
|
657
|
-
assemble_beamline,
|
|
658
620
|
assemble_detector_data,
|
|
659
621
|
)
|
|
660
622
|
|
|
@@ -24,25 +24,23 @@ from .lut import (
|
|
|
24
24
|
)
|
|
25
25
|
from .types import (
|
|
26
26
|
DetectorLtotal,
|
|
27
|
-
DetectorTofData,
|
|
28
27
|
MonitorLtotal,
|
|
29
|
-
MonitorTofData,
|
|
30
28
|
PulseStrideOffset,
|
|
31
29
|
TimeOfFlightLookupTable,
|
|
32
30
|
TimeOfFlightLookupTableFilename,
|
|
31
|
+
TofDetector,
|
|
32
|
+
TofMonitor,
|
|
33
33
|
)
|
|
34
34
|
from .workflow import GenericTofWorkflow
|
|
35
35
|
|
|
36
36
|
__all__ = [
|
|
37
37
|
"DetectorLtotal",
|
|
38
|
-
"DetectorTofData",
|
|
39
38
|
"DiskChoppers",
|
|
40
39
|
"DistanceResolution",
|
|
41
40
|
"GenericTofWorkflow",
|
|
42
41
|
"LookupTableRelativeErrorThreshold",
|
|
43
42
|
"LtotalRange",
|
|
44
43
|
"MonitorLtotal",
|
|
45
|
-
"MonitorTofData",
|
|
46
44
|
"NumberOfSimulatedNeutrons",
|
|
47
45
|
"PulsePeriod",
|
|
48
46
|
"PulseStride",
|
|
@@ -53,7 +51,9 @@ __all__ = [
|
|
|
53
51
|
"TimeOfFlightLookupTable",
|
|
54
52
|
"TimeOfFlightLookupTableFilename",
|
|
55
53
|
"TimeResolution",
|
|
54
|
+
"TofDetector",
|
|
56
55
|
"TofLookupTableWorkflow",
|
|
56
|
+
"TofMonitor",
|
|
57
57
|
"providers",
|
|
58
58
|
"simulate_chopper_cascade_using_tof",
|
|
59
59
|
]
|
|
@@ -12,6 +12,7 @@ from collections.abc import Callable
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
import scipp as sc
|
|
14
14
|
import scippneutron as scn
|
|
15
|
+
import scippnexus as snx
|
|
15
16
|
from scippneutron._utils import elem_unit
|
|
16
17
|
|
|
17
18
|
try:
|
|
@@ -20,21 +21,23 @@ except ImportError:
|
|
|
20
21
|
from .interpolator_scipy import Interpolator as InterpolatorImpl
|
|
21
22
|
|
|
22
23
|
from ..nexus.types import (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
MonitorData,
|
|
24
|
+
EmptyDetector,
|
|
25
|
+
EmptyMonitor,
|
|
26
|
+
GravityVector,
|
|
27
27
|
MonitorType,
|
|
28
|
+
Position,
|
|
29
|
+
RawDetector,
|
|
30
|
+
RawMonitor,
|
|
28
31
|
RunType,
|
|
29
32
|
)
|
|
30
33
|
from .resample import rebin_strictly_increasing
|
|
31
34
|
from .types import (
|
|
32
35
|
DetectorLtotal,
|
|
33
|
-
DetectorTofData,
|
|
34
36
|
MonitorLtotal,
|
|
35
|
-
MonitorTofData,
|
|
36
37
|
PulseStrideOffset,
|
|
37
38
|
TimeOfFlightLookupTable,
|
|
39
|
+
TofDetector,
|
|
40
|
+
TofMonitor,
|
|
38
41
|
)
|
|
39
42
|
|
|
40
43
|
|
|
@@ -271,30 +274,42 @@ def _time_of_flight_data_events(
|
|
|
271
274
|
|
|
272
275
|
|
|
273
276
|
def detector_ltotal_from_straight_line_approximation(
|
|
274
|
-
|
|
277
|
+
detector: EmptyDetector[RunType],
|
|
278
|
+
source_position: Position[snx.NXsource, RunType],
|
|
279
|
+
sample_position: Position[snx.NXsample, RunType],
|
|
280
|
+
gravity: GravityVector,
|
|
275
281
|
) -> DetectorLtotal[RunType]:
|
|
276
|
-
"""
|
|
277
|
-
|
|
282
|
+
"""Compute Ltotal for the detector pixels.
|
|
283
|
+
|
|
278
284
|
This is a naive straight-line approximation to Ltotal based on basic component
|
|
279
285
|
positions.
|
|
280
286
|
|
|
281
287
|
Parameters
|
|
282
288
|
----------
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
289
|
+
detector:
|
|
290
|
+
Data array with detector positions.
|
|
291
|
+
source_position:
|
|
292
|
+
Position of the neutron source.
|
|
293
|
+
sample_position:
|
|
294
|
+
Position of the sample.
|
|
295
|
+
gravity:
|
|
296
|
+
Gravity vector.
|
|
287
297
|
"""
|
|
288
|
-
graph =
|
|
298
|
+
graph = {
|
|
299
|
+
**scn.conversion.graph.beamline.beamline(scatter=True),
|
|
300
|
+
'source_position': lambda: source_position,
|
|
301
|
+
'sample_position': lambda: sample_position,
|
|
302
|
+
'gravity': lambda: gravity,
|
|
303
|
+
}
|
|
289
304
|
return DetectorLtotal[RunType](
|
|
290
|
-
|
|
305
|
+
detector.transform_coords(
|
|
291
306
|
"Ltotal", graph=graph, keep_intermediate=False
|
|
292
307
|
).coords["Ltotal"]
|
|
293
308
|
)
|
|
294
309
|
|
|
295
310
|
|
|
296
311
|
def monitor_ltotal_from_straight_line_approximation(
|
|
297
|
-
monitor_beamline:
|
|
312
|
+
monitor_beamline: EmptyMonitor[RunType, MonitorType],
|
|
298
313
|
) -> MonitorLtotal[RunType, MonitorType]:
|
|
299
314
|
"""
|
|
300
315
|
Compute Ltotal for the monitor.
|
|
@@ -334,11 +349,11 @@ def _compute_tof_data(
|
|
|
334
349
|
|
|
335
350
|
|
|
336
351
|
def detector_time_of_flight_data(
|
|
337
|
-
detector_data:
|
|
352
|
+
detector_data: RawDetector[RunType],
|
|
338
353
|
lookup: TimeOfFlightLookupTable,
|
|
339
354
|
ltotal: DetectorLtotal[RunType],
|
|
340
355
|
pulse_stride_offset: PulseStrideOffset,
|
|
341
|
-
) ->
|
|
356
|
+
) -> TofDetector[RunType]:
|
|
342
357
|
"""
|
|
343
358
|
Convert the time-of-arrival data to time-of-flight data using a lookup table.
|
|
344
359
|
The output data will have a time-of-flight coordinate.
|
|
@@ -357,7 +372,7 @@ def detector_time_of_flight_data(
|
|
|
357
372
|
When pulse-skipping, the offset of the first pulse in the stride. This is
|
|
358
373
|
typically zero but can be a small integer < pulse_stride.
|
|
359
374
|
"""
|
|
360
|
-
return
|
|
375
|
+
return TofDetector[RunType](
|
|
361
376
|
_compute_tof_data(
|
|
362
377
|
da=detector_data,
|
|
363
378
|
lookup=lookup,
|
|
@@ -368,11 +383,11 @@ def detector_time_of_flight_data(
|
|
|
368
383
|
|
|
369
384
|
|
|
370
385
|
def monitor_time_of_flight_data(
|
|
371
|
-
monitor_data:
|
|
386
|
+
monitor_data: RawMonitor[RunType, MonitorType],
|
|
372
387
|
lookup: TimeOfFlightLookupTable,
|
|
373
388
|
ltotal: MonitorLtotal[RunType, MonitorType],
|
|
374
389
|
pulse_stride_offset: PulseStrideOffset,
|
|
375
|
-
) ->
|
|
390
|
+
) -> TofMonitor[RunType, MonitorType]:
|
|
376
391
|
"""
|
|
377
392
|
Convert the time-of-arrival data to time-of-flight data using a lookup table.
|
|
378
393
|
The output data will have a time-of-flight coordinate.
|
|
@@ -391,7 +406,7 @@ def monitor_time_of_flight_data(
|
|
|
391
406
|
When pulse-skipping, the offset of the first pulse in the stride. This is
|
|
392
407
|
typically zero but can be a small integer < pulse_stride.
|
|
393
408
|
"""
|
|
394
|
-
return
|
|
409
|
+
return TofMonitor[RunType, MonitorType](
|
|
395
410
|
_compute_tof_data(
|
|
396
411
|
da=monitor_data,
|
|
397
412
|
lookup=lookup,
|
ess/reduce/time_of_flight/lut.py
CHANGED
|
@@ -12,7 +12,7 @@ import numpy as np
|
|
|
12
12
|
import sciline as sl
|
|
13
13
|
import scipp as sc
|
|
14
14
|
|
|
15
|
-
from ..nexus.types import DiskChoppers
|
|
15
|
+
from ..nexus.types import AnyRun, DiskChoppers
|
|
16
16
|
from .types import TimeOfFlightLookupTable
|
|
17
17
|
|
|
18
18
|
|
|
@@ -380,7 +380,7 @@ def make_tof_lookup_table(
|
|
|
380
380
|
|
|
381
381
|
|
|
382
382
|
def simulate_chopper_cascade_using_tof(
|
|
383
|
-
choppers: DiskChoppers,
|
|
383
|
+
choppers: DiskChoppers[AnyRun],
|
|
384
384
|
source_position: SourcePosition,
|
|
385
385
|
neutrons: NumberOfSimulatedNeutrons,
|
|
386
386
|
pulse_stride: PulseStride,
|
|
@@ -33,9 +33,9 @@ class MonitorLtotal(sl.Scope[RunType, MonitorType, sc.Variable], sc.Variable):
|
|
|
33
33
|
"""Total path length of neutrons from source to monitor."""
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class
|
|
36
|
+
class TofDetector(sl.Scope[RunType, sc.DataArray], sc.DataArray):
|
|
37
37
|
"""Detector data with time-of-flight coordinate."""
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
class
|
|
40
|
+
class TofMonitor(sl.Scope[RunType, MonitorType, sc.DataArray], sc.DataArray):
|
|
41
41
|
"""Monitor data with time-of-flight coordinate."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: essreduce
|
|
3
|
-
Version: 25.
|
|
3
|
+
Version: 25.11.0
|
|
4
4
|
Summary: Common data reduction tools for the ESS facility
|
|
5
5
|
Author: Scipp contributors
|
|
6
6
|
License-Expression: BSD-3-Clause
|
|
@@ -20,10 +20,10 @@ Classifier: Typing :: Typed
|
|
|
20
20
|
Requires-Python: >=3.11
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
|
-
Requires-Dist: sciline>=25.
|
|
23
|
+
Requires-Dist: sciline>=25.11.0
|
|
24
24
|
Requires-Dist: scipp>=25.04.0
|
|
25
25
|
Requires-Dist: scippneutron>=25.02.0
|
|
26
|
-
Requires-Dist: scippnexus>=
|
|
26
|
+
Requires-Dist: scippnexus>=25.06.0
|
|
27
27
|
Provides-Extra: test
|
|
28
28
|
Requires-Dist: ipywidgets>=8.1; extra == "test"
|
|
29
29
|
Requires-Dist: numba>=0.59; extra == "test"
|
|
@@ -9,24 +9,24 @@ ess/reduce/workflow.py,sha256=738-lcdgsORYfQ4A0UTk2IgnbVxC3jBdpscpaOFIpdc,3114
|
|
|
9
9
|
ess/reduce/data/__init__.py,sha256=uDtqkmKA_Zwtj6II25zntz9T812XhdCn3tktYev4uyY,486
|
|
10
10
|
ess/reduce/data/_registry.py,sha256=50qY36y5gd2i3JP0Ks6bXApGcW6l70qA6riO0m9Bz4o,11475
|
|
11
11
|
ess/reduce/live/__init__.py,sha256=jPQVhihRVNtEDrE20PoKkclKV2aBF1lS7cCHootgFgI,204
|
|
12
|
-
ess/reduce/live/raw.py,sha256=
|
|
12
|
+
ess/reduce/live/raw.py,sha256=d86s5fBjdf6tI_FWNMG4ZG67GCY2JADOobrinncNIjE,24367
|
|
13
13
|
ess/reduce/live/roi.py,sha256=Hs-pW98k41WU6Kl3UQ41kQawk80c2QNOQ_WNctLzDPE,3795
|
|
14
14
|
ess/reduce/live/workflow.py,sha256=bsbwvTqPhRO6mC__3b7MgU7DWwAnOvGvG-t2n22EKq8,4285
|
|
15
|
-
ess/reduce/nexus/__init__.py,sha256=
|
|
16
|
-
ess/reduce/nexus/_nexus_loader.py,sha256=
|
|
15
|
+
ess/reduce/nexus/__init__.py,sha256=8TLqqALxRV5_QdCwLAjq3r6xneq6rzdh2dD7d9AXkYo,1065
|
|
16
|
+
ess/reduce/nexus/_nexus_loader.py,sha256=8jN97CbFaSJ6XZEFzkoeAGyol8WpLTUZsHkUWu8WHsU,23136
|
|
17
17
|
ess/reduce/nexus/json_generator.py,sha256=ME2Xn8L7Oi3uHJk9ZZdCRQTRX-OV_wh9-DJn07Alplk,2529
|
|
18
18
|
ess/reduce/nexus/json_nexus.py,sha256=QrVc0p424nZ5dHX9gebAJppTw6lGZq9404P_OFl1giA,10282
|
|
19
|
-
ess/reduce/nexus/types.py,sha256=
|
|
20
|
-
ess/reduce/nexus/workflow.py,sha256=
|
|
19
|
+
ess/reduce/nexus/types.py,sha256=g5oBBEYPH7urF1tDP0tqXtixhQN8JDpe8vmiKrPiUW0,9320
|
|
20
|
+
ess/reduce/nexus/workflow.py,sha256=6mgvYW69kBtyhzbfZCi-WzJ3VhcKnx9z2qtXTVXH04E,23169
|
|
21
21
|
ess/reduce/scripts/grow_nexus.py,sha256=hET3h06M0xlJd62E3palNLFvJMyNax2kK4XyJcOhl-I,3387
|
|
22
|
-
ess/reduce/time_of_flight/__init__.py,sha256=
|
|
23
|
-
ess/reduce/time_of_flight/eto_to_tof.py,sha256=
|
|
22
|
+
ess/reduce/time_of_flight/__init__.py,sha256=Av6Pu_AKO0tF8IsWXchUXjjHps7ts2NFVnui6k3Eq-o,1425
|
|
23
|
+
ess/reduce/time_of_flight/eto_to_tof.py,sha256=aPPQYbbz_73eq5dQCS97q02D2UUFntOfow2lWkkRyxg,14993
|
|
24
24
|
ess/reduce/time_of_flight/fakes.py,sha256=0gtbSX3ZQilaM4ZP5dMr3fqbnhpyoVsZX2YEb8GgREE,4489
|
|
25
25
|
ess/reduce/time_of_flight/interpolator_numba.py,sha256=wh2YS3j2rOu30v1Ok3xNHcwS7t8eEtZyZvbfXOCtgrQ,3835
|
|
26
26
|
ess/reduce/time_of_flight/interpolator_scipy.py,sha256=_InoAPuMm2qhJKZQBAHOGRFqtvvuQ8TStoN7j_YgS4M,1853
|
|
27
|
-
ess/reduce/time_of_flight/lut.py,sha256=
|
|
27
|
+
ess/reduce/time_of_flight/lut.py,sha256=bNf3EmMw86pp3lB499zvKEkCkcDlqS2eHFvyVX4bCBk,18750
|
|
28
28
|
ess/reduce/time_of_flight/resample.py,sha256=Opmi-JA4zNH725l9VB99U4O9UlM37f5ACTCGtwBcows,3718
|
|
29
|
-
ess/reduce/time_of_flight/types.py,sha256=
|
|
29
|
+
ess/reduce/time_of_flight/types.py,sha256=VhJYLcLA_NfU-lILFNxjBkQUaC8AeNr_DJMeQuNgZOc,1302
|
|
30
30
|
ess/reduce/time_of_flight/workflow.py,sha256=mkgESvQ5Yt3CyAsa1iewkjBOHUqrHm5rRc1EhOQRewQ,2213
|
|
31
31
|
ess/reduce/widgets/__init__.py,sha256=SoSHBv8Dc3QXV9HUvPhjSYWMwKTGYZLpsWwsShIO97Q,5325
|
|
32
32
|
ess/reduce/widgets/_base.py,sha256=_wN3FOlXgx_u0c-A_3yyoIH-SdUvDENGgquh9S-h5GI,4852
|
|
@@ -40,9 +40,9 @@ ess/reduce/widgets/_spinner.py,sha256=2VY4Fhfa7HMXox2O7UbofcdKsYG-AJGrsgGJB85nDX
|
|
|
40
40
|
ess/reduce/widgets/_string_widget.py,sha256=iPAdfANyXHf-nkfhgkyH6gQDklia0LebLTmwi3m-iYQ,1482
|
|
41
41
|
ess/reduce/widgets/_switchable_widget.py,sha256=fjKz99SKLhIF1BLgGVBSKKn3Lu_jYBwDYGeAjbJY3Q8,2390
|
|
42
42
|
ess/reduce/widgets/_vector_widget.py,sha256=aTaBqCFHZQhrIoX6-sSqFWCPePEW8HQt5kUio8jP1t8,1203
|
|
43
|
-
essreduce-25.
|
|
44
|
-
essreduce-25.
|
|
45
|
-
essreduce-25.
|
|
46
|
-
essreduce-25.
|
|
47
|
-
essreduce-25.
|
|
48
|
-
essreduce-25.
|
|
43
|
+
essreduce-25.11.0.dist-info/licenses/LICENSE,sha256=nVEiume4Qj6jMYfSRjHTM2jtJ4FGu0g-5Sdh7osfEYw,1553
|
|
44
|
+
essreduce-25.11.0.dist-info/METADATA,sha256=q1TSHnOhJnGdAOulSP-Z-ML81kytiWoqn7PRpMn7wYM,1937
|
|
45
|
+
essreduce-25.11.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
46
|
+
essreduce-25.11.0.dist-info/entry_points.txt,sha256=PMZOIYzCifHMTe4pK3HbhxUwxjFaZizYlLD0td4Isb0,66
|
|
47
|
+
essreduce-25.11.0.dist-info/top_level.txt,sha256=0JxTCgMKPLKtp14wb1-RKisQPQWX7i96innZNvHBr-s,4
|
|
48
|
+
essreduce-25.11.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|