From 64a8cc035fd56c98593be6ed0e1bb3a8ca6c033f Mon Sep 17 00:00:00 2001 From: hitz_s Date: Thu, 24 Sep 2026 08:08:21 +0200 Subject: [PATCH] Add curent_foil to reference foil changer --- debye_bec/devices/reffoilchanger.py | 69 ++++++++++++++++++- .../file_writer/debye_nexus_structure.py | 12 +++- 2 files changed, 78 insertions(+), 3 deletions(-) diff --git a/debye_bec/devices/reffoilchanger.py b/debye_bec/devices/reffoilchanger.py index 9bd5a9c..d3daee9 100644 --- a/debye_bec/devices/reffoilchanger.py +++ b/debye_bec/devices/reffoilchanger.py @@ -5,8 +5,9 @@ from __future__ import annotations import enum from typing import TYPE_CHECKING +from bec_lib.logger import bec_logger from ophyd import Component as Cpt -from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV +from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV, Signal from ophyd.status import DeviceStatus from ophyd_devices.interfaces.base_classes.psi_device_base import PSIDeviceBase from ophyd_devices.utils.errors import DeviceStopError @@ -14,6 +15,8 @@ from ophyd_devices.utils.errors import DeviceStopError if TYPE_CHECKING: from bec_lib.devicemanager import ScanInfo +logger = bec_logger.logger + class Status(int, enum.Enum): """Enum class for the status field""" @@ -34,6 +37,63 @@ class OpMode(int, enum.Enum): ERRORMODE = 3 +N_FOILS = 38 + + +class CurrentFoilSignal(Signal): + """ + Soft signal reflecting the description of the foil currently + inserted. Recomputed whenever 'ref_rb', 'status' or any of the + `foilNN` signals on the parent device change. + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self._subscribed = False + + def _foil_signal(self): + if self.parent.status.get() != Status.INSERTED: + return None + idx = self.parent.ref_rb.get() + try: + idx = int(round(idx)) + 1 + except (TypeError, ValueError): + return None + return getattr(self.parent, f"foil{idx:02d}", None) + + def _compute(self): + sig = self._foil_signal() + if sig is None: + return "" + try: + return sig.get() + except Exception: + logger.exception("current_foil: failed to read %s", sig.name) + return "" + + def get(self, **kwargs): + self._readback = self._compute() + return self._readback + + def _on_upstream_change(self, value=None, timestamp=None, **kwargs): + old_value = self._readback + new_value = self._compute() + self._readback = new_value + self._run_subs( + sub_type=self.SUB_VALUE, old_value=old_value, value=new_value, timestamp=timestamp + ) + + def subscribe_to_parent_signals(self): + if self._subscribed: + return + self.parent.ref_rb.subscribe(self._on_upstream_change, run=False) + self.parent.status.subscribe(self._on_upstream_change, run=False) + for i in range(1, N_FOILS + 1): + getattr(self.parent, f"foil{i:02d}").subscribe(self._on_upstream_change, run=False) + self._subscribed = True + self._readback = self._compute() + + class Reffoilchanger(PSIDeviceBase): """Class for the ES2 Reference Foil Changer""" @@ -71,8 +131,12 @@ class Reffoilchanger(PSIDeviceBase): ) ref_set = Cpt(EpicsSignal, suffix="ES2-REF:SELN-SET", kind="config", doc="Requested reference") ref_rb = Cpt( - EpicsSignalRO, suffix="ES2-REF:SELN-RB", kind="config", doc="Currently set reference" + EpicsSignalRO, + suffix="ES2-REF:SELN-RB", + kind="config", + doc="Currently set reference (angle)", ) + current_foil = Cpt(CurrentFoilSignal, value="", kind="normal", doc="Inserted reference") foil01 = Cpt(EpicsSignalRO, suffix="ES-REFFOIL:FOIL01.DESC", kind="config", doc="Foil 01") foil02 = Cpt(EpicsSignalRO, suffix="ES-REFFOIL:FOIL02.DESC", kind="config", doc="Foil 02") @@ -115,6 +179,7 @@ class Reffoilchanger(PSIDeviceBase): def __init__(self, *, name: str, prefix: str = "", scan_info: ScanInfo | None = None, **kwargs): super().__init__(name=name, prefix=prefix, scan_info=scan_info, **kwargs) + self.current_foil.subscribe_to_parent_signals() self.foils = [ self.foil01, diff --git a/debye_bec/file_writer/debye_nexus_structure.py b/debye_bec/file_writer/debye_nexus_structure.py index 79f1044..f647b29 100644 --- a/debye_bec/file_writer/debye_nexus_structure.py +++ b/debye_bec/file_writer/debye_nexus_structure.py @@ -236,7 +236,9 @@ class DebyeNexusStructure(DefaultFormat): self.configuration.get("nidaq", {}).get("nidaq_add_chans", {}).get("value") ) - rle = self.configuration.get("nidaq", {}).get("nidaq_enable_compression", {}).get("value") + rle = ( + self.configuration.get("nidaq", {}).get("nidaq_enable_compression", {}).get("value") + ) measurement_mode = entry.create_group(name="mode") measurement_mode.attrs["NX_class"] = "NX_CHAR" @@ -288,6 +290,14 @@ class DebyeNexusStructure(DefaultFormat): ) ref_trans.attrs["NX_class"] = "NX_CHAR" + foil = ( + self.device_manager.devices.reffoilchanger.read(cached=True) + .get("current_foil") + .get("value") + ) + ref_foil = ai2ai4_active.create_dataset(name="Reference", data=foil) + ref_foil.attrs["NX_class"] = "NX_CHAR" + main_data = entry.create_group(name="data") main_data.attrs["NX_class"] = "NXdata"