diff --git a/src/aaredaq/aaredb.py b/src/aaredaq/aaredb.py index 3f80fa9f..ae55cd81 100644 --- a/src/aaredaq/aaredb.py +++ b/src/aaredaq/aaredb.py @@ -1,14 +1,12 @@ import io from typing import List, Optional -import numpy as np import aareDBclient import cv2 +import numpy as np import requests from aareDBclient import SetTellPosition, SampleEventCreate, SetTellPositionRequest - -from aaredaq.beamline import MXBeamline -from aaredaq.models import ( +from aaredaqlib.models import ( SampleShortInfo, PuckLoadedInfo, PuckInfo, @@ -16,6 +14,8 @@ from aaredaq.models import ( SampleShortInfoList, ) +from aaredaq.beamline import MXBeamline + class AareWrapper: def __init__( diff --git a/src/aaredaq/config.py b/src/aaredaq/config.py index a0daff3e..c84528b0 100644 --- a/src/aaredaq/config.py +++ b/src/aaredaq/config.py @@ -6,17 +6,18 @@ import numpy as np import redis import redis_lock from aaredaqlib.coordinate import Coordinate - -from aaredaq.beamline import MXBeamline -from aaredaq.models import ( +from aaredaqlib.models import ( BeamlineSettingsModel, BeamCenterCoeffModel, LoopCenteringZoomModel, def_loop_centering_zoom, SampleShortInfo, + SessionStatus, BeamlineStateEnum, SessionsStateEnum, ) +from aaredaq.beamline import MXBeamline + ABR_POS_ALIGN_DEF = Coordinate(x=-18, y=-0.266, z=0) ABR_POS_MOUNT = Coordinate(x=-18, y=0, z=0) ABR_OMEGA_MOUNT = 0.0 @@ -82,6 +83,10 @@ class BeamlineConfig: return None return int(tmp) + def session_status(self, session: int) -> SessionStatus: + return SessionStatus(session=self.session_state(session), + current_pgroup=self.pgroup) + def session_state(self, session: int) -> SessionsStateEnum: curr_session = self.active_session if curr_session is None: diff --git a/src/aaredaq/daq.py b/src/aaredaq/daq.py index 5b6abd05..374ca3e9 100644 --- a/src/aaredaq/daq.py +++ b/src/aaredaq/daq.py @@ -7,6 +7,11 @@ import numpy as np import redis from aaredaqlib.coordinate import Coordinate, SmargonCoordinate from aaredaqlib.helical_geometry import HelicalScanRequest +from aaredaqlib.models import ( + SampleShortInfo, + PuckLoadedInfo, + SampleShortInfoList, + DAQStatusModel, BeamlineStatus, ) from aaredaqlib.raster_grid import RasterGridRequest from aaredaqlib.rotation_scan import RotationScanRequest from aaredaqlib.sample_geometry import SampleGeometryModel @@ -18,11 +23,6 @@ from aaredaq.config import BeamlineConfig, ABR_POS_MOUNT from aaredaq.config import BeamlineStateEnum from aaredaq.devices import BeamlineDevices from aaredaq.mlbox import MlBox -from aaredaq.models import ( - SampleShortInfo, - PuckLoadedInfo, - SampleShortInfoList, - DAQStatusModel, ) class TransformationInvalidException(Exception): @@ -331,7 +331,6 @@ class AareDAQ: self.__cfg.state_busy = False raise e - @property def dtz(self) -> float: tmp = self.__cfg.dtz @@ -348,7 +347,7 @@ class AareDAQ: self.__cfg.state_busy = False raise RuntimeError("Cannot set dtz during data collection") elif state == BeamlineStateEnum.SampleAlignment: - self.__devs.dtz.move(val) + self.__devs.dtz = val self.__cfg.dtz = val self.__cfg.state_busy = False @@ -705,16 +704,24 @@ class AareDAQ: self.__cfg.state_busy = False raise e + @property + def beamline_status(self) -> BeamlineStatus: + return BeamlineStatus( + energy_keV=self.__devs, + detector_distnace_mm=self.__devs.dtz.value, + ring_current_mA=self.__devs.ring_current, + light=self.light, + cryojet_K=self.__devs.cryojet_temp + ) @property def status(self) -> DAQStatusModel: - # session_status should be set by FastAPI server + # session should be set by FastAPI server return DAQStatusModel( - geom=self.sample_geometry, state=self.state, busy=self.busy, - light=self.light, - current_pgroup=self.__cfg.pgroup, + geom=self.sample_geometry, + bl=self.beamline_status, sample=self.sample ) diff --git a/src/aaredaq/devices.py b/src/aaredaq/devices.py index 3830e37e..21cae8bd 100644 --- a/src/aaredaq/devices.py +++ b/src/aaredaq/devices.py @@ -1,4 +1,7 @@ +from xml.sax.handler import property_dom_node + from aaredaqlib.coordinate import Coordinate +from aaredaqlib.models import BeamlineStatus from epics import PV from aaredaq.aaredb import AareWrapper @@ -30,6 +33,10 @@ class BeamlineDevices: self.tell = TellClient(beamline) self.smargon = smargon.Smargon(beamline) + self.__energy_pv = PV(f"{BEAMLINE}-OP_DCCM:ENERGY1") + self.__ring_current_pv = PV(f"ARS07-DPCT-0100:CURR") + self.__cryojet_temp = PV(f"{BEAMLINE}-ES-CRSM:TEMP_RBV") + self.magnet_position_sensor = PV(f"{BEAMLINE}-ES-DF1:CBOX-CMP1") self.magnet_position_sensor_readout = PV(f"{BEAMLINE}-ES-DF1:CBOX-USER1") @@ -209,6 +216,18 @@ class BeamlineDevices: wait_position(self.gmy, pos.y, 0.005) wait_position(self.gmz, pos.z, 0.005) + @property + def energy_kev(self) -> float: + return self.__energy_pv.value + + @property + def ring_current(self) -> float: + return self.__ring_current_pv.value + + @property + def cryojet_temp(self) -> float: + return self.__cryojet_temp.value + def enable_motors(self): self.aerotech.unlock() self.dtz.refresh() # Why ?? diff --git a/src/aaredaq/models.py b/src/aaredaq/models.py deleted file mode 100644 index b143742a..00000000 --- a/src/aaredaq/models.py +++ /dev/null @@ -1,157 +0,0 @@ -from enum import Enum -from typing import Annotated, Literal, Tuple, List, Optional - -from pydantic import BaseModel, Field - -from aaredaqlib.coordinate import Coordinate -from aaredaqlib.sample_geometry import SampleGeometryModel - - -class DewarAddress(BaseModel): - segment: Literal["A", "B", "C", "D", "E", "F", "X", "R"] - pos: Annotated[int, Field(ge=1, le=5)] - - -class SampleDewarAddress(BaseModel): - puck: DewarAddress - pin: Annotated[int, Field(ge=1, le=16)] - - -# From the database for puck loading -class PuckInfo(BaseModel): - db_id: int - puck_name: str - dewar_name: str - user: str = "" - location: Optional[DewarAddress] = None - - -# From TELL to database after loading -class PuckLoadedInfo(BaseModel): - puck_name: str - location: DewarAddress - - -# From database to TELL after loading -class SampleShortInfo(BaseModel): - db_id: int - puck_name: str - dewar_name: str - sample_name: str - user: str = "" - pin: Annotated[int, Field(ge=1, le=16)] - location: DewarAddress | None = None - priority: Optional[float] = 1.0 - comment: Optional[str] = None - mount_count: int = 0 - def tell_address(self) -> SampleDewarAddress: - return SampleDewarAddress(puck=self.location, pin=self.pin) - - def loc_str(self) -> str: - if self.location is None: - return "-" - else: - return f"{self.location.segment}{self.location.pos}-{self.pin}" - - def loc_str_sort(self) -> str: - if self.location is None: - return "" - else: - return f"{self.location.segment}{self.location.pos}-{self.pin:02d}" - - -class SampleShortInfoList(BaseModel): - s: List[SampleShortInfo] - - -class BeamCenterCoeffModel(BaseModel): - """ - Model to calculate beam center for a given zoom level based on a quadratic approximation - For both x and y it contains tuple of coefficients a, b, c (a*zoom^2 + b*zoom + c) - Default is beam center in 1000,1000 at any zoom level - """ - - coeff_x: Tuple[float, float, float] = (0, 0, 1000.0) - coeff_y: Tuple[float, float, float] = (0, 0, 1000.0) - - def apply(self, zoom: float): - return Coordinate( - x=self.coeff_x[0] * zoom**2 + self.coeff_x[1] * zoom + self.coeff_x[2], - y=self.coeff_y[0] * zoom**2 + self.coeff_y[1] * zoom + self.coeff_y[2], - ) - - -class LoopCenteringZoomModelElem(BaseModel): - zoom_value: float - sam_cam_gain: float - sam_cam_exp: float - - -class LoopCenteringZoomModel(BaseModel): - z: List[LoopCenteringZoomModelElem] - - -# zoom gain exp (X06DA) -# 1 50 0.05 -# 200 50 0.05 -# 500 70 0.05 -# 700 150 0.05 -# 800 100 0.10 -# 1000 200 0.10 - - -def def_loop_centering_zoom() -> LoopCenteringZoomModel: - return LoopCenteringZoomModel( - z=[ - LoopCenteringZoomModelElem( - zoom_value=200, sam_cam_gain=50.0, sam_cam_exp=0.05 - ) - ] - ) - - -class BeamlineStateEnum(Enum): - Maintenance = 1 - SampleExchange = 2 - SampleAlignment = 3 - DataCollection = 4 - DewarTransfer = 5 - XrayFluorescence = 6 - BeamLocation = 7 - Moving = 8 - RobotSampleExchange = 9 - # Busy state is used whenever transition between two states happen or mounting/data collection procedure happens - - -class SessionsStateEnum(Enum): - OwnedByYou = 1 - OwnedByElse = 2 - Vacant = 3 - -class DAQStatusModel(BaseModel): - geom: SampleGeometryModel - state: BeamlineStateEnum - busy: bool - light: Annotated[float, Field(ge=0.0, le=100.0)] - session: SessionsStateEnum = SessionsStateEnum.Vacant - sample: SampleShortInfo | None = None - current_pgroup: str | None - staff: bool = False - - -class BeamlineSettingsModel(BaseModel): - # Float properties - cryojet_park_position: float = 12.0 - cryojet_measurement_position: float = 5.0 - dtz_collection: float = 130 - dtz_park: float = 150.0 - dtz_wash_sample_distance: float = 150.0 - dtz_bsz_safety_margin: float = 50.0 - bsz: float = 25.0 - - camera_max_magnification: float = 1.0 - camera_min_magnification: float = 500.0 - camera_translation_factor_a: float = 0.00253 - camera_translation_factor_b: float = 255.0 - - cryojet_in_use: bool = True diff --git a/src/aaredaq/server.py b/src/aaredaq/server.py index 45f6361a..7be3b63a 100644 --- a/src/aaredaq/server.py +++ b/src/aaredaq/server.py @@ -1,30 +1,27 @@ import io from typing import Tuple -import urllib3 -from fastapi import HTTPException -import logging - 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 +from aaredaqlib.rotation_scan import RotationScanRequest +from aaredaqlib.sample_geometry import SampleGeometryModel +from aaredaqlib.screening_scan import ScreeningScanRequest from fastapi import FastAPI, Depends +from fastapi import HTTPException from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from starlette.responses import StreamingResponse from urllib3.exceptions import InsecureRequestWarning from aaredaq import auth -from aaredaq.auth import TokenData from aaredaq.beamline import mx_beamline from aaredaq.config import BeamlineConfig from aaredaq.daq import AareDAQ -from aaredaq.models import SampleShortInfo, DAQStatusModel, BeamlineStateEnum, BeamlineSettingsModel, \ - SampleShortInfoList -from aaredaqlib.coordinate import SmargonCoordinate, Coordinate -from aaredaqlib.helical_geometry import HelicalScanRequest -from aaredaqlib.raster_grid import RasterGridRequest -from aaredaqlib.rotation_scan import RotationScanRequest -from aaredaqlib.sample_geometry import SampleGeometryModel -from aaredaqlib.screening_scan import ScreeningScanRequest app = FastAPI() @@ -47,8 +44,9 @@ 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 = cfg.session_state(data.session) - ret.staff = data.staff + ret.session = SessionStatus(current_pgroup = cfg.pgroup, + session=cfg.session_state(data.session), + staff=data.staff) return ret diff --git a/src/mxlibs3/tell_client.py b/src/mxlibs3/tell_client.py index 97e6c842..76a477de 100755 --- a/src/mxlibs3/tell_client.py +++ b/src/mxlibs3/tell_client.py @@ -7,15 +7,15 @@ from typing import List from urllib.parse import urlparse import requests - -from aaredaq.beamline import MXBeamline # noqa: F401 -from aaredaq.models import ( +from aaredaqlib.models import ( PuckLoadedInfo, SampleShortInfo, DewarAddress, SampleDewarAddress, PuckInfo, ) + +from aaredaq.beamline import MXBeamline # noqa: F401 from mxlibs3.pshell_client import PShellClient logger = logging.getLogger(__name__)