Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I24 serial: Use DetectorParams in parameter model #708

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dependencies = [
"matplotlib",
"nexgen",
"numpy",
"opencv-python", # Needed for I24 ssx moveonclick. To be changed to headless once this is moved to separate ui.
"opencv-python", # Needed for I24 ssx moveonclick. To be changed to headless once this is moved to separate ui.
"opentelemetry-distro",
"opentelemetry-exporter-otlp",
"pydantic",
Expand Down
6 changes: 3 additions & 3 deletions src/mx_bluesky/beamlines/i24/serial/dcid.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import os
import subprocess
from functools import lru_cache
from typing import Literal

import bluesky.plan_stubs as bps
import requests
Expand All @@ -18,6 +17,7 @@
from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER
from mx_bluesky.beamlines.i24.serial.parameters import (
BeamSettings,
DetectorName,
ExtruderParameters,
FixedTargetParameters,
)
Expand Down Expand Up @@ -50,7 +50,7 @@ def read_beam_info_from_hardware(
dcm: DCM,
mirrors: FocusMirrorsMode,
beam_center: DetectorBeamCenter,
detector_name: Literal["eiger", "pilatus"],
detector_name: DetectorName,
):
""" Read the beam information from hardware.

Expand All @@ -59,7 +59,7 @@ def read_beam_info_from_hardware(
mirrors (FocusMirrorMode): The device describing the focus mirror mode settings.
beam_center (DetectorBeamCenter): A device to set and read the beam center on \
the detector.
detector_name (Literal["eiger", "pilatus"]): The detector currently in use.
detector_name (DetectorName): The detector currently in use.

Returns:
BeamSettings parameter model.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ def main_extruder_plan(
start_time: datetime,
) -> MsgGenerator:
yield from sup.set_detector_beam_center_plan(
beam_center_device, parameters.detector_name
beam_center_device,
parameters.detector_params,
parameters.detector_distance_mm,
)

# Setting up the beamline
Expand Down Expand Up @@ -281,7 +283,7 @@ def main_extruder_plan(
SSX_LOGGER.info("Using Eiger detector")

SSX_LOGGER.debug(f"Creating the directory for the collection in {filepath}.")
Path(filepath).mkdir(parents=True, exist_ok=True)
# NOTE Directory now created by the parameter model

caput(pv.eiger_seqID, int(caget(pv.eiger_seqID)) + 1)
SSX_LOGGER.info(f"Eiger quickshot setup: filepath {filepath}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def start_i24(
SSX_LOGGER.info("Using Eiger detector")

SSX_LOGGER.debug(f"Creating the directory for the collection in {filepath}.")
Path(filepath).mkdir(parents=True, exist_ok=True)
# NOTE Directory now created by the parameter model

SSX_LOGGER.info(f"Triggered Eiger setup: filepath {filepath}")
SSX_LOGGER.info(f"Triggered Eiger setup: filename {filename}")
Expand Down Expand Up @@ -548,7 +548,9 @@ def main_fixed_target_plan(
SSX_LOGGER.info("Running a chip collection on I24")

yield from sup.set_detector_beam_center_plan(
beam_center_device, parameters.detector_name
beam_center_device,
parameters.detector_params,
parameters.detector_distance_mm,
)

SSX_LOGGER.info("Getting Program Dictionary")
Expand Down
3 changes: 2 additions & 1 deletion src/mx_bluesky/beamlines/i24/serial/parameters/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from mx_bluesky.beamlines.i24.serial.parameters.constants import SSXType
from mx_bluesky.beamlines.i24.serial.parameters.constants import DetectorName, SSXType
from mx_bluesky.beamlines.i24.serial.parameters.experiment_parameters import (
BeamSettings,
ChipDescription,
Expand All @@ -13,6 +13,7 @@

__all__ = [
"SSXType",
"DetectorName",
"BeamSettings",
"ExtruderParameters",
"ChipDescription",
Expand Down
18 changes: 13 additions & 5 deletions src/mx_bluesky/beamlines/i24/serial/parameters/constants.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
from enum import Enum
from enum import StrEnum
from os import environ
from pathlib import Path

from mx_bluesky.beamlines.i24.serial.log import _read_visit_directory_from_file


class SSXType(Enum):
class SSXType(StrEnum):
FIXED = "Serial Fixed"
EXTRUDER = "Serial Jet"


BEAM_CENTER_POS: dict[str, list] = {
"eiger": [1600.0, 1697.4],
"pilatus": [1284.7, 1308.6],
class DetectorName(StrEnum):
EIGER = "eiger"
PILATUS = "pilatus"


# TODO figue sth out for tests
LUT_FILES_PATH = Path("/dls_sw/i24/software/daq_configuration/lookup")

BEAM_CENTER_LUT_FILES = {
DetectorName.EIGER: LUT_FILES_PATH / "DetDistToBeamXYConverterE9M.txt",
DetectorName.PILATUS: LUT_FILES_PATH / "DetDistToBeamXYConverterP6M.txt",
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import json
from abc import abstractmethod
from pathlib import Path
from typing import Literal

import numpy as np
from dodal.devices.detector import DetectorParams, TriggerMode
from dodal.devices.detector.det_dim_constants import EIGER2_X_9M_SIZE, PILATUS_6M_SIZE
from pydantic import BaseModel, ConfigDict, computed_field, field_validator

from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import (
ChipType,
MappingType,
PumpProbeSetting,
)
from mx_bluesky.beamlines.i24.serial.parameters.constants import SSXType
from mx_bluesky.beamlines.i24.serial.parameters.constants import (
BEAM_CENTER_LUT_FILES,
DetectorName,
SSXType,
)


class SerialExperiment(BaseModel):
Expand All @@ -22,7 +27,7 @@ class SerialExperiment(BaseModel):
filename: str
exposure_time_s: float
detector_distance_mm: float
detector_name: Literal["eiger", "pilatus"]
detector_name: DetectorName
transmission: float

@field_validator("visit", mode="before")
Expand All @@ -34,7 +39,9 @@ def _parse_visit(cls, visit: str | Path):

@property
def collection_directory(self) -> Path:
return Path(self.visit) / self.directory
directory = Path(self.visit) / self.directory
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property is accessed in 9 different places in production code, I don't think it should be creating the directory.

directory.mkdir(parents=True, exist_ok=True)
return directory


class LaserExperiment(BaseModel):
Expand Down Expand Up @@ -62,6 +69,10 @@ def nexgen_experiment_type(self) -> str:
def ispyb_experiment_type(self) -> SSXType:
pass

@property
@abstractmethod
def detector_params(self) -> DetectorParams: ...


class ExtruderParameters(SerialAndLaserExperiment):
"""Extruder parameter model."""
Expand All @@ -77,6 +88,32 @@ def nexgen_experiment_type(self) -> str:
def ispyb_experiment_type(self) -> SSXType:
return SSXType.EXTRUDER

@property
def detector_params(self):
det_dist_to_beam_lut = BEAM_CENTER_LUT_FILES[self.detector_name]
det_size_constants = (
EIGER2_X_9M_SIZE
if self.detector_name is DetectorName.EIGER
else PILATUS_6M_SIZE
)

self.collection_directory.mkdir(parents=True, exist_ok=True)

return DetectorParams(
detector_size_constants=det_size_constants,
exposure_time=self.exposure_time_s,
directory=self.collection_directory.as_posix(),
prefix=self.filename,
detector_distance=self.detector_distance_mm,
omega_start=0.0,
omega_increment=0.0,
num_images_per_trigger=1,
num_triggers=self.num_images,
det_dist_to_beam_converter_path=det_dist_to_beam_lut.as_posix(),
use_roi_mode=False, # Dasabled
trigger_mode=TriggerMode.SET_FRAMES, # For now...
)


class ChipDescription(BaseModel):
"""Parameters defining the chip in use for FT collection."""
Expand Down Expand Up @@ -132,6 +169,32 @@ def nexgen_experiment_type(self) -> str:
def ispyb_experiment_type(self) -> SSXType:
return SSXType.FIXED

@property
def detector_params(self):
det_dist_to_beam_lut = BEAM_CENTER_LUT_FILES[self.detector_name]
det_size_constants = (
EIGER2_X_9M_SIZE
if self.detector_name is DetectorName.EIGER
else PILATUS_6M_SIZE
)

self.collection_directory.mkdir(parents=True, exist_ok=True)

return DetectorParams(
detector_size_constants=det_size_constants,
exposure_time=self.exposure_time_s,
directory=self.collection_directory.as_posix(),
prefix=self.filename,
detector_distance=self.detector_distance_mm,
omega_start=0.0,
omega_increment=0.0,
num_images_per_trigger=self.num_exposures,
num_triggers=self.total_num_images,
det_dist_to_beam_converter_path=det_dist_to_beam_lut.as_posix(),
use_roi_mode=False, # Dasabled
trigger_mode=TriggerMode.SET_FRAMES, # For now...
)

@computed_field # type: ignore # Mypy doesn't like it
@property
def total_num_images(self) -> int:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

import bluesky.plan_stubs as bps
from dodal.beamlines import i24
from dodal.devices.detector.detector import DetectorParams
from dodal.devices.i24.aperture import Aperture, AperturePositions
from dodal.devices.i24.beam_center import DetectorBeamCenter
from dodal.devices.i24.beamstop import Beamstop, BeamstopPositions
from dodal.devices.i24.dual_backlight import BacklightPositions, DualBacklight
from dodal.devices.i24.i24_detector_motion import DetectorMotion

from mx_bluesky.beamlines.i24.serial.log import SSX_LOGGER
from mx_bluesky.beamlines.i24.serial.parameters.constants import BEAM_CENTER_POS
from mx_bluesky.beamlines.i24.serial.setup_beamline import pv
from mx_bluesky.beamlines.i24.serial.setup_beamline.ca import caget, caput

Expand Down Expand Up @@ -55,22 +55,20 @@ def move_detector_stage_to_position_plan(

def set_detector_beam_center_plan(
beam_center_device: DetectorBeamCenter,
detector_name: str,
detector_params: DetectorParams,
detector_distace: float,
group: str = "set_beamcenter",
wait: bool = True,
):
"""A small temporary plan to set up the beam center on the detector in use."""
# NOTE This will be removed once the detectors are using ophyd_async devices
# See https://github.com/DiamondLightSource/mx-bluesky/issues/62
SSX_LOGGER.debug(
f"Set beam center on {detector_name} detector: {BEAM_CENTER_POS[detector_name]}"
)
yield from bps.abs_set(
beam_center_device.beam_x, BEAM_CENTER_POS[detector_name][0], group=group
)
yield from bps.abs_set(
beam_center_device.beam_y, BEAM_CENTER_POS[detector_name][1], group=group
beam_position_x, beam_position_y = detector_params.get_beam_position_pixels(
detector_distace
)
SSX_LOGGER.info(f"Setting beam center to: {beam_position_x}, {beam_position_y}")
yield from bps.abs_set(beam_center_device.beam_x, beam_position_x, group=group)
yield from bps.abs_set(beam_center_device.beam_y, beam_position_y, group=group)
if wait:
yield from bps.wait(group=group)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#Table giving position of beam X and Y as a function of detector distance
#Units mm mm mm
# Eiger values
# distance beamY beamX (values from mosflm)
Units mm mm mm
200 119.78 127.0
1500 119.4 126.9
27 changes: 23 additions & 4 deletions tests/unit_tests/beamlines/i24/serial/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
from __future__ import annotations

from pathlib import Path
from unittest.mock import patch

import pytest
from dodal.beamlines import i24
from dodal.devices.hutch_shutter import (
Expand All @@ -21,17 +24,25 @@

from mx_bluesky.beamlines.i24.serial.fixed_target.ft_utils import ChipType
from mx_bluesky.beamlines.i24.serial.parameters import (
DetectorName,
ExtruderParameters,
FixedTargetParameters,
get_chip_format,
)

TEST_PATH = Path("tests/test_data/test_daq_configuration")

TEST_LUT = {
DetectorName.EIGER: TEST_PATH / "lookup/test_det_dist_converter.txt",
DetectorName.PILATUS: TEST_PATH / "lookup/test_det_dist_converter.txt",
}


@pytest.fixture
def dummy_params_without_pp():
oxford_defaults = get_chip_format(ChipType.Oxford)
params = {
"visit": "foo",
"visit": "/tmp/dls/i24/fixed/foo",
"directory": "bar",
"filename": "chip",
"exposure_time_s": 0.01,
Expand All @@ -45,13 +56,17 @@ def dummy_params_without_pp():
"checker_pattern": False,
"chip_map": [1],
}
return FixedTargetParameters(**params)
with patch(
"mx_bluesky.beamlines.i24.serial.parameters.experiment_parameters.BEAM_CENTER_LUT_FILES",
new=TEST_LUT,
):
yield FixedTargetParameters(**params)


@pytest.fixture
def dummy_params_ex():
params = {
"visit": "foo",
"visit": "/tmp/dls/i24/extruder/foo",
"directory": "bar",
"filename": "protein",
"exposure_time_s": 0.1,
Expand All @@ -61,7 +76,11 @@ def dummy_params_ex():
"num_images": 10,
"pump_status": False,
}
return ExtruderParameters(**params)
with patch(
"mx_bluesky.beamlines.i24.serial.parameters.experiment_parameters.BEAM_CENTER_LUT_FILES",
new=TEST_LUT,
):
yield ExtruderParameters(**params)


def patch_motor(motor: Motor, initial_position: float = 0):
Expand Down
Loading
Loading