diff --git a/daq/src/aaredaq/daq.py b/daq/src/aaredaq/daq.py
index 90cd6246..b00a2013 100644
--- a/daq/src/aaredaq/daq.py
+++ b/daq/src/aaredaq/daq.py
@@ -177,6 +177,11 @@ class AareDAQ:
raise
def create_sample(self, target: SampleShortInfo):
+ curr_sample = self.__cfg.current_sample
+
+ if curr_sample is not None and curr_sample.location is not None:
+ raise Exception("Sample from TELL is loaded")
+
self.__aare.create_manual_sample(target)
self.__cfg.current_sample = target
@@ -839,3 +844,10 @@ class AareDAQ:
if self.__cfg.state == BeamlineStateEnum.DataCollection:
self.__devs.aerotech.stop()
self.__jfjoch.cancel()
+
+ def anneal(self, time_s: float):
+ self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment)
+ try:
+ self.__devs.anneal(time_s)
+ finally:
+ self.__cfg.state_busy = False
diff --git a/daq/src/aaredaq/devices.py b/daq/src/aaredaq/devices.py
index 34091480..9b1717f6 100644
--- a/daq/src/aaredaq/devices.py
+++ b/daq/src/aaredaq/devices.py
@@ -1,3 +1,5 @@
+import time
+
from epics import PV
from aaredaqlib.beamline import MXBeamline
@@ -47,6 +49,7 @@ class BeamlineDevices:
self.bsy = MyMotor(f"{BEAMLINE}-ES-BS:TRY1")
self.__bpm = PV(f"{BEAMLINE}-OP-XBPM1:SumAll:MeanValue_RBV")
+ self.__anneal = PV(f"{BEAMLINE}-ES-ANN:SET_POS")
self.aerotech = aerotech.Abr(beamline)
@@ -339,4 +342,9 @@ class BeamlineDevices:
# 2 nA -> 4e11 ph/s
if self.transmission.get() is None:
return 0.0
- return self.transmission.get() * self.__bpm.value / 2.0 * 4e11
\ No newline at end of file
+ return self.transmission.get() * self.__bpm.value / 2.0 * 4e11
+
+ def anneal(self, value: float):
+ self.__anneal.put(1)
+ time.sleep(value)
+ self.__anneal.put(0)
diff --git a/daq/src/aaredaq/server.py b/daq/src/aaredaq/server.py
index ecc176b3..cf83b7c5 100644
--- a/daq/src/aaredaq/server.py
+++ b/daq/src/aaredaq/server.py
@@ -98,6 +98,12 @@ async def save_abr_meas_pos(token: str = Depends(oauth2_scheme)):
daq.save_abr_meas_pos()
return "OK"
+@app.post("/beamline/anneal")
+async def anneal(time_s: float, token: str = Depends(oauth2_scheme)):
+ auth.check_jwt_rw(cfg, auth.parse_token(token))
+ daq.anneal(time_s)
+ return "OK"
+
@app.post("/beamline/goto_abr_meas_pos")
async def goto_abr_meas_pos(token: str = Depends(oauth2_scheme)):
auth.check_jwt_rw(cfg, auth.parse_token(token))
diff --git a/gui/src/aaregui/main_window.py b/gui/src/aaregui/main_window.py
index c68e0cdf..f81ecf1f 100644
--- a/gui/src/aaregui/main_window.py
+++ b/gui/src/aaregui/main_window.py
@@ -18,6 +18,7 @@ from aaredaqlib.sample_geometry import SampleGeometryModel
from aaregui.panels.beamline_controls import BeamlineControls
from aaregui.panels.data_collection_settings import DataCollectionSettings
+from aaregui.panels.manual_sample_panel import ManualSamplePanel
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
@@ -121,6 +122,13 @@ class MainWindow(QMainWindow):
self.job_list_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea)
self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.job_list_dock)
+ self.manual_sample_panel = ManualSamplePanel()
+
+ self.manual_sample_dock = QDockWidget("Manual sample", self)
+ self.manual_sample_dock.setWidget(self.manual_sample_panel)
+ self.manual_sample_dock.setAllowedAreas(Qt.DockWidgetArea.BottomDockWidgetArea)
+ self.addDockWidget(Qt.DockWidgetArea.BottomDockWidgetArea, self.manual_sample_dock)
+
self.setCentralWidget(top_widget)
self.setWindowTitle("AareGUI")
@@ -228,11 +236,14 @@ class MainWindow(QMainWindow):
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)
+ self.daq.update.connect(self.manual_sample_panel.update_daq_status)
self.daq.standard_scan_completed.connect(self.rotation.scan_completed)
self.daq.automated_scan_done.connect(self.job_list_panel.automated_scan_done)
self.daq.raster_scan_completed.connect(self.raster.grid_scan_completed)
+ self.manual_sample_panel.sample_manual.connect(self.daq.sample_manual)
+
def create_menu_bar(self):
"""Create a menu bar with File->Quit and Help->About."""
# Main menu bar
@@ -262,6 +273,13 @@ class MainWindow(QMainWindow):
show_job_list_action.triggered.connect(lambda: self.job_list_dock.setVisible(show_job_list_action.isChecked()))
view_menu.addAction(show_job_list_action)
+ show_manual_sample_action = QAction("Show manual sample", self)
+ show_manual_sample_action.setCheckable(True)
+ show_manual_sample_action.setChecked(True)
+ show_manual_sample_action.triggered.connect(self.manual_sample_dock.setVisible)
+ # When dock visibility changes, update the action's checked state
+ show_manual_sample_action.triggered.connect(lambda: self.manual_sample_dock.setVisible(show_job_list_action.isChecked()))
+ view_menu.addAction(show_manual_sample_action)
# Help menu
help_menu = menu_bar.addMenu("Help")
about_action = QAction("About", self) # Action for 'About'
diff --git a/gui/src/aaregui/panels/manual_sample_panel.py b/gui/src/aaregui/panels/manual_sample_panel.py
index 8ba9a9e0..9693cdf2 100644
--- a/gui/src/aaregui/panels/manual_sample_panel.py
+++ b/gui/src/aaregui/panels/manual_sample_panel.py
@@ -1,41 +1,123 @@
from PySide6.QtCore import Signal, Slot
-from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QTextEdit, QPushButton
+from PySide6.QtWidgets import QWidget, QGridLayout, QLabel, QTextEdit, QPushButton, QCheckBox, QLineEdit
+from aareDBclient import DataCollectionParameters
-from aaredaqlib.models import SampleShortInfo
+from aaredaqlib.models import SampleShortInfo, DAQStatusModel
+from aaregui.widgets.number_line_edit import NumberLineEdit
from aaregui.widgets.title_label import TitleLabel
-class OmegaPanel(QWidget):
+class ManualSamplePanel(QWidget):
sample_manual = Signal(SampleShortInfo)
sample_clear = Signal()
def __init__(self, parent=None):
super().__init__(parent)
- self.__sample = SampleShortInfo(
- db_id = -1,
- puck_name="",
- dewar_name="",
- sample_name="Manual",
- pin=0
- )
+ self.__sample_name = "Lyso"
+
+ self.__pgroup = "p16371"
grid_layout = QGridLayout(self)
- grid_layout.addWidget(TitleLabel("Manual sample", self), 0, 0, 1, 2)
+ grid_layout.addWidget(TitleLabel("Manual sample", self), 0, 0, 1, 3)
- grid_layout.addWidget(QLabel("Name"), 1, 0)
- self._text_name = QTextEdit(self.__sample.sample_name)
+ grid_layout.addWidget(QLabel("Sample"), 1, 0)
+ self._text_name = QLineEdit(self.__sample_name)
grid_layout.addWidget(self._text_name, 1, 1)
self._text_name.textChanged.connect(self._name_changed)
+ self._text_name.setStyleSheet("background-color: rgb(255, 255, 255);")
+
+ # Unit cell parameters
+ self._unit_cell = QCheckBox("Provide unit cell")
+ grid_layout.addWidget(self._unit_cell, 2, 1)
+
+ # a, b, c parameters (in Ångströms)
+ grid_layout.addWidget(QLabel("a"), 3, 0)
+ self._text_a = NumberLineEdit(5, 1000, 39, parent=self)
+ grid_layout.addWidget(self._text_a, 3, 1)
+ grid_layout.addWidget(QLabel("Å"), 3, 2)
+
+ grid_layout.addWidget(QLabel("b"), 4, 0)
+ self._text_b = NumberLineEdit(5, 1000, 78, parent=self)
+ grid_layout.addWidget(self._text_b, 4, 1)
+ grid_layout.addWidget(QLabel("Å"), 4, 2)
+
+ grid_layout.addWidget(QLabel("c"), 5, 0)
+ self._text_c = NumberLineEdit(5, 1000, 78, parent=self)
+ grid_layout.addWidget(self._text_c, 5, 1)
+ grid_layout.addWidget(QLabel("Å"), 5, 2)
+
+ # alpha, beta, gamma parameters (in degrees)
+ grid_layout.addWidget(QLabel("α"), 6, 0)
+ self._text_alpha = NumberLineEdit(30, 330, 90, parent=self)
+ grid_layout.addWidget(self._text_alpha, 6, 1)
+ grid_layout.addWidget(QLabel("°"), 6, 2)
+
+ grid_layout.addWidget(QLabel("β"), 7, 0)
+ self._text_beta = NumberLineEdit(30, 330, 90, parent=self)
+ grid_layout.addWidget(self._text_beta, 7, 1)
+ grid_layout.addWidget(QLabel("°"), 7, 2)
+
+ grid_layout.addWidget(QLabel("γ"), 8, 0)
+ self._text_gamma = NumberLineEdit(30, 330, 90, parent=self)
+ grid_layout.addWidget(self._text_gamma, 8, 1)
+ grid_layout.addWidget(QLabel("°"), 8, 2)
+
+ grid_layout.addWidget(QLabel("SG"), 9, 0)
+ self._text_sg = NumberLineEdit(1, 250, 1, 0, parent=self)
+ grid_layout.addWidget(self._text_sg, 9, 1)
+
self._add_button = QPushButton("Add")
- grid_layout.addWidget(self._add_button, 2, 0, 1 ,2)
+ grid_layout.addWidget(self._add_button, 10, 0, 1, 3)
self._add_button.clicked.connect(self._add_clicked)
+ self._unit_cell.toggled.connect(self._unit_cell_toggled)
+ self._unit_cell_toggled(False)
+
+ @Slot(bool)
+ def _unit_cell_toggled(self, checked: bool):
+ if checked:
+ self._text_a.setEnabled(True)
+ self._text_b.setEnabled(True)
+ self._text_c.setEnabled(True)
+ self._text_alpha.setEnabled(True)
+ self._text_beta.setEnabled(True)
+ self._text_gamma.setEnabled(True)
+ self._text_sg.setEnabled(True)
+ else:
+ self._text_a.setEnabled(False)
+ self._text_b.setEnabled(False)
+ self._text_c.setEnabled(False)
+ self._text_alpha.setEnabled(False)
+ self._text_beta.setEnabled(False)
+ self._text_gamma.setEnabled(False)
+ self._text_sg.setEnabled(False)
+
@Slot(str)
- def _name_vhanged(self, s: str):
- self.__sample.sample_name = s
+ def _name_changed(self, s: str):
+ self.__sample_name = s
@Slot()
def _add_clicked(self):
- self.sample_manual.emit(self.__sample)
+ data_processing = None
+ if self._unit_cell.isChecked():
+ data_processing = DataCollectionParameters(
+ spacegroupnumber=int(self._text_sg.value),
+ cellparameters=f"{self._text_a.value:.2f} {self._text_b.value:.2f} {self._text_c.value:.2f} {self._text_alpha.value:.2f} {self._text_beta.value:.2f} {self._text_gamma.value:.2f}"
+ )
+
+ s = SampleShortInfo(
+ db_id=-1,
+ puck_name="",
+ dewar_name="",
+ sample_name=self.__sample_name,
+ pin=1,
+ aaredb_params=data_processing,
+ user=self.__pgroup,
+ )
+ self.sample_manual.emit(s)
+
+ @Slot(DAQStatusModel)
+ def update_daq_status(self, s: DAQStatusModel):
+ self.__pgroup = s.session.current_pgroup
diff --git a/gui/src/aaregui/panels/tell_sample_panel.py b/gui/src/aaregui/panels/tell_sample_panel.py
index dbc81d9c..2254f9db 100644
--- a/gui/src/aaregui/panels/tell_sample_panel.py
+++ b/gui/src/aaregui/panels/tell_sample_panel.py
@@ -111,9 +111,14 @@ class TellSamplePanel(QFrame):
self.table_model.updateCurrentSample(current_puck=None, current_sample=None)
else:
try:
- self.curr_sample_label.setText(
- f"Current sample: {sample.sample_name} ({sample.location.segment}{sample.location.pos}-{sample.pin})"
- )
+ if sample.location is None:
+ self.curr_sample_label.setText(
+ f"Current sample: {sample.sample_name} (Manual mount)"
+ )
+ else:
+ self.curr_sample_label.setText(
+ f"Current sample: {sample.sample_name} ({sample.location.segment}{sample.location.pos}-{sample.pin})"
+ )
self.table_model.updateCurrentSample(
current_puck=sample.puck_name, current_sample=sample.db_id
)