Bragg-edge imaging with ODIN#
This notebook illustrates how to convert recorded events on the ODIN detector to a single wavelength spectrum, revealing a Bragg edge in the data. WFM mode was used in the chopper cascade.
[1]:
import scipp as sc
from ess.reduce import time_of_flight
from ess import odin
import ess.odin.data # noqa: F401
from ess.imaging.types import *
Create and configure the workflow#
[2]:
wf = odin.OdinBraggEdgeWorkflow()
wf[Filename[SampleRun]] = odin.data.iron_simulation_sample_small()
wf[NeXusDetectorName] = "event_mode_detectors/timepix3"
wf[time_of_flight.TimeOfFlightLookupTableFilename] = odin.data.odin_tof_lookup_table()
Downloading file 'iron_simulation_sample_small.nxs' from 'https://public.esss.dk/groups/scipp/ess/odin/1/iron_simulation_sample_small.nxs' to '/home/runner/.cache/ess/odin'.
Downloading file 'ODIN-tof-lookup-table.h5' from 'https://public.esss.dk/groups/scipp/ess/odin/1/ODIN-tof-lookup-table.h5' to '/home/runner/.cache/ess/odin'.
First look at the data#
We load the raw detector data and perform a quick visualization of the event_time_offset spectrum.
[3]:
tmpx3 = wf.compute(RawDetector[SampleRun])
tmpx3
[3]:
- dim_0: 1024
- dim_1: 1024
- detector_number(dim_0, dim_1)int321, 2, ..., 1048575, 1048576
Values:
array([[ 1, 2, 3, ..., 1022, 1023, 1024], [ 1025, 1026, 1027, ..., 2046, 2047, 2048], [ 2049, 2050, 2051, ..., 3070, 3071, 3072], ..., [1045505, 1045506, 1045507, ..., 1046526, 1046527, 1046528], [1046529, 1046530, 1046531, ..., 1047550, 1047551, 1047552], [1047553, 1047554, 1047555, ..., 1048574, 1048575, 1048576]], shape=(1024, 1024), dtype=int32) - position(dim_0, dim_1)vector3m[-0.007033 0.007033 0. ], [-0.007019 0.007033 0. ], ..., [ 0.007019 -0.007033 0. ], [ 0.007033 -0.007033 0. ]
Values:
array([[[-0.007033, 0.007033, 0. ], [-0.007019, 0.007033, 0. ], [-0.007006, 0.007033, 0. ], ..., [ 0.007006, 0.007033, 0. ], [ 0.007019, 0.007033, 0. ], [ 0.007033, 0.007033, 0. ]], [[-0.007033, 0.007019, 0. ], [-0.007019, 0.007019, 0. ], [-0.007006, 0.007019, 0. ], ..., [ 0.007006, 0.007019, 0. ], [ 0.007019, 0.007019, 0. ], [ 0.007033, 0.007019, 0. ]], [[-0.007033, 0.007006, 0. ], [-0.007019, 0.007006, 0. ], [-0.007006, 0.007006, 0. ], ..., [ 0.007006, 0.007006, 0. ], [ 0.007019, 0.007006, 0. ], [ 0.007033, 0.007006, 0. ]], ..., [[-0.007033, -0.007006, 0. ], [-0.007019, -0.007006, 0. ], [-0.007006, -0.007006, 0. ], ..., [ 0.007006, -0.007006, 0. ], [ 0.007019, -0.007006, 0. ], [ 0.007033, -0.007006, 0. ]], [[-0.007033, -0.007019, 0. ], [-0.007019, -0.007019, 0. ], [-0.007006, -0.007019, 0. ], ..., [ 0.007006, -0.007019, 0. ], [ 0.007019, -0.007019, 0. ], [ 0.007033, -0.007019, 0. ]], [[-0.007033, -0.007033, 0. ], [-0.007019, -0.007033, 0. ], [-0.007006, -0.007033, 0. ], ..., [ 0.007006, -0.007033, 0. ], [ 0.007019, -0.007033, 0. ], [ 0.007033, -0.007033, 0. ]]], shape=(1024, 1024, 3)) - x_pixel_offset(dim_0, dim_1)float32m-0.007033, -0.007019, ..., 0.007019, 0.007033
Values:
array([[-0.007033, -0.007019, -0.007006, ..., 0.007006, 0.007019, 0.007033], [-0.007033, -0.007019, -0.007006, ..., 0.007006, 0.007019, 0.007033], [-0.007033, -0.007019, -0.007006, ..., 0.007006, 0.007019, 0.007033], ..., [-0.007033, -0.007019, -0.007006, ..., 0.007006, 0.007019, 0.007033], [-0.007033, -0.007019, -0.007006, ..., 0.007006, 0.007019, 0.007033], [-0.007033, -0.007019, -0.007006, ..., 0.007006, 0.007019, 0.007033]], shape=(1024, 1024), dtype=float32) - y_pixel_offset(dim_0, dim_1)float32m0.007033, 0.007033, ..., -0.007033, -0.007033
Values:
array([[ 0.007033, 0.007033, 0.007033, ..., 0.007033, 0.007033, 0.007033], [ 0.007019, 0.007019, 0.007019, ..., 0.007019, 0.007019, 0.007019], [ 0.007006, 0.007006, 0.007006, ..., 0.007006, 0.007006, 0.007006], ..., [-0.007006, -0.007006, -0.007006, ..., -0.007006, -0.007006, -0.007006], [-0.007019, -0.007019, -0.007019, ..., -0.007019, -0.007019, -0.007019], [-0.007033, -0.007033, -0.007033, ..., -0.007033, -0.007033, -0.007033]], shape=(1024, 1024), dtype=float32)
- (dim_0, dim_1)float32countsbinned data [len=2, len=0, ..., len=1, len=3]
dim='event', content=DataArray( dims=(event: 1000000), data=float32[counts], coords={'event_time_offset':float64[ns], 'event_time_zero':datetime64[ns]})
[4]:
tmpx3.bins.concat().hist(event_time_offset=300).plot()
[4]:
Compute neutron time-of-flight/wavelength#
We will now use the workflow to compute the neutron time-of-flight (equivalent to wavelength) using a lookup table built from the beamline chopper information.
[5]:
wf.visualize(TofDetector[SampleRun], graph_attr={"rankdir": "LR"})
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/backend/execute.py:76, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
75 kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
---> 76 proc = _run_input_lines(cmd, input_lines, kwargs=kwargs)
77 else:
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/backend/execute.py:96, in _run_input_lines(cmd, input_lines, kwargs)
95 def _run_input_lines(cmd, input_lines, *, kwargs):
---> 96 popen = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
98 stdin_write = popen.stdin.write
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/subprocess.py:1026, in Popen.__init__(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize, process_group)
1023 self.stderr = io.TextIOWrapper(self.stderr,
1024 encoding=encoding, errors=errors)
-> 1026 self._execute_child(args, executable, preexec_fn, close_fds,
1027 pass_fds, cwd, env,
1028 startupinfo, creationflags, shell,
1029 p2cread, p2cwrite,
1030 c2pread, c2pwrite,
1031 errread, errwrite,
1032 restore_signals,
1033 gid, gids, uid, umask,
1034 start_new_session, process_group)
1035 except:
1036 # Cleanup if the child failed starting.
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/subprocess.py:1955, in Popen._execute_child(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session, process_group)
1954 if err_filename is not None:
-> 1955 raise child_exception_type(errno_num, err_msg, err_filename)
1956 else:
FileNotFoundError: [Errno 2] No such file or directory: PosixPath('dot')
The above exception was the direct cause of the following exception:
ExecutableNotFound Traceback (most recent call last)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/IPython/core/formatters.py:1036, in MimeBundleFormatter.__call__(self, obj, include, exclude)
1033 method = get_real_method(obj, self.print_method)
1035 if method is not None:
-> 1036 return method(include=include, exclude=exclude)
1037 return None
1038 else:
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/jupyter_integration.py:98, in JupyterIntegration._repr_mimebundle_(self, include, exclude, **_)
96 include = set(include) if include is not None else {self._jupyter_mimetype}
97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
99 for mimetype, method_name in MIME_TYPES.items()
100 if mimetype in include}
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/jupyter_integration.py:98, in <dictcomp>(.0)
96 include = set(include) if include is not None else {self._jupyter_mimetype}
97 include -= set(exclude or [])
---> 98 return {mimetype: getattr(self, method_name)()
99 for mimetype, method_name in MIME_TYPES.items()
100 if mimetype in include}
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/jupyter_integration.py:112, in JupyterIntegration._repr_image_svg_xml(self)
110 def _repr_image_svg_xml(self) -> str:
111 """Return the rendered graph as SVG string."""
--> 112 return self.pipe(format='svg', encoding=SVG_ENCODING)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/piping.py:104, in Pipe.pipe(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
55 def pipe(self,
56 format: typing.Optional[str] = None,
57 renderer: typing.Optional[str] = None,
(...) 61 engine: typing.Optional[str] = None,
62 encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
63 """Return the source piped through the Graphviz layout command.
64
65 Args:
(...) 102 '<?xml version='
103 """
--> 104 return self._pipe_legacy(format,
105 renderer=renderer,
106 formatter=formatter,
107 neato_no_op=neato_no_op,
108 quiet=quiet,
109 engine=engine,
110 encoding=encoding)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/_tools.py:185, in deprecate_positional_args.<locals>.decorator.<locals>.wrapper(*args, **kwargs)
177 wanted = ', '.join(f'{name}={value!r}'
178 for name, value in deprecated.items())
179 warnings.warn(f'The signature of {func_name} will be reduced'
180 f' to {supported_number} positional arg{s_}{qualification}'
181 f' {list(supported)}: pass {wanted} as keyword arg{s_}',
182 stacklevel=stacklevel,
183 category=category)
--> 185 return func(*args, **kwargs)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/piping.py:121, in Pipe._pipe_legacy(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
112 @_tools.deprecate_positional_args(supported_number=1, ignore_arg='self')
113 def _pipe_legacy(self,
114 format: typing.Optional[str] = None,
(...) 119 engine: typing.Optional[str] = None,
120 encoding: typing.Optional[str] = None) -> typing.Union[bytes, str]:
--> 121 return self._pipe_future(format,
122 renderer=renderer,
123 formatter=formatter,
124 neato_no_op=neato_no_op,
125 quiet=quiet,
126 engine=engine,
127 encoding=encoding)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/piping.py:149, in Pipe._pipe_future(self, format, renderer, formatter, neato_no_op, quiet, engine, encoding)
146 if encoding is not None:
147 if codecs.lookup(encoding) is codecs.lookup(self.encoding):
148 # common case: both stdin and stdout need the same encoding
--> 149 return self._pipe_lines_string(*args, encoding=encoding, **kwargs)
150 try:
151 raw = self._pipe_lines(*args, input_encoding=self.encoding, **kwargs)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/backend/piping.py:212, in pipe_lines_string(engine, format, input_lines, encoding, renderer, formatter, neato_no_op, quiet)
206 cmd = dot_command.command(engine, format,
207 renderer=renderer,
208 formatter=formatter,
209 neato_no_op=neato_no_op)
210 kwargs = {'input_lines': input_lines, 'encoding': encoding}
--> 212 proc = execute.run_check(cmd, capture_output=True, quiet=quiet, **kwargs)
213 return proc.stdout
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/graphviz/backend/execute.py:81, in run_check(cmd, input_lines, encoding, quiet, **kwargs)
79 except OSError as e:
80 if e.errno == errno.ENOENT:
---> 81 raise ExecutableNotFound(cmd) from e
82 raise
84 if not quiet and proc.stderr:
ExecutableNotFound: failed to execute PosixPath('dot'), make sure the Graphviz executables are on your systems' PATH
[5]:
<graphviz.graphs.Digraph at 0x7f59d04082d0>
Inspect the lookup table#
It is always a good idea to quickly plot the TOF lookup table, as a sanity check.
[6]:
table = wf.compute(time_of_flight.TimeOfFlightLookupTable)
table.plot(figsize=(9, 4))
[6]:
Compute neutron wavelengths#
[7]:
sample_wavs = wf.compute(WavelengthDetector[SampleRun])
sample_wavs.bins.concat().hist(wavelength=300).plot()
---------------------------------------------------------------------------
UnsatisfiedRequirement Traceback (most recent call last)
Cell In[7], line 1
----> 1 sample_wavs = wf.compute(WavelengthDetector[SampleRun])
3 sample_wavs.bins.concat().hist(wavelength=300).plot()
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:191, in Pipeline.compute(self, tp, reporter, **kwargs)
170 def compute(
171 self,
172 tp: type | Iterable[type] | "UnionType", # noqa: UP037 (needed by Sphinx)
173 reporter: Reporter | None = None,
174 **kwargs: Any,
175 ) -> Any:
176 """
177 Compute result for the given keys.
178
(...) 189 Keyword arguments passed to the ``.get()`` method.
190 """
--> 191 return self.get(tp, **kwargs).compute(reporter=reporter)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:281, in Pipeline.get(self, keys, scheduler, handler, max_depth)
278 info = f'{e} Requested node not in graph. Did you mean one of: {nodes}?'
279 # Not raising `from e` because that includes noisy traceback of internals,
280 # which are not relevant to the user.
--> 281 raise type(e)(f'{info}\n\n') from None
282 return TaskGraph(
283 graph=graph,
284 targets=targets if multi else keys, # type: ignore[arg-type]
285 scheduler=scheduler,
286 )
UnsatisfiedRequirement: Missing input node 'LookupTableRelativeErrorThreshold'. Affects requested targets (via providers given in parentheses):
1. LookupTableRelativeErrorThreshold → (ess.reduce.time_of_flight.eto_to_tof.mask_large_uncertainty_in_lut_detector) → ErrorLimitedTofLookupTable[NXdetector] → (ess.reduce.time_of_flight.eto_to_tof.detector_time_of_flight_data) → TofDetector[SampleRun] → (ess.imaging.conversion.compute_detector_wavelength) → WavelengthDetector[SampleRun]
Process the open-beam run#
We now reuse the same workflow to process the open-beam run that will be used later for normalization.
[8]:
wf[Filename[OpenBeamRun]] = odin.data.iron_simulation_ob_small()
openbeam_wavs = wf.compute(WavelengthDetector[OpenBeamRun])
openbeam_wavs.bins.concat().hist(wavelength=300).plot()
Downloading file 'iron_simulation_ob_small.nxs' from 'https://public.esss.dk/groups/scipp/ess/odin/1/iron_simulation_ob_small.nxs' to '/home/runner/.cache/ess/odin'.
---------------------------------------------------------------------------
UnsatisfiedRequirement Traceback (most recent call last)
Cell In[8], line 2
1 wf[Filename[OpenBeamRun]] = odin.data.iron_simulation_ob_small()
----> 2 openbeam_wavs = wf.compute(WavelengthDetector[OpenBeamRun])
4 openbeam_wavs.bins.concat().hist(wavelength=300).plot()
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:191, in Pipeline.compute(self, tp, reporter, **kwargs)
170 def compute(
171 self,
172 tp: type | Iterable[type] | "UnionType", # noqa: UP037 (needed by Sphinx)
173 reporter: Reporter | None = None,
174 **kwargs: Any,
175 ) -> Any:
176 """
177 Compute result for the given keys.
178
(...) 189 Keyword arguments passed to the ``.get()`` method.
190 """
--> 191 return self.get(tp, **kwargs).compute(reporter=reporter)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:281, in Pipeline.get(self, keys, scheduler, handler, max_depth)
278 info = f'{e} Requested node not in graph. Did you mean one of: {nodes}?'
279 # Not raising `from e` because that includes noisy traceback of internals,
280 # which are not relevant to the user.
--> 281 raise type(e)(f'{info}\n\n') from None
282 return TaskGraph(
283 graph=graph,
284 targets=targets if multi else keys, # type: ignore[arg-type]
285 scheduler=scheduler,
286 )
UnsatisfiedRequirement: Missing input node 'LookupTableRelativeErrorThreshold'. Affects requested targets (via providers given in parentheses):
1. LookupTableRelativeErrorThreshold → (ess.reduce.time_of_flight.eto_to_tof.mask_large_uncertainty_in_lut_detector) → ErrorLimitedTofLookupTable[NXdetector] → (ess.reduce.time_of_flight.eto_to_tof.detector_time_of_flight_data) → TofDetector[OpenBeamRun] → (ess.imaging.conversion.compute_detector_wavelength) → WavelengthDetector[OpenBeamRun]
Select region of interest by masking outer regions#
Making a 2D histogram of the data shows a dark square region in the centre of the detector panel; this is the region of interest, where the square sample has absorbed neutrons.
[9]:
sample_wavs.hist().plot(aspect='equal')
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[9], line 1
----> 1 sample_wavs.hist().plot(aspect='equal')
NameError: name 'sample_wavs' is not defined
The brighter areas around the edges are regions where neutrons did not travel through the sample. We thus want to mask those out using masking rules based on the spatial coordinates of the data:
[10]:
wf[MaskingRules] = {
'x_pixel_offset': lambda x: (x < sc.scalar(-5.8e-3, unit='m').to(unit=x.unit)) | (x > sc.scalar(5.8e-3, unit='m').to(unit=x.unit)),
'y_pixel_offset': lambda y: (y < sc.scalar(-5.8e-3, unit='m').to(unit=y.unit)) | (y > sc.scalar(5.8e-3, unit='m').to(unit=y.unit))
}
[11]:
masked = wf.compute(CorrectedDetector[SampleRun])
masked.hist().plot(aspect='equal')
---------------------------------------------------------------------------
UnsatisfiedRequirement Traceback (most recent call last)
Cell In[11], line 1
----> 1 masked = wf.compute(CorrectedDetector[SampleRun])
3 masked.hist().plot(aspect='equal')
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:191, in Pipeline.compute(self, tp, reporter, **kwargs)
170 def compute(
171 self,
172 tp: type | Iterable[type] | "UnionType", # noqa: UP037 (needed by Sphinx)
173 reporter: Reporter | None = None,
174 **kwargs: Any,
175 ) -> Any:
176 """
177 Compute result for the given keys.
178
(...) 189 Keyword arguments passed to the ``.get()`` method.
190 """
--> 191 return self.get(tp, **kwargs).compute(reporter=reporter)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:281, in Pipeline.get(self, keys, scheduler, handler, max_depth)
278 info = f'{e} Requested node not in graph. Did you mean one of: {nodes}?'
279 # Not raising `from e` because that includes noisy traceback of internals,
280 # which are not relevant to the user.
--> 281 raise type(e)(f'{info}\n\n') from None
282 return TaskGraph(
283 graph=graph,
284 targets=targets if multi else keys, # type: ignore[arg-type]
285 scheduler=scheduler,
286 )
UnsatisfiedRequirement: Missing input node 'LookupTableRelativeErrorThreshold'. Affects requested targets (via providers given in parentheses):
1. LookupTableRelativeErrorThreshold → (ess.reduce.time_of_flight.eto_to_tof.mask_large_uncertainty_in_lut_detector) → ErrorLimitedTofLookupTable[NXdetector] → (ess.reduce.time_of_flight.eto_to_tof.detector_time_of_flight_data) → TofDetector[SampleRun] → (ess.imaging.conversion.compute_detector_wavelength) → WavelengthDetector[SampleRun] → (ess.odin.masking.apply_masks) → CorrectedDetector[SampleRun]
Normalize to open beam#
Finally, we use the masked sample and open-beam data to obtain a normalized signal, which reveals the Fe Bragg edges:
[12]:
wbins = sc.linspace('wavelength', 1.1, 9.4, 301, unit='angstrom')
normalized = (
wf.compute(CorrectedDetector[SampleRun]).bins.concat().hist(wavelength=wbins) /
wf.compute(CorrectedDetector[OpenBeamRun]).bins.concat().hist(wavelength=wbins)
)
normalized.plot()
---------------------------------------------------------------------------
UnsatisfiedRequirement Traceback (most recent call last)
Cell In[12], line 4
1 wbins = sc.linspace('wavelength', 1.1, 9.4, 301, unit='angstrom')
3 normalized = (
----> 4 wf.compute(CorrectedDetector[SampleRun]).bins.concat().hist(wavelength=wbins) /
5 wf.compute(CorrectedDetector[OpenBeamRun]).bins.concat().hist(wavelength=wbins)
6 )
8 normalized.plot()
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:191, in Pipeline.compute(self, tp, reporter, **kwargs)
170 def compute(
171 self,
172 tp: type | Iterable[type] | "UnionType", # noqa: UP037 (needed by Sphinx)
173 reporter: Reporter | None = None,
174 **kwargs: Any,
175 ) -> Any:
176 """
177 Compute result for the given keys.
178
(...) 189 Keyword arguments passed to the ``.get()`` method.
190 """
--> 191 return self.get(tp, **kwargs).compute(reporter=reporter)
File ~/work/ess/ess/.pixi/envs/docs-essimaging/lib/python3.11/site-packages/sciline/pipeline.py:281, in Pipeline.get(self, keys, scheduler, handler, max_depth)
278 info = f'{e} Requested node not in graph. Did you mean one of: {nodes}?'
279 # Not raising `from e` because that includes noisy traceback of internals,
280 # which are not relevant to the user.
--> 281 raise type(e)(f'{info}\n\n') from None
282 return TaskGraph(
283 graph=graph,
284 targets=targets if multi else keys, # type: ignore[arg-type]
285 scheduler=scheduler,
286 )
UnsatisfiedRequirement: Missing input node 'LookupTableRelativeErrorThreshold'. Affects requested targets (via providers given in parentheses):
1. LookupTableRelativeErrorThreshold → (ess.reduce.time_of_flight.eto_to_tof.mask_large_uncertainty_in_lut_detector) → ErrorLimitedTofLookupTable[NXdetector] → (ess.reduce.time_of_flight.eto_to_tof.detector_time_of_flight_data) → TofDetector[SampleRun] → (ess.imaging.conversion.compute_detector_wavelength) → WavelengthDetector[SampleRun] → (ess.odin.masking.apply_masks) → CorrectedDetector[SampleRun]
Save the final result#
[13]:
from scippneutron.io import save_xye
to_disk = normalized.copy(deep=False)
to_disk.coords['wavelength'] = sc.midpoints(to_disk.coords['wavelength'])
save_xye('fe_bragg_edge.xye', to_disk)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[13], line 3
1 from scippneutron.io import save_xye
----> 3 to_disk = normalized.copy(deep=False)
4 to_disk.coords['wavelength'] = sc.midpoints(to_disk.coords['wavelength'])
6 save_xye('fe_bragg_edge.xye', to_disk)
NameError: name 'normalized' is not defined