Server: Combine helical and rotation data collection in one data structure

This commit is contained in:
2025-05-30 10:29:58 +02:00
parent 72e6d858bc
commit 3dd5b5a686
9 changed files with 57 additions and 71 deletions
@@ -1,6 +0,0 @@
from aaredaqlib.coordinate import SmargonCoordinate
from aaredaqlib.rotation_scan import RotationScanRequest
class HelicalScanRequest(RotationScanRequest):
end: SmargonCoordinate
+2 -2
View File
@@ -1,7 +1,7 @@
import math
from typing import Annotated
from pydantic import Field, AfterValidator
from pydantic import Field, AfterValidator, BaseModel
from aaredaqlib.coordinate import Coordinate, positive_coords, SmargonCoordinate
from aaredaqlib.sample_geometry import SampleGeometryModel
@@ -13,7 +13,7 @@ def normalize_angle(angle_deg: float) -> float:
return normalized_angle
class RasterGridRequest(ScanRequest):
class RasterGridRequest(BaseModel):
# Number of grid elements
n_x: Annotated[int, Field(ge=1)]
n_y: Annotated[int, Field(ge=1)]
+4 -2
View File
@@ -1,9 +1,11 @@
from pydantic import BaseModel
from aaredaqlib.coordinate import SmargonCoordinate
from aaredaqlib.scan_request import ScanRequest
class RotationScanRequest(ScanRequest):
class RotationScanRequest(BaseModel):
start: SmargonCoordinate | None = None # None = start where you are
end: SmargonCoordinate | None = None
start_omega_deg: float = 0
omega_incr_deg: float
+8 -4
View File
@@ -2,14 +2,18 @@ from abc import abstractmethod, ABC
from pydantic import BaseModel
class ScanRequest(ABC, BaseModel):
from aaredaqlib.raster_grid import RasterGridRequest
from aaredaqlib.rotation_scan import RotationScanRequest
from aaredaqlib.screening_scan import ScreeningScanRequest
class ScanRequest(BaseModel):
dtz: float
transmission: float
file_prefix: str
exp_time_s: float
image_number: int
@abstractmethod
def get_image_number(self) -> int:
pass
measurement: RasterGridRequest | ScreeningScanRequest | RotationScanRequest
+2 -2
View File
@@ -1,7 +1,7 @@
from aaredaqlib.scan_request import ScanRequest
from pydantic import BaseModel
class ScreeningScanRequest(ScanRequest):
class ScreeningScanRequest(BaseModel):
omega_start_deg: float
omega_step_deg: float
steps: int
+15 -31
View File
@@ -6,7 +6,6 @@ import cv2
import numpy as np
import redis
from aaredaqlib.coordinate import Coordinate, SmargonCoordinate
from aaredaqlib.helical_geometry import HelicalScanRequest
from aaredaqlib.models import (
SampleShortInfo,
PuckLoadedInfo,
@@ -232,41 +231,26 @@ class AareDAQ:
self.__cfg.state_busy = False
raise e
def measure_helical(self, h: HelicalScanRequest) -> float:
start = time.perf_counter()
self.__cfg.try_set_busy(timeout=ceil(h.time_sec + 360))
self.__set_state(BeamlineStateEnum.DataCollection)
try:
self.__devs.smargon.target = h.start
self.__devs.aerotech.measure_standard(
h.omega_start, h.total_omega, h.time_sec
)
smargon_time_step = h.time_sec / float(h.steps)
pos_step = (h.end.sh_mm - h.start.sh_mm) * (1.0 / float(h.steps))
for i in range(h.steps):
self.__devs.smargon.target = SmargonCoordinate(
sh_mm=h.start.sh_mm + pos_step * i
)
time.sleep(smargon_time_step)
self.__devs.aerotech.wait_scan_done(h.time_sec + 60)
self.__devs.aerotech.reset()
self.__cfg.state_busy = False
except Exception as e:
self.__cfg.state_busy = False
raise e
end = time.perf_counter()
return end - start
def __rotation(self, request: RotationScanRequest):
self.__set_state(BeamlineStateEnum.DataCollection)
if request.start is not None:
self.__devs.smargon.target = request.start
self.__devs.smargon.wait()
self.__devs.aerotech.measure_standard(
request.start_omega_deg, request.total_omega_deg, request.total_time_sec
)
if request.start is not None and request.end is not None:
smargon_time_step = request.time_sec / float(request.steps)
pos_step = (request.end.sh_mm - request.start.sh_mm) * (1.0 / float(request.steps))
for i in range(request.steps):
self.__devs.smargon.target = SmargonCoordinate(
sh_mm=request.start.sh_mm + pos_step * i
)
time.sleep(smargon_time_step)
self.__devs.aerotech.wait_scan_done(request.total_time_sec + 60)
self.__devs.aerotech.reset()
+19 -13
View File
@@ -5,7 +5,6 @@ import cv2
import urllib3
import uvicorn
from aaredaqlib.coordinate import SmargonCoordinate, Coordinate
from aaredaqlib.helical_geometry import HelicalScanRequest
from aaredaqlib.models import SampleShortInfo, DAQStatusModel, BeamlineStateEnum, BeamlineSettingsModel, \
SampleShortInfoList, SessionStatus
from aaredaqlib.raster_grid import RasterGridRequest
@@ -44,7 +43,7 @@ async def status(token: str = Depends(oauth2_scheme)) -> DAQStatusModel:
data = auth.parse_token(token)
auth.check_jwt_ro(cfg, data)
ret = daq.status
ret.session = SessionStatus(current_pgroup = cfg.pgroup,
ret.session = SessionStatus(current_pgroup=cfg.pgroup,
session=cfg.session_state(data.session),
staff=data.staff)
return ret
@@ -85,36 +84,42 @@ async def smargon(val: SmargonCoordinate, token: str = Depends(oauth2_scheme)):
daq.smargon = val
return "OK"
@app.post("/beamline/tweak_abr_meas_pos")
async def tweak_abr_meas_pos(val: Coordinate, token: str = Depends(oauth2_scheme)):
auth.check_jwt_staff(auth.parse_token(token))
daq.tweak_abr_meas_pos(val)
return "OK"
@app.post("/beamline/save_abr_meas_pos")
async def save_abr_meas_pos(token: str = Depends(oauth2_scheme)):
auth.check_jwt_staff(auth.parse_token(token))
daq.save_abr_meas_pos()
return "OK"
@app.post("/beam_center/mark")
async def mark_beam_center(x: float, y: float, token: str = Depends(oauth2_scheme)):
auth.check_jwt_staff(auth.parse_token(token))
daq.mark_beam(x, y)
return "OK"
@app.post("/beam_center/clear")
async def clear_beam_center(token: str = Depends(oauth2_scheme)):
auth.check_jwt_staff(auth.parse_token(token))
daq.clear_mark_beam()
return "OK"
@app.post("/shutter/close")
async def close_shutter(token: str = Depends(oauth2_scheme)):
auth.check_jwt_rw(cfg, auth.parse_token(token))
daq.close_shutter()
return "OK"
async def get_image(token: str = Depends(oauth2_scheme)):
auth.check_jwt_ro(cfg, auth.parse_token(token))
@@ -141,16 +146,17 @@ async def sample(token: str = Depends(oauth2_scheme)) -> SampleShortInfo:
sample_name="Other user sample",
puck_name="",
dewar_name="",
db_id = -1,
pin = sample.pin,
db_id=-1,
pin=sample.pin,
location=sample.location
)
@app.post("/tell/mount")
async def mount(dbid: int, token: str = Depends(oauth2_scheme)):
token_data = auth.parse_token(token)
auth.check_jwt_rw(cfg, auth.parse_token(token))
#st = daq.sample_spreadsheet
# st = daq.sample_spreadsheet
st = SampleShortInfoList(s=[])
index = -1
@@ -230,19 +236,13 @@ async def screening(val: ScreeningScanRequest, token: str = Depends(oauth2_schem
return "OK"
@app.post("/scan/helical")
async def helical(val: HelicalScanRequest, token: str = Depends(oauth2_scheme)):
auth.check_jwt_rw(cfg, auth.parse_token(token))
daq.measure_helical(val)
return "OK"
@app.post("/scan/auto")
async def auto(s: SampleShortInfo, token: str = Depends(oauth2_scheme)):
auth.check_jwt_rw(cfg, auth.parse_token(token))
runtime = daq.measure(s)
return f"{runtime:0.3f}"
# ALC routines
@app.post("/alc/background")
async def alc_background(token: str = Depends(oauth2_scheme)) -> str:
@@ -257,11 +257,14 @@ async def alc_center_loop(token: str = Depends(oauth2_scheme)) -> str:
daq.auto_loop_center()
return "OK"
@app.post("/alc/ml_bounding_box")
async def alc_ml_bounding_box(token: str = Depends(oauth2_scheme), move: bool = False, filename: str = "") -> Tuple[float, float, float, float] | None:
async def alc_ml_bounding_box(token: str = Depends(oauth2_scheme), move: bool = False, filename: str = "") -> Tuple[
float, float, float, float] | None:
auth.check_jwt_rw(cfg, auth.parse_token(token))
return daq.ml_bounding_box(move=move)
# Access management
@app.get("/access/pgroup")
async def pgroup(token: str = Depends(oauth2_scheme)) -> str:
@@ -301,16 +304,19 @@ async def force_current_session(token: str = Depends(oauth2_scheme)) -> str:
auth.force_current_sesion(cfg, data)
return "OK"
@app.get("/beamline/settings")
async def get_settings(token: str = Depends(oauth2_scheme)) -> BeamlineSettingsModel:
auth.check_jwt_staff(auth.parse_token(token))
return cfg.settings
@app.put("/beamline/settings")
async def put_settings(s: BeamlineSettingsModel, token: str = Depends(oauth2_scheme)):
auth.check_jwt_staff(auth.parse_token(token))
cfg.settings = s
LOGGING_CONFIG = {
"version": 1,
"disable_existing_loggers": False,
@@ -7,7 +7,6 @@ from PySide6.QtWidgets import (
QPushButton,
QWidget,
)
from aaredaqlib.helical_geometry import HelicalScanRequest
from aaredaqlib.rotation_scan import RotationScanRequest
from aaredaqlib.sample_geometry import SampleGeometryModel
from aaredaqlib.screening_scan import ScreeningScanRequest
@@ -84,9 +83,6 @@ class DataCollectionSettings(QFrame):
return
s = ScreeningScanRequest(
omega_start_deg=self.screening.start_angle.value,
exp_time_s=self.screening.image_time_enter.value,
omega_step_deg=data["omega_step_deg"],
+7 -7
View File
@@ -10,12 +10,12 @@ class FilePathPanel(QWidget):
grid_layout.addWidget(TitleLabel("Dataset path", self), 0, 0, 1, 2)
grid_layout.addWidget(QLabel("File prefix", parent=self), 1, 0)
self.file_prefix_edit = QLineEdit(parent=self)
self.file_prefix_edit.setStyleSheet("background-color: rgb(255, 255, 255);")
grid_layout.addWidget(self.file_prefix_edit, 1, 1)
grid_layout.addWidget(QLabel("Directory", parent=self), 2, 0)
grid_layout.addWidget(QLabel("Directory", parent=self), 1, 0)
self.directory_edit = QLineEdit(parent=self)
self.directory_edit.setStyleSheet("background-color: rgb(255, 255, 255);")
grid_layout.addWidget(self.directory_edit, 2, 1)
grid_layout.addWidget(self.directory_edit, 1, 1)
grid_layout.addWidget(QLabel("File prefix", parent=self), 2, 0)
self.file_prefix_edit = QLineEdit(parent=self)
self.file_prefix_edit.setStyleSheet("background-color: rgb(255, 255, 255);")
grid_layout.addWidget(self.file_prefix_edit, 2, 1)