WIP big becclient refactor
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import os
|
||||
|
||||
from aare.beamline_dispatch.protocols import AuthDispatch, BeamlineDispatch
|
||||
from aarecommon.config.beamline import MXBeamline
|
||||
|
||||
from aare.beamline_dispatch.protocols import AuthDispatch, BeamlineDispatch, ConfigKeys
|
||||
|
||||
|
||||
class DefaultAuthDispatch(AuthDispatch):
|
||||
@@ -12,13 +14,49 @@ class DefaultAuthDispatch(AuthDispatch):
|
||||
return key
|
||||
|
||||
|
||||
class DefaultConfigKeys(ConfigKeys):
|
||||
def __init__(self, beamline: MXBeamline):
|
||||
self._beamline = beamline
|
||||
|
||||
@property
|
||||
def bl_lower(self) -> str:
|
||||
return self._beamline.lower()
|
||||
|
||||
@property
|
||||
def bl_upper(self) -> str:
|
||||
return self._beamline.upper()
|
||||
|
||||
@property
|
||||
def bl_name(self) -> str:
|
||||
match self._beamline:
|
||||
case MXBeamline.X06SA:
|
||||
return "pxi"
|
||||
case MXBeamline.X10SA:
|
||||
return "pxii"
|
||||
case MXBeamline.X06DA:
|
||||
return "pxiii"
|
||||
case MXBeamline.SIMULATED:
|
||||
return "simulated"
|
||||
case _:
|
||||
raise ValueError(f"Beamline {self._beamline} has no common name!")
|
||||
|
||||
@property
|
||||
def device_yml_path(self) -> str:
|
||||
return f"/sls/{self.bl_lower}/config/bec/production/{self.bl_name}_bec/{self.bl_name}_bec/device_configs/{self.bl_name}-devices.yaml"
|
||||
|
||||
|
||||
class DefaultDispatch(BeamlineDispatch):
|
||||
"""Default implementation for anything which can vary between beamlines and/or simulation.
|
||||
Should be safe and fail rather than assuming anything."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(self, beamline: MXBeamline) -> None:
|
||||
self._auth = DefaultAuthDispatch()
|
||||
self._config = DefaultConfigKeys(beamline)
|
||||
|
||||
@property
|
||||
def auth(self):
|
||||
return self._auth
|
||||
|
||||
@property
|
||||
def config(self):
|
||||
return self._config
|
||||
|
||||
@@ -22,12 +22,26 @@ class BecMacros(ABC):
|
||||
def bl_energy(energy_ev, move_gap=True, mono_scan=True, plot=True): ...
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def get_current_energy(): ...
|
||||
def get_current_energy() -> float: ...
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def mono_pitch_scan(plot=True): ...
|
||||
|
||||
|
||||
class ConfigKeys(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def bl_lower(self) -> str: ...
|
||||
@property
|
||||
@abstractmethod
|
||||
def bl_upper(self) -> str: ...
|
||||
@property
|
||||
@abstractmethod
|
||||
def bl_name(self) -> str: ...
|
||||
@property
|
||||
def device_yml_path(self) -> str: ...
|
||||
|
||||
|
||||
class BeamlineDispatch(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
@@ -35,3 +49,6 @@ class BeamlineDispatch(ABC):
|
||||
@property
|
||||
@abstractmethod
|
||||
def bec_macros(self) -> BecMacros: ...
|
||||
@property
|
||||
@abstractmethod
|
||||
def config(self) -> ConfigKeys: ...
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from typing import Any
|
||||
|
||||
from aare.beamline_dispatch.default.beamline_dispatch import DefaultDispatch
|
||||
from aarecommon.config.beamline import MXBeamline
|
||||
|
||||
from aare.beamline_dispatch.default.beamline_dispatch import DefaultConfigKeys, DefaultDispatch
|
||||
from aare.beamline_dispatch.protocols import AuthDispatch, BecMacros
|
||||
|
||||
|
||||
@@ -32,6 +34,7 @@ class SimulatedDispatch(DefaultDispatch):
|
||||
def __init__(self) -> None:
|
||||
self._auth = SimulatedAuthDispatch()
|
||||
self._bec_macros = SimulatedBecMacros()
|
||||
self._config = DefaultConfigKeys(MXBeamline.SIMULATED)
|
||||
|
||||
@property
|
||||
def bec_macros(self):
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from typing import Any
|
||||
|
||||
from aarecommon.config.beamline import MXBeamline
|
||||
|
||||
from aare.beamline_dispatch.default.beamline_dispatch import DefaultDispatch
|
||||
from aare.beamline_dispatch.protocols import BecMacros
|
||||
|
||||
@@ -45,8 +47,8 @@ class X06daBecMacros(BecMacros):
|
||||
|
||||
|
||||
class X06daDispatch(DefaultDispatch):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
def __init__(self, beamline: MXBeamline) -> None:
|
||||
super().__init__(beamline)
|
||||
self._bec_macros = X06daBecMacros()
|
||||
|
||||
@property
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
from typing import Any
|
||||
|
||||
from aarecommon.config.beamline import MXBeamline
|
||||
|
||||
from aare.beamline_dispatch.default.beamline_dispatch import DefaultDispatch
|
||||
from aare.beamline_dispatch.protocols import BecMacros
|
||||
|
||||
@@ -39,8 +41,8 @@ class X10SaBecMacros(BecMacros):
|
||||
|
||||
|
||||
class X10saDispatch(DefaultDispatch):
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
def __init__(self, beamline: MXBeamline) -> None:
|
||||
super().__init__(beamline)
|
||||
self._bec_macros = X10SaBecMacros()
|
||||
|
||||
@property
|
||||
|
||||
+7
-75
@@ -11,16 +11,12 @@ from aarecommon.config.logger_events import log_timing
|
||||
from aarecommon.math.coordinate import AerotechCoordinate, SmargonCoordinate
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
from aarecommon.models.models import SampleCameraSettings, StagePositionEnum
|
||||
from epics import PV
|
||||
|
||||
from aare.devices import aerotech, smargon
|
||||
from aare.devices.area_detector import AutoEnum, epicsAD
|
||||
from aare.devices.bec_worker import BECClientWorker
|
||||
from aare.devices.enum_pv import EnumPV
|
||||
from aare.devices.experimental_hutch_shutter import ExperimentalHutchShutter
|
||||
from aare.devices.my_motor import MyMotor
|
||||
from aare.devices.pss_state import PssState
|
||||
from aare.devices.set_get_pv import PredefinedPV, SetGetPV
|
||||
from aare.devices.tell_client import make_tell_client
|
||||
|
||||
logger = setup_logger("aareDAQ")
|
||||
@@ -37,78 +33,14 @@ class BeamlineDevices:
|
||||
logger.debug("initialising BEC worker done")
|
||||
self._smargon = smargon.Smargon(beamline)
|
||||
self.exp_shutter = ExperimentalHutchShutter(beamline=self._beamline)
|
||||
self.dtz_mod = cfg_get("daq.detector_distance_limit_modifier", 1.0)
|
||||
|
||||
# TODO convert epics pvs to BEC -> need to get all samcam signals into a device
|
||||
# BEC device for pss state also good
|
||||
# Personnel Safety System: gates whether the robot is allowed to move.
|
||||
self.pss = PssState(beamline=self._beamline)
|
||||
|
||||
# faster to define the dtz object here than in functions and then use
|
||||
self._dtz = self.bec_worker.dev.det_z
|
||||
self.dtz_mod = cfg_get("daq.detector_distance_limit_modifier", 1.0)
|
||||
# TODO convert epics pvs to BEC
|
||||
self._sample_cam = epicsAD(f"{BEAMLINE}-ES-MS:")
|
||||
|
||||
self._front_light = PredefinedPV(
|
||||
name="front_light",
|
||||
setpv=f"{BEAMLINE}-ES-FL:SET",
|
||||
getpv=f"{BEAMLINE}-ES-FL:SET",
|
||||
predefs={"off": 1.49, "half": 2.0, "max": 3.0},
|
||||
timeout=10.0,
|
||||
)
|
||||
self._back_light = PredefinedPV(
|
||||
name="back_light",
|
||||
setpv=f"{BEAMLINE}-ES-BL:SET",
|
||||
getpv=f"{BEAMLINE}-ES-BL:SET",
|
||||
predefs={"off": 0, "half": 0.98, "max": 1.2},
|
||||
timeout=10.0,
|
||||
)
|
||||
|
||||
# self._front_light = self.bec_worker.dev.fl_bright # need wrapper on bec_worker layer
|
||||
# self._back_light = self.bec_worker.dev.bl_bright #need wrapper on bec_worker layer
|
||||
|
||||
self._back_light_pos = EnumPV(
|
||||
name="back_light_pos",
|
||||
setpv=f"{BEAMLINE}-ES-BL:POS-SET",
|
||||
getpv=f"{BEAMLINE}-ES-BL:POS-GET",
|
||||
timeout=10.0,
|
||||
)
|
||||
|
||||
self._ringcurrent = self.bec_worker.ring_current
|
||||
|
||||
self._zoom = SetGetPV(
|
||||
name="zoom", setpv=f"{BEAMLINE}-ES-MS:ZOOM.VAL", getpv=f"{BEAMLINE}-ES-MS:ZOOM.RBV"
|
||||
)
|
||||
|
||||
self._cryojet_pos = EnumPV(
|
||||
name="cryojet_pos",
|
||||
setpv=f"{BEAMLINE}-ES-CS:POS-SET",
|
||||
getpv=f"{BEAMLINE}-ES-CS:POS-GET",
|
||||
timeout=10.0,
|
||||
)
|
||||
|
||||
self._cryojet_x = MyMotor(f"{BEAMLINE}-ES-CS:TRX") # currently in is 5 out is 15?
|
||||
|
||||
self._cryojet_temperature_get = PV(f"{BEAMLINE}-ES-CS:TEMP_RBV")
|
||||
self._cryojet_temperature_set = PV(f"{BEAMLINE}-ES-CS:TEMP.VAL")
|
||||
|
||||
if self._beamline == MXBeamline.X06DA:
|
||||
self._transmission = SetGetPV(
|
||||
name="transmission",
|
||||
setpv=f"{BEAMLINE}-ES-BCFI:TRANSM-SET",
|
||||
getpv=f"{BEAMLINE}-ES-BCFI:TRANSM-GET",
|
||||
)
|
||||
else:
|
||||
self._transmission = SetGetPV(
|
||||
name="transmission",
|
||||
setpv=f"{BEAMLINE}-ES-SSFI:TRANSM-SET",
|
||||
getpv=f"{BEAMLINE}-ES-SSFI:TRANSM-GET",
|
||||
)
|
||||
|
||||
self._fast_shutter = PV(f"{BEAMLINE}-ES-SHUTTER:SET")
|
||||
|
||||
self.magnet_position_sensor = PV(f"{BEAMLINE}-ES-DFS:CBOX-CMP1")
|
||||
self.magnet_position_sensor_readout = PV(f"{BEAMLINE}-ES-DFS:CBOX-USER1")
|
||||
# self.magnet_position_sensor_readout = PV(f"{BEAMLINE}-ES-DFS:CBOX-REFVAL1")
|
||||
self.magnet_position_sensor_state = PV(f"{BEAMLINE}-ES-DFS:CBOX-STATE")
|
||||
|
||||
def restart_bec_worker(self, simulated: bool = False) -> None:
|
||||
try:
|
||||
if getattr(self, "bec_worker", None) is not None and not simulated:
|
||||
@@ -141,7 +73,7 @@ class BeamlineDevices:
|
||||
# Transmission
|
||||
@property
|
||||
def transmission(self) -> float:
|
||||
return self._transmission.value
|
||||
return self.bec_worker.tra
|
||||
|
||||
@transmission.setter
|
||||
def transmission(self, value: float):
|
||||
@@ -178,14 +110,14 @@ class BeamlineDevices:
|
||||
# Zoom
|
||||
@property
|
||||
def zoom(self) -> float:
|
||||
return self._zoom.value
|
||||
return self._samcam_zoom.get()
|
||||
|
||||
@zoom.setter
|
||||
def zoom(self, value: float):
|
||||
self.set_zoom(value, wait=True)
|
||||
|
||||
def set_zoom(self, value: float, /, wait: bool = True):
|
||||
self._zoom.move(value, wait=wait)
|
||||
self._samcam_zoom.put(value, wait=wait)
|
||||
|
||||
# Optics
|
||||
@property
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import sys
|
||||
import time
|
||||
from enum import Enum
|
||||
from enum import Enum, StrEnum
|
||||
|
||||
from aarecommon.config.beamline import cfg_get, mx_beamline
|
||||
from aarecommon.config.logger import setup_logger
|
||||
from aarecommon.config.logger_events import log_timing
|
||||
from aarecommon.errors.exception_handler import BECCommunicationError
|
||||
from aarecommon.errors.exception_handler import BECCommunicationError, BECException
|
||||
from aarecommon.models.beamline import MXBeamline
|
||||
from bec_ipython_client import BECIPythonClient
|
||||
from bec_ipython_client.signals import OperationMode
|
||||
from bec_lib.device import RPCError, ScanRequestError
|
||||
from bec_lib.devicemanager import DeviceContainer
|
||||
from bec_lib.procedures.helper import FrontendProcedureHelper
|
||||
from bec_lib.service_config import ServiceConfig
|
||||
|
||||
@@ -49,39 +50,49 @@ class BeamlineState(str, Enum):
|
||||
XTAL_SNAPSHOT = "xtal_snapshot"
|
||||
|
||||
|
||||
class BecDevices(StrEnum):
|
||||
DET_Z = "det_z"
|
||||
FL_BRIGHT = "fl_bright"
|
||||
BL_BRIGHT = "bl_bright"
|
||||
BL_POS = "bl_pos"
|
||||
SCAM_ZOOM = "scam_zoom"
|
||||
CRYO_POS = "cryo_pos"
|
||||
CRYO_TEMP = "cryo_temp"
|
||||
CRYO_X = "cryo_x"
|
||||
TRANSM = "transm"
|
||||
BCU_SHUTTER = "bcu_shutter"
|
||||
MAG_OK = "mag_ok"
|
||||
MAG_RBV = "mag_rbv"
|
||||
|
||||
|
||||
class MissingDevicesError(BECException): ...
|
||||
|
||||
|
||||
class BECClientWorker:
|
||||
def __init__(self, beamline: MXBeamline, name: str = "default"):
|
||||
BEAMLINE = beamline.value.lower()
|
||||
self.beamline = beamline
|
||||
if self.beamline is MXBeamline.X06DA:
|
||||
self._beamline_name = "pxiii"
|
||||
elif self.beamline is MXBeamline.X10SA:
|
||||
self._beamline_name = "pxii"
|
||||
elif self.beamline is MXBeamline.X06DA:
|
||||
self._beamline_name = "pxi"
|
||||
elif self.beamline is MXBeamline.SIMULATED:
|
||||
self._beamline_name = "SIMULATED"
|
||||
else:
|
||||
raise ValueError(f"Unknown beamline: {beamline}")
|
||||
|
||||
self.dispatch = get_beamline_dispatch()
|
||||
|
||||
if self.beamline is MXBeamline.SIMULATED:
|
||||
if beamline is MXBeamline.SIMULATED:
|
||||
self.simulated = True
|
||||
|
||||
else:
|
||||
self.simulated = False
|
||||
logger.debug(f"Initializing BECClientWorker for {BEAMLINE} beamline")
|
||||
host = cfg_get("daq.hardware.bec_url", f"{BEAMLINE}-bec-001.psi.ch")
|
||||
logger.debug(
|
||||
f"Initializing BECClientWorker for {self.dispatch.config.bl_lower} beamline"
|
||||
)
|
||||
host = cfg_get(
|
||||
"daq.hardware.bec_url", f"{self.dispatch.config.bl_lower}-bec-001.psi.ch"
|
||||
)
|
||||
service_config = ServiceConfig(redis={"host": host, "port": 6379})
|
||||
service_config.config["log_writer"]["base_path"] = "/tmp/logs"
|
||||
# service_config.config["user_macros"]["base_path"]=f'/sls/{BEAMLINE}/config/bec/production/pxiii_bec/pxiii_bec'
|
||||
# print(service_config.config)
|
||||
self.client = BECIPythonClient(config=service_config, mode=OperationMode.Procedure)
|
||||
self.client.start()
|
||||
# self.client.config.update_session_with_file("/sls/x10sa/config/bec/production/bec/bec_lib/bec_lib/config_helper.py")
|
||||
self.dev = self.client.device_manager.devices
|
||||
print(self.dev.keys())
|
||||
self.dev: DeviceContainer = self.client.device_manager.devices
|
||||
missing_devices = {str(d) for d in list(BecDevices) if d not in self.dev}
|
||||
if missing_devices:
|
||||
raise MissingDevicesError(
|
||||
f"{missing_devices} were not found in the BEC session. Available: {list(self.dev.keys())}. If no devices are available, load a BEC device config."
|
||||
)
|
||||
self.scans = self.client.scans
|
||||
self.macros = self.dispatch.bec_macros
|
||||
self.helper = FrontendProcedureHelper(self.client.connector)
|
||||
@@ -94,26 +105,11 @@ class BECClientWorker:
|
||||
logger.debug(f"simulated is {self.simulated}")
|
||||
|
||||
def _init_beamline_environment(self):
|
||||
try:
|
||||
self.position_devices, self.planner = self.macros.init_beamline_environment()
|
||||
self._backlight_brightness = self.position_devices["bl_bright"]
|
||||
self._frontlight_brightness = self.position_devices["fl_bright"]
|
||||
self._zoom = self.dev.scam_zoom
|
||||
self._ring_current = self.dev.sls_current
|
||||
except Exception as e:
|
||||
logger.error(f"Error initialising planar and position devices: {e}")
|
||||
self.position_devices = None
|
||||
self.planner = None
|
||||
self._backlight_brightness = None
|
||||
self._frontlight_brightness = None
|
||||
try:
|
||||
self._zoom = self.dev.scam_zoom
|
||||
self._ring_current = self.dev.sls_current
|
||||
except Exception as e:
|
||||
logger.exception("Error initialising zoom and ring_current")
|
||||
self._zoom = None
|
||||
self.ring_current = None
|
||||
raise RuntimeError(f"Error initialising BEC devices: {e}") from e
|
||||
self.position_devices, self.planner = self.macros.init_beamline_environment()
|
||||
self._backlight_brightness = self.position_devices["bl_bright"]
|
||||
self._frontlight_brightness = self.position_devices["fl_bright"]
|
||||
self._zoom = self.dev[BecDevices.SCAM_ZOOM]
|
||||
self._ring_current = self.dev.sls_current
|
||||
|
||||
def _bec_error(
|
||||
self, exc: Exception, *, operation: str, tags: list[str] | None = None
|
||||
@@ -219,28 +215,6 @@ class BECClientWorker:
|
||||
except Exception:
|
||||
logger.exception("Error sending scilog message")
|
||||
|
||||
def run_macro(self, macro_name: str, *args, queue: str = "default", **kwargs):
|
||||
if self.simulated:
|
||||
logger.debug(f"Simulating macro {macro_name}")
|
||||
return None
|
||||
try:
|
||||
return self.client.proc.run_macro(macro_name, *args, queue=queue)
|
||||
except Exception as e:
|
||||
raise self._bec_error(e, operation=f"run_macro:{macro_name}") from e
|
||||
|
||||
def run_macro_blocked(self, macro_name: str, *args, queue: str = "default", **kwargs):
|
||||
if self.simulated:
|
||||
logger.debug(f"Simulating macro {macro_name}")
|
||||
return None
|
||||
try:
|
||||
status = self.run_macro(macro_name, *args, queue=queue)
|
||||
print(status)
|
||||
status.wait()
|
||||
print(status)
|
||||
return status
|
||||
except Exception as e:
|
||||
raise self._bec_error(e, operation=f"run_macro_blocked:{macro_name}") from e
|
||||
|
||||
@log_timing(logger, "BEC move_to")
|
||||
def move_to(self, state: BeamlineState):
|
||||
start = time.perf_counter()
|
||||
@@ -299,27 +273,6 @@ class BECClientWorker:
|
||||
except Exception as e:
|
||||
raise self._bec_error(e, operation="list_all_user_macros") from e
|
||||
|
||||
def _list_all_macros(self):
|
||||
result = self.client.macros.list_user_macros()
|
||||
if result is None:
|
||||
return []
|
||||
return result
|
||||
|
||||
def load_user_macros(self):
|
||||
if self.simulated:
|
||||
logger.debug("Simulating load_user_macros")
|
||||
return None
|
||||
try:
|
||||
return self._load_user_macros()
|
||||
except Exception as e:
|
||||
raise self._bec_error(e, operation="load_user_macros") from e
|
||||
|
||||
def _load_user_macros(self):
|
||||
result = self.macros.load_all_user_macros()
|
||||
if result is None:
|
||||
logger.warning("BEC load_all_user_macros returned None")
|
||||
return result
|
||||
|
||||
def reinitialise_planner_and_position_devices(self, method: str = "auto"):
|
||||
"""
|
||||
Reinitialise BEC position devices and planner.
|
||||
@@ -337,9 +290,7 @@ class BECClientWorker:
|
||||
logger.debug(f"Simulating reinitialise_planner_and_position_devices(method={method})")
|
||||
return []
|
||||
try:
|
||||
self.client.config.update_session_with_file(
|
||||
f"/sls/{self.beamline}/config/bec/production/{self._beamline_name}_bec/{self._beamline_name}_bec/device_configs/{self._beamline_name}-devices.yaml"
|
||||
)
|
||||
self.client.config.update_session_with_file(self.dispatch.config.device_yml_path)
|
||||
self._init_beamline_environment()
|
||||
logger.info(f"Reinitialised BEC planner and position devices using method={method}")
|
||||
return self.list_position_devices()
|
||||
@@ -356,7 +307,7 @@ class BECClientWorker:
|
||||
self.macros.mono_pitch_scan(plot)
|
||||
except Exception as e:
|
||||
raise self._bec_error(e, operation="mono_pitch_scan", tags=["mono_pitch_scan"]) from e
|
||||
if self.beamline is MXBeamline.X06DA:
|
||||
if self.dispatch.config.bl_upper == MXBeamline.X06DA:
|
||||
addtional_text = [f"New dcm_pitch position: {self.dev.dcm_pitch.position:5f}"]
|
||||
else:
|
||||
addtional_text = [f"New dcm_theta2 position: {self.dev.dccm_theta2.position:5f}"]
|
||||
|
||||
Reference in New Issue
Block a user