mirror of
https://github.com/ivan-usov-org/bec.git
synced 2025-04-22 02:20:02 +02:00
To have a better separation of concern between messages and how they are conveyed in connectors. BECMessage can be simple dataclasses, leaving the serialization to the connector which transport those. The serialization module itself can be isolated, and in the case of msgpack it can be extended to understand how to encode/decode BECMessage, to simplify writing code like with BundleMessage or to be able to automatically encode numpy or BECStatus objects. Finally, client objects (producers and consumers) can receive BECMessage objects instead of having to dump or load themselves.
223 lines
9.0 KiB
Python
223 lines
9.0 KiB
Python
"""
|
|
SCAN PLUGINS
|
|
|
|
All new scans should be derived from ScanBase. ScanBase provides various methods that can be customized and overriden
|
|
but they are executed in a specific order:
|
|
|
|
- self.initialize # initialize the class if needed
|
|
- self.read_scan_motors # used to retrieve the start position (and the relative position shift if needed)
|
|
- self.prepare_positions # prepare the positions for the scan. The preparation is split into multiple sub fuctions:
|
|
- self._calculate_positions # calculate the positions
|
|
- self._set_positions_offset # apply the previously retrieved scan position shift (if needed)
|
|
- self._check_limits # tests to ensure the limits won't be reached
|
|
- self.open_scan # send an open_scan message including the scan name, the number of points and the scan motor names
|
|
- self.stage # stage all devices for the upcoming acquisiton
|
|
- self.run_baseline_readings # read all devices to get a baseline for the upcoming scan
|
|
- self.scan_core # run a loop over all position
|
|
- self._at_each_point(ind, pos) # called at each position with the current index and the target positions as arguments
|
|
- self.finalize # clean up the scan, e.g. move back to the start position; wait everything to finish
|
|
- self.unstage # unstage all devices that have been staged before
|
|
- self.cleanup # send a close scan message and perform additional cleanups if needed
|
|
"""
|
|
|
|
import time
|
|
from bec_lib import messages
|
|
|
|
from bec_lib import MessageEndpoints, bec_logger
|
|
from scan_server.scans import FlyScanBase
|
|
|
|
logger = bec_logger.logger
|
|
|
|
|
|
class SgalilGrid(FlyScanBase):
|
|
scan_name = "sgalil_grid"
|
|
scan_report_hint = "scan_progress"
|
|
required_kwargs = []
|
|
arg_input = {}
|
|
arg_bundle_size = {"bundle": len(arg_input), "min": None, "max": None}
|
|
enforce_sync = False
|
|
|
|
def __init__(
|
|
self,
|
|
start_y: float,
|
|
end_y: float,
|
|
interval_y: int,
|
|
start_x: float,
|
|
end_x: float,
|
|
interval_x: int,
|
|
*args,
|
|
exp_time: float = 0.1,
|
|
readout_time: float = 0.1,
|
|
**kwargs,
|
|
):
|
|
"""
|
|
SGalil-based grid scan.
|
|
|
|
Args:
|
|
start_y (float): start position of y axis (fast axis)
|
|
end_y (float): end position of y axis (fast axis)
|
|
interval_y (int): number of points in y axis
|
|
start_x (float): start position of x axis (slow axis)
|
|
end_x (float): end position of x axis (slow axis)
|
|
interval_x (int): number of points in x axis
|
|
exp_time (float): exposure time in seconds. Default is 0.1s
|
|
readout_time (float): readout time in seconds, minimum of 3e-3s (3ms)
|
|
|
|
Exp:
|
|
scans.sgalil_grid(start_y = val1, end_y= val1, interval_y = val1, start_x = val1, end_x = val1, interval_x = val1, exp_time = 0.02, readout_time = 3e-3)
|
|
|
|
|
|
"""
|
|
super().__init__(*args, **kwargs)
|
|
# Always scan from positive x & y to negative x & y
|
|
if start_y > end_y:
|
|
self.start_y = start_y
|
|
self.end_y = end_y
|
|
else:
|
|
self.start_y = end_y
|
|
self.end_y = start_y
|
|
if start_x > end_x:
|
|
self.start_x = start_x
|
|
self.end_x = end_x
|
|
else:
|
|
self.start_x = end_x
|
|
self.end_x = start_x
|
|
self.interval_y = interval_y
|
|
self.interval_x = interval_x
|
|
self.exp_time = exp_time
|
|
self.readout_time = readout_time
|
|
self.num_pos = int(interval_x * interval_y)
|
|
self.scan_motors = ["samx", "samy"]
|
|
# Scan progress related variables
|
|
self.timeout_progress = 0
|
|
self.progress_point = 0
|
|
self.timeout_scan_abortion = 10 # 42 # duty cycles of scan segment update
|
|
self.sleep_time = 1
|
|
|
|
def scan_report_instructions(self):
|
|
if not self.scan_report_hint:
|
|
yield None
|
|
return
|
|
yield from self.stubs.scan_report_instruction({"scan_progress": ["mcs"]})
|
|
|
|
def pre_scan(self):
|
|
yield from self._move_and_wait([self.start_x, self.start_y])
|
|
yield from self.stubs.pre_scan()
|
|
# TODO move to start position
|
|
|
|
def scan_progress(self) -> int:
|
|
"""Timeout of the progress bar. This gets updated in the frequency of scan segments"""
|
|
msg = self.device_manager.producer.get(MessageEndpoints.device_progress("mcs"))
|
|
if not msg:
|
|
self.timeout_progress += 1
|
|
return self.timeout_progress
|
|
# TODO which update is that!
|
|
updated_progress = int(msg.content["value"])
|
|
if updated_progress == int(self.progress_point):
|
|
self.timeout_progress += 1
|
|
return self.timeout_progress
|
|
else:
|
|
self.timeout_progress = 0
|
|
self.progress_point = updated_progress
|
|
return self.timeout_progress
|
|
|
|
def scan_core(self):
|
|
"""
|
|
This is the main event loop.
|
|
"""
|
|
|
|
# set up the delay generators
|
|
status_ddg_detectors_burst = yield from self.stubs.send_rpc_and_wait(
|
|
"ddg_detectors",
|
|
"burst_enable",
|
|
count=self.interval_y,
|
|
delay=0,
|
|
period=(self.exp_time + self.readout_time),
|
|
config="first",
|
|
)
|
|
status_ddg_mcs_burst = yield from self.stubs.send_rpc_and_wait(
|
|
"ddg_mcs",
|
|
"burst_enable",
|
|
count=self.interval_y,
|
|
delay=0,
|
|
period=(self.exp_time + self.readout_time),
|
|
config="first",
|
|
)
|
|
# Disable burst mod on DDF for fsh and EN of MCS card
|
|
status_ddg_fsh_burst = yield from self.stubs.send_rpc_and_wait("ddg_fsh", "burst_disable")
|
|
# Set width of FSH opening to 0
|
|
status_ddg_fsh_ttlwidth = yield from self.stubs.send_rpc_and_wait(
|
|
"ddg_fsh",
|
|
"set_channels",
|
|
"width",
|
|
0,
|
|
channels=["channelCD"],
|
|
)
|
|
|
|
# TODO disable fsh ddg bc SGalil trigger it directly
|
|
# Setup triggering
|
|
status_ddg_detectors_source = yield from self.stubs.send_rpc_and_wait(
|
|
"ddg_detectors", "source.set", 2
|
|
)
|
|
status_ddg_mcs_source = yield from self.stubs.send_rpc_and_wait("ddg_mcs", "source.set", 1)
|
|
# Setup mcs_points per line
|
|
# status_mcs_points_per_line = yield from self.stubs.send_rpc_and_wait(
|
|
# "mcs", "num_use_all.set", self.interval_y + 1
|
|
# )
|
|
# status_mcs_lines = yield from self.stubs.send_rpc_and_wait(
|
|
# "mcs", "num_lines.set", self.interval_x
|
|
# )
|
|
|
|
# status_ddg_mcs_ttlwidth = yield from self.stubs.send_rpc_and_wait(
|
|
# "ddg_mcs", "set_channels", "width", 3e-3
|
|
# )
|
|
status_ddg_mcs_ttldelay = yield from self.stubs.send_rpc_and_wait(
|
|
"ddg_mcs", "set_channels", "delay", 0
|
|
)
|
|
|
|
# wait for the delay generators to finish setting up
|
|
status_ddg_detectors_source.wait()
|
|
status_ddg_mcs_source.wait()
|
|
trigger_ddg_fsh = yield from self.stubs.send_rpc_and_wait("ddg_fsh", "trigger")
|
|
# trigger_ddg_fsh.wait()
|
|
# status_mcs_points_per_line.wait()
|
|
# status_mcs_lines.wait()
|
|
|
|
yield from self.stubs.kickoff(
|
|
device="samx",
|
|
parameter={
|
|
"start_y": self.start_y,
|
|
"end_y": self.end_y,
|
|
"interval_y": self.interval_y,
|
|
"start_x": self.start_x,
|
|
"end_x": self.end_x,
|
|
"interval_x": self.interval_x,
|
|
"exp_time": self.exp_time,
|
|
"readout_time": self.readout_time,
|
|
},
|
|
)
|
|
target_diid = self.DIID - 1
|
|
while True:
|
|
# readout the primary device and wait for the fly scan to finish
|
|
yield from self.stubs.read_and_wait(
|
|
group="primary", wait_group="readout_primary", pointID=self.pointID
|
|
)
|
|
self.pointID += 1
|
|
status = self.stubs.get_req_status(
|
|
device="samx", RID=self.metadata["RID"], DIID=target_diid
|
|
)
|
|
if status:
|
|
break
|
|
time.sleep(self.sleep_time)
|
|
if self.scan_progress() > int(self.timeout_scan_abortion / self.sleep_time):
|
|
logger.info(f"would have raised a scan abortion here")
|
|
# raise ScanAbortion()
|
|
|
|
# try:
|
|
# logger.info(f'Scan progress check {self.scan_progress()} and {int(self.timeout_scan_abortion/self.sleep_time)}')
|
|
# logger.info(f'Potential scan abortion {self.scan_progress() > int(self.timeout_scan_abortion/self.sleep_time)}')
|
|
# if self.scan_progress() > int(self.timeout_scan_abortion/self.sleep_time):
|
|
# logger.info('Testing Scan abortion, would have raised here!')
|
|
# except Exception as exc:
|
|
# logger.info(f'{exc}')
|