wip changes from the beamline
Some checks failed
CI for csaxs_bec / test (push) Failing after 1m8s
CI for csaxs_bec / test (pull_request) Failing after 1m15s

This commit is contained in:
x01dc
2025-11-28 17:27:48 +01:00
parent 28da69a38c
commit 5d87b03018
4 changed files with 87 additions and 43 deletions

View File

@@ -156,7 +156,7 @@ class flomniGuiTools:
)
self.progressbar.set_value([progress, subtomo_progress, 0])
if self.text_box is not None:
text = f"Progress report:\n Tomo type: ....................... {self.progress['tomo_type']}\n Projection: ...................... {self.progress['projection']:.0f}\n Total projections expected ....... {self.progress['total_projections']}\n Angle: ........................... {self.progress['angle']}\n Current subtomo: ................. {self.progress['subtomo']}\n Current projection within subtomo: {self.progress['subtomo_projection']}\n Total projections per subtomo: ... {self.progress['subtomo_total_projections']}"
text = f"Progress report:\n Tomo type: ....................... {self.progress['tomo_type']}\n Projection: ...................... {self.progress['projection']:.0f}\n Total projections expected ....... {self.progress['total_projections']}\n Angle: ........................... {self.progress['angle']}\n Current subtomo: ................. {self.progress['subtomo']}\n Current projection within subtomo: {self.progress['subtomo_projection']}\n Total projections per subtomo: ... {self.progress['subtomo_total_projections']}"
self.text_box.set_plain_text(text)

View File

@@ -365,6 +365,18 @@ rtz:
readOnly: false
readoutPriority: on_request
rt_flyer:
description: flomni rt flyer
deviceClass: csaxs_bec.devices.omny.rt.rt_flomni_ophyd.RtFlomniFlyer
deviceConfig:
host: mpc2844.psi.ch
port: 2222
enabled: true
onFailure: buffer
readOnly: false
readoutPriority: async
############################################################
####################### Cameras ############################
############################################################

View File

@@ -10,7 +10,7 @@ from ophyd import Component as Cpt
from ophyd import Device, DeviceStatus, PositionerBase, Signal
from ophyd.status import wait as status_wait
from ophyd.utils import LimitError
from ophyd_devices.utils.bec_signals import AsyncSignal
from ophyd_devices.utils.bec_signals import AsyncMultiSignal, ProgressSignal
from ophyd_devices.utils.controller import Controller, threadlocked
from ophyd_devices.utils.socket import SocketIO, raise_if_disconnected
from prettytable import PrettyTable
@@ -741,7 +741,26 @@ class RtFlomniMotor(Device, PositionerBase):
class RtFlomniFlyer(Device):
USER_ACCESS = ["controller"]
data = Cpt(AsyncSignal, "data", ndim=1, async_update={"type": "add", "max_shape": [None]})
data = Cpt(
AsyncMultiSignal,
name="data",
signals=[
"target_x",
"average_x_st_fzp",
"stdev_x_st_fzp",
"target_y",
"average_y_st_fzp",
"stdev_y_st_fzp",
"average_rotz",
"stdev_rotz",
"average_stdeviations_x_st_fzp",
"average_stdeviations_y_st_fzp",
],
ndim=0,
max_size=10000,
async_update={"type": "add", "max_shape": [None]},
)
progress = Cpt(ProgressSignal, name="progress")
def __init__(
self,
@@ -765,15 +784,11 @@ class RtFlomniFlyer(Device):
read_attrs=read_attrs,
configuration_attrs=configuration_attrs,
parent=parent,
host=host,
port=port,
socket_cls=socket_cls,
device_manager=device_manager,
**kwargs,
)
self.shutdown_event = threading.Event()
self.controller = RtFlomniController(
socket_cls=socket_cls, socket_host=host, socket_port=port
socket_cls=socket_cls, socket_host=host, socket_port=port, device_manager=device_manager
)
self.average_stdeviations_x_st_fzp = 0
self.average_stdeviations_y_st_fzp = 0
@@ -805,11 +820,20 @@ class RtFlomniFlyer(Device):
)
if current_position_in_scan > 5:
while current_position_in_scan > read_counter + 1:
return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",")
return_table = (
self.controller.socket_put_and_receive(f"r{read_counter}")
).split(",")
logger.info(f"Read {read_counter} out of {number_of_positions_planned}")
read_counter = read_counter + 1
signals = self._get_signals_from_table(return_table)
self.data.set(signals)
self.progress.put(
value=read_counter,
max_value=number_of_positions_planned,
done=(number_of_positions_planned == read_counter),
)
logger.info(f"Updating progress: {read_counter} / {number_of_positions_planned}")
if self.shutdown_event.wait(0.05):
logger.info("Shutdown event set, stopping readout.")
@@ -819,57 +843,65 @@ class RtFlomniFlyer(Device):
# read the last samples even though scan is finished already
while number_of_positions_planned > read_counter and not self.shutdown_event.is_set():
return_table = (self.socket_put_and_receive(f"r{read_counter}")).split(",")
return_table = (self.controller.socket_put_and_receive(f"r{read_counter}")).split(",")
logger.info(f"Read {read_counter} out of {number_of_positions_planned}")
read_counter = read_counter + 1
signals = self._get_signals_from_table(return_table)
logger.info(f"Setting data: {signals}")
self.data.set(signals)
self.progress.put(
value=read_counter,
max_value=number_of_positions_planned,
done=(number_of_positions_planned == read_counter),
)
logger.info(f"Updating progress: {read_counter} / {number_of_positions_planned}")
# NOTE: No need to set the status to failed if the shutdown_event is set.
# The stop() method will take care of that.
status.set_finished()
logger.info(
"Flomni statistics: Average of all standard deviations: x"
f" {self.average_stdeviations_x_st_fzp/read_counter*1000:.1f}, y"
f" {self.average_stdeviations_y_st_fzp/read_counter*1000:.1f}"
)
if read_counter != 0:
logger.info(
"Flomni statistics: Average of all standard deviations: x"
f" {self.average_stdeviations_x_st_fzp/read_counter*1000:.1f}, y"
f" {self.average_stdeviations_y_st_fzp/read_counter*1000:.1f}"
)
def _get_signals_from_table(self, return_table) -> dict:
self.average_stdeviations_x_st_fzp += float(return_table[4])
self.average_stdeviations_y_st_fzp += float(return_table[7])
signals = {
"target_x": {"value": float(return_table[2])},
"average_x_st_fzp": {"value": float(return_table[3])},
"stdev_x_st_fzp": {"value": float(return_table[4])},
"target_y": {"value": float(return_table[5])},
"average_y_st_fzp": {"value": float(return_table[6])},
"stdev_y_st_fzp": {"value": float(return_table[7])},
"average_rotz": {"value": float(return_table[8])},
"stdev_rotz": {"value": float(return_table[9])},
"average_stdeviations_x_st_fzp": {
f"{self.name}_data_target_x": {"value": float(return_table[2])},
f"{self.name}_data_average_x_st_fzp": {"value": float(return_table[3])},
f"{self.name}_data_stdev_x_st_fzp": {"value": float(return_table[4])},
f"{self.name}_data_target_y": {"value": float(return_table[5])},
f"{self.name}_data_average_y_st_fzp": {"value": float(return_table[6])},
f"{self.name}_data_stdev_y_st_fzp": {"value": float(return_table[7])},
f"{self.name}_data_average_rotz": {"value": float(return_table[8])},
f"{self.name}_data_stdev_rotz": {"value": float(return_table[9])},
f"{self.name}_data_average_stdeviations_x_st_fzp": {
"value": self.average_stdeviations_x_st_fzp / (int(return_table[0]) + 1)
},
"average_stdeviations_y_st_fzp": {
f"{self.name}_data_average_stdeviations_y_st_fzp": {
"value": self.average_stdeviations_y_st_fzp / (int(return_table[0]) + 1)
},
}
return signals
def start_readout(self, status: DeviceStatus):
logger.info("Starting readout thread.")
readout = threading.Thread(target=self.read_positions_from_sampler, args=(status,))
readout.start()
def kickoff(self):
def kickoff(self) -> DeviceStatus:
self.shutdown_event.clear()
while not self._min_scan_buffer_reached and not self.shutdown_event.wait(0.001):
while not self.controller._min_scan_buffer_reached and not self.shutdown_event.wait(0.001):
...
self.start_scan()
self.controller.start_scan()
self.shutdown_event.wait(0.1)
def complete(self) -> DeviceStatus:
"""Wait until the flyer is done."""
status = DeviceStatus(self)
self.start_readout(status)
return status

View File

@@ -26,12 +26,12 @@ import numpy as np
from bec_lib import bec_logger, messages
from bec_lib.endpoints import MessageEndpoints
from bec_server.scan_server.errors import ScanAbortion
from bec_server.scan_server.scans import SyncFlyScanBase
from bec_server.scan_server.scans import AsyncFlyScanBase
logger = bec_logger.logger
class FlomniFermatScan(SyncFlyScanBase):
class FlomniFermatScan(AsyncFlyScanBase):
scan_name = "flomni_fermat_scan"
scan_type = "fly"
required_kwargs = ["fovx", "fovy", "exp_time", "step", "angle"]
@@ -97,6 +97,7 @@ class FlomniFermatScan(SyncFlyScanBase):
logger.warning("The zshift is smaller than -100 um. It will be limited to -100 um.")
self.zshift = -100
self.flomni_rotation_status = None
self.flyer_num_pos = 0
def initialize(self):
self.scan_motors = []
@@ -107,10 +108,6 @@ class FlomniFermatScan(SyncFlyScanBase):
self.positions, corridor_size=self.optim_trajectory_corridor
)
@property
def monitor_sync(self):
return "rt_flomni"
def reverse_trajectory(self):
"""
Reverse the trajectory. Every other scan should be reversed to
@@ -135,13 +132,13 @@ class FlomniFermatScan(SyncFlyScanBase):
if flip_axes:
self.positions = np.flipud(self.positions)
self.num_pos = len(self.positions)
self.flyer_num_pos = len(self.positions)
self._check_min_positions()
def _check_min_positions(self):
if self.num_pos < 20:
if self.flyer_num_pos < 20:
raise ScanAbortion(
f"The number of positions must exceed 20. Currently: {self.num_pos}."
f"The number of positions must exceed 20. Currently: {self.flyer_num_pos}."
)
def _prepare_setup(self):
@@ -150,6 +147,8 @@ class FlomniFermatScan(SyncFlyScanBase):
yield from self.stubs.send_rpc_and_wait("rty", "set", self.positions[0][1])
yield from self.stubs.scan_report_instruction({"device_progress": ["rt_flyer"]})
def _prepare_setup_part2(self):
if self.flomni_rotation_status:
self.flomni_rotation_status.wait()
@@ -280,12 +279,13 @@ class FlomniFermatScan(SyncFlyScanBase):
return np.array(positions)
def scan_core(self):
yield from self.stubs.kickoff(device="rt_flyer")
status = yield from self.stubs.complete(device="rt_flyer", wait=False)
status = yield from self.stubs.kickoff(device="rt_flyer", wait=False)
while not status.done:
yield from self.stubs.read(group="monitored")
yield from self.stubs.read(group="monitored", point_id=self.point_id)
time.sleep(1)
self.point_id += 1
logger.debug("reading monitors")
self.num_pos = self.point_id
def move_to_start(self):
"""return to the start position"""