Source code for ewoksfluo.tasks.sum_detectors.sum_spectra
from typing import Sequence
import h5py
import numpy
from ewokscore import Task
from .. import nexus_utils
from ...io.hdf5 import split_h5uri
from ...io.hdf5 import ReadHdf5File
from ..math import eval_hdf5_expression
from ..math import format_expression_template
from ..hdf5_utils import link_bliss_scan
from ..hdf5_utils import create_hdf5_link
DEFAULTS = {
"xrf_spectra_uri_template": "instrument/{}/data",
"detector_normalization_template": "1./<instrument/{}/live_time>",
}
[docs]
class SumXrfSpectra(
Task,
input_names=[
"bliss_scan_uri",
"detector_names",
"output_root_uri",
],
optional_input_names=[
"xrf_spectra_uri_template",
"detector_normalization_template",
],
output_names=[
"bliss_scan_uri",
"detector_name",
"xrf_spectra_uri_template",
"output_root_uri",
],
):
"""Add single-scan XRF spectra from multiple detectors"""
[docs]
def run(self):
start_time = nexus_utils.now()
params = {**DEFAULTS, **self.get_input_values()}
bliss_scan_uri: str = params["bliss_scan_uri"]
detector_names: Sequence[str] = params["detector_names"]
xrf_spectra_uri_template: str = params["xrf_spectra_uri_template"]
detector_normalization_template: str = params["detector_normalization_template"]
output_root_uri: str = params["output_root_uri"]
if len(detector_names) < 1:
raise ValueError("Expected at least 1 detector to sum")
_, scan_h5path = split_h5uri(bliss_scan_uri)
sumdetector_name = "mcasum"
with nexus_utils.save_in_ewoks_process(
output_root_uri,
start_time,
process_config={
"detector_normalization_template": detector_normalization_template
},
default_levels=(scan_h5path, "sumspectra"),
) as (process_group, already_existed):
outentry = process_group.parent
if not already_existed:
sum_spectra = _sum_spectra(
bliss_scan_uri,
xrf_spectra_uri_template,
detector_names,
detector_normalization_template,
)
link_bliss_scan(outentry, bliss_scan_uri, retry_timeout=0)
nxdata = nexus_utils.create_nxdata(
process_group, "mcasum", signal="data"
)
nxdata.attrs["interpretation"] = "spectrum"
dset = nxdata.create_dataset("data", data=sum_spectra)
nxdetector = outentry["instrument"].create_group(sumdetector_name)
nxdetector.attrs["NX_class"] = "NXdetector"
create_hdf5_link(nxdetector, "data", dset)
create_hdf5_link(outentry["measurement"], sumdetector_name, dset)
output_root_uri = f"{outentry.file.filename}::{outentry.name}"
self.outputs.bliss_scan_uri = output_root_uri
self.outputs.detector_name = sumdetector_name
self.outputs.xrf_spectra_uri_template = DEFAULTS["xrf_spectra_uri_template"]
self.outputs.output_root_uri = output_root_uri
def _sum_spectra(
bliss_scan_uri: str,
xrf_spectra_uri_template: str,
detector_names: str,
detector_normalization_template: str,
) -> numpy.ndarray:
"""Add spectra from multiple detectors after normalizing the spectra to a common live time."""
input_file, scan_h5path = split_h5uri(bliss_scan_uri)
with ReadHdf5File(input_file) as h5file:
sum_spectra = None
scan_group = h5file[scan_h5path]
for detector_name in detector_names:
xrf_spectra_dataset = scan_group[
xrf_spectra_uri_template.format(detector_name)
]
assert isinstance(xrf_spectra_dataset, h5py.Dataset)
xrf_spectra_data = xrf_spectra_dataset[()]
weight_expression = format_expression_template(
detector_normalization_template, detector_name
)
weight = eval_hdf5_expression(bliss_scan_uri, weight_expression)
weight = weight.reshape((len(weight), 1))
if sum_spectra is None:
sum_spectra = xrf_spectra_data * weight
else:
sum_spectra += xrf_spectra_data * weight
return sum_spectra