Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 1 addition & 7 deletions packages/essreflectometry/src/ess/amor/workflow.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
# Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
from ..reflectometry.conversions import (
add_proton_charge_coord,
add_proton_charge_mask,
)
from ..reflectometry.corrections import correct_by_footprint, correct_by_proton_charge
from ..reflectometry.types import (
BeamDivergenceLimits,
Expand Down Expand Up @@ -38,9 +34,7 @@ def add_coords_masks_and_apply_corrections(

# For some older Amor files there are no entries in the proton charge log
if len(proton_charge) != 0:
da = add_proton_charge_coord(da, proton_charge)
da = add_proton_charge_mask(da)
da = correct_by_proton_charge(da)
da = correct_by_proton_charge(da, proton_charge=proton_charge)

return ReducibleData[RunType](da)

Expand Down
21 changes: 20 additions & 1 deletion packages/essreflectometry/src/ess/estia/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@
SampleSizeResolution,
WavelengthResolution,
)
from .workflow import EstiaMcStasWorkflow, EstiaWorkflow
from .workflow import (
EstiaMcStasMonitorHistogramWorkflow,
EstiaMcStasMonitorIntegratedWorkflow,
EstiaMcStasProtonChargeWorkflow,
EstiaMcStasUnnormalizedWorkflow,
EstiaMcStasWorkflow,
EstiaMonitorHistogramWorkflow,
EstiaMonitorIntegratedWorkflow,
EstiaProtonChargeWorkflow,
EstiaUnnormalizedWorkflow,
EstiaWorkflow,
)

try:
__version__ = importlib.metadata.version(__package__ or __name__)
Expand All @@ -18,7 +29,15 @@

__all__ = [
"AngularResolution",
"EstiaMcStasMonitorHistogramWorkflow",
"EstiaMcStasMonitorIntegratedWorkflow",
"EstiaMcStasProtonChargeWorkflow",
"EstiaMcStasUnnormalizedWorkflow",
"EstiaMcStasWorkflow",
"EstiaMonitorHistogramWorkflow",
"EstiaMonitorIntegratedWorkflow",
"EstiaProtonChargeWorkflow",
"EstiaUnnormalizedWorkflow",
"EstiaWorkflow",
"SampleSizeResolution",
"WavelengthResolution",
Expand Down
89 changes: 75 additions & 14 deletions packages/essreflectometry/src/ess/estia/corrections.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,92 @@
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
import sciline
import scipp as sc
from ess.reduce.uncertainty import UncertaintyBroadcastMode

from ..reflectometry.conversions import (
add_proton_charge_coord,
add_proton_charge_mask,
)
from ..reflectometry.corrections import correct_by_proton_charge
from ..reflectometry import corrections as common_corrections
from ..reflectometry.corrections import RunNormalization
from ..reflectometry.types import (
BeamDivergenceLimits,
CoordTransformationGraph,
CorrectionsToApply,
ProtonCharge,
ReducibleData,
RunType,
RunUnnormalizedData,
WavelengthBins,
WavelengthDetector,
YIndexLimits,
ZIndexLimits,
)
from .conversions import add_coords
from .maskings import add_masks
from .types import WavelengthMonitor


def normalize_by_monitor_histogram(
detector: RunUnnormalizedData[RunType],
*,
monitor: WavelengthMonitor[RunType],
uncertainty_broadcast_mode: UncertaintyBroadcastMode,
) -> ReducibleData[RunType]:
"""Normalize detector data by a histogrammed monitor.

The detector is normalized according to

.. math::

d_i^\\text{Norm} = \\frac{d_i}{m_i} \\Delta \\lambda_i

Parameters
----------
detector:
Input event data in wavelength.
monitor:
A histogrammed monitor in wavelength.
uncertainty_broadcast_mode:
Choose how uncertainties of the monitor are broadcast to the sample data.

Returns
-------
:
`detector` normalized by a monitor.

See also
--------
ess.reduce.normalization.normalize_by_monitor_histogram:
For details and the actual implementation.
"""
return common_corrections.normalize_by_monitor_histogram(
detector=detector,
monitor=monitor,
uncertainty_broadcast_mode=uncertainty_broadcast_mode,
)


def normalize_by_monitor_integrated(
detector: RunUnnormalizedData[RunType],
*,
monitor: WavelengthMonitor[RunType],
uncertainty_broadcast_mode: UncertaintyBroadcastMode,
) -> ReducibleData[RunType]:
"""Normalize detector data by an integrated wavelength monitor."""
return common_corrections.normalize_by_monitor_integrated(
detector=detector,
monitor=monitor,
uncertainty_broadcast_mode=uncertainty_broadcast_mode,
)


def insert_run_normalization(
workflow: sciline.Pipeline, run_norm: RunNormalization
) -> None:
"""Insert providers for a specific ESTIA run normalization into a workflow."""
common_corrections.insert_run_normalization(
workflow,
run_norm,
monitor_histogram_provider=normalize_by_monitor_histogram,
monitor_integrated_provider=normalize_by_monitor_integrated,
)


def add_coords_masks_and_apply_corrections(
Expand All @@ -29,25 +95,20 @@ def add_coords_masks_and_apply_corrections(
zlims: ZIndexLimits,
bdlim: BeamDivergenceLimits,
wbins: WavelengthBins,
proton_charge: ProtonCharge[RunType],
graph: CoordTransformationGraph[RunType],
corrections_to_apply: CorrectionsToApply,
) -> ReducibleData[RunType]:
) -> RunUnnormalizedData[RunType]:
"""
Computes coordinates, masks and corrections that are
the same for the sample measurement and the reference measurement.
"""
da = add_coords(da, graph)
da = add_masks(da, ylim, zlims, bdlim, wbins)

if len(proton_charge) != 0:
da = add_proton_charge_coord(da, proton_charge)
da = add_proton_charge_mask(da)

for correction in corrections_to_apply:
da = correction(da)

return ReducibleData[RunType](da)
return RunUnnormalizedData[RunType](da)


def correct_by_footprint(da: sc.DataArray) -> sc.DataArray:
Expand All @@ -61,6 +122,6 @@ def assume_time_series_constant_with_zero_default_value_if_empty(da: sc.DataArra
return da.mean() if len(da) > 0 else sc.scalar(0.0, unit=da.unit)


default_corrections = {correct_by_proton_charge, correct_by_footprint}
default_corrections = {correct_by_footprint}

providers = (add_coords_masks_and_apply_corrections,)
16 changes: 7 additions & 9 deletions packages/essreflectometry/src/ess/estia/mcstas.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
DetectorLtotal,
DetectorRotation,
Filename,
ProtonCharge,
RawDetector,
ReducibleData,
RunType,
RunUnnormalizedData,
SampleRotation,
SampleRotationOffset,
WavelengthBins,
Expand Down Expand Up @@ -223,10 +222,11 @@ def load_mcstas(

da.bins.coords['event_time_zero'] = (
sc.scalar(0, unit='s') * da.bins.coords['t']
).to(unit='ns')
).to(unit='ns', dtype='int64') + sc.datetime(0, unit='ns')
da.bins.coords['event_time_offset'] = (
sc.scalar(1, unit='s') * da.bins.coords['t']
).to(unit='ns') % sc.scalar(1 / 14, unit='s').to(unit='ns')
(sc.scalar(1, unit='s') * da.bins.coords['t']).to(unit='ns')
% sc.scalar(1 / 14, unit='s').to(unit='ns')
).to(dtype='int32')
da.bins.coords.pop('t')

if 'L' in da.bins.coords:
Expand Down Expand Up @@ -292,24 +292,22 @@ def use_mcstas_wavelengths_instead_of_estimates_from_time_of_arrival(
zlims: ZIndexLimits,
bdlim: BeamDivergenceLimits,
wbins: WavelengthBins,
proton_charge: ProtonCharge[RunType],
graph: CoordTransformationGraph[RunType],
corrections_to_apply: CorrectionsToApply,
) -> ReducibleData[RunType]:
) -> RunUnnormalizedData[RunType]:
out = add_coords_masks_and_apply_corrections(
da=da,
ylim=ylim,
zlims=zlims,
bdlim=bdlim,
wbins=wbins,
proton_charge=proton_charge,
graph={
**graph,
"wavelength": lambda wavelength_from_mcstas: wavelength_from_mcstas,
},
corrections_to_apply=corrections_to_apply,
)
return ReducibleData[RunType](out)
return RunUnnormalizedData[RunType](out)


providers = (
Expand Down
9 changes: 8 additions & 1 deletion packages/essreflectometry/src/ess/estia/types.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
from typing import NewType
from typing import NewType, TypeAlias

import scipp as sc
from ess.reduce.nexus.types import CaveMonitor
from ess.reduce.unwrap.types import WavelengthMonitor as _WavelengthMonitor

from ess.reflectometry.types import RunType

WavelengthResolution = NewType("WavelengthResolution", sc.Variable)
AngularResolution = NewType("AngularResolution", sc.Variable)
SampleSizeResolution = NewType("SampleSizeResolution", sc.Variable)


WavelengthMonitor: TypeAlias = _WavelengthMonitor[RunType, CaveMonitor]
Loading
Loading