GUI/DAQ: Integrate sample mounting logic and improve file path management

- Added `SampleMountLogic` for handling sample-related updates.
- Extended file path handling with additional macros (`{sample}`, `{sample_id}`, `{prefix}`).
- Updated `beam size` limits in GUI.
- Modified DAQ flux computation using BPM values.
- Enhanced `SampleShortInfo` model with `aaredb_params`.
This commit is contained in:
2025-06-24 16:31:46 +02:00
parent d0c777decd
commit 7e0a006668
10 changed files with 83 additions and 34 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ dependencies = [
"pydantic==2.11.4",
"numpy==2.2.5",
"jfjoch_client==1.0.0rc51",
"aareDB==0.1.1a8"
"aareDB==0.1.1a9"
]
[lint]
+2
View File
@@ -1,6 +1,7 @@
from enum import Enum
from typing import Annotated, Literal, Tuple, List, Optional
from aareDBclient.models.data_collection_parameters import DataCollectionParameters
from pydantic import BaseModel, Field
from aaredaqlib.coordinate import Coordinate
@@ -44,6 +45,7 @@ class SampleShortInfo(BaseModel):
puck_name: str
dewar_name: str
sample_name: str
aaredb_params: Optional[DataCollectionParameters] = None
user: str = ""
pin: Annotated[int, Field(ge=1, le=16)]
location: DewarAddress | None = None
+2 -1
View File
@@ -92,7 +92,8 @@ class AareWrapper:
location=dewar_address,
priority=1.0 if s.priority is None else s.priority,
comment=s.comments,
mount_count=s.mount_count or 0
mount_count=s.mount_count or 0,
aaredb_params=s.data_collection_parameters
)
)
return SampleShortInfoList(s=ret)
+1 -1
View File
@@ -795,7 +795,7 @@ class AareDAQ:
light=self.light,
cryojet_K=self.__devs.cryojet_temp,
shutter_open=self.__devs.shutter,
flux_ph_s=3.0e12,
flux_ph_s=self.__devs.flux,
sample_camera=self.__devs.samcam_settings,
name=self.__bl,
transmission=self.__devs.transmission.get(),
+8
View File
@@ -48,6 +48,8 @@ class BeamlineDevices:
self.__collimator = PV(f"{BEAMLINE}-ES-COL:TRY1")
self.__bpm = PV(f"{BEAMLINE}-OP-XBPM1:SumAll:MeanValue_RBV")
self.aerotech = aerotech.Abr(beamline)
self.aerotech.reload_programs()
@@ -263,3 +265,9 @@ class BeamlineDevices:
def samcam_settings(self, settings: SampleCameraSettings):
print(settings)
self.sample_cam.setup(settings.gain, settings.exposure)
@property
def flux(self) -> float:
# Very approximate value - to be changed
# 2 nA -> 4e11 ph/s
return self.__bpm.value / 2.0 * 4e11
+21 -14
View File
@@ -21,6 +21,7 @@ from aaregui.panels.data_collection_settings import DataCollectionSettings
from aaregui.panels.sample_queue_panel import SampleQueuePanel
from aaregui.panels.tell_sample_panel import TellSamplePanel
from aaregui.scan_logic.raster_grid_manager import RasterGridManager
from aaregui.scan_logic.sample_mount_logic import SampleMountLogic
from aaregui.threads.camera_thread import SampleCameraThread
from aaregui.threads.daq_worker import DAQWorker
from aaregui.threads.jfjoch_viewer import JFJochDBusClient
@@ -111,6 +112,8 @@ class MainWindow(QMainWindow):
self.tell_samples_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea)
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.tell_samples_dock)
self.sample_logic = SampleMountLogic()
self.job_list_dock = QDockWidget("Automation list", self)
self.job_list_dock.setWidget(self.job_list_panel)
self.job_list_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea)
@@ -126,20 +129,6 @@ class MainWindow(QMainWindow):
self.daq = DAQWorker(base_url=self.__base_url, token=self.__token)
self.daq.spreadsheet.connect(self.tell_samples.new_sample_list)
self.daq.update.connect(self.beamline.omega_panel.update_daq_status)
self.daq.update.connect(self.beamline.smargon_panel.update_daq_status)
self.daq.update.connect(self.beamline.beam_size.update_daq_status)
self.daq.update.connect(self.beamline.beam_center.update_daq_status)
self.daq.update.connect(self.data_collection.update_daq_status)
self.daq.update.connect(self.beamline.illumination_panel.update_daq_status)
self.daq.update.connect(self.raster.update_daq_status)
self.daq.update.connect(self.camera_image.update_daq_status)
self.daq.update.connect(self.tell_samples.update_daq_status)
self.daq.update.connect(self.beamline.abr_tweak.update_daq_status)
self.daq.update.connect(self.status_bar.update_daq_status)
self.daq.update.connect(self.beamline.samcam.update_daq_status)
self.daq.update.connect(self.beamline.zoom_panel.update_daq_status)
self.daq.update.connect(self.beamline.beam_mark.update_daq_status)
self.daq.raster_scan_completed.connect(self.raster.grid_scan_completed)
@@ -218,6 +207,24 @@ class MainWindow(QMainWindow):
self.raster.file_ready.connect(self.viewer.load_file)
self.raster.image_selected.connect(self.viewer.load_image)
self.sample_logic.sample_changed.connect(self.data_collection.file_path_panel.update_sample)
self.daq.update.connect(self.beamline.omega_panel.update_daq_status)
self.daq.update.connect(self.beamline.smargon_panel.update_daq_status)
self.daq.update.connect(self.beamline.beam_size.update_daq_status)
self.daq.update.connect(self.beamline.beam_center.update_daq_status)
self.daq.update.connect(self.data_collection.update_daq_status)
self.daq.update.connect(self.beamline.illumination_panel.update_daq_status)
self.daq.update.connect(self.raster.update_daq_status)
self.daq.update.connect(self.camera_image.update_daq_status)
self.daq.update.connect(self.tell_samples.update_daq_status)
self.daq.update.connect(self.beamline.abr_tweak.update_daq_status)
self.daq.update.connect(self.status_bar.update_daq_status)
self.daq.update.connect(self.beamline.samcam.update_daq_status)
self.daq.update.connect(self.beamline.zoom_panel.update_daq_status)
self.daq.update.connect(self.beamline.beam_mark.update_daq_status)
self.daq.update.connect(self.sample_logic.update_daq_status)
def create_menu_bar(self):
"""Create a menu bar with File->Quit and Help->About."""
# Main menu bar
+2 -2
View File
@@ -16,10 +16,10 @@ class BeamSizeWidget(QWidget):
grid_layout.addWidget(TitleLabel("Beam size", self), 0, 0, 1, 5)
self.x = NumberLineEdit(1, 40.0, 10, parent=self)
self.x = NumberLineEdit(1, 400.0, 10, parent=self)
self.x.newValue.connect(self.beam_size_edited)
self.y = NumberLineEdit(1, 40.0, 10, parent=self)
self.y = NumberLineEdit(1, 400.0, 10, parent=self)
self.y.newValue.connect(self.beam_size_edited)
grid_layout.addWidget(QLabel("x:"), 1, 0)
@@ -69,4 +69,3 @@ class DataCollectionSettings(QFrame):
def update_daq_status(self, s: DAQStatusModel):
self.raster.update_daq_status(s)
self.screening.update_daq_status(s)
self.file_path_panel.update_daq_status(s)
+28 -14
View File
@@ -4,7 +4,7 @@ from datetime import datetime
from PySide6.QtCore import Signal, Slot, Qt
from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QLineEdit, QSpinBox, QCheckBox
from aaredaqlib.models import DAQStatusModel
from aaredaqlib.models import SampleShortInfo
from aaregui.widgets.title_label import TitleLabel
@@ -34,12 +34,25 @@ class FilePathPanel(QWidget):
grid_layout.addWidget(QLabel("Directory", parent=self), 2, 0)
self.directory_edit = QLineEdit("{date}/{puck}/{pos}", parent=self)
self.directory_edit.setStyleSheet("background-color: rgb(255, 255, 255);")
self.directory_edit.setToolTip("Provide subdirectory for your files, you can use \"{date}\" as macro for date.")
self.directory_edit.setToolTip("Provide subdirectory for your files. The following macros are allowed: <br/>"
"<b>{date}</b> - date in format yyyymmdd <br/>"
"<b>{puck}</b> - puck name <br/>"
"<b>{pos}</b> - pin position in puck <br/>"
"<b>{sample}</b> - sample name <br/>"
"<b>{sample_id}</b> - sample id <br/>"
"<b>{prefix}</b> - file prefix value")
grid_layout.addWidget(self.directory_edit, 2, 1)
grid_layout.addWidget(QLabel("File prefix", parent=self), 3, 0)
self.file_prefix_edit = QLineEdit("{sample}", parent=self)
self.file_prefix_edit.setStyleSheet("background-color: rgb(255, 255, 255);")
self.file_prefix_edit.setToolTip("Provide file prefix for your files. The following macros are allowed: <br/>"
"<b>{date}</b> - date in format yyyymmdd <br/>"
"<b>{puck}</b> - puck name <br/>"
"<b>{pos}</b> - pin position in puck <br/>"
"<b>{sample}</b> - sample name <br/>"
"<b>{sample_id}</b> - sample id")
grid_layout.addWidget(self.file_prefix_edit, 3, 1)
grid_layout.addWidget(QLabel("Run number", parent=self), 4, 0)
@@ -72,6 +85,8 @@ class FilePathPanel(QWidget):
file_prefix = self.file_prefix_edit.text()
run_number = self.run_number_edit.value()
dir_name = dir_name.replace('{prefix}', file_prefix)
if dir_name == "":
self.__filename = ""
elif dir_name[-1] == "/":
@@ -120,22 +135,21 @@ class FilePathPanel(QWidget):
def filename(self) -> str:
return self.__filename
@Slot(DAQStatusModel)
def update_daq_status(self, status: DAQStatusModel):
if status.sample is None:
@Slot(SampleShortInfo)
def update_sample(self, sample: SampleShortInfo):
if sample is None:
self.__sample_id = -1
self.__sample_name = "sample"
self.__dewar_pos = "None"
self.__puck_name = "Manual"
self.__puck_pos = 99
else:
self.__sample_name = status.sample.sample_name
self.__dewar_pos = status.sample.loc_str()
self.__puck_name = status.sample.puck_name
self.__puck_pos = status.sample.pin
self.update_filename()
self.__sample_name = sample.sample_name
self.__dewar_pos = sample.loc_str()
self.__puck_name = sample.puck_name
self.__puck_pos = sample.pin
self.run_number_edit.setValue(1)
if sample.aaredb_params is not None and sample.aaredb_params.directory is not None:
self.directory_edit.setText(sample.aaredb_params.directory)
sample_id_old = self.__sample_id
self.__sample_id = status.sample.db_id
if self.__sample_id != sample_id_old:
self.run_number_edit.setValue(1)
self.update_filename()
@@ -0,0 +1,18 @@
from PySide6.QtCore import QObject, Slot, Signal
from aaredaqlib.models import DAQStatusModel, SampleShortInfo
class SampleMountLogic(QObject):
sample_changed = Signal(SampleShortInfo)
def __init__(self, parent=None):
super().__init__(parent)
self.__sample = None
@Slot(DAQStatusModel)
def update_daq_status(self, s: DAQStatusModel):
if s.sample != self.__sample:
self.sample_changed.emit(s.sample)
self.__sample = s.sample