Skip to content

Commit ac77b12

Browse files
authored
Merge pull request #31 from scipp/orso-corrections
Track ORSO corrections
2 parents b99fbd6 + c826b4d commit ac77b12

File tree

10 files changed

+159
-85
lines changed

10 files changed

+159
-85
lines changed

docs/examples/amor.ipynb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@
187187
"cell_type": "markdown",
188188
"metadata": {},
189189
"source": [
190-
"Unfortunately, some metadata could not be determined autoamtically.\n",
190+
"Unfortunately, some metadata could not be determined automatically.\n",
191191
"In particular, we need to specify the sample manually:"
192192
]
193193
},
@@ -230,6 +230,22 @@
230230
"iofq_dataset.info.reduction.script = 'https://scipp.github.io/essreflectometry/examples/amor.html'"
231231
]
232232
},
233+
{
234+
"cell_type": "markdown",
235+
"metadata": {},
236+
"source": [
237+
"To support tracking provenance, we also list the corrections that were done by the workflow and store them in the dataset:"
238+
]
239+
},
240+
{
241+
"cell_type": "code",
242+
"execution_count": null,
243+
"metadata": {},
244+
"outputs": [],
245+
"source": [
246+
"iofq_dataset.info.reduction.corrections = orso.find_corrections(metadata_pipeline.get(orso.OrsoIofQDataset))"
247+
]
248+
},
233249
{
234250
"cell_type": "markdown",
235251
"metadata": {},

src/essreflectometry/amor/load.py

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
import scippnexus as snx
88

99
from ..logging import get_logger
10-
from ..types import Filename, RawData, RawEvents, Run
10+
from ..types import ChopperCorrectedTofEvents, Filename, RawData, RawEvents, Run
1111
from .data import get_path
1212
from .types import BeamlineParams
1313

1414

15-
def _tof_correction(data: sc.DataArray, dim: str = 'tof') -> sc.DataArray:
15+
def chopper_tof_correction(data: RawEvents[Run]) -> ChopperCorrectedTofEvents[Run]:
1616
"""
1717
A correction for the presence of the chopper with respect to the "true" ToF.
1818
Also fold the two pulses.
@@ -22,17 +22,13 @@ def _tof_correction(data: sc.DataArray, dim: str = 'tof') -> sc.DataArray:
2222
----------
2323
data:
2424
Input data array to correct.
25-
dim:
26-
Name of the time of flight dimension.
2725
2826
Returns
2927
-------
3028
:
3129
ToF corrected data array.
3230
"""
33-
# TODO
34-
# if 'orso' in data.attrs:
35-
# data.attrs['orso'].value.reduction.corrections += ['chopper ToF correction']
31+
dim = 'tof'
3632
tof_unit = data.bins.coords[dim].bins.unit
3733
tau = sc.to_unit(
3834
1 / (2 * data.coords['source_chopper_2'].value['frequency'].data),
@@ -48,7 +44,15 @@ def _tof_correction(data: sc.DataArray, dim: str = 'tof') -> sc.DataArray:
4844
# Apply the offset on both bins
4945
data.bins.coords[dim] += offset
5046
# Rebin to exclude second (empty) pulse range
51-
return data.bin({dim: sc.concat([0.0 * sc.units.us, tau], dim)})
47+
data = data.bin({dim: sc.concat([0.0 * sc.units.us, tau], dim)})
48+
49+
# Ad-hoc correction described in
50+
# https://scipp.github.io/ess/instruments/amor/amor_reduction.html
51+
data.coords['position'].fields.y += data.coords['position'].fields.z * sc.tan(
52+
2.0 * data.coords['sample_rotation'] - (0.955 * sc.units.deg)
53+
)
54+
55+
return ChopperCorrectedTofEvents[Run](data)
5256

5357

5458
def _assemble_event_data(dg: sc.DataGroup) -> sc.DataArray:
@@ -141,19 +145,7 @@ def extract_events(
141145
for key, value in beamline.items():
142146
data.coords[key] = value
143147

144-
# if orso is not None:
145-
# populate_orso(orso=orso, data=full_data, filename=filename)
146-
# data.attrs['orso'] = sc.scalar(orso)
147-
148-
# Perform tof correction and fold two pulses
149-
data = _tof_correction(data)
150-
151-
# Ad-hoc correction described in
152-
# https://scipp.github.io/ess/instruments/amor/amor_reduction.html
153-
data.coords['position'].fields.y += data.coords['position'].fields.z * sc.tan(
154-
2.0 * data.coords['sample_rotation'] - (0.955 * sc.units.deg)
155-
)
156148
return RawEvents[Run](data)
157149

158150

159-
providers = (extract_events, load_raw_nexus)
151+
providers = (extract_events, load_raw_nexus, chopper_tof_correction)

src/essreflectometry/amor/orso.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# SPDX-License-Identifier: BSD-3-Clause
2-
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
2+
# Copyright (c) 2024 Scipp contributors (https://github.com/scipp)
33
"""ORSO utilities for Amor."""
44
from typing import Optional
55

src/essreflectometry/calibrations.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import scipp as sc
44

55
from . import supermirror
6-
7-
# from ..reflectometry import orso
86
from .types import QBins
97

108

src/essreflectometry/conversions.py

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
from scippneutron._utils import elem_dtype, elem_unit
88
from scippneutron.conversion.graph import beamline, tof
99

10-
# from . import orso
1110
from .types import (
11+
ChopperCorrectedTofEvents,
1212
FootprintCorrectedData,
1313
HistogrammedQData,
1414
QBins,
1515
QData,
16-
RawEvents,
1716
Run,
1817
SpecularReflectionCoordTransformGraph,
1918
ThetaData,
@@ -119,7 +118,7 @@ def specular_reflection() -> SpecularReflectionCoordTransformGraph:
119118

120119

121120
def tof_to_wavelength(
122-
data_array: RawEvents[Run],
121+
data_array: ChopperCorrectedTofEvents[Run],
123122
graph: SpecularReflectionCoordTransformGraph,
124123
wavelength_edges: Optional[WavelengthEdges],
125124
) -> WavelengthData[Run]:
@@ -144,23 +143,6 @@ def tof_to_wavelength(
144143
data_array_wav = data_array.transform_coords(["wavelength"], graph=graph)
145144
if wavelength_edges is not None:
146145
data_array_wav = data_array_wav.bin({wavelength_edges.dim: wavelength_edges})
147-
# TODO
148-
# try:
149-
# from orsopy import fileio
150-
151-
# unit = data_array_wav.coords['wavelength'].unit
152-
# # This insures that when the unit is Å it is written as
153-
# # angstrom in the ORSO object.
154-
# if unit == 'angstrom':
155-
# unit = 'angstrom'
156-
# orso_measurement = data_array_wav.attrs['orso'].value.data_source.measurement
157-
# orso_measurement.instrument_settings.wavelength = fileio.base.ValueRange(
158-
# float(data_array_wav.coords['wavelength'].min().value),
159-
# float(data_array_wav.coords['wavelength'].max().value),
160-
# unit,
161-
# )
162-
# except ImportError:
163-
# orso.not_found_warning()
164146
return WavelengthData[Run](data_array_wav)
165147

166148

@@ -185,18 +167,6 @@ def wavelength_to_theta(
185167
New data array with theta coordinate.
186168
"""
187169
data_array_theta = data_array.transform_coords(['theta'], graph=graph)
188-
# TODO
189-
# try:
190-
# from orsopy import fileio
191-
192-
# orso_measurement = data_array_theta.attrs['orso'].value.data_source.measurement
193-
# orso_measurement.instrument_settings.incident_angle = fileio.base.ValueRange(
194-
# float(data_array_theta.coords['theta'].min().value),
195-
# float(data_array_theta.coords['theta'].max().value),
196-
# data_array_theta.bins.coords['theta'].min().unit,
197-
# )
198-
# import inspect
199-
200170
# # Determine if 'gravity' is in the graph and if to add the gravity correction
201171
# if any(
202172
# [

src/essreflectometry/corrections.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55

66
from .supermirror import SupermirrorCalibrationFactor
77
from .tools import fwhm_to_std
8-
9-
# from . import orso
108
from .types import (
119
FootprintCorrectedData,
1210
HistogrammedQData,
@@ -40,12 +38,6 @@ def footprint_correction(data_array: ThetaData[Run]) -> FootprintCorrectedData[R
4038
fwhm_to_std(data_array.coords['sample_size'] / size_of_beam_on_sample)
4139
)
4240
data_array_fp_correction = data_array / footprint_scale.squeeze()
43-
# try:
44-
# data_array_fp_correction.attrs['orso'].value.reduction.corrections += [
45-
# 'footprint correction'
46-
# ]
47-
# except KeyError:
48-
# orso.not_found_warning()
4941
return FootprintCorrectedData[Run](data_array_fp_correction)
5042

5143

@@ -98,11 +90,6 @@ def normalize_by_counts(
9890
f'regime. The maximum counts found is {data_array.values[ind]} at '
9991
f'index {ind}. The total number of counts is {ncounts.value}.'
10092
)
101-
# TODO
102-
# try:
103-
# norm.attrs['orso'].value.reduction.corrections += ['total counts']
104-
# except KeyError:
105-
# orso.not_found_warning()
10693
return norm
10794

10895

src/essreflectometry/normalize.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
33
import scipp as sc
44

5-
# from ..reflectometry import orso
65
from .types import IofQ, NormalizedIofQ, Reference, Sample
76

87

@@ -28,17 +27,6 @@ def normalize_by_supermirror(
2827
"""
2928
normalized = sample / supermirror
3029
normalized.masks['no_reference_neutrons'] = (supermirror == sc.scalar(0)).data
31-
# TODO
32-
# try:
33-
# normalized.attrs['orso'] = sample.attrs['orso']
34-
# normalized.attrs['orso'].value.reduction.corrections = list(
35-
# set(
36-
# sample.attrs['orso'].value.reduction.corrections
37-
# + supermirror.attrs['orso'].value.reduction.corrections
38-
# )
39-
# )
40-
# except KeyError:
41-
# orso.not_found_warning()
4230
return NormalizedIofQ(normalized)
4331

4432

src/essreflectometry/orso.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,37 @@
11
# SPDX-License-Identifier: BSD-3-Clause
2-
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
2+
# Copyright (c) 2024 Scipp contributors (https://github.com/scipp)
33
"""ORSO utilities for reflectometry.
44
55
The Sciline providers and types in this module largely ignore the metadata
66
of reference runs and only use the metadata of the sample run.
77
"""
88

9+
import graphlib
910
import os
1011
import platform
1112
from datetime import datetime, timezone
12-
from typing import NewType, Optional
13+
from typing import Any, NewType, Optional
1314

1415
from dateutil.parser import parse as parse_datetime
1516
from orsopy.fileio import base as orso_base
1617
from orsopy.fileio import data_source, orso, reduction
1718

18-
from .types import Filename, RawData, Reference, Sample
19+
from .supermirror import SupermirrorCalibrationFactor
20+
from .types import (
21+
ChopperCorrectedTofEvents,
22+
Filename,
23+
FootprintCorrectedData,
24+
IofQ,
25+
RawData,
26+
Reference,
27+
Sample,
28+
)
29+
30+
try:
31+
from sciline.task_graph import TaskGraph
32+
except ModuleNotFoundError:
33+
TaskGraph = Any
34+
1935

2036
OrsoCreator = NewType('OrsoCreator', orso_base.Person)
2137
"""ORSO creator, that is, the person who processed the data."""
@@ -142,6 +158,47 @@ def build_orso_data_source(
142158
)
143159

144160

161+
_CORRECTIONS_BY_GRAPH_KEY = {
162+
ChopperCorrectedTofEvents[Sample]: 'chopper ToF correction',
163+
FootprintCorrectedData[Sample]: 'footprint correction',
164+
IofQ[Sample]: 'total counts',
165+
SupermirrorCalibrationFactor: 'supermirror calibration',
166+
}
167+
168+
169+
def find_corrections(task_graph: TaskGraph) -> list[str]:
170+
"""Determine the list of corrections for ORSO from a task graph.
171+
172+
Checks for known keys in the graph that correspond to corrections
173+
that should be tracked in an ORSO output dataset.
174+
Bear in mind that this exclusively checks the types used as keys in a task graph,
175+
it cannot detect other corrections that are performed within providers
176+
or outside the graph.
177+
178+
Parameters
179+
----------
180+
:
181+
task_graph:
182+
The task graph used to produce output data.
183+
184+
Returns
185+
-------
186+
:
187+
List of corrections in the order they are applied in.
188+
"""
189+
toposort = graphlib.TopologicalSorter(
190+
{
191+
key: tuple(provider.arg_spec.keys())
192+
for key, provider in task_graph._graph.items()
193+
}
194+
)
195+
return [
196+
c
197+
for key in toposort.static_order()
198+
if (c := _CORRECTIONS_BY_GRAPH_KEY.get(key, None)) is not None
199+
]
200+
201+
145202
providers = (
146203
build_orso_data_source,
147204
build_orso_measurement,

src/essreflectometry/types.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ class RawEvents(sciline.Scope[Run, sc.DataArray], sc.DataArray):
1717
binned by `detector_number` (pixel of the detector frame)."""
1818

1919

20+
class ChopperCorrectedTofEvents(sciline.Scope[Run, sc.DataArray], sc.DataArray):
21+
"""Event time data after correcting tof for choppers."""
22+
23+
2024
class WavelengthData(sciline.Scope[Run, sc.DataArray], sc.DataArray):
2125
"""Event data with wavelengths computed for every event,
2226
binned by `detector_number` (pixel of the detector frame)"""

0 commit comments

Comments
 (0)