Skip to content

Commit 5876959

Browse files
Merge pull request #212 from scipp/fix-run-mapping
Fix run mapping functionality
2 parents af1321d + 3a469af commit 5876959

File tree

5 files changed

+92
-15
lines changed

5 files changed

+92
-15
lines changed

src/ess/isissans/__init__.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@
44
import importlib.metadata
55

66
from . import general, io, sans2d, zoom
7-
from .general import DetectorBankOffset, MonitorOffset, SampleOffset, default_parameters
7+
from .general import (
8+
DetectorBankOffset,
9+
MonitorOffset,
10+
MonitorSpectrumNumber,
11+
SampleOffset,
12+
default_parameters,
13+
)
814
from .io import CalibrationFilename
915
from .visualization import plot_flat_detector_xy
1016

@@ -21,6 +27,7 @@
2127
'CalibrationFilename',
2228
'DetectorBankOffset',
2329
'MonitorOffset',
30+
'MonitorSpectrumNumber',
2431
'SampleOffset',
2532
'default_parameters',
2633
'io',

src/ess/isissans/general.py

Lines changed: 50 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
Providers for the ISIS instruments.
55
"""
66

7-
from typing import NewType
7+
from dataclasses import dataclass
8+
from typing import Generic, NewType
89

910
import sciline
1011
import scipp as sc
@@ -45,6 +46,17 @@ class MonitorOffset(sciline.Scope[MonitorType, sc.Variable], sc.Variable):
4546
"""
4647

4748

49+
@dataclass
50+
class MonitorSpectrumNumber(Generic[MonitorType]):
51+
"""
52+
Spectrum number for monitor data.
53+
54+
This is used to identify the monitor in ISIS histogram data files.
55+
"""
56+
57+
value: int
58+
59+
4860
DetectorBankOffset = NewType('DetectorBankOffset', sc.Variable)
4961
SampleOffset = NewType('SampleOffset', sc.Variable)
5062

@@ -61,6 +73,10 @@ def default_parameters() -> dict:
6173
SampleOffset: SampleOffset(sc.vector([0, 0, 0], unit='m')),
6274
NonBackgroundWavelengthRange: None,
6375
Period: None,
76+
# Not used for event files, setting default so the workflow works. If histogram
77+
# data is used, the user should set this to the correct value.
78+
MonitorSpectrumNumber[Incident]: MonitorSpectrumNumber[Incident](-1),
79+
MonitorSpectrumNumber[Transmission]: MonitorSpectrumNumber[Transmission](-1),
6480
}
6581

6682

@@ -132,12 +148,43 @@ def get_calibrated_isis_detector(
132148

133149

134150
def get_monitor_data(
135-
dg: LoadedFileContents[RunType], nexus_name: NeXusMonitorName[MonitorType]
151+
dg: LoadedFileContents[RunType],
152+
nexus_name: NeXusMonitorName[MonitorType],
153+
spectrum_number: MonitorSpectrumNumber[MonitorType],
136154
) -> NeXusComponent[MonitorType, RunType]:
155+
"""
156+
Extract monitor data that was loaded together with detector data.
157+
158+
If the raw file is histogram data, Mantid stores this as a Workspace2D, where some
159+
or all spectra correspond to monitors.
160+
161+
Parameters
162+
----------
163+
dg:
164+
Data loaded with Mantid and converted to Scipp.
165+
nexus_name:
166+
Name of the monitor in the NeXus file, e.g. 'incident_monitor' or
167+
'transmission_monitor'. Used when raw data is an EventWorkspace, where
168+
monitors are stored in a group with this name.
169+
spectrum_number:
170+
Spectrum number of the monitor in the NeXus file, e.g., 3 for incident monitor
171+
or 4 for transmission monitor. This is used when the raw data is a
172+
Workspace2D, where the monitor data is stored in a spectrum with this number.
173+
174+
Returns
175+
-------
176+
:
177+
Monitor data extracted from the loaded file.
178+
"""
137179
# The generic NeXus workflow will try to extract 'data' from this, which is exactly
138180
# what we also have in the Mantid data. We use the generic workflow since it also
139181
# applies offsets, etc.
140-
monitor = dg['monitors'][nexus_name]['data']
182+
if 'monitors' in dg:
183+
# From EventWorkspace
184+
monitor = dg['monitors'][nexus_name]['data']
185+
else:
186+
# From Workspace2D
187+
monitor = sc.values(dg["data"]["spectrum", sc.index(spectrum_number.value)])
141188
return NeXusComponent[MonitorType, RunType](
142189
sc.DataGroup(data=monitor, position=monitor.coords['position'])
143190
)

src/ess/isissans/mantidio.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
File loading functions for ISIS data using Mantid.
55
"""
66

7+
import threading
78
from typing import NewType, NoReturn
89

910
import sciline
@@ -99,12 +100,28 @@ def from_data_workspace(
99100

100101

101102
def load_run(filename: Filename[RunType], period: Period) -> DataWorkspace[RunType]:
102-
loaded = _mantid_simpleapi.Load(
103-
Filename=str(filename), LoadMonitors=True, StoreInADS=False
104-
)
103+
# Loading many small files with Mantid is, for some reason, very slow when using
104+
# the default number of threads in the Dask threaded scheduler (1 thread worked
105+
# best, 2 is a bit slower but still fast). We can either limit that thread count,
106+
# or add a lock here, which is more specific.
107+
with load_run.lock:
108+
try:
109+
loaded = _mantid_simpleapi.Load(
110+
Filename=str(filename), LoadMonitors=True, StoreInADS=False
111+
)
112+
except TypeError:
113+
# Not loaded using LoadEventNexus, so LoadMonitor option is not available.
114+
loaded = _mantid_simpleapi.Load(Filename=str(filename), StoreInADS=False)
105115
if isinstance(loaded, _mantid_api.Workspace):
106116
# A single workspace
107117
data_ws = loaded
118+
if isinstance(data_ws, _mantid_api.WorkspaceGroup):
119+
if period is None:
120+
raise ValueError(
121+
f'Needs {Period} to be set to know what '
122+
'section of the event data to load'
123+
)
124+
data_ws = data_ws.getItem(period)
108125
else:
109126
# Separate data and monitor workspaces
110127
data_ws = loaded.OutputWorkspace
@@ -121,6 +138,8 @@ def load_run(filename: Filename[RunType], period: Period) -> DataWorkspace[RunTy
121138
return DataWorkspace[RunType](data_ws)
122139

123140

141+
load_run.lock = threading.Lock()
142+
124143
providers = (
125144
from_data_workspace,
126145
load_calibration,

src/ess/sans/workflow.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from . import common, conversions, i_of_q, masking, normalization
1313
from .types import (
1414
BackgroundRun,
15-
CleanSummedQ,
1615
CorrectForGravity,
1716
Denominator,
1817
DetectorBankSizes,
@@ -30,6 +29,7 @@
3029
TransmissionRun,
3130
WavelengthBands,
3231
WavelengthMask,
32+
WavelengthScaledQ,
3333
)
3434

3535

@@ -99,8 +99,8 @@ def _set_runs(
9999
pipeline = pipeline.copy()
100100
runs = pd.DataFrame({Filename[key]: runs}).rename_axis(axis_name)
101101
for part in (Numerator, Denominator):
102-
pipeline[CleanSummedQ[key, part]] = (
103-
pipeline[CleanSummedQ[key, part]]
102+
pipeline[WavelengthScaledQ[key, part]] = (
103+
pipeline[WavelengthScaledQ[key, part]]
104104
.map(runs)
105105
.reduce(index=axis_name, func=merge_contributions)
106106
)

tests/loki/iofq_test.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
BackgroundSubtractedIofQ,
1717
BackgroundSubtractedIofQxy,
1818
BeamCenter,
19-
CleanSummedQ,
2019
CleanWavelength,
2120
CorrectForGravity,
2221
Denominator,
@@ -33,6 +32,7 @@
3332
UncertaintyBroadcastMode,
3433
WavelengthBands,
3534
WavelengthBins,
35+
WavelengthScaledQ,
3636
)
3737

3838
sys.path.insert(0, str(Path(__file__).resolve().parent))
@@ -252,17 +252,21 @@ def test_pipeline_IofQ_merging_events_yields_consistent_results():
252252
assert all(sc.variances(iofq1.data) > sc.variances(iofq3.data))
253253
assert sc.allclose(
254254
sc.values(
255-
pipeline_single.compute(CleanSummedQ[SampleRun, Numerator]).hist().data
255+
pipeline_single.compute(WavelengthScaledQ[SampleRun, Numerator]).hist().data
256256
)
257257
* N,
258258
sc.values(
259-
pipeline_triple.compute(CleanSummedQ[SampleRun, Numerator]).hist().data
259+
pipeline_triple.compute(WavelengthScaledQ[SampleRun, Numerator]).hist().data
260260
),
261261
)
262262
assert sc.allclose(
263-
sc.values(pipeline_single.compute(CleanSummedQ[SampleRun, Denominator]).data)
263+
sc.values(
264+
pipeline_single.compute(WavelengthScaledQ[SampleRun, Denominator]).data
265+
)
264266
* N,
265-
sc.values(pipeline_triple.compute(CleanSummedQ[SampleRun, Denominator]).data),
267+
sc.values(
268+
pipeline_triple.compute(WavelengthScaledQ[SampleRun, Denominator]).data
269+
),
266270
)
267271

268272

0 commit comments

Comments
 (0)