Skip to content

Commit

Permalink
Merge pull request #67 from scipp/masking-with-calibration
Browse files Browse the repository at this point in the history
Compute d-spacing from calibration
  • Loading branch information
jl-wynen authored Jun 21, 2024
2 parents f996235 + 2973a28 commit 4e8edf6
Show file tree
Hide file tree
Showing 15 changed files with 101 additions and 76 deletions.
3 changes: 2 additions & 1 deletion docs/user-guide/dream/dream-data-reduction.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
" Filename[SampleRun]: dream.data.simulated_diamond_sample(),\n",
" Filename[VanadiumRun]: dream.data.simulated_vanadium_sample(),\n",
" Filename[EmptyCanRun]: dream.data.simulated_empty_can(),\n",
" CalibrationFilename: None,\n",
" NeXusDetectorName: \"mantle\",\n",
" # The upper bounds mode is not yet implemented.\n",
" UncertaintyBroadcastMode: UncertaintyBroadcastMode.drop,\n",
Expand Down Expand Up @@ -286,7 +287,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.10.13"
}
},
"nbformat": 4,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.10.13"
}
},
"nbformat": 4,
Expand Down
14 changes: 14 additions & 0 deletions src/ess/dream/io/geant4.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import sciline
import scipp as sc
from ess.powder.types import (
CalibrationData,
CalibrationFilename,
Filename,
NeXusDetectorDimensions,
NeXusDetectorName,
Expand Down Expand Up @@ -196,6 +198,17 @@ def geant4_detector_dimensions(
return NeXusDetectorDimensions[NeXusDetectorName](data.sizes)


def geant4_load_calibration(
filename: CalibrationFilename,
) -> CalibrationData:
if filename is not None:
# Needed to build a complete pipeline.
raise NotImplementedError(
"Calibration data loading is not implemented for DREAM GEANT4 data."
)
return CalibrationFilename(None)


providers = (
extract_geant4_detector,
extract_geant4_detector_data,
Expand All @@ -204,5 +217,6 @@ def geant4_detector_dimensions(
get_source_position,
patch_detector_data,
geant4_detector_dimensions,
geant4_load_calibration,
)
"""Geant4-providers for Sciline pipelines."""
2 changes: 1 addition & 1 deletion src/ess/powder/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
del importlib

providers = (
*conversion.providers_with_positions,
*conversion.providers,
*correction.providers,
*filtering.providers,
*grouping.providers,
Expand Down
30 changes: 22 additions & 8 deletions src/ess/powder/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
DataWithScatteringCoordinates,
DspacingData,
ElasticCoordTransformGraph,
MaskedData,
NormalizedByProtonCharge,
RunType,
)
Expand Down Expand Up @@ -83,9 +84,9 @@ def _consume_positions(position, sample_position, source_position):


def to_dspacing_with_calibration(
data: NormalizedByProtonCharge[RunType],
calibration: CalibrationData,
) -> DspacingData[RunType]:
data: sc.DataArray,
calibration: sc.Dataset,
) -> sc.DataArray:
"""
Transform coordinates to d-spacing from calibration parameters.
Expand Down Expand Up @@ -177,7 +178,7 @@ def add_scattering_coordinates_from_positions(
data: NormalizedByProtonCharge[RunType], graph: ElasticCoordTransformGraph
) -> DataWithScatteringCoordinates[RunType]:
"""
Add ``wavelength``, ``two_theta``, and ``dspacing`` coordinates to the data.
Add ``wavelength`` and ``two_theta`` coordinates to the data.
The input ``data`` must have a ``tof`` coordinate, as well as the necessary
positions of the beamline components (source, sample, detectors) to compute
the scattering coordinates.
Expand All @@ -190,15 +191,28 @@ def add_scattering_coordinates_from_positions(
Coordinate transformation graph.
"""
out = data.transform_coords(
["two_theta", "wavelength", "dspacing"], graph=graph, keep_intermediate=False
["two_theta", "wavelength"], graph=graph, keep_intermediate=False
)
return DataWithScatteringCoordinates[RunType](out)


providers_with_calibration = (to_dspacing_with_calibration,)
"""Sciline providers for coordinate transformations."""
def convert_to_dspacing(
data: MaskedData[RunType],
graph: ElasticCoordTransformGraph,
calibration: CalibrationData,
) -> DspacingData[RunType]:
if calibration is None:
out = data.transform_coords(["dspacing"], graph=graph, keep_intermediate=False)
return DspacingData[RunType](out)
out = to_dspacing_with_calibration(data, calibration=calibration)
for key in ('wavelength', 'two_theta'):
if key in out.coords.keys():
out.coords.set_aligned(key, False)
return DspacingData[RunType](out)


providers_with_positions = (
providers = (
powder_coordinate_transformation_graph,
add_scattering_coordinates_from_positions,
convert_to_dspacing,
)
10 changes: 5 additions & 5 deletions src/ess/powder/correction.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,11 +179,11 @@ def merge_calibration(*, into: sc.DataArray, calibration: sc.Dataset) -> sc.Data
--------
ess.powder.load_calibration
"""
dim = calibration.dim
if not sc.identical(into.coords[dim], calibration.coords[dim]):
raise ValueError(
f"Coordinate {dim} of calibration and target dataset do not agree."
)
for name, coord in calibration.coords.items():
if not sc.identical(into.coords[name], coord):
raise ValueError(
f"Coordinate {name} of calibration and target dataset do not agree."
)
out = into.copy(deep=False)
for name in ("difa", "difc", "tzero"):
if name in out.coords:
Expand Down
17 changes: 1 addition & 16 deletions src/ess/powder/external/powgen/beamline.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@
import scipp as sc

from ...types import (
CalibrationData,
NeXusDetectorDimensions,
NeXusDetectorName,
RawCalibrationData,
)
from .types import DetectorInfo

DETECTOR_BANK_SIZES = {"powgen_detector": {"bank": 23, "column": 154, "row": 7}}

Expand Down Expand Up @@ -56,18 +53,6 @@ def map_detector_to_spectrum(
return out.rename_dims({"detector": "spectrum"})


def preprocess_calibration_data(
data: RawCalibrationData, detector_info: DetectorInfo
) -> CalibrationData:
"""Convert calibration data to a format that can be used by Scipp.
The raw calibration data is encoded in terms of a `'detector'` coordinate.
This needs to be converted to a `'spectrum'` coordinate to align
if with sample data.
"""
return CalibrationData(map_detector_to_spectrum(data, detector_info=detector_info))


def powgen_detector_dimensions(
detector_name: NeXusDetectorName,
) -> NeXusDetectorDimensions[NeXusDetectorName]:
Expand All @@ -77,5 +62,5 @@ def powgen_detector_dimensions(
)


providers = (preprocess_calibration_data, powgen_detector_dimensions)
providers = (powgen_detector_dimensions,)
"""Sciline providers for POWGEN beamline processing."""
29 changes: 17 additions & 12 deletions src/ess/powder/external/powgen/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,16 @@

from ...types import (
AccumulatedProtonCharge,
CalibrationData,
CalibrationFilename,
Filename,
NeXusDetectorDimensions,
NeXusDetectorName,
ProtonCharge,
RawCalibrationData,
RawDataAndMetadata,
ReducibleDetectorData,
RunType,
SampleRun,
)
from .types import DetectorInfo

_version = "1"

Expand All @@ -41,6 +39,7 @@ def _make_pooch():
"PG3_4844_event.zip": "md5:a644c74f5e740385469b67431b690a3e",
"PG3_4866_event.zip": "md5:5bc49def987f0faeb212a406b92b548e",
"PG3_FERNS_d4832_2011_08_24.zip": "md5:0fef4ed5f61465eaaa3f87a18f5bb80d",
"PG3_FERNS_d4832_2011_08_24_spectrum.h5": "md5:7aee0b40deee22d57e21558baa7a6a1a", # noqa: E501
},
)

Expand Down Expand Up @@ -89,7 +88,7 @@ def powgen_tutorial_vanadium_file() -> str:


def powgen_tutorial_calibration_file() -> str:
return _get_path("PG3_FERNS_d4832_2011_08_24.zip")
return _get_path("PG3_FERNS_d4832_2011_08_24_spectrum.h5")


def pooch_load(filename: Filename[RunType]) -> RawDataAndMetadata[RunType]:
Expand All @@ -103,9 +102,21 @@ def pooch_load(filename: Filename[RunType]) -> RawDataAndMetadata[RunType]:
return RawDataAndMetadata[RunType](sc.io.load_hdf5(filename))


def pooch_load_calibration(filename: CalibrationFilename) -> RawCalibrationData:
def pooch_load_calibration(
filename: CalibrationFilename,
detector_dimensions: NeXusDetectorDimensions[NeXusDetectorName],
) -> CalibrationData:
"""Load the calibration data for the POWGEN test data."""
return RawCalibrationData(sc.io.load_hdf5(filename))
if filename is None:
return CalibrationFilename(None)
ds = sc.io.load_hdf5(filename)
ds = sc.Dataset(
{
key: da.fold(dim='spectrum', sizes=detector_dimensions)
for key, da in ds.items()
}
)
return CalibrationData(ds)


def extract_raw_data(
Expand All @@ -120,11 +131,6 @@ def extract_raw_data(
return ReducibleDetectorData[RunType](out)


def extract_detector_info(dg: RawDataAndMetadata[SampleRun]) -> DetectorInfo:
"""Return the detector info from a loaded data group."""
return DetectorInfo(dg["detector_info"])


def extract_proton_charge(dg: RawDataAndMetadata[RunType]) -> ProtonCharge[RunType]:
"""Return the proton charge from a loaded data group."""
return ProtonCharge[RunType](dg["proton_charge"])
Expand All @@ -141,7 +147,6 @@ def extract_accumulated_proton_charge(
pooch_load,
pooch_load_calibration,
extract_accumulated_proton_charge,
extract_detector_info,
extract_proton_charge,
extract_raw_data,
)
Expand Down
19 changes: 0 additions & 19 deletions src/ess/powder/external/powgen/types.py

This file was deleted.

6 changes: 3 additions & 3 deletions src/ess/powder/grouping.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@

from .types import (
DspacingBins,
DspacingData,
FocussedDataDspacing,
FocussedDataDspacingTwoTheta,
MaskedData,
RunType,
TwoThetaBins,
)


def focus_data_dspacing(
data: MaskedData[RunType],
data: DspacingData[RunType],
dspacing_bins: DspacingBins,
) -> FocussedDataDspacing[RunType]:
out = data.bins.concat().bin({dspacing_bins.dim: dspacing_bins})
return FocussedDataDspacing[RunType](out)


def focus_data_dspacing_and_two_theta(
data: MaskedData[RunType],
data: DspacingData[RunType],
dspacing_bins: DspacingBins,
twotheta_bins: TwoThetaBins,
) -> FocussedDataDspacingTwoTheta[RunType]:
Expand Down
8 changes: 2 additions & 6 deletions src/ess/powder/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

# 2 Workflow parameters

CalibrationFilename = NewType("CalibrationFilename", str)
CalibrationFilename = NewType("CalibrationFilename", str | None)
"""Filename of the instrument calibration file."""


Expand Down Expand Up @@ -78,7 +78,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
super().__init__(*args, **kwargs)


CalibrationData = NewType("CalibrationData", sc.Dataset)
CalibrationData = NewType("CalibrationData", sc.Dataset | None)
"""Detector calibration data."""

DataFolder = NewType("DataFolder", str)
Expand Down Expand Up @@ -155,10 +155,6 @@ class ProtonCharge(sciline.Scope[RunType, sc.DataArray], sc.DataArray):
"""Time-dependent proton charge."""


RawCalibrationData = NewType("RawCalibrationData", sc.Dataset)
"""Calibration data as loaded from file, needs preprocessing before using."""


class RawDataAndMetadata(sciline.Scope[RunType, sc.DataGroup], sc.DataGroup):
"""Raw data and associated metadata."""

Expand Down
2 changes: 2 additions & 0 deletions tests/dream/geant4_reduction_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from ess import powder
from ess.powder.types import (
AccumulatedProtonCharge,
CalibrationFilename,
DspacingBins,
EmptyCanRun,
Filename,
Expand Down Expand Up @@ -49,6 +50,7 @@ def params(request):
Filename[SampleRun]: dream.data.simulated_diamond_sample(),
Filename[VanadiumRun]: dream.data.simulated_vanadium_sample(),
Filename[EmptyCanRun]: dream.data.simulated_empty_can(),
CalibrationFilename: None,
UncertaintyBroadcastMode: UncertaintyBroadcastMode.drop,
DspacingBins: sc.linspace('dspacing', 0.0, 2.3434, 201, unit='angstrom'),
TofMask: lambda x: (x < sc.scalar(0.0, unit='ns'))
Expand Down
1 change: 0 additions & 1 deletion tests/powder/conversion_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,3 @@ def test_add_scattering_coordinates_from_positions():

assert 'wavelength' in result.coords
assert 'two_theta' in result.coords
assert 'dspacing' in result.coords
Loading

0 comments on commit 4e8edf6

Please sign in to comment.