From a017449a96049ddf7357493608a52a8374fb3e08 Mon Sep 17 00:00:00 2001 From: David Hammer <dhammer@mailbox.org> Date: Fri, 8 Oct 2021 16:38:41 +0200 Subject: [PATCH] Allow overriding calibration constant ID --- src/calng/base_correction.py | 17 +++++++++ src/calng/calcat_utils.py | 73 +++++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 9 deletions(-) diff --git a/src/calng/base_correction.py b/src/calng/base_correction.py index c3b608ad..97ec168f 100644 --- a/src/calng/base_correction.py +++ b/src/calng/base_correction.py @@ -366,6 +366,23 @@ class BaseCorrection(PythonDevice): self._buffer_lock = threading.Lock() self.KARABO_SLOT(self.loadMostRecentConstants) self.KARABO_SLOT(self.requestScene) + # TODO: the CalCatFriend could add these for us + # note: overly complicated slot function creation necessary for closure to work + def make_wrapper_capturing_constant(constant): + def aux(): + self.calcat_friend.get_specific_constant_version_and_call_me_back( + constant, self._load_constant_to_gpu + ) + + return aux + + for constant in self._constant_enum_class: + slot_name = f"foundConstants.{constant.name}.overrideConstantVersion" + meth_name = slot_name.replace(".", "_") + self.KARABO_SLOT( + make_wrapper_capturing_constant(constant), + slotName=meth_name, + ) def preReconfigure(self, config): for path in config.getPaths(): diff --git a/src/calng/calcat_utils.py b/src/calng/calcat_utils.py index 577d526e..78c9a953 100644 --- a/src/calng/calcat_utils.py +++ b/src/calng/calcat_utils.py @@ -22,6 +22,7 @@ from karabo.bound import ( BOOL_ELEMENT, DOUBLE_ELEMENT, NODE_ELEMENT, + SLOT_ELEMENT, STRING_ELEMENT, UINT32_ELEMENT, ) @@ -93,6 +94,22 @@ def _add_status_schema_from_enum(schema, prefix, enum_class): .readOnly() .initialValue("") .commit(), + STRING_ELEMENT(schema) + .key(f"{constant_node}.constantVersionId") + .description( + "This field is editable - if for any reason a specific constant " + "version is desired, the constant version ID (as used in CalCat) can " + "be set here and the slot below can be called to load this particular " + "version, overriding the automatic loading of latest constants." + ) + .assignmentOptional() + .defaultValue("") + .reconfigurable() + .commit(), + SLOT_ELEMENT(schema) + .key(f"{constant_node}.overrideConstantVersion") + .displayedName("Override constant version") + .commit() ) @@ -248,9 +265,9 @@ class BaseCalcatFriend: """Helper to get value from attached device schema""" return self.device.get(f"{self.param_prefix}.{key}") - def _set_status(self, key, value): + def _set_status(self, constant, key, value): """Helper to update information about found constants on device""" - self.device.set(f"{self.status_prefix}.{key}", value) + self.device.set(f"{self.status_prefix}.{constant.name}.{key}", value) @functools.cached_property def detector_id(self): @@ -328,18 +345,18 @@ class BaseCalcatFriend: constant = self._constant_enum_class[constant] calibration_id = self.calibration_id(constant.name) - self._set_status(f"{constant.name}.calibrationId", calibration_id) + self._set_status(constant, f"calibrationId", calibration_id) condition = self._constants_need_conditions[constant]() condition_id = self.condition_id( self._karabo_da_to_float_uuid[karabo_da], condition ) - self._set_status(f"{constant.name}.conditionId", condition_id) + self._set_status(constant, f"conditionId", condition_id) constant_id = self.constant_id( calibration_id=calibration_id, condition_id=condition_id ) - self._set_status(f"{constant.name}.constantId", constant_id) + self._set_status(constant, f"constantId", constant_id) resp = CalibrationConstantVersion.get_by_uk( self.client, @@ -352,7 +369,8 @@ class BaseCalcatFriend: timestamp = resp["data"][ "begin_at" ] # TODO: check which key we like (also has begin_validity_at) - self._set_status(f"{constant.name}.createdAt", timestamp) + self._set_status(constant, f"createdAt", timestamp) + self._set_status(constant, f"constantVersionId", resp["data"]["id"]) file_path = ( self.caldb_store / resp["data"]["path_to_file"] / resp["data"]["file_name"] @@ -361,10 +379,34 @@ class BaseCalcatFriend: with h5py.File(file_path, "r") as fd: constant_data = np.array(fd[resp["data"]["data_set_name"]]["data"]) self.cached_constants[constant] = constant_data - self._set_status(f"{constant.name}.found", True) + self._set_status(constant, f"found", True) return constant_data + def get_specific_constant_version(self, constant): + # TODO: warn if PDU or constant type does not match + # TODO: warn if result is list (happens for empty version ID) + constant_version_id = self.device.get( + f"{self.status_prefix}.{constant.name}.constantVersionId" + ) + + resp = CalibrationConstantVersion.get_by_id(self.client, constant_version_id) + _check_resp(resp) + file_path = ( + self.caldb_store / resp["data"]["path_to_file"] / resp["data"]["file_name"] + ) + # TODO: handle FileNotFoundError if we are led astray + with h5py.File(file_path, "r") as fd: + constant_data = np.array(fd[resp["data"]["data_set_name"]]["data"]) + self.cached_constants[constant] = constant_data + self._set_status(constant, f"createdAt", resp["data"]["begin_at"]) + self._set_status(constant, f"calibrationId", "manual override") + self._set_status(constant, f"conditionId", "manual override") + self._set_status(constant, f"constantId", "manual override") + self._set_status(constant, f"constantVersionId", constant_version_id) + self._set_status(constant, f"found", True) + return constant_data + def get_constant_version_and_call_me_back( self, constant, callback, snapshot_at=None ): @@ -380,10 +422,23 @@ class BaseCalcatFriend: thread.start() return thread + def get_specific_constant_version_and_call_me_back(self, constant, callback): + """Blindly load whatever CalCat points to for CCV - user must be confident that + this CCV corresponds to correct kind of constant.""" + + # TODO: warn user about all the things that go wrong + def aux(): + data = self.get_specific_constant_version(constant) + callback(constant, data) + + thread = threading.Thread(target=aux) + thread.start() + return thread + def flush_constants(self): for constant in self._constant_enum_class: - self._set_status(f"{constant.name}.createdAt", "") - self._set_status(f"{constant.name}.found", False) + self._set_status(constant, f"createdAt", "") + self._set_status(constant, f"found", False) class AgipdConstants(enum.Enum): -- GitLab