Source code for csaxs_bec.bec_ipython_client.plugins.LamNI.lamni_optics_mixin

import builtins
import time

from rich import box
from rich.console import Console
from rich.table import Table

from csaxs_bec.bec_ipython_client.plugins.cSAXS import epics_put
from csaxs_bec.bec_ipython_client.plugins.omny.omny_general_tools import OMNYTools

dev = builtins.__dict__.get("dev")
bec = builtins.__dict__.get("bec")
scans = builtins.__dict__.get("scans")

[docs] def umv(*args): return scans.umv(*args, relative=False)
[docs] class LamNIInitError(Exception): pass
[docs] class LaMNIInitStages: """Handles hardware initialization and referencing of LamNI stages.""" def __init__(self, client): super().__init__() self.client = client self.OMNYTools = OMNYTools(self.client) def lamni_init_stages(self): if self.OMNYTools.yesno("Start initialization of LamNI stages. OK?"): print("starting...") dev.lsamrot.enabled = True else: return if self.check_all_axes_of_lamni_referenced(): if self.OMNYTools.yesno("All axes are referenced. Continue anyways?"): print("ok then...") else: return axis_id_lsamrot = dev.lsamrot._config["deviceConfig"].get("axis_Id") if dev.lsamrot.controller.get_motor_limit_switch(axis_id_lsamrot)[1] == False: if self.OMNYTools.yesno("The rotation stage will be moved to one limit"): print("starting...") else: return self.drive_axis_to_limit(dev.lsamrot, "forward") dev.lsamrot.enabled = False print("Now hard reboot the controller and run the initialization routine again.") print("Remark: The controller will be disabled in bec. It will be enabled by running the init route, \nbut in case needed, to enable manually set dev.lsamrot.enabled=True") return if self.OMNYTools.yesno( "Init of loptz. Can the stage move to the upstream limit without collision?" ): print("ok then...") else: return print("Referencing loptz") self.drive_axis_to_limit(dev.loptz, "forward") self.find_reference_mark(dev.loptz) print("Referencing loptx") self.drive_axis_to_limit(dev.loptx, "reverse") self.find_reference_mark(dev.loptx) print("Referencing lopty") self.drive_axis_to_limit(dev.lopty, "forward") self.find_reference_mark(dev.lopty) print("Referencing lsamx") self.drive_axis_to_limit(dev.lsamx, "forward") self.find_reference_mark(dev.lsamx) print("Referencing lsamy") self.drive_axis_to_limit(dev.lsamy, "reverse") self.find_reference_mark(dev.lsamy) print("Referencing lsamrot") self.drive_axis_to_limit(dev.lsamrot, "reverse") time.sleep(0.1) self.find_reference_mark(dev.lsamrot) if self.OMNYTools.yesno( "Init of leye. Can the stage move to -x limit without collision?" ): print("starting...") else: return print("Referencing leyex") self.drive_axis_to_limit(dev.leyex, "forward") print("Referencing leyey") self.drive_axis_to_limit(dev.leyey, "forward") print("Init of Smaract stages") dev.losax.controller.find_reference_mark(2, 0, 1000, 1) time.sleep(1) dev.losax.controller.find_reference_mark(0, 0, 1000, 1) time.sleep(1) dev.losax.controller.find_reference_mark(1, 0, 1000, 1) time.sleep(1) self._align_setup() def find_reference_mark(self, device): axis_id = device._config["deviceConfig"].get("axis_Id") axis_id_numeric = self.axis_id_to_numeric(axis_id) device.controller.find_reference(axis_id_numeric) def drive_axis_to_limit(self, device, direction): axis_id = device._config["deviceConfig"].get("axis_Id") axis_id_numeric = self.axis_id_to_numeric(axis_id) device.controller.drive_axis_to_limit(axis_id_numeric, direction) def axis_id_to_numeric(self, axis_id) -> int: return ord(axis_id.lower()) - 97 def _align_setup(self): if self.OMNYTools.yesno("Start moving stages to default initial positions?"): print("Start moving stages...") else: print("Stopping.") return lsamx_center = dev.lsamx.user_parameter.get("center") if lsamx_center is None: raise LamNIInitError( "Could not find a lsamx center position. Please check your device config." ) lsamy_center = dev.lsamy.user_parameter.get("center") if lsamy_center is None: raise LamNIInitError( "Could not find a lsamy center position. Please check your device config." ) umv(dev.lsamx, lsamx_center, dev.lsamy, lsamy_center, dev.loptx, -0.3, dev.lopty, 0) umv(dev.losax, -1) umv(dev.loptz, 82.25) umv(dev.lsamrot, -1) umv(dev.lsamrot, 0) time.sleep(2) dev.rtx.controller.feedback_disable_and_even_reset_lamni_angle_interferometer() def check_all_axes_of_lamni_referenced(self): if ( dev.losax.controller.axis_is_referenced(0) & dev.losax.controller.axis_is_referenced(1) & dev.losax.controller.axis_is_referenced(2) & dev.lsamx.controller.all_axes_referenced() ): print("All axes of LamNI are referenced.") return True else: return False
[docs] class LamNIOpticsMixin: """Optics movement methods: FZP, OSA, central stop and X-ray eye.""" @staticmethod def _get_user_param_safe(device, var): param = dev[device].user_parameter if not param or param.get(var) is None: raise ValueError(f"Device {device} has no user parameter definition for {var}.") return param.get(var) def leye_out(self): self.loptics_in() dev.fsh.fshopen() leyey_out = self._get_user_param_safe("leyey", "out") umv(dev.leyey, leyey_out) epics_put("XOMNYI-XEYE-ACQ:0", 2) umv(dev.lsamrot, 0) umv(dev.dttrz, 5854, dev.fttrz, 2395) def leye_in(self): bec.queue.next_dataset_number += 1 umv(dev.lsamrot, 0) umv(dev.dttrz, 6419.677, dev.fttrz, 2959.979) while True: moved_out = (input("Did the flight tube move out? (Y/n)") or "y").lower() if moved_out == "y": break if moved_out == "n": return leyex_in = self._get_user_param_safe("leyex", "in") leyey_in = self._get_user_param_safe("leyey", "in") umv(dev.leyex, leyex_in, dev.leyey, leyey_in) self.align.update_frame() def _lfzp_in(self): loptx_in = self._get_user_param_safe("loptx", "in") lopty_in = self._get_user_param_safe("lopty", "in") umv(dev.loptx, loptx_in, dev.lopty, lopty_in)
[docs] def lfzp_in(self): """Move in the LamNI zone plate, disabling/re-enabling RT feedback around the move.""" if "rtx" in dev and dev.rtx.enabled: dev.rtx.controller.feedback_disable() self._lfzp_in() if "rtx" in dev and dev.rtx.enabled: dev.rtx.controller.feedback_enable_with_reset()
[docs] def loptics_in(self): """Move in the LamNI optics (FZP + OSA).""" self.lfzp_in() self.losa_in()
[docs] def loptics_out(self): """Move out the LamNI optics.""" if "rtx" in dev and dev.rtx.enabled: dev.rtx.controller.feedback_disable() self.losa_out() loptx_out = self._get_user_param_safe("loptx", "out") lopty_out = self._get_user_param_safe("lopty", "out") umv(dev.loptx, loptx_out, dev.lopty, lopty_out) if "rtx" in dev and dev.rtx.enabled: time.sleep(1) dev.rtx.controller.feedback_enable_with_reset()
def lcs_in(self): pass def lcs_out(self): umv(dev.lcsy, 3) def losa_in(self): losax_in = self._get_user_param_safe("losax", "in") losay_in = self._get_user_param_safe("losay", "in") losaz_in = self._get_user_param_safe("losaz", "in") umv(dev.losax, losax_in, dev.losay, losay_in) umv(dev.losaz, losaz_in) def losa_out(self): losay_out = self._get_user_param_safe("losay", "out") losaz_out = self._get_user_param_safe("losaz", "out") umv(dev.losaz, losaz_out) umv(dev.losay, losay_out) def lfzp_info(self, mokev_val=-1): if mokev_val == -1: try: mokev_val = dev.mokev.readback.get() except Exception: print( "Device mokev does not exist. You can specify the energy in keV as an argument instead." ) return loptz_val = dev.loptz.read()["loptz"]["value"] distance = -loptz_val + 85.6 + 52 print(f"The sample is in a distance of {distance:.1f} mm from the FZP.") diameters = [80e-6, 100e-6, 120e-6, 150e-6, 170e-6, 200e-6, 220e-6, 250e-6] console = Console() table = Table( title=f"At the current energy of {mokev_val:.4f} keV we have following options:", box=box.SQUARE, ) table.add_column("Diameter", justify="center") table.add_column("Focal distance", justify="center") table.add_column("Current beam size", justify="center") wavelength = 1.2398e-9 / mokev_val for diameter in diameters: outermost_zonewidth = 60e-9 focal_distance = diameter * outermost_zonewidth / wavelength beam_size = ( -diameter / (focal_distance * 1000) * (focal_distance * 1000 - distance) * 1e6 ) table.add_row( f"{diameter*1e6:.2f} microns", f"{focal_distance:.2f} mm", f"{beam_size:.2f} microns", ) console.print(table) print( "The numbers presented here are for a sample in the plane of the lamni sample holder.\n" )