From f38c94490aa5d455a172d6f3eab642ea391cb8c2 Mon Sep 17 00:00:00 2001 From: x01dc Date: Mon, 5 Jan 2026 13:14:10 +0100 Subject: [PATCH] csaxs master class added and init smar positions --- .../bec_ipython_client/plugins/cSAXS/cSAXS.py | 40 +++ .../plugins/cSAXS/initialize_stages.py | 114 -------- .../plugins/cSAXS/smaract.py | 253 ++++++++++++++++++ csaxs_bec/device_configs/smaract_test.yaml | 47 ++++ 4 files changed, 340 insertions(+), 114 deletions(-) create mode 100644 csaxs_bec/bec_ipython_client/plugins/cSAXS/cSAXS.py delete mode 100644 csaxs_bec/bec_ipython_client/plugins/cSAXS/initialize_stages.py create mode 100644 csaxs_bec/bec_ipython_client/plugins/cSAXS/smaract.py diff --git a/csaxs_bec/bec_ipython_client/plugins/cSAXS/cSAXS.py b/csaxs_bec/bec_ipython_client/plugins/cSAXS/cSAXS.py new file mode 100644 index 0000000..0fe94a1 --- /dev/null +++ b/csaxs_bec/bec_ipython_client/plugins/cSAXS/cSAXS.py @@ -0,0 +1,40 @@ +# import builtins +# import datetime +# import os +# import subprocess +# import time +# from pathlib import Path + +# import numpy as np +from bec_lib import bec_logger +# from bec_lib.alarm_handler import AlarmBase +# from bec_lib.pdf_writer import PDFWriter +from typeguard import typechecked + + +from csaxs_bec.bec_ipython_client.plugins.cSAXS.smaract import cSAXSInitSmaractStages +from csaxs_bec.bec_ipython_client.plugins.cSAXS.smaract import cSAXSSmaract +from csaxs_bec.bec_ipython_client.plugins.omny.omny_general_tools import OMNYTools + +class cSAXSError(Exception): + pass + +class cSAXS( + cSAXSInitSmaractStages, + cSAXSSmaract, +): + def __init__(self, client): + super().__init__(client) + self.client = client + self.device_manager = client.device_manager + self.OMNYTools = OMNYTools(self.client) + + +# this is the csaxs master file that imports all routines from csaxs +# can be imported in the bec client by +# +# from csaxs_bec.bec_ipython_client.plugins.cSAXS.cSAXS import cSAXS +# csaxs = cSAXS(bec) +# +# then all commands can be accessed by for example +# csaxs._cSAXS_smaract_stages_..... \ No newline at end of file diff --git a/csaxs_bec/bec_ipython_client/plugins/cSAXS/initialize_stages.py b/csaxs_bec/bec_ipython_client/plugins/cSAXS/initialize_stages.py deleted file mode 100644 index d6dcc6c..0000000 --- a/csaxs_bec/bec_ipython_client/plugins/cSAXS/initialize_stages.py +++ /dev/null @@ -1,114 +0,0 @@ -import builtins -import time -from pathlib import Path - -from bec_lib import bec_logger - -# Logger initialization -logger = bec_logger.logger - -if builtins.__dict__.get("bec") is not None: - bec = builtins.__dict__.get("bec") - dev = builtins.__dict__.get("dev") - umv = builtins.__dict__.get("umv") - umvr = builtins.__dict__.get("umvr") - -class cSAXSInitError(Exception): - pass - -class cSAXSError(Exception): - pass - -class cSAXSInitStagesMixin: - # Class-level mappings for axes and devices - AXIS_MAP = {c: i for i, c in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ")} - - devices = { - "xbpm3x": "A", - "xbpm3y": "B", - "sl3trxi": "C", - "sl3trxo": "D", - "sl3trxb": "E", - "sl3trxt": "F", - "fast_shutter_n1_x": "H", - "fast_shutter_o1_x": "G", - "fast_shutter_o2_x": "F", - "filter_array_1_x": "B", - "filter_array_2_x": "C", - "filter_array_3_x": "D", - "filter_array_4_x": "E", - "sl4trxi": "G", - "sl4trxo": "H", - "sl4trxb": "I", - "sl4trxt": "A", - "sl5trxi": "C", - "sl5trxo": "D", - "sl5trxb": "E", - "sl5trxt": "F", - "xbimtrx": "A", - "xbimtry": "B", - } - - def __init__(self): - """ - Initializes the class. No need to pass 'dev' since it's globally available. - """ - pass # No need for 'dev' parameter anymore - - def _cSAXS_smaract_stages_init(self): - """ - Initialize all Smaract stages by setting speed, finding the reference mark, and sleeping. - """ - for dev_name, axis_letter in self.devices.items(): - ch = self.AXIS_MAP[axis_letter] # Get the channel number for the axis - d = getattr(dev, dev_name) # Access the device instance using `getattr` - - try: - # Set the speed (this is an example, adjust as needed) - print(f"Setting speed for {dev_name} (axis {ch})...") - d.controller.set_closed_loop_move_speed(ch, 1) # Example speed value (1) - - # Find the reference mark for the axis - print(f"Finding reference mark for {dev_name} (axis {ch})...") - d.controller.find_reference_mark(ch, 0, 1000, 1) # Example reference find parameters - - # Sleep after the operation - print(f"Sleeping for 0.1s after initializing {dev_name} (axis {ch})...") - time.sleep(0.1) - - except AttributeError: - print(f"Device {dev_name} does not have a controller or method to initialize.") - except Exception as e: - print(f"Error initializing device {dev_name} (axis {ch}): {e}") - - def _cSAXS_smaract_stages_check_all_referenced(self): - """ - Check if all axes of the devices are referenced. - """ - for dev_name, axis_letter in self.devices.items(): - ch = self.AXIS_MAP[axis_letter] # Get the channel number for the axis - d = getattr(dev, dev_name) # Access the device instance using `getattr` - - try: - # Check if the axis is referenced on the device controller - if not d.controller.axis_is_referenced(ch): - print(f"Device {dev_name} (axis {ch}) is NOT referenced.") - else: - print(f"Device {dev_name} (axis {ch}) is referenced.") - - except AttributeError: - print(f"Device {dev_name} does not have a controller or axis_is_referenced method.") - except Exception as e: - print(f"Error checking device {dev_name} (axis {ch}): {e}") - -# Usage example: - -# Assuming `dev` is a globally available device manager containing all the device instances -# Create an instance of the mixin class -#cSAXS_init = cSAXSInitStagesMixin() - -# To initialize all stages: -#cSAXS_init._cSAXS_smaract_stages_init() - -# To check if all axes are referenced: -#cSAXS_init._cSAXS_smaract_stages_check_all_referenced() diff --git a/csaxs_bec/bec_ipython_client/plugins/cSAXS/smaract.py b/csaxs_bec/bec_ipython_client/plugins/cSAXS/smaract.py new file mode 100644 index 0000000..d5eb9cb --- /dev/null +++ b/csaxs_bec/bec_ipython_client/plugins/cSAXS/smaract.py @@ -0,0 +1,253 @@ +import builtins +import time +#from pathlib import Path + +from bec_lib import bec_logger + + +# Logger initialization +logger = bec_logger.logger + +if builtins.__dict__.get("bec") is not None: + bec = builtins.__dict__.get("bec") + dev = builtins.__dict__.get("dev") + umv = builtins.__dict__.get("umv") + umvr = builtins.__dict__.get("umvr") + +class cSAXSInitSmaractStagesError(Exception): + pass + + +class cSAXSInitSmaractStages: + # Class-level mappings for axes and devices + AXIS_MAP = {c: i for i, c in enumerate("ABCDEFGHIJKLMNOPQRSTUVWXYZ")} + + devices = { + "xbpm3x": "A", + "xbpm3y": "B", + "sl3trxi": "C", + "sl3trxo": "D", + "sl3trxb": "E", + "sl3trxt": "F", + "fast_shutter_n1_x": "H", + "fast_shutter_o1_x": "G", + "fast_shutter_o2_x": "F", + "filter_array_1_x": "B", + "filter_array_2_x": "C", + "filter_array_3_x": "D", + "filter_array_4_x": "E", + "sl4trxi": "G", + "sl4trxo": "H", + "sl4trxb": "I", + "sl4trxt": "A", + "sl5trxi": "C", + "sl5trxo": "D", + "sl5trxb": "E", + "sl5trxt": "F", + "xbimtrx": "A", + "xbimtry": "B", + } + + def __init__(self, client) -> None: + self.client = client + + def smaract_initialize_all_stages(self): + """ + Initialize all Smaract stages by setting speed, finding the reference mark, and sleeping. + """ + for dev_name, axis_letter in self.devices.items(): + ch = self.AXIS_MAP[axis_letter] # Get the channel number for the axis + d = getattr(dev, dev_name) # Access the device instance using `getattr` + + try: + # Set the speed (this is an example, adjust as needed) + print(f"Setting speed for {dev_name} (axis {ch})...") + d.controller.set_closed_loop_move_speed(ch, 1) # Example speed value (1) + + # Find the reference mark for the axis + print(f"Finding reference mark for {dev_name} (axis {ch})...") + d.controller.find_reference_mark(ch, 0, 1000, 1) # Example reference find parameters + + # Sleep after the operation + print(f"Sleeping for 0.1s after initializing {dev_name} (axis {ch})...") + time.sleep(0.1) + + except AttributeError: + print(f"Device {dev_name} does not have a controller or method to initialize.") + except Exception as e: + print(f"Error initializing device {dev_name} (axis {ch}): {e}") + + self.smaract_all_components_to_initial_position() + + def smaract_check_all_referenced(self): + """ + Check if all axes of the devices are referenced. + """ + for dev_name, axis_letter in self.devices.items(): + ch = self.AXIS_MAP[axis_letter] # Get the channel number for the axis + d = getattr(dev, dev_name) # Access the device instance using `getattr` + + try: + # Check if the axis is referenced on the device controller + if not d.controller.axis_is_referenced(ch): + print(f"Device {dev_name} (axis {ch}) is NOT referenced.") + else: + print(f"Device {dev_name} (axis {ch}) is referenced.") + + except AttributeError: + print(f"Device {dev_name} does not have a controller or axis_is_referenced method.") + except Exception as e: + print(f"Error checking device {dev_name} (axis {ch}): {e}") + + def smaract_all_components_to_initial_position( + self, + skip_devices=None, + ): + """ + Move all SmarAct-based components to their configured init_position. + + Parameters + ---------- + skip_devices : iterable of str, optional + Device names to skip (e.g. ["fast_shutter_n1_x"]). + """ + + skip_devices = set(skip_devices or []) + + # First confirmation: intent + if not self.OMNYTools.yesno( + "Do you want to move all SmarAct-based components to their " + "configured initial position?", + "y", + ): + return + + planned_moves = [] + not_referenced = [] + missing_params = [] + + # --- Pre-check phase --- + for dev_name, axis_letter in self.devices.items(): + + if dev_name in skip_devices: + bec_logger.logger.info( + f"[cSAXS] Skipping device {dev_name} (user request)." + ) + continue + + try: + d = getattr(dev, dev_name) + ch = self.AXIS_MAP[axis_letter] + + # Reference check + if not d.controller.axis_is_referenced(ch): + not_referenced.append(dev_name) + continue + + # Fetch init_position + init_pos = self.OMNYTools._get_user_param_safe( + dev_name, + "init_position", + ) + + if init_pos is None: + missing_params.append(dev_name) + continue + + planned_moves.append((dev_name, init_pos)) + + except AttributeError: + bec_logger.logger.warning( + f"[cSAXS] Device {dev_name} not accessible, skipping." + ) + + except Exception as exc: + bec_logger.logger.error( + f"[cSAXS] Error during pre-check for {dev_name}: {exc}" + ) + + # --- Hard stop conditions --- + if not_referenced: + bec_logger.logger.error( + "[cSAXS] The following devices are NOT referenced:\n" + + ", ".join(not_referenced) + ) + bec_logger.logger.error( + "[cSAXS] Aborting motion. Please reference axes first." + ) + return + + if not planned_moves: + bec_logger.logger.warning( + "[cSAXS] No valid initial positions found. Nothing to do." + ) + return + + # --- Summary table --- + print("\nPlanned SmarAct motions to initial position:") + print("-" * 60) + print(f"{'Device':<35} {'Init position':>20}") + print("-" * 60) + for dev_name, init_pos in planned_moves: + print(f"{dev_name:<35} {init_pos:>20}") + print("-" * 60) + + if missing_params: + print( + "\nNote: The following devices have no init_position defined " + "and will be skipped:" + ) + print(", ".join(missing_params)) + + if skip_devices: + print( + "\nNote: The following devices were explicitly skipped:" + ) + print(", ".join(sorted(skip_devices))) + + # Second confirmation: execution + if not self.OMNYTools.yesno( + "Proceed with the motions listed above?", + "y", + ): + bec_logger.logger.info( + "[cSAXS] Motion to initial position aborted by user." + ) + return + + # --- Execution phase --- + for dev_name, init_pos in planned_moves: + try: + d = getattr(dev, dev_name) + bec_logger.logger.info( + f"[cSAXS] Moving {dev_name} to init_position = {init_pos}" + ) + umv(d, init_pos) + + except Exception as exc: + bec_logger.logger.error( + f"[cSAXS] Failed to move {dev_name}: {exc}" + ) + + bec_logger.logger.info( + "[cSAXS] SmarAct motion to initial positions completed." + ) + + # example usage + # csaxs.smaract_all_components_to_initial_position( + # skip_devices=[ + # "fast_shutter_n1_x", + # "fast_shutter_o1_x", + # ] + # ) + +class cSAXSSmaract: + + def __init__(self, client) -> None: + self.client = client + + def fshn1in(self): + # Fetch in position + in_pos = self.OMNYTools._get_user_param_safe("fast_shutter_n1_x","in") + umv(dev.fast_shutter_n1_x,in_pos) + diff --git a/csaxs_bec/device_configs/smaract_test.yaml b/csaxs_bec/device_configs/smaract_test.yaml index ce3268a..0f0baae 100644 --- a/csaxs_bec/device_configs/smaract_test.yaml +++ b/csaxs_bec/device_configs/smaract_test.yaml @@ -16,6 +16,8 @@ xbpm3x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -22.5 xbpm3y: description: X-ray beam position y monitor 1 in ESbox1 @@ -34,6 +36,8 @@ xbpm3y: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -2 sl3trxi: description: ESbox1 slit 3 inner blade movement @@ -52,6 +56,8 @@ sl3trxi: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -5.5 sl3trxo: description: ESbox1 slit 3 outer blade movement @@ -70,6 +76,8 @@ sl3trxo: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 6 sl3trxb: description: ESbox1 slit 3 bottom blade movement @@ -88,6 +96,8 @@ sl3trxb: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -5.8 sl3trxt: description: ESbox1 slit 3 top blade movement @@ -106,6 +116,8 @@ sl3trxt: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 5.5 fast_shutter_n1_x: description: ESbox1 New fast shutter 1 x movment @@ -124,6 +136,9 @@ fast_shutter_n1_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -7 + in: 0 fast_shutter_o1_x: description: ESbox1 Old fast shutter 1 x movment @@ -142,6 +157,8 @@ fast_shutter_o1_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -15.8 fast_shutter_o2_x: description: ESbox1 Old fast shutter 2 x movment @@ -160,6 +177,8 @@ fast_shutter_o2_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -15.5 filter_array_1_x: description: ESbox1 Filter Array 1 x movment @@ -178,6 +197,8 @@ filter_array_1_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 25 filter_array_2_x: description: ESbox1 Filter Array 2 x movment @@ -196,6 +217,8 @@ filter_array_2_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 25.5 filter_array_3_x: description: ESbox1 Filter Array 3 x movment @@ -214,6 +237,8 @@ filter_array_3_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 25.8 filter_array_4_x: description: ESbox1 Filter Array 4 x movment @@ -232,6 +257,8 @@ filter_array_4_x: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 25 sl4trxi: description: ESbox1 slit 4 inner blade movement @@ -250,6 +277,8 @@ sl4trxi: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -5.5 sl4trxo: description: ESbox1 slit 4 outer blade movement @@ -268,6 +297,8 @@ sl4trxo: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 6 sl4trxb: description: ESbox1 slit 4 bottom blade movement @@ -286,6 +317,8 @@ sl4trxb: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -5.8 sl4trxt: description: ESbox1 slit 4 top blade movement @@ -304,6 +337,8 @@ sl4trxt: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 5.5 ################## XBOX 2 ES ##################### @@ -324,6 +359,8 @@ sl5trxi: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -6 sl5trxo: description: ESbox2 slit 5 outer blade movement @@ -342,6 +379,8 @@ sl5trxo: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 5.5 sl5trxb: description: ESbox2 slit 5 bottom blade movement @@ -360,6 +399,8 @@ sl5trxb: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -5.5 sl5trxt: description: ESbox1 slit 5 top blade movement @@ -378,6 +419,8 @@ sl5trxt: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 6 xbimtrx: description: ESbox2 beam intensity monitor x movement @@ -396,6 +439,8 @@ xbimtrx: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: -14.7 xbimtry: description: ESbox2 beam intensity monitor y movement @@ -414,3 +459,5 @@ xbimtry: onFailure: buffer readOnly: false readoutPriority: baseline + userParameter: + init_position: 0