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

Use dodal devices more widely for I24 #116

Merged
merged 12 commits into from
Jul 19, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from dodal.devices.hutch_shutter import HutchShutter, ShutterDemand
from dodal.devices.i24.aperture import Aperture
from dodal.devices.i24.beamstop import Beamstop
from dodal.devices.i24.dcm import DCM
from dodal.devices.i24.dual_backlight import DualBacklight
from dodal.devices.i24.I24_detector_motion import DetectorMotion
from dodal.devices.zebra import DISCONNECT, SOFT_IN3, Zebra
Expand Down Expand Up @@ -185,6 +186,7 @@ def run_extruder_plan(
beamstop: Beamstop = inject("beamstop"),
detector_stage: DetectorMotion = inject("detector_motion"),
shutter: HutchShutter = inject("shutter"),
dcm: DCM = inject("dcm"),
) -> MsgGenerator:
setup_logging()
start_time = datetime.now()
Expand Down Expand Up @@ -358,8 +360,9 @@ def run_extruder_plan(
dcid.notify_start()

if parameters.detector_name == "eiger":
wavelength = yield from bps.rd(dcm.wavelength_in_a)
logger.debug("Call nexgen server for nexus writing.")
call_nexgen(None, start_time, parameters, "extruder")
call_nexgen(None, start_time, parameters, wavelength, "extruder")

aborted = False
timeout_time = time.time() + parameters.num_images * parameters.exposure_time_s + 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from dodal.devices.hutch_shutter import HutchShutter, ShutterDemand
from dodal.devices.i24.aperture import Aperture
from dodal.devices.i24.beamstop import Beamstop
from dodal.devices.i24.dcm import DCM
from dodal.devices.i24.dual_backlight import DualBacklight
from dodal.devices.i24.I24_detector_motion import DetectorMotion
from dodal.devices.i24.pmac import PMAC
Expand Down Expand Up @@ -492,22 +493,23 @@ def start_i24(
# Open the hutch shutter
yield from bps.abs_set(shutter, ShutterDemand.OPEN, wait=True)

return start_time.ctime(), dcid
return start_time, dcid


@log.log_on_entry
def finish_i24(
zebra: Zebra,
pmac: PMAC,
shutter: HutchShutter,
dcm: DCM,
parameters: FixedTargetParameters,
):
logger.info(f"Finish I24 data collection with {parameters.detector_name} detector.")

filepath = parameters.collection_directory
filename = parameters.filename
transmission = (float(caget(pv.pilat_filtertrasm)),)
wavelength = float(caget(pv.dcm_lambda))
wavelength = yield from bps.rd(dcm.wavelength_in_a)

if parameters.detector_name == "pilatus":
logger.debug("Finish I24 Pilatus")
Expand Down Expand Up @@ -578,6 +580,7 @@ def run_fixed_target_plan(
beamstop: Beamstop = inject("beamstop"),
detector_stage: DetectorMotion = inject("detector_motion"),
shutter: HutchShutter = inject("shutter"),
dcm: DCM = inject("dcm"),
) -> MsgGenerator:
setup_logging()
# ABORT BUTTON
Expand Down Expand Up @@ -649,12 +652,14 @@ def run_fixed_target_plan(
logger.debug("Notify DCID of the start of the collection.")
dcid.notify_start()

wavelength = yield from bps.rd(dcm.wavelength_in_a)
if parameters.detector_name == "eiger":
logger.debug("Start nexus writing service.")
call_nexgen(
Copy link
Contributor

Choose a reason for hiding this comment

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

Could: It would be nice to have a test that covered that call_nexgen has been called with the expected params

chip_prog_dict,
start_time,
parameters,
wavelength,
)

logger.info("Data Collection running")
Expand Down Expand Up @@ -714,13 +719,13 @@ def run_fixed_target_plan(
caput(pv.eiger_acquire, 0)
caput(pv.eiger_ODcapture, "Done")

end_time = yield from finish_i24(zebra, pmac, shutter, parameters)
end_time = yield from finish_i24(zebra, pmac, shutter, dcm, parameters)

dcid.collection_complete(end_time, aborted=aborted)
logger.debug("Notify DCID of end of collection.")
dcid.notify_end()

logger.debug("Quick summary of settings")
logger.debug(f"Chip name = {parameters.filename} sub_dir = {parameters.directory}")
logger.debug(f"Start Time = {start_time}")
logger.debug(f"Start Time = {start_time.ctime()}")
logger.debug(f"End Time = {end_time}")
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from blueapi.core import MsgGenerator
from dodal.beamlines import i24
from dodal.common import inject
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 dodal.devices.i24.pmac import PMAC, EncReset, LaserSettings

Expand Down Expand Up @@ -626,7 +628,13 @@ def moveto(place: str = "origin", pmac: PMAC = inject("pmac")) -> MsgGenerator:


@log.log_on_entry
def moveto_preset(place: str, pmac: PMAC = inject("pmac")) -> MsgGenerator:
def moveto_preset(
place: str,
pmac: PMAC = inject("pmac"),
beamstop: Beamstop = inject("beamstop"),
backlight: DualBacklight = inject("backlight"),
det_stage: DetectorMotion = inject("detector_motion"),
) -> MsgGenerator:
setup_logging()

# Non Chip Specific Move
Expand All @@ -636,16 +644,22 @@ def moveto_preset(place: str, pmac: PMAC = inject("pmac")) -> MsgGenerator:

elif place == "load_position":
logger.info("load position")
caput(pv.bs_mp_select, "Robot")
caput(pv.bl_mp_select, "Out")
caput(pv.det_z, 1300)
yield from bps.abs_set(
beamstop.pos_select, BeamstopPositions.ROBOT, group=place
)
yield from bps.abs_set(backlight, BacklightPositions.OUT, group=place)
yield from bps.abs_set(det_stage.z, 1300, group=place)
yield from bps.wait(group=place)

elif place == "collect_position":
logger.info("collect position")
caput(pv.me14e_filter, 20)
yield from bps.mv(pmac.x, 0.0, pmac.y, 0.0, pmac.z, 0.0)
caput(pv.bs_mp_select, "Data Collection")
caput(pv.bl_mp_select, "In")
yield from bps.abs_set(
beamstop.pos_select, BeamstopPositions.DATA_COLLECTION, group=place
)
yield from bps.abs_set(backlight, BacklightPositions.IN, group=place)
yield from bps.wait(group=place)
Comment on lines +658 to +662
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: As above, a mv might be nicer?


elif place == "microdrop_position":
logger.info("microdrop align position")
Expand Down
7 changes: 0 additions & 7 deletions src/mx_bluesky/I24/serial/setup_beamline/pv.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,6 @@ def __which__():
dcm_lambda = "BL24I-MO-DCM-01:LAMBDA"
dcm_energy = "BL24I-MO-DCM-01:ENERGY"

# OLD Mono. Left for short term reference only 10Nov21
# dcm_bragg = 'BL24I-OP-DCM-01:BRAGG'
# dcm_t2 = 'BL24I-OP-DCM-01:T2'
# dcm_roll1 = 'BL24I-OP-DCM-01:ROLL1'
# dcm_pitch2 = 'BL24I-OP-DCM-01:PITCH2'
# dcm_lambda = 'BL24I-OP-DCM-01:LAMBDA'
# dcm_energy = 'BL24I-OP-DCM-01:ENERGY'
# S2
s2_x_plus = "BL24I-AL-SLITS-02:X:PLUS"
s2_x_minus = "BL24I-AL-SLITS-02:X:MINUS"
Expand Down
2 changes: 2 additions & 0 deletions src/mx_bluesky/I24/serial/setup_beamline/pv_abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
Takes the PV tables from I24's setup_beamline and wraps a slightly more
abstract wrapper around them.
"""

from typing import Union

from mx_bluesky.I24.serial.setup_beamline import pv
Expand Down Expand Up @@ -56,6 +57,7 @@ class pv:
detector_distance = pv.eiger_detdist
wavelength = pv.eiger_wavelength
transmission = "BL24I-EA-PILAT-01:cam1:FilterTransm"
filenameRBV = pv.eiger_ODfilenameRBV
file_name = pv.eiger_ODfilename
file_path = pv.eiger_ODfilepath
file_template = None
Expand Down
12 changes: 6 additions & 6 deletions src/mx_bluesky/I24/serial/write_nexus.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,16 @@

from mx_bluesky.I24.serial.fixed_target.ft_utils import ChipType, MappingType
from mx_bluesky.I24.serial.parameters import ExtruderParameters, FixedTargetParameters
from mx_bluesky.I24.serial.setup_beamline import Eiger, caget, cagetstring, pv
from mx_bluesky.I24.serial.setup_beamline import Eiger, caget, cagetstring

logger = logging.getLogger("I24ssx.nexus_writer")


def call_nexgen(
chip_prog_dict: Dict,
chip_prog_dict: Dict | None,
start_time: datetime,
parameters: ExtruderParameters | FixedTargetParameters,
wavelength: float,
expt_type: Literal["fixed-target", "extruder"] = "fixed-target",
):
det_type = parameters.detector_name
Expand All @@ -42,7 +43,7 @@ def call_nexgen(
currentchipmap = None
pump_status = parameters.pump_status

filename_prefix = cagetstring(pv.eiger_ODfilenameRBV)
filename_prefix = cagetstring(Eiger.pv.filenameRBV)
meta_h5 = (
pathlib.Path(parameters.visit)
/ parameters.directory
Expand All @@ -62,8 +63,7 @@ def call_nexgen(
logger.warning(f"Giving up waiting for {meta_h5} after {max_wait} seconds")
return False

transmission = (float(caget(pv.pilat_filtertrasm)),)
wavelength = float(caget(pv.dcm_lambda))
transmission = (float(caget(Eiger.pv.transmission)),)

if det_type == Eiger.name:
logger.debug(
Expand All @@ -76,7 +76,7 @@ def call_nexgen(

payload = {
"beamline": "i24",
"beam_center": [caget(pv.eiger_beamx), caget(pv.eiger_beamy)],
"beam_center": [caget(Eiger.pv.beamx), caget(Eiger.pv.beamy)],
"chipmap": currentchipmap,
"chip_info": chip_prog_dict,
"det_dist": parameters.detector_distance_mm,
Expand Down
7 changes: 7 additions & 0 deletions tests/I24/serial/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
)
from dodal.devices.i24.aperture import Aperture
from dodal.devices.i24.beamstop import Beamstop
from dodal.devices.i24.dcm import DCM
from dodal.devices.i24.dual_backlight import DualBacklight
from dodal.devices.i24.pmac import PMAC
from dodal.devices.zebra import Zebra
Expand Down Expand Up @@ -118,3 +119,9 @@ def pmac(RE):
patch_motor(pmac.z),
):
yield pmac


@pytest.fixture
def dcm(RE) -> DCM:
dcm = i24.dcm(fake_with_ophyd_sim=True)
return dcm
22 changes: 18 additions & 4 deletions tests/I24/serial/extruder/test_extruder_collect.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from unittest.mock import call, patch
from unittest.mock import ANY, call, patch

import bluesky.plan_stubs as bps
import pytest
Expand Down Expand Up @@ -129,7 +129,9 @@ async def test_laser_check(
"mx_bluesky.I24.serial.extruder.i24ssx_Extruder_Collect_py3v2.ExtruderParameters"
)
@patch("mx_bluesky.I24.serial.extruder.i24ssx_Extruder_Collect_py3v2.setup_logging")
@patch("mx_bluesky.I24.serial.extruder.i24ssx_Extruder_Collect_py3v2.bps.rd")
def test_run_extruder_quickshot_with_eiger(
fake_read,
fake_log_setup,
mock_params,
mock_quickshot_plan,
Expand All @@ -149,12 +151,19 @@ def test_run_extruder_quickshot_with_eiger(
backlight,
beamstop,
detector_stage,
dcm,
dummy_params,
):
mock_params.from_file.return_value = dummy_params
fake_det.return_value = Eiger()
RE(run_extruder_plan(zebra, aperture, backlight, beamstop, detector_stage, shutter))
assert fake_nexgen.call_count == 1
fake_read.side_effect = [fake_generator(0.6)] # Wavelength read from dcm
RE(
run_extruder_plan(
zebra, aperture, backlight, beamstop, detector_stage, shutter, dcm
)
)
fake_nexgen.assert_called_once_with(None, ANY, dummy_params, 0.6, "extruder")
# assert fake_nexgen.call_count == 1
assert fake_dcid.call_count == 1
assert fake_sup.setup_beamline_for_collection_plan.call_count == 1
# Check temporary piilatus hack is in there
Expand Down Expand Up @@ -202,11 +211,16 @@ def test_run_extruder_pump_probe_with_pilatus(
backlight,
beamstop,
detector_stage,
dcm,
dummy_params_pp,
):
mock_params.from_file.return_value = dummy_params_pp
fake_det.return_value = Pilatus()
RE(run_extruder_plan(zebra, aperture, backlight, beamstop, detector_stage, shutter))
RE(
run_extruder_plan(
zebra, aperture, backlight, beamstop, detector_stage, shutter, dcm
)
)
assert fake_dcid.call_count == 1
assert fake_sup.move_detector_stage_to_position_plan.call_count == 1
mock_pp_plan.assert_called_once()
Expand Down
35 changes: 27 additions & 8 deletions tests/I24/serial/fixed_target/test_chip_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
from unittest.mock import ANY, MagicMock, call, mock_open, patch

import pytest
from dodal.devices.i24.beamstop import Beamstop
from dodal.devices.i24.dual_backlight import DualBacklight
from dodal.devices.i24.I24_detector_motion import DetectorMotion
from dodal.devices.i24.pmac import PMAC
from ophyd_async.core import get_mock_put

Expand Down Expand Up @@ -96,20 +99,28 @@ async def test_moveto_chip_aspecific(fake_log: MagicMock, pmac: PMAC, RE):
@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_Chip_Manager_py3v1.setup_logging")
@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_Chip_Manager_py3v1.caput")
async def test_moveto_preset(
fake_caput: MagicMock, fake_log: MagicMock, pmac: PMAC, RE
fake_caput: MagicMock,
fake_log: MagicMock,
pmac: PMAC,
beamstop: Beamstop,
backlight: DualBacklight,
detector_stage: DetectorMotion,
RE,
):
RE(moveto_preset("zero", pmac))
RE(moveto_preset("zero", pmac, beamstop, backlight, detector_stage))
assert await pmac.pmac_string.get_value() == "!x0y0z0"

RE(moveto_preset("load_position", pmac))
assert fake_caput.call_count == 3
RE(moveto_preset("load_position", pmac, beamstop, backlight, detector_stage))
assert await beamstop.pos_select.get_value() == "Robot"
assert await backlight.backlight_position.pos_level.get_value() == "Out"
assert await detector_stage.z.user_readback.get_value() == 1300


@pytest.mark.parametrize(
"pos_request, expected_num_caput, expected_pmac_move",
"pos_request, expected_num_caput, expected_pmac_move, other_devices",
[
("collect_position", 3, [0.0, 0.0, 0.0]),
("microdrop_position", 0, [6.0, -7.8, 0.0]),
("collect_position", 1, [0.0, 0.0, 0.0], True),
("microdrop_position", 0, [6.0, -7.8, 0.0], False),
],
)
@patch("mx_bluesky.I24.serial.fixed_target.i24ssx_Chip_Manager_py3v1.setup_logging")
Expand All @@ -120,16 +131,24 @@ async def test_moveto_preset_with_pmac_move(
pos_request: str,
expected_num_caput: int,
expected_pmac_move: List,
other_devices: bool,
pmac: PMAC,
beamstop: Beamstop,
backlight: DualBacklight,
detector_stage: DetectorMotion,
RE,
):
RE(moveto_preset(pos_request, pmac))
RE(moveto_preset(pos_request, pmac, beamstop, backlight, detector_stage))
assert fake_caput.call_count == expected_num_caput

assert await pmac.x.user_readback.get_value() == expected_pmac_move[0]
assert await pmac.y.user_readback.get_value() == expected_pmac_move[1]
assert await pmac.z.user_readback.get_value() == expected_pmac_move[2]

if other_devices:
assert await beamstop.pos_select.get_value() == "Data Collection"
assert await backlight.backlight_position.pos_level.get_value() == "In"


@pytest.mark.parametrize(
"laser_setting, expected_pmac_string",
Expand Down
Loading