DAQ/GUI - Fluorescence spectrum in a single call
This commit is contained in:
@@ -429,6 +429,14 @@ class BeamMarkCoeffModel(BaseModel):
|
||||
y=self.coeff_y[0] * zoom**2 + self.coeff_y[1] * zoom + self.coeff_y[2],
|
||||
)
|
||||
|
||||
class FluorescenceSpectrumParameterModel(BaseModel):
|
||||
acq_time_s: float
|
||||
|
||||
class FluorescenceSpectrumOutputModel(BaseModel):
|
||||
bkg: list[float] | None = None
|
||||
spectrum: list[float]
|
||||
energy_eV: list[float]
|
||||
|
||||
class MLBoxType(Enum):
|
||||
Loop_all = 0
|
||||
Pin = 1
|
||||
|
||||
+23
-1
@@ -3,6 +3,7 @@ import json
|
||||
import math
|
||||
import statistics
|
||||
import time
|
||||
from asyncio import sleep
|
||||
from datetime import datetime
|
||||
from math import ceil
|
||||
from typing import List, Tuple, Optional, Callable, Dict
|
||||
@@ -34,7 +35,8 @@ from aaredaqlib.models import (
|
||||
PuckLoadedInfo,
|
||||
SampleShortInfoList,
|
||||
DAQStatusModel, BeamlineStatus, SessionStatus, SampleCameraSettings, AutofocusSettings, BoundingBoxModel,
|
||||
ZoomModeEnum, CrystalSize, SimpleScanParameters, MLBoxModel)
|
||||
ZoomModeEnum, CrystalSize, SimpleScanParameters, MLBoxModel, FluorescenceSpectrumParameterModel,
|
||||
FluorescenceSpectrumOutputModel)
|
||||
from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid, CompletedRasterGridElem
|
||||
from aaredaqlib.rotation_scan import RotationScanRequest, CompletedRotationScan
|
||||
from aaredaqlib.sample_geometry import SampleGeometryModel
|
||||
@@ -1525,11 +1527,31 @@ class AareDAQ:
|
||||
finally:
|
||||
self.__cfg.state_busy = False
|
||||
|
||||
def fluorimeter_take_spectrum(self, fm: FluorescenceSpectrumParameterModel) -> FluorescenceSpectrumOutputModel:
|
||||
self.__cfg.set_busy(BeamlineStateEnum.SampleAlignment)
|
||||
try:
|
||||
self.__devs.fluorimeter.start_acquisition(erase=True)
|
||||
self.__devs.aerotech.set_shutter(1)
|
||||
sleep(fm.acq_time_s)
|
||||
self.__devs.aerotech.set_shutter(0)
|
||||
self.__devs.fluorimeter.stop_acquisition()
|
||||
spectrum = self.__devs.fluorimeter.get_current_data()
|
||||
energy = [1.0 * i + 0.0 for i in range(len(spectrum))]
|
||||
self.__cfg.state_busy = False
|
||||
return FluorescenceSpectrumOutputModel(spectrum=spectrum,
|
||||
bkg=self.__devs.fluorimeter.get_current_background(),
|
||||
energy_eV=energy)
|
||||
except Exception as e:
|
||||
self.__cfg.state_busy = False
|
||||
raise e
|
||||
|
||||
def fluorimeter_start(self, erase: bool = False):
|
||||
self.__devs.aerotech.set_shutter(1)
|
||||
self.__devs.fluorimeter.start_acquisition(erase=erase)
|
||||
|
||||
def fluorimeter_stop(self):
|
||||
self.__devs.fluorimeter.stop_acquisition()
|
||||
self.__devs.aerotech.set_shutter(0)
|
||||
|
||||
def fluorimeter_status(self) -> int | None:
|
||||
return self.__devs.fluorimeter.check_status()
|
||||
|
||||
@@ -10,7 +10,8 @@ from aaredaqlib.coordinate import SmargonCoordinate, Coordinate
|
||||
from aaredaqlib.logger_config import setup_logger
|
||||
from aaredaqlib.models import SampleShortInfo, DAQStatusModel, BeamlineStateEnum, BeamlineSettingsModel, \
|
||||
SampleShortInfoList, SessionStatus, SampleCameraSettings, AutofocusSettings, TokenData, \
|
||||
CryojetSettingsModel, SimpleScanParameters, CrystalSize
|
||||
CryojetSettingsModel, SimpleScanParameters, CrystalSize, FluorescenceSpectrumParameterModel, \
|
||||
FluorescenceSpectrumOutputModel
|
||||
from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid
|
||||
from aaredaqlib.rotation_scan import RotationScanRequest, CompletedRotationScan
|
||||
from aaredaqlib.sample_geometry import SampleGeometryModel
|
||||
@@ -546,10 +547,15 @@ async def get_all_pgroups(token: str = Depends(oauth2_scheme)):
|
||||
logger.error(f"Failed to list pgroups: {e}")
|
||||
return []
|
||||
|
||||
@app.post("/fluorimeter/spectrum")
|
||||
async def fluorimeter_spectrum(input: FluorescenceSpectrumParameterModel, token: str = Depends(oauth2_scheme)) -> FluorescenceSpectrumOutputModel:
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
return daq.fluorimeter_take_spectrum(input)
|
||||
|
||||
@app.post("/fluorimeter/start")
|
||||
async def fluorimeter_start(erase: bool = False, token: str = Depends(oauth2_scheme)) -> str:
|
||||
auth.check_jwt_rw(cfg, auth.parse_token(token))
|
||||
daq.fluorimeter_start(erase=erase)
|
||||
daq.fluorimeter_start(erase)
|
||||
return "OK"
|
||||
|
||||
@app.post("/fluorimeter/stop")
|
||||
|
||||
@@ -356,13 +356,8 @@ class MainWindow(QMainWindow):
|
||||
self.status_bar.get_all_pgroups.connect(self.daq.get_all_pgroups)
|
||||
self.daq.staff_pgroups_loaded.connect(self.status_bar.staff_pgroups_loaded)
|
||||
|
||||
self.fluor_panel.start.connect(self.daq.fluorimeter_start)
|
||||
self.fluor_panel.start_erase.connect(self.daq.fluorimeter_start_erase)
|
||||
self.fluor_panel.stop.connect(self.daq.fluorimeter_stop)
|
||||
self.fluor_panel.snapshot.connect(self.daq.fluorimeter_request_snapshot)
|
||||
self.fluor_panel.live.connect(self.daq.fluorimeter_start_erase)
|
||||
self.fluor_panel.live.connect(self.daq.start_fluorimeter_stream)
|
||||
self.daq.fluorimeter_update.connect(self.fluor_panel.update_plot)
|
||||
self.fluor_panel.spectrum.connect(self.daq.fluorimeter_spectrum)
|
||||
self.daq.fluorimeter_spectrum_update.connect(self.fluor_panel.update_plot)
|
||||
|
||||
def create_menu_bar(self):
|
||||
"""Create a menu bar with File->Quit and Help->About."""
|
||||
|
||||
@@ -4,6 +4,7 @@ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
||||
from matplotlib.figure import Figure
|
||||
import numpy as np
|
||||
|
||||
from aaredaqlib.models import FluorescenceSpectrumParameterModel, FluorescenceSpectrumOutputModel
|
||||
from aaregui.widgets.number_line_edit import NumberLineEdit
|
||||
from aaregui.widgets.title_label import TitleLabel
|
||||
from aaredaqlib.logger_config import setup_logger
|
||||
@@ -11,59 +12,36 @@ from aaredaqlib.logger_config import setup_logger
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
class FluorescencePanel(QWidget):
|
||||
|
||||
start = Signal()
|
||||
start_erase = Signal()
|
||||
stop = Signal()
|
||||
snapshot = Signal()
|
||||
live = Signal()
|
||||
spectrum = Signal(FluorescenceSpectrumParameterModel)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
grid = QGridLayout(self)
|
||||
grid.addWidget(TitleLabel("Fluorescence", self), 0, 0, 1, 4)
|
||||
grid.addWidget(TitleLabel("Fluorescence", self), 0, 0)
|
||||
|
||||
self.btn_start = QPushButton("Start")
|
||||
self.btn_start_erase = QPushButton("Erase+Start")
|
||||
self.btn_stop = QPushButton("Stop")
|
||||
self.btn_live = QPushButton("Start Live")
|
||||
self.btn_snapshot = QPushButton("Snapshot")
|
||||
for i, b in enumerate((self.btn_start, self.btn_start_erase, self.btn_stop, self.btn_live, self.btn_snapshot), start=1):
|
||||
grid.addWidget(b, 1, i - 1)
|
||||
self.btn_start = QPushButton("Spectrum")
|
||||
grid.addWidget(self.btn_start, 1, 0)
|
||||
|
||||
self.fig = Figure(figsize=(5, 3), tight_layout=True)
|
||||
self.ax = self.fig.add_subplot(111)
|
||||
self.canvas = FigureCanvas(self.fig)
|
||||
grid.addWidget(self.canvas, 2, 0, 1, 4)
|
||||
grid.addWidget(self.canvas, 2, 0)
|
||||
|
||||
# Wire buttons
|
||||
self.btn_start.clicked.connect(self.start.emit)
|
||||
self.btn_start_erase.clicked.connect(self.start_erase.emit)
|
||||
self.btn_stop.clicked.connect(self.stop.emit)
|
||||
self.btn_snapshot.clicked.connect(self.snapshot.emit)
|
||||
self.btn_live.clicked.connect(self.live.emit)
|
||||
self.btn_start.clicked.connect(lambda: self.spectrum.emit(FluorescenceSpectrumParameterModel(acq_time_s=0.1)))
|
||||
|
||||
|
||||
@Slot(list, list, int)
|
||||
def update_plot(self, data, background, status):
|
||||
@Slot(FluorescenceSpectrumOutputModel)
|
||||
def update_plot(self, f: FluorescenceSpectrumOutputModel):
|
||||
try:
|
||||
self.ax.clear()
|
||||
|
||||
if data:
|
||||
y = np.array(data, dtype=float)
|
||||
x = np.arange(len(y), dtype=int)
|
||||
if len(f.spectrum) > 0 and len(f.spectrum) == len(f.energy_eV):
|
||||
x = np.array(f.energy_eV, dtype=float)
|
||||
y = np.array(f.spectrum, dtype=float)
|
||||
self.ax.plot(x, y, lw=1.0, label="Data")
|
||||
|
||||
if background:
|
||||
b = np.array(background, dtype=float)
|
||||
xb = np.arange(len(b), dtype=int)
|
||||
self.ax.plot(xb, b, lw=1.0, label="Background")
|
||||
|
||||
self.ax.set_xlabel("Channel")
|
||||
self.ax.set_xlabel("Energy eV")
|
||||
self.ax.set_ylabel("Counts")
|
||||
if self.ax.has_data():
|
||||
self.ax.legend(loc="best")
|
||||
self.ax.grid(True, alpha=0.3)
|
||||
self.canvas.draw_idle()
|
||||
except Exception as e:
|
||||
|
||||
@@ -9,7 +9,7 @@ from jfjoch_client import ScanResult, ScanResultImagesInner
|
||||
|
||||
from aaredaqlib.coordinate import SmargonCoordinate, Coordinate
|
||||
from aaredaqlib.models import DAQStatusModel, SampleShortInfoList, SampleShortInfo, SampleCameraSettings, \
|
||||
AutofocusSettings, SimpleScanParameters
|
||||
AutofocusSettings, SimpleScanParameters, FluorescenceSpectrumParameterModel, FluorescenceSpectrumOutputModel
|
||||
from aaredaqlib.raster_grid import RasterGridRequest, CompletedRasterGrid
|
||||
from aaredaqlib.rotation_scan import RotationScanRequest, CompletedRotationScan
|
||||
|
||||
@@ -34,6 +34,7 @@ class DAQWorker(QObject):
|
||||
face_detection_result = Signal(dict)
|
||||
staff_pgroups_loaded = Signal(list)
|
||||
fluorimeter_update = Signal(list, list, int)
|
||||
fluorimeter_spectrum_update = Signal(FluorescenceSpectrumOutputModel)
|
||||
|
||||
def __init__(self, base_url: str | None, token: str, parent=None):
|
||||
super().__init__(parent)
|
||||
@@ -560,6 +561,26 @@ class DAQWorker(QObject):
|
||||
logger.error(f"Fluorimeter background error: {e}")
|
||||
self.http_error.emit(str(e))
|
||||
|
||||
@Slot()
|
||||
def fluorimeter_spectrum(self, f: FluorescenceSpectrumParameterModel):
|
||||
if self.__base_url is None:
|
||||
return
|
||||
req = QNetworkRequest(QUrl(f"{self.__base_url}/fluorimeter/spectrum"))
|
||||
req.setRawHeader(b"Authorization", f"Bearer {self.__token}".encode("utf-8"))
|
||||
req.setRawHeader(b"Content-Type", b"application/json")
|
||||
body = f.model_dump_json()
|
||||
reply = self.__net_manager.post(req, QByteArray(body.encode("utf-8")))
|
||||
reply.finished.connect(lambda: self._handle_fluorimeter_spectrum(reply))
|
||||
|
||||
def _handle_fluorimeter_spectrum(self, reply: QNetworkReply):
|
||||
try:
|
||||
response_data = self.handle_response(reply)
|
||||
parsed_response = FluorescenceSpectrumOutputModel.model_validate_json(response_data)
|
||||
self.fluorimeter_spectrum_update.emit(parsed_response)
|
||||
except Exception as e:
|
||||
logger.error(f"Exception from fluorimeter spectrum: {e}")
|
||||
self.http_error.emit(str(e))
|
||||
|
||||
@Slot()
|
||||
def fluorimeter_request_snapshot(self):
|
||||
if self.__base_url is None:
|
||||
|
||||
Reference in New Issue
Block a user