Source code for ess.amor.resolution
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
import scipp as sc
from ..reflectometry.tools import fwhm_to_std
from ..reflectometry.types import (
DetectorSpatialResolution,
FootprintCorrectedData,
QBins,
QResolution,
SampleRun,
SampleSize,
)
from .types import (
AngularResolution,
Chopper1Position,
Chopper2Position,
SampleSizeResolution,
WavelengthResolution,
)
[docs]
def wavelength_resolution(
da: FootprintCorrectedData[SampleRun],
chopper_1_position: Chopper1Position[SampleRun],
chopper_2_position: Chopper2Position[SampleRun],
) -> WavelengthResolution:
"""
Find the wavelength resolution contribution as described in Section 4.3.3 of the
Amor publication (doi: 10.1016/j.nima.2016.03.007).
Parameters
----------
chopper_1_position:
Position of first chopper (the one closer to the source).
chopper_2_position:
Position of second chopper (the one closer to the sample).
pixel_position:
Positions for detector pixels.
Returns
-------
:
The angular resolution variable, as standard deviation.
"""
pixel_position = da.coords["position"]
chopper_midpoint = (chopper_1_position + chopper_2_position) * sc.scalar(0.5)
distance_between_choppers = sc.norm(chopper_2_position - chopper_1_position)
chopper_detector_distance = sc.norm(pixel_position - chopper_midpoint)
return WavelengthResolution(
fwhm_to_std(distance_between_choppers / chopper_detector_distance)
)
[docs]
def sample_size_resolution(
da: FootprintCorrectedData[SampleRun],
sample_size: SampleSize[SampleRun],
) -> SampleSizeResolution:
"""
The resolution from the projected sample size, where it may be bigger
than the detector pixel resolution as described in Section 4.3.3 of the Amor
publication (doi: 10.1016/j.nima.2016.03.007).
Parameters
----------
pixel_position:
Positions for detector pixels.
sample_size:
Size of sample.
Returns
-------
:
Standard deviation of contribution from the sample size.
"""
return fwhm_to_std(
sc.to_unit(sample_size, "m")
/ sc.to_unit(
sc.norm(da.coords["position"] - da.coords["sample_position"]),
"m",
copy=False,
)
)
[docs]
def angular_resolution(
da: FootprintCorrectedData[SampleRun],
detector_spatial_resolution: DetectorSpatialResolution[SampleRun],
) -> AngularResolution:
"""
Determine the angular resolution as described in Section 4.3.3 of the Amor
publication (doi: 10.1016/j.nima.2016.03.007).
Parameters
----------
pixel_position:
Positions for detector pixels.
theta:
Theta values for events.
detector_spatial_resolution:
FWHM of detector pixel resolution.
Returns
-------
:
Angular resolution standard deviation
"""
theta = da.bins.coords["theta"]
return (
fwhm_to_std(
sc.to_unit(
sc.atan(
sc.to_unit(detector_spatial_resolution, "m")
/ sc.to_unit(
sc.norm(da.coords["position"] - da.coords["sample_position"]),
"m",
copy=False,
)
),
theta.bins.unit,
copy=False,
)
)
/ theta
)
[docs]
def sigma_Q(
da: FootprintCorrectedData[SampleRun],
angular_resolution: AngularResolution,
wavelength_resolution: WavelengthResolution,
sample_size_resolution: SampleSizeResolution,
qbins: QBins,
) -> QResolution:
"""
Combine all of the components of the resolution and add Q contribution.
Parameters
----------
angular_resolution:
Angular resolution contribution.
wavelength_resolution:
Wavelength resolution contribution.
sample_size_resolution:
Sample size resolution contribution.
q_bins:
Q-bin values.
Returns
-------
:
Combined resolution function.
"""
h = da.bins.concat().hist(Q=qbins)
s = (
(
da
* (
angular_resolution**2
+ wavelength_resolution**2
+ sample_size_resolution**2
)
* da.bins.coords['Q'] ** 2
)
.bins.concat()
.hist(Q=qbins)
)
return sc.sqrt(sc.values(s / h))
providers = (sigma_Q, angular_resolution, wavelength_resolution, sample_size_resolution)