diff --git a/setup.py b/setup.py index 12f4ff59aa431a362b12f81ad538b7ba2306b00e..cd8c38518b518bf4a659ba20c147fbd8cc3a31f1 100644 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ setup(name='calng', 'CalibrationManager = calng.CalibrationManager:CalibrationManager', 'AgipdCondition = calng.conditions:AgipdCondition.AgipdCondition', 'JungfrauCondition = calng.conditions.JungfrauCondition:JungfrauCondition', + 'LpdCondition = calng.conditions.LpdCondition:LpdCondition', 'Agipd1MGeometry = calng.geometries.Agipd1MGeometry:Agipd1MGeometry', 'Dssc1MGeometry = calng.geometries:Dssc1MGeometry.Dssc1MGeometry', 'Epix100Geometry = calng.geometries:Epix100Geometry.Epix100Geometry', diff --git a/src/calng/base_correction.py b/src/calng/base_correction.py index 0073ee26dfa00c226251ee65f9d9a7427ae7c14f..0ace7697145a9f4402bc26cdeb504968e31b6445 100644 --- a/src/calng/base_correction.py +++ b/src/calng/base_correction.py @@ -50,6 +50,7 @@ class FramefilterSpecType(enum.Enum): class WarningLampType(enum.Enum): FRAME_FILTER = enum.auto() MEMORY_CELL_RANGE = enum.auto() + CONSTANT_OPERATING_PARAMETERS = enum.auto() PREVIEW_SETTINGS = enum.auto() CORRECTION_RUNNER = enum.auto() OUTPUT_BUFFER = enum.auto() diff --git a/src/calng/conditions/LpdCondition.py b/src/calng/conditions/LpdCondition.py new file mode 100644 index 0000000000000000000000000000000000000000..6d467fd167e1c37cd561b4cbcab27f5ed872dfaa --- /dev/null +++ b/src/calng/conditions/LpdCondition.py @@ -0,0 +1,31 @@ +from karabo.middlelayer import ( + AccessMode, + Assignment, + Slot, + State, + String, + getDevice, + get_array_data, + sleep, +) +from ..corrections import LpdCorrection +from .. import base_condition, utils + + +class LpdCondition(base_condition.ConditionBase): + someCorrectionDeviceId = String( + displayedName="Correction device", + description="Correction devices expose the cell table as a property. Specify " + "the name of one of the correction devices in the pipeline to allow monitoring " + "of the memoryCellOrder parameter.", + assignment=Assignment.MANDATORY, + accessMode=AccessMode.INITONLY, + ) + + @property + def keys_to_get(self): + return { + self.someCorrectionDeviceId.value: [ + ("dataFormat.cellId", "memoryCellOrder", utils.cell_table_to_string) + ] + } diff --git a/src/calng/corrections/JungfrauCorrection.py b/src/calng/corrections/JungfrauCorrection.py index 9d3234b747893c28887da093291931fa93f4a6b7..e25add50b518b46c5029544a9246e3dadf98c1b3 100644 --- a/src/calng/corrections/JungfrauCorrection.py +++ b/src/calng/corrections/JungfrauCorrection.py @@ -34,6 +34,12 @@ class Constants(enum.Enum): RelativeGain10Hz = enum.auto() +bad_pixel_constants = { + Constants.BadPixelsDark10Hz, + Constants.BadPixelsFF10Hz, +} + + # from pycalibration (TOOD: move to common shared lib) class GainModes(enum.Enum): DYNAMIC_GAIN = "dynamicgain" @@ -119,12 +125,10 @@ class JungfrauBaseRunner(base_kernel_runner.BaseKernelRunner): self.offset_map[:] = self._xp.asarray(constant_data, dtype=np.float32) elif constant is Constants.RelativeGain10Hz: self.rel_gain_map[:] = self._xp.asarray(constant_data, dtype=np.float32) - elif constant in ( - Constants.BadPixelsDark10Hz, - Constants.BadPixelsFF10Hz, - ): + elif constant in bad_pixel_constants: self.bad_pixel_map |= self._xp.asarray(constant_data, dtype=np.uint32) - self.override_bad_pixel_flags_to_use(self._override_bad_pixel_flags) + else: + raise ValueError(f"Unexpected constant type {constant}") @property def preview_data_views(self): @@ -698,6 +702,8 @@ class JungfrauCorrection(base_correction.BaseCorrection): ) def _load_constant_to_runner(self, constant, constant_data): + if constant in bad_pixel_constants: + constant_data &= self._override_bad_pixel_flags self.kernel_runner.load_constant(constant, constant_data) def postReconfigure(self): @@ -713,31 +719,14 @@ class JungfrauCorrection(base_correction.BaseCorrection): if update.has("corrections.badPixels.subsetToUse"): self.log_status_info("Updating bad pixel maps based on subset specified") - if any( - update.get( - f"corrections.badPixels.subsetToUse.{field.name}", default=False - ) - for field in utils.BadPixelValues - ): - self.log_status_info( - "Some fields reenabled, reloading cached bad pixel constants" - ) - with self.calcat_friend.cached_constants_lock: - self.kernel_runner.flush_buffers( - { - Constants.BadPixelsDark10Hz, - Constants.BadPixelsFF10Hz, - } - ) - for ( - constant, - data, - ) in self.calcat_friend.cached_constants.items(): - if "BadPixels" in constant.name: - self._load_constant_to_runner(constant, data) - self.kernel_runner.override_bad_pixel_flags_to_use( - self._override_bad_pixel_flags - ) + # note: now just always reloading from cache for convenience + with self.calcat_friend.cached_constants_lock: + self.kernel_runner.flush_buffers(bad_pixel_constants) + for constant in bad_pixel_constants: + if constant in self.calcat_friend.cached_constants: + self._load_constant_to_runner( + constant, self.calcat_friend.cached_constants[constant] + ) if self._preview_friend is not None: self._preview_friend.reconfigure(update) diff --git a/src/calng/corrections/LpdCorrection.py b/src/calng/corrections/LpdCorrection.py index ffae49dd607b808cb4ecac79d82280f1f7de24e1..31c25ca07058454f2fadca63490770bb1ab0f186 100644 --- a/src/calng/corrections/LpdCorrection.py +++ b/src/calng/corrections/LpdCorrection.py @@ -2,6 +2,7 @@ import enum import numpy as np from karabo.bound import ( + BOOL_ELEMENT, DOUBLE_ELEMENT, KARABO_CLASSINFO, OUTPUT_CHANNEL, @@ -188,8 +189,8 @@ class LpdCalcatFriend(base_calcat.BaseCalcatFriend): @property def _constants_need_conditions(self): return { - Constants.Offset: self.dark_condition, - Constants.BadPixelsDark: self.dark_condition, + Constants.Offset: self.with_cell_condition, + Constants.BadPixelsDark: self.with_cell_condition, Constants.GainAmpMap: self.category_condition, Constants.FFMap: self.category_condition, Constants.RelativeGain: self.category_condition, @@ -249,14 +250,32 @@ class LpdCalcatFriend(base_calcat.BaseCalcatFriend): .defaultValue(0) .reconfigurable() .commit(), + + BOOL_ELEMENT(schema) + .key("constantParameters.useMemoryCellOrder") + .displayedName("Use memory cell order parameter") + .assignmentOptional() + .defaultValue(True) + .reconfigurable() + .commit(), + + STRING_ELEMENT(schema) + .key("constantParameters.memoryCellOrder") + .displayedName("Memory cell order") + .assignmentOptional() + .defaultValue("") + .reconfigurable() + .commit(), ) + managed_keys.add("constantParameters.useMemoryCellOrder") + managed_keys.add("constantParameters.memoryCellOrder") managed_keys.add("constantParameters.feedbackCapacitor") managed_keys.add("constantParameters.photonEnergy") managed_keys.add("constantParameters.category") base_calcat.add_status_schema_from_enum(schema, Constants) - def dark_condition(self): + def basic_condition(self): res = base_calcat.OperatingConditions() res["Memory cells"] = self._get_param("memoryCells") res["Sensor Bias Voltage"] = self._get_param("biasVoltage") @@ -266,8 +285,15 @@ class LpdCalcatFriend(base_calcat.BaseCalcatFriend): return res + def with_cell_condition(self): + res = self.basic_condition() + if self._get_param("useMemoryCellOrder"): + res["Memory cell order"] = self._get_param("memoryCellOrder") + + return res + def illuminated_condition(self): - res = self.dark_condition() + res = self.basic_condition() res["Source Energy"] = self._get_param("photonEnergy") return res @@ -425,6 +451,17 @@ class LpdCorrection(BaseCorrection): cell_table, pulse_table, ): + with self.warning_context( + "processingState", WarningLampType.CONSTANT_OPERATING_PARAMETERS + ) as warn: + if ( + cell_table_string := utils.cell_table_to_string(cell_table) + ) != self.unsafe_get( + "constantParameters.memoryCellOrder" + ) and self.unsafe_get( + "constantParameters.useMemoryCellOrder" + ): + warn(f"Cell order does not match input; input: {cell_table_string}") if self._frame_filter is not None: try: cell_table = cell_table[self._frame_filter] diff --git a/src/calng/utils.py b/src/calng/utils.py index 464a1958cf6695d0a227214fbf763bea0efe1828..7c48ebf3ef18803c1cfd27024f1464c356281139 100644 --- a/src/calng/utils.py +++ b/src/calng/utils.py @@ -554,3 +554,7 @@ def quadrant_views(A): for row in np.vsplit(A, 2): res.extend(np.hsplit(row, 2)) return res + + +def cell_table_to_string(cell_table): + return ",".join(map(str, cell_table.ravel())) + ","