From 4fead59a62d547cf9c058c143871b269ff4c7d4b Mon Sep 17 00:00:00 2001 From: David Hammer <dhammer@mailbox.org> Date: Thu, 6 Jan 2022 14:32:38 +0100 Subject: [PATCH] Initial Jungfrau device boilerplate --- setup.py | 1 + src/calng/JungfrauCorrection.py | 226 ++++++++++++++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 src/calng/JungfrauCorrection.py diff --git a/setup.py b/setup.py index 94b98d0d..4aea697e 100644 --- a/setup.py +++ b/setup.py @@ -26,6 +26,7 @@ setup(name='calng', 'karabo.bound_device': [ 'AgipdCorrection = calng.AgipdCorrection:AgipdCorrection', 'DsscCorrection = calng.DsscCorrection:DsscCorrection', + 'JungfrauCorrection = calng.JungfrauCorrection:JungfrauCorrection', 'ModuleStacker = calng.ModuleStacker:ModuleStacker', 'ShmemToZMQ = calng.ShmemToZMQ:ShmemToZMQ', ], diff --git a/src/calng/JungfrauCorrection.py b/src/calng/JungfrauCorrection.py new file mode 100644 index 00000000..b2c8b8cd --- /dev/null +++ b/src/calng/JungfrauCorrection.py @@ -0,0 +1,226 @@ +import enum +import timeit + +import cupy +import numpy as np +from karabo.bound import ( + DOUBLE_ELEMENT, + KARABO_CLASSINFO, + OVERWRITE_ELEMENT, + VECTOR_STRING_ELEMENT, +) +from karabo.common.states import State + +from . import base_gpu, calcat_utils, utils +from ._version import version as deviceVersion +from .base_correction import BaseCorrection, add_correction_step_schema + + +class JungfrauConstants(enum.Enum): + Offset10Hz = enum.auto() + BadPixelsDark10Hz = enum.auto() + + +class JungfrauGainMode(enum.IntEnum): + # TODO: coordinate with pycalibration and check what is saved by control device + # gain stages: G0, G1, G2 (plus secret HG0 - high CDS) + dynamicgain = enum.auto() # default; uses G0-G2 + dynamichg0 = enum.auto() # uses HG0, G1, G2 + fixgain1 = enum.auto() # fix, use only G1 + fixgain2 = enum.auto() # fix, use only G2 + forceswitchg1 = enum.auto() # only for darks + forceswitchg2 = enum.auto() # only for darks + + +class CorrectionFlags(enum.IntFlag): + NONE = 0 + OFFSET = 1 + REL_GAIN = 2 + + +class JungfrauGpuRunner(base_gpu.BaseGpuRunner): + _kernel_source_filename = "jungfrau_gpu_kernels.cpp" + _corrected_axis_order = ... # TODO: get specs for jungfrau data + + def __init__( + self, + pixels_x, + pixels_y, + memory_cells, + constant_memory_cells, + input_data_dtype=cupy.uint16, + output_data_dtype=cupy.float32, + ): + self.input_shape = ... + self.processed_shape = ... + super().__ini__( + pixels_x, + pixels_y, + memory_cells, + constant_memory_cells, + input_data_dtype, + output_data_dtype, + ) + self.map_shape = ... + # is jungfrau stuff gain mapped? + self.offset_map_gpu = cupy.zeros(..., dtype=cupy.float32) + self.rel_gain_map_gpu = cupy.ones(..., dtype=cupy.float32) + + +class JungfrauCalcatFriend(calcat_utils.BaseCalcatFriend): + _constant_enum_class = JungfrauConstants + + def __init__(self, device, *args, **kwargs): + super().__init__(device, *args, **kwargs) + self._constants_need_conditions = { + JungfrauConstants.Offset10Hz: self.dark_condition, + JungfrauConstants.BadPixelsDark10Hz: self.dark_condition, + } + + @staticmethod + def add_schema( + schema, + managed_keys, + param_prefix="constantParameters", + status_prefix="foundConstants", + ): + super(JungfrauCalcatFriend, JungfrauCalcatFriend).add_schema( + schema, managed_keys, "jungfrau-Type", param_prefix, status_prefix + ) + + # set some defaults for common parameters + ( + OVERWRITE_ELEMENT(schema) + .key(f"{param_prefix}.pixelsX") + .setNewDefaultValue(1024) + .commit(), + OVERWRITE_ELEMENT(schema) + .key(f"{param_prefix}.pixelsY") + .setNewDefaultValue(512) + .commit(), + OVERWRITE_ELEMENT(schema) + .key(f"{param_prefix}.memoryCells") + .setNewDefaultValue(1) + .commit(), + OVERWRITE_ELEMENT(schema) + .key(f"{param_prefix}.biasVoltage") + .setNewDefaultValue(90) + .commit(), + ) + + # add extra parameters + ( + DOUBLE_ELEMENT(schema) + .key(f"{param_prefix}.integrationTime") + .displayedName("Integration time") + .description("Integration time in ms") + .assignmentOptional() + .defaultValue(350) + .reconfigurable() + .commit(), + DOUBLE_ELEMENT(schema) + .key(f"{param_prefix}.sensorTemperature") + .displayedName("Sensor temperature") + .description("Sensor temperature in K") + .assignmentOptional() + .defaultValue(291) + .reconfigurable() + .commit(), + DOUBLE_ELEMENT(schema) + .key(f"{param_prefix}.gainSetting") + .displayedName("Gain setting") + .description("Feedback capacitor setting; 0 is default, 1 is HG0") + .assignmentOptional() + .defaultValue(0) + .reconfigurable() + .commit(), + ) + managed_keys.add(f"{param_prefix}.integrationTime") + managed_keys.add(f"{param_prefix}.sensorTemperature") + managed_keys.add(f"{param_prefix}.gainSetting") + + calcat_utils.add_status_schema_from_enum( + schema, status_prefix, JungfrauConstants + ) + + def dark_condition(self): + res = calcat_utils.OperatingConditions() + res["Memory cells"] = self._get_param("memoryCells") + res["Sensor Bias Voltage"] = self._get_param("biasVoltage") + res["Pixels X"] = self._get_param("pixelsX") + res["Pixels Y"] = self._get_param("pixelsY") + res["Integration Time"] = self._get_param("integrationTime") + res["Sensor Temperature"] = self._get_param("sensorTemperature") + res["Gain Setting"] = self._get_param("gainSetting") + return res + + +@KARABO_CLASSINFO("JungfrauCorrection", deviceVersion) +class JungfrauCorrection(BaseCorrection): + _correction_flag_class = CorrectionFlags + _correction_field_names = ( + ("offset", CorrectionFlags.OFFSET), + ("relGain", CorrectionFlags.REL_GAIN), + ) + _kernel_runner_class = JungfrauGpuRunner + _calcat_friend_class = JungfrauCalcatFriend + _constant_enum_class = JungfrauConstants + + @staticmethod + def expectedParameters(expected): + super(JungfrauCorrection, JungfrauCorrection).expectedParameters(expected) + ( + OVERWRITE_ELEMENT(expected) + .key("dataFormat.memoryCells") + .setNewDefaultValue(1) + .commit(), + OVERWRITE_ELEMENT(expected) + .key("preview.selectionMode") + .setNewDefaultValue("frame") + .commit(), + ) + + JungfrauCalcatFriend.add_schema(expected, JungfrauCorrection._managed_keys) + add_correction_step_schema( + expected, + JungfrauCorrection._managed_keys, + JungfrauCorrection._correction_field_names, + ) + + # mandatory: manager needs this in schema + ( + VECTOR_STRING_ELEMENT(expected) + .key("managedKeys") + .assignmentOptional() + .defaultValue(list(JungfrauCorrection._managed_keys)) + .commit() + ) + + @property + def input_data_shape(self): + # TODO: check up on this + return ( + self._schema_cache["dataFormat.memoryCells"], + 1, + self._schema_cache["dataFormat.pixelsX"], + self._schema_cache["dataFormat.pixelsY"], + ) + + def __init__(self, config): + super().__init__(config) + # TODO: gain mode as constant parameter and / or device configuration + self.gain_mode = JungfrauGainMode[config.get("constantParameters.gainMode")] + # TODO: rest of this + + def process_data( + self, + data_hash, + metadata, + source, + train_id, + image_data, + cell_table, + do_generate_preview, + ): + # TODO + ... -- GitLab