fix: online changes to integrate devices in BEC

This commit is contained in:
e21206 2023-08-30 22:27:47 +02:00
parent d694f6594d
commit fbfa562713
10 changed files with 122 additions and 43 deletions

View File

@ -334,7 +334,8 @@ class DelayGeneratorDG645(Device):
self._producer = bec_utils.MockProducer() self._producer = bec_utils.MockProducer()
self.device_manager = bec_utils.MockDeviceManager() self.device_manager = bec_utils.MockDeviceManager()
self.scaninfo = BecScaninfoMixin(device_manager, sim_mode) self.scaninfo = BecScaninfoMixin(device_manager, sim_mode)
self.all_channels = ["channelT0", "channelAB", "channelCD", "channelEF", "channelGH"] self._all_channels = ["channelT0", "channelAB", "channelCD", "channelEF", "channelGH"]
self._all_delay_pairs = ["AB", "CD", "EF", "GH"]
self.wait_for_connection() # Make sure to be connected before talking to PVs self.wait_for_connection() # Make sure to be connected before talking to PVs
self._init_ddg() self._init_ddg()
self._ddg_is_okay() self._ddg_is_okay()
@ -386,7 +387,7 @@ class DelayGeneratorDG645(Device):
def _set_channels(self, signal: str, value: Any, channels: List = None) -> None: def _set_channels(self, signal: str, value: Any, channels: List = None) -> None:
if not channels: if not channels:
channels = self.all_channels channels = self._all_channels
for chname in channels: for chname in channels:
channel = getattr(self, chname, None) channel = getattr(self, chname, None)
if not channel: if not channel:
@ -404,6 +405,17 @@ class DelayGeneratorDG645(Device):
self._init_ddg_pol_allchannels(self.polarity.get()) self._init_ddg_pol_allchannels(self.polarity.get())
self._init_ddg_amp_allchannels(self.amplitude.get()) self._init_ddg_amp_allchannels(self.amplitude.get())
self._init_ddg_offset_allchannels(self.offset.get()) self._init_ddg_offset_allchannels(self.offset.get())
self._set_channels(
"reference",
0,
[f"channel{self._all_delay_pairs[ii]}.ch1" for ii in range(len(self._all_delay_pairs))],
)
for ii in range(len(self._all_delay_pairs)):
self._set_channels(
"reference",
2 * ii + 1,
[f"channel{self._all_delay_pairs[ii]}.ch2"],
)
self._set_trigger(TriggerSource.SINGLE_SHOT) self._set_trigger(TriggerSource.SINGLE_SHOT)
self.level.set(self.thres_trig_level.get()) self.level.set(self.thres_trig_level.get())
@ -474,6 +486,7 @@ class DelayGeneratorDG645(Device):
# if self.scaninfo.scan_type == "step": # if self.scaninfo.scan_type == "step":
if self.source.read()[self.source.name]["value"] == int(TriggerSource.SINGLE_SHOT): if self.source.read()[self.source.name]["value"] == int(TriggerSource.SINGLE_SHOT):
self.trigger_shot.set(1).wait() self.trigger_shot.set(1).wait()
super().trigger()
def burstEnable(self, count, delay, period, config="all"): def burstEnable(self, count, delay, period, config="all"):
"""Enable the burst mode""" """Enable the burst mode"""

View File

@ -21,3 +21,8 @@ from .specMotors import (
from ophyd import EpicsSignal, EpicsSignalRO, EpicsMotor from ophyd import EpicsSignal, EpicsSignalRO, EpicsMotor
from ophyd.sim import SynAxis, SynSignal, SynPeriodicSignal from ophyd.sim import SynAxis, SynSignal, SynPeriodicSignal
from ophyd.quadem import QuadEM from ophyd.quadem import QuadEM
# cSAXS
from .mcs_csaxs import McsCsaxs
from .eiger9m_csaxs import Eiger9mCsaxs
from .pilatus_csaxs import PilatusCsaxs

View File

@ -7,6 +7,21 @@ class BecScaninfoMixin:
def __init__(self, device_manager: DeviceManagerBase = None, sim_mode=False) -> None: def __init__(self, device_manager: DeviceManagerBase = None, sim_mode=False) -> None:
self.device_manager = device_manager self.device_manager = device_manager
self.sim_mode = sim_mode self.sim_mode = sim_mode
self.bec_info_msg = {
"RID": "mockrid",
"queueID": "mockqueuid",
"scan_number": 1,
"exp_time": 26e-3,
"num_points": 10000,
"readout_time": 2e-3,
"scan_type": "fly",
}
def get_bec_info_msg(self) -> None:
return self.bec_info_msg
def change_config(self, bec_info_msg: dict) -> None:
self.bec_info_msg = bec_info_msg
def _get_current_scan_msg(self) -> BECMessage.ScanStatusMessage: def _get_current_scan_msg(self) -> BECMessage.ScanStatusMessage:
if not self.sim_mode: if not self.sim_mode:
@ -16,15 +31,7 @@ class BecScaninfoMixin:
return BECMessage.ScanStatusMessage( return BECMessage.ScanStatusMessage(
scanID="1", scanID="1",
status={}, status={},
info={ info=self.bec_info_msg,
"RID": "mockrid",
"queueID": "mockqueuid",
"scan_number": 1,
"exp_time": 26e-3,
"num_points": 10000,
"readout_time": 2e-3,
"scan_type": "fly",
},
) )
def _get_username(self) -> str: def _get_username(self) -> str:

View File

@ -4,7 +4,7 @@ from typing import Any, List
import numpy as np import numpy as np
from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV from ophyd import EpicsSignal, EpicsSignalRO, EpicsSignalWithRBV
from ophyd import CamBase, DetectorBase from ophyd import CamBase, DetectorBase, Device
from ophyd import ADComponent as ADCpt from ophyd import ADComponent as ADCpt
from ophyd.areadetector.plugins import FileBase from ophyd.areadetector.plugins import FileBase
@ -25,7 +25,7 @@ class EigerError(Exception):
pass pass
class SlsDetectorCam(CamBase, FileBase): class SlsDetectorCam(Device): # CamBase, FileBase):
detector_type = ADCpt(EpicsSignalRO, "DetectorType_RBV") detector_type = ADCpt(EpicsSignalRO, "DetectorType_RBV")
setting = ADCpt(EpicsSignalWithRBV, "Setting") setting = ADCpt(EpicsSignalWithRBV, "Setting")
delay_time = ADCpt(EpicsSignalWithRBV, "DelayTime") delay_time = ADCpt(EpicsSignalWithRBV, "DelayTime")
@ -63,6 +63,10 @@ class SlsDetectorCam(CamBase, FileBase):
json_frame_mode = ADCpt(EpicsSignalWithRBV, "JsonFrameMode") json_frame_mode = ADCpt(EpicsSignalWithRBV, "JsonFrameMode")
json_detector_mode = ADCpt(EpicsSignalWithRBV, "JsonDetectorMode") json_detector_mode = ADCpt(EpicsSignalWithRBV, "JsonDetectorMode")
# fixes due to missing PVs from CamBase
acquire = ADCpt(EpicsSignal, "Acquire")
detector_state = ADCpt(EpicsSignalRO, "DetectorState_RBV")
class TriggerSource(int, enum.Enum): class TriggerSource(int, enum.Enum):
AUTO = 0 AUTO = 0
@ -127,8 +131,8 @@ class Eiger9mCsaxs(DetectorBase):
self.name = name self.name = name
self.wait_for_connection() # Make sure to be connected before talking to PVs self.wait_for_connection() # Make sure to be connected before talking to PVs
if not sim_mode: if not sim_mode:
self._producer = self.device_manager.producer
self.device_manager = device_manager self.device_manager = device_manager
self._producer = self.device_manager.producer
else: else:
self._producer = bec_utils.MockProducer() self._producer = bec_utils.MockProducer()
self.device_manager = bec_utils.MockDeviceManager() self.device_manager = bec_utils.MockDeviceManager()
@ -139,7 +143,6 @@ class Eiger9mCsaxs(DetectorBase):
self.filewriter = FileWriterMixin(self.service_cfg) self.filewriter = FileWriterMixin(self.service_cfg)
self.reduce_readout = 1e-3 # 3 ms self.reduce_readout = 1e-3 # 3 ms
self.triggermode = 0 # 0 : internal, scan must set this if hardware triggered self.triggermode = 0 # 0 : internal, scan must set this if hardware triggered
self.mokev = 12
self._init_eiger9m() self._init_eiger9m()
self._init_standard_daq() self._init_standard_daq()
@ -149,7 +152,6 @@ class Eiger9mCsaxs(DetectorBase):
def _init_eiger9m(self) -> None: def _init_eiger9m(self) -> None:
"""Init parameters for Eiger 9m""" """Init parameters for Eiger 9m"""
self._set_det_threshold()
self._set_trigger(TriggerSource.GATING) self._set_trigger(TriggerSource.GATING)
self.cam.acquire.set(0) self.cam.acquire.set(0)
@ -184,7 +186,7 @@ class Eiger9mCsaxs(DetectorBase):
def _prep_det(self) -> None: def _prep_det(self) -> None:
self._set_det_threshold() self._set_det_threshold()
self._set_acquisition_params() self._set_acquisition_params()
self._set_trigger(TriggerSource.TRIGGER) self._set_trigger(TriggerSource.GATING)
def _set_det_threshold(self) -> None: def _set_det_threshold(self) -> None:
# threshold_energy PV exists on Eiger 9M? # threshold_energy PV exists on Eiger 9M?
@ -226,7 +228,6 @@ class Eiger9mCsaxs(DetectorBase):
self.std_client.start_writer_async( self.std_client.start_writer_async(
{"output_file": self.filepath, "n_images": self.scaninfo.num_frames} {"output_file": self.filepath, "n_images": self.scaninfo.num_frames}
) )
logger.info("Waiting for std daq to be armed")
while True: while True:
det_ctrl = self.std_client.get_status()["acquisition"]["state"] det_ctrl = self.std_client.get_status()["acquisition"]["state"]
if det_ctrl == "WAITING_IMAGES": if det_ctrl == "WAITING_IMAGES":
@ -240,16 +241,18 @@ class Eiger9mCsaxs(DetectorBase):
def stage(self) -> List[object]: def stage(self) -> List[object]:
"""stage the detector and file writer""" """stage the detector and file writer"""
self.scaninfo.load_scan_metadata() self.scaninfo.load_scan_metadata()
self.mokev = self.device_manager.devices.mokev.read()[ self.mokev = self.device_manager.devices.mokev.obj.read()[
self.device_manager.devices.mokev.name self.device_manager.devices.mokev.name
]["value"] ]["value"]
self._prep_det() self._prep_det()
logger.info("Waiting for std daq to be armed")
self._prep_file_writer() self._prep_file_writer()
logger.info("std_daq is ready")
msg = BECMessage.FileMessage(file_path=self.filepath, done=False) msg = BECMessage.FileMessage(file_path=self.filepath, done=False)
self._producer.set_and_publish( self._producer.set_and_publish(
MessageEndpoints.public_file(self.scaninfo.scanID, "eiger9m"), MessageEndpoints.public_file(self.scaninfo.scanID, self.name),
msg.dumps(), msg.dumps(),
) )
self.arm_acquisition() self.arm_acquisition()
@ -279,13 +282,13 @@ class Eiger9mCsaxs(DetectorBase):
break break
time.sleep(0.005) time.sleep(0.005)
# Message to BEC # Message to BEC
# state = True state = True
# msg = BECMessage.FileMessage(file_path=self.filepath, done=True, successful=state) msg = BECMessage.FileMessage(file_path=self.filepath, done=True, successful=state)
# self._producer.set_and_publish( self._producer.set_and_publish(
# MessageEndpoints.public_file(self.metadata["scanID"], self.name), MessageEndpoints.public_file(self.scaninfo.scanID, self.name),
# msg.dumps(), msg.dumps(),
# ) )
return super().unstage() return super().unstage()
def arm_acquisition(self) -> None: def arm_acquisition(self) -> None:

View File

@ -9,6 +9,9 @@ from ophyd.areadetector.plugins import HDF5Plugin, HDF5Plugin_V21, FilePlugin_V2
from bec_lib.core.file_utils import FileWriterMixin from bec_lib.core.file_utils import FileWriterMixin
from bec_lib.core import MessageEndpoints, BECMessage, RedisConnector from bec_lib.core import MessageEndpoints, BECMessage, RedisConnector
from bec_lib.core import bec_logger from bec_lib.core import bec_logger
from ophyd_devices.epics.devices.bec_scaninfo_mixin import BecScaninfoMixin
from ophyd_devices.utils import bec_utils
logger = bec_logger.logger logger = bec_logger.logger
@ -34,6 +37,10 @@ class EpicsDXPFalcon(Device):
current_pixel = Cpt(EpicsSignalRO, "CurrentPixel") current_pixel = Cpt(EpicsSignalRO, "CurrentPixel")
class FalconError(Exception):
pass
class FalconHDF5Plugins(HDF5Plugin_V21, FilePlugin_V22): class FalconHDF5Plugins(HDF5Plugin_V21, FilePlugin_V22):
pass pass
@ -80,6 +87,7 @@ class FalconCsaxs(Device):
configuration_attrs=None, configuration_attrs=None,
parent=None, parent=None,
device_manager=None, device_manager=None,
sim_mode=False,
**kwargs, **kwargs,
): ):
super().__init__( super().__init__(
@ -91,15 +99,23 @@ class FalconCsaxs(Device):
parent=parent, parent=parent,
**kwargs, **kwargs,
) )
self.device_manager = device_manager if device_manager is None and not sim_mode:
self.name = name raise FalconError("Add DeviceManager to initialization or init with sim_mode=True")
self.username = "e21206"
# TODO once running from BEC
# self.username = self.device_manager.producer.get(MessageEndpoints.account()).decode()
self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.username}/Data10/data/"} self.name = name
self.wait_for_connection() # Make sure to be connected before talking to PVs
if not sim_mode:
self.device_manager = device_manager
self._producer = self.device_manager.producer
else:
self._producer = bec_utils.MockProducer()
self.device_manager = bec_utils.MockDeviceManager()
self.scaninfo = BecScaninfoMixin(device_manager, sim_mode)
# TODO
self.scaninfo.username = "e21206"
self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"}
self.filewriter = FileWriterMixin(self.service_cfg) self.filewriter = FileWriterMixin(self.service_cfg)
self._producer = RedisConnector(["localhost:6379"]).producer()
self.readout = 0.003 # 3 ms self.readout = 0.003 # 3 ms
self._value_pixel_per_buffer = 16 self._value_pixel_per_buffer = 16
# TODO create file template from filewriter compile filename # TODO create file template from filewriter compile filename
@ -218,3 +234,20 @@ class FalconCsaxs(Device):
# TODO raise error # TODO raise error
logger.warning("Returned in unknown state") logger.warning("Returned in unknown state")
return state return state
def stop(self, *, success=False) -> None:
"""Stop acquisition
Stop or Stop and Erase
"""
self._clean_up.set(1)
# self.erase_all.set(1)
self.unstage()
super().stop(success=success)
self._stopped = True
# Automatically connect to test environmenr if directly invoked
if __name__ == "__main__":
falcon = FalconCsaxs(name="falcon", prefix="X12SA-SITORO::", sim_mode=True)
falcon.stage()

View File

@ -154,8 +154,8 @@ class McsCsaxs(SIS38XX):
self.name = name self.name = name
self.wait_for_connection() # Make sure to be connected before talking to PVs self.wait_for_connection() # Make sure to be connected before talking to PVs
if not sim_mode: if not sim_mode:
self._producer = self.device_manager.producer
self.device_manager = device_manager self.device_manager = device_manager
self._producer = self.device_manager.producer
else: else:
self._producer = bec_utils.MockProducer() self._producer = bec_utils.MockProducer()
self.device_manager = bec_utils.MockDeviceManager() self.device_manager = bec_utils.MockDeviceManager()
@ -164,6 +164,7 @@ class McsCsaxs(SIS38XX):
self.scaninfo.username = "e21206" self.scaninfo.username = "e21206"
self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"} self.service_cfg = {"base_path": f"/sls/X12SA/data/{self.scaninfo.username}/Data10/"}
self.filewriter = FileWriterMixin(self.service_cfg) self.filewriter = FileWriterMixin(self.service_cfg)
self._stopped = False
self._init_mcs() self._init_mcs()
def _init_mcs(self) -> None: def _init_mcs(self) -> None:
@ -202,11 +203,12 @@ class McsCsaxs(SIS38XX):
"""Set readout mode of mcs card """Set readout mode of mcs card
Check ReadoutMode class for more information about options Check ReadoutMode class for more information about options
""" """
# self.read_mode.set(ReadoutMode.EVENT)
self.read_mode.set(ReadoutMode.PASSIVE) self.read_mode.set(ReadoutMode.PASSIVE)
def _read_mcs_card(self) -> None: def _read_mcs_card(self) -> None:
# TODO how to properly trigger the readout!!! # TODO how to properly trigger the readout!!!
self.read_all.set(1) self.read_all.put(1, use_complete=False)
def readout_data(self) -> List: def readout_data(self) -> List:
self._read_mcs_card() self._read_mcs_card()
@ -250,8 +252,11 @@ class McsCsaxs(SIS38XX):
det_ctrl = self.acquiring.read()[self.acquiring.name]["value"] det_ctrl = self.acquiring.read()[self.acquiring.name]["value"]
if det_ctrl == 0: if det_ctrl == 0:
break break
if self._stopped:
break
time.sleep(0.005) time.sleep(0.005)
self._read_mcs_card() if not self._stopped:
self._read_mcs_card()
# Message to BEC # Message to BEC
# state = True # state = True
@ -260,6 +265,7 @@ class McsCsaxs(SIS38XX):
# MessageEndpoints.public_file(self.metadata["scanID"], self.name), # MessageEndpoints.public_file(self.metadata["scanID"], self.name),
# msg.dumps(), # msg.dumps(),
# ) # )
self._stopped = False
return super().unstage() return super().unstage()
def arm_acquisition(self) -> None: def arm_acquisition(self) -> None:
@ -277,7 +283,7 @@ class McsCsaxs(SIS38XX):
""" """
self.stop_all.set(1) self.stop_all.set(1)
# self.erase_all.set(1) # self.erase_all.set(1)
self.unstage() # self.unstage()
super().stop(success=success) super().stop(success=success)
self._stopped = True self._stopped = True

View File

@ -248,3 +248,9 @@ class PilatusCsaxs(DetectorBase):
self.unstage() self.unstage()
super().stop(success=success) super().stop(success=success)
self._stopped = True self._stopped = True
# Automatically connect to test environmenr if directly invoked
if __name__ == "__main__":
pilatus_2 = PilatusCsaxs(name="pilatus_2", prefix="X12SA-ES-PILATUS300K:", sim_mode=True)
pilatus_2.stage()

View File

@ -181,7 +181,7 @@ class MonoTheta2(VirtualEpicsSignalRO):
MONO_THETA2_OFFSETS_FILENAME = ( MONO_THETA2_OFFSETS_FILENAME = (
"/import/work/sls/spec/local/X12SA/macros/spec_data/mono_th2_offsets.txt" "/sls/X12SA/data/gac-x12saop/spec/macros/spec_data/mono_th2_offsets.txt"
) )

View File

@ -247,6 +247,7 @@ class GalilController(Controller):
interval_x: int, interval_x: int,
exp_time: float, exp_time: float,
readtime: float, readtime: float,
**kwargs,
) -> tuple: ) -> tuple:
"""_summary_ """_summary_
@ -266,9 +267,8 @@ class GalilController(Controller):
LimitError: Raised if the speed is above 2mm/s or below 0.02mm/s LimitError: Raised if the speed is above 2mm/s or below 0.02mm/s
""" """
#
# time.sleep(0.2) axes_referenced = self.controller.axis_is_referenced()
# Check limits # Check limits
# TODO check sign of stage, or not necessary # TODO check sign of stage, or not necessary
check_values = [start_y, end_y, start_x, end_x] check_values = [start_y, end_y, start_x, end_x]

View File

@ -16,9 +16,15 @@ class MockDeviceManager:
self.devices = devices() self.devices = devices()
class OphydObject:
def __init__(self) -> None:
self.name = "mock_mokev"
self.obj = mokev()
class devices: class devices:
def __init__(self): def __init__(self):
self.mokev = mokev() self.mokev = OphydObject()
class mokev: class mokev:
@ -26,4 +32,4 @@ class mokev:
self.name = "mock_mokev" self.name = "mock_mokev"
def read(self): def read(self):
return {self.name: {"value": 12.4, "timestamp": time.time()}} return {self.name: {"value": 16.0, "timestamp": time.time()}}