From 5877f48c95b1142cf552a39355eef8836b1cd985 Mon Sep 17 00:00:00 2001 From: appel_c Date: Mon, 8 Dec 2025 18:11:11 +0100 Subject: [PATCH] fix(eiger): add dectris-decompression and dependencies. --- csaxs_bec/devices/jungfraujoch/eiger.py | 8 ++- .../jungfraujoch/jungfraujoch_preview.py | 69 ++++++++++++++++++- pyproject.toml | 2 + 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/csaxs_bec/devices/jungfraujoch/eiger.py b/csaxs_bec/devices/jungfraujoch/eiger.py index b8319d7..09bb20c 100644 --- a/csaxs_bec/devices/jungfraujoch/eiger.py +++ b/csaxs_bec/devices/jungfraujoch/eiger.py @@ -84,7 +84,7 @@ class EigerError(Exception): class Eiger(PSIDeviceBase): """ - Base integration of the Eiger1.5M and Eiger9M at cSAXS. All relevant + Base integration of the Eiger1.5M and Eiger9M at cSAXS. """ USER_ACCESS = ["detector_distance", "beam_center"] @@ -208,12 +208,13 @@ class Eiger(PSIDeviceBase): # Setup Detector settings, here we may also set the energy already as this might be time consuming settings = DetectorSettings(frame_time_us=int(500), timing=DetectorTiming.TRIGGER) - self.jfj_client.set_detector_settings(settings, timeout=10) + self.jfj_client.set_detector_settings(settings, timeout=5) # Set the file writer to the appropriate output for the HDF5 file file_writer_settings = FileWriterSettings(overwrite=True, format=FileWriterFormat.NXMXVDS) logger.debug( f"Setting writer_settings: {yaml.dump(file_writer_settings.to_dict(), indent=4)}" ) + # Setup the file writer settings self.jfj_client.api.config_file_writer_put( file_writer_settings=file_writer_settings, _request_timeout=10 ) @@ -230,6 +231,7 @@ class Eiger(PSIDeviceBase): """ start_time = time.time() scan_msg = self.scan_info.msg + # Set acquisition parameter # TODO add check of mono energy, this can then also be passed to DatasetSettings incident_energy = 12.0 @@ -250,8 +252,10 @@ class Eiger(PSIDeviceBase): successful=False, hinted_h5_entries={"data": "entry/data/data"}, ) + # JFJ adds _master.h5 automatically path = os.path.relpath(self._full_path, start="/sls/x12sa/data").removesuffix("_master.h5") + data_settings = DatasetSettings( image_time_us=int(frame_time_us * 1e6), # This is currently ignored ntrigger=ntrigger, diff --git a/csaxs_bec/devices/jungfraujoch/jungfraujoch_preview.py b/csaxs_bec/devices/jungfraujoch/jungfraujoch_preview.py index bfda46d..ed439ed 100644 --- a/csaxs_bec/devices/jungfraujoch/jungfraujoch_preview.py +++ b/csaxs_bec/devices/jungfraujoch/jungfraujoch_preview.py @@ -15,6 +15,68 @@ logger = bec_logger.logger ZMQ_TOPIC_FILTER = b"" +import cbor2 +import numpy as np +from dectris.compression import decompress + + +def decode_multi_dim_array(tag, column_major): + dimensions, contents = tag.value + if isinstance(contents, list): + array = np.empty((len(contents),), dtype=object) + array[:] = contents + elif isinstance(contents, (np.ndarray, np.generic)): + array = contents + else: + raise cbor2.CBORDecodeValueError("expected array or typed array") + return array.reshape(dimensions, order="F" if column_major else "C") + + +def decode_typed_array(tag, dtype): + if not isinstance(tag.value, bytes): + raise cbor2.CBORDecodeValueError("expected byte string in typed array") + return np.frombuffer(tag.value, dtype=dtype) + + +def decode_dectris_compression(tag): + algorithm, elem_size, encoded = tag.value + return decompress(encoded, algorithm, elem_size=elem_size) + + +tag_decoders = { + 40: lambda tag: decode_multi_dim_array(tag, column_major=False), + 64: lambda tag: decode_typed_array(tag, dtype="u1"), + 65: lambda tag: decode_typed_array(tag, dtype=">u2"), + 66: lambda tag: decode_typed_array(tag, dtype=">u4"), + 67: lambda tag: decode_typed_array(tag, dtype=">u8"), + 68: lambda tag: decode_typed_array(tag, dtype="u1"), + 69: lambda tag: decode_typed_array(tag, dtype="