Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
859b8fc
inital commit - must check to make sure i can find kappa and twotheta
Matt-Carre May 11, 2026
a495a84
has everything that works not commented out
Matt-Carre May 12, 2026
b9157bc
Forgot to change the test - not working stuff commented out
Matt-Carre May 12, 2026
8c4d187
Forgot to change the test - not working stuff commented out - deleted…
Matt-Carre May 12, 2026
d11ceba
removes unessecary wait=True
Matt-Carre May 12, 2026
0de1403
after checking, renamed some params
Matt-Carre May 12, 2026
113eeb6
alters final test
Matt-Carre May 13, 2026
6b74bef
makes sure everything is noted even if not used
Matt-Carre May 13, 2026
a2a1048
updates to work with new dodal - still locked to old dodal in uv
Matt-Carre May 18, 2026
a01db42
Merge branch 'main' into 99_metadata_data
Matt-Carre May 18, 2026
6aae395
merged in main and updated to ophyd async v0.17a4
Matt-Carre May 18, 2026
7d0a4b7
updated to main on pyproject.toml
Matt-Carre May 19, 2026
5765bb8
updated remaining sections
Matt-Carre May 19, 2026
56e40f7
alters code based on tests, uncomments seemingly broken code that sho…
Matt-Carre May 19, 2026
830f378
fixes tests via create_mock_signals
Matt-Carre May 20, 2026
495d6d7
improves coverage
Matt-Carre May 20, 2026
123ddc9
remoed extra stuff in conftest
Matt-Carre May 20, 2026
8da6f9d
alters code based on comments
Matt-Carre May 21, 2026
9a41ec5
Merge remote-tracking branch 'origin/eiger_test_ophyd_ver_17' into be…
noemifrisina May 26, 2026
91f7bd4
Merge branch 'main' into beamline-eiger-test
noemifrisina Jul 24, 2026
ba0e623
Move to INENC3 which is where the new phi axis from the serial stages…
noemifrisina Jul 24, 2026
9931c2a
Start adding the eiger for the collection
noemifrisina Jul 24, 2026
4dfce19
Kickoff and complete collection
noemifrisina Jul 24, 2026
3b2437b
Finish up changes by unstaging during abort and end
noemifrisina Jul 24, 2026
dca5697
Add some logging
noemifrisina Jul 24, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,24 @@ def calculate_beam_centre_from_lut(
return beam_centre_px


def write_eiger_params(
def set_eiger_params(
parameters: SerialExperimentEh2,
energy: float,
wavelength: float,
eiger: EigerDetector,
wait: bool = True,
group: str = "eiger_metadata",
group: str = "eiger_setup",
):
# Odin
# After an acquisition, OdinData’s metawriter sets its acquisitionID to None,
# which is invalid so it needs to be set at least to an empty string
yield from bps.abs_set(eiger.od.acquisition_id, "", wait=True)
yield from bps.abs_set(
eiger.od.file_path, parameters.collection_directory, wait=True
)
yield from bps.abs_set(eiger.od.file_prefix, parameters.filename_prefix, wait=True)

# Eiger config
beam_centre = calculate_beam_centre_from_lut(
parameters.detector_distance_mm,
parameters.detector_constants.DET_SIZE_CONSTANTS,
Expand Down
3 changes: 2 additions & 1 deletion src/i19_bluesky/serial/panda_plans/panda_setup_plans.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,6 @@ def reset_panda(panda: HDFPanda, group="reset_panda"):
DeviceSettingsConstants.PANDA_THROUGH_ZEBRA,
panda,
)
yield from bps.abs_set(panda.outenc[1].val, "INENC1.VAL", group=group) # type: ignore
# Moved to INENC3 as that's there the new serial stages are connected
yield from bps.abs_set(panda.outenc[1].val, "INENC3.VAL", group=group) # type: ignore
yield from bps.abs_set(panda.outenc[2].val, "INENC2.VAL", group=group) # type: ignore
3 changes: 2 additions & 1 deletion src/i19_bluesky/serial/panda_plans/panda_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,5 @@ def generate_panda_seq_table(

def setup_outenc_vals(panda: HDFPanda, group="setup_outenc_vals"):
yield from bps.abs_set(panda.outenc[1].val, "ZERO", group=group) # type: ignore
yield from bps.abs_set(panda.outenc[2].val, "INENC1.VAL", group=group) # type: ignore
# Moved to INENC3 as that's there the new serial stages are connected
yield from bps.abs_set(panda.outenc[2].val, "INENC3.VAL", group=group) # type: ignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def trigger_panda_collection(
)
LOGGER.info("Arm panda and move phi")
yield from arm_panda(devices.panda)
LOGGER.info("Arm eiger")
yield from bps.trigger(devices.eiger.detector.arm)
LOGGER.info("Kickoff eiger")
yield from bps.kickoff(devices.eiger, wait=True)
for i, (well_num, coords) in enumerate(parameters.wells_to_collect.items()):
yield from move_stage_x_and_z(coords[0], coords[2], devices.serial_stages)
LOGGER.info(f"Moved to well {well_num}")
Expand All @@ -63,3 +63,5 @@ def trigger_panda_collection(
parameters.panda_rotation_params.scan_start_deg,
wait=True,
)
LOGGER.debug("Complete")
yield from bps.complete(devices.eiger, wait=True)
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def run_on_collection_end(
serial_stages: XYZPhiStage,
shutter: AccessControlledShutter,
):
LOGGER.info("Disarm eiger")
yield from bps.trigger(eiger.detector.disarm)
LOGGER.info("Unstage eiger")
yield from bps.unstage(eiger, wait=True)
LOGGER.info("Disarm panda")
yield from disarm_panda(panda)
yield from reset_panda(panda)
Expand All @@ -63,7 +63,7 @@ def run_on_collection_abort(
) -> MsgGenerator:
LOGGER.warning("ABORT")
yield from bps.abs_set(diffractometer.phi.motor_stop, 1, wait=True)
yield from bps.trigger(eiger.detector.disarm)
yield from bps.unstage(eiger, wait=True)
yield from disarm_panda(panda)


Expand Down
36 changes: 28 additions & 8 deletions src/i19_bluesky/serial/setup_beamline_plans/setup_beamline.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
PinColRequest,
PinholeCollimatorControl,
)
from ophyd_async.core import DetectorTrigger, TriggerInfo

from i19_bluesky.eh2.backlight_plan import move_backlight_out
from i19_bluesky.eh2.pincol_control_plans import move_pin_col_to_requested_in_position
Expand All @@ -19,23 +20,21 @@
move_detector_stage,
setup_sample_stage,
)
from i19_bluesky.serial.device_setup_plans.eiger_metadata import write_eiger_params
from i19_bluesky.serial.device_setup_plans.eiger_setup_plans import set_eiger_params


def setup_eh2_serial_collection(
parameters: SerialExperimentEh2,
devices: SerialCollectionEh2PandaComposite,
) -> MsgGenerator:
# Stage detector
LOGGER.info("Stage detector")
yield from bps.stage(devices.eiger)
# Open shutter
LOGGER.info("Open experiment shutter if EH2 is the active hutch")
yield from open_experiment_shutter(devices.shutter)
# Set up eiger - TO BE ADDED - IN SEPARATE BRANCH
# Read energy and wavelength from dcm to then set up eiger
energ_in_kev = yield from bps.rd(devices.energy_device.energy_in_kev)
wavelength_in_a = yield from bps.rd(devices.energy_device.wavelength_in_a)
yield from write_eiger_params(
parameters, energ_in_kev, wavelength_in_a, devices.eiger
)
# Set up beamline for collection
LOGGER.info("Set up the beamline before collection")
yield from setup_beamline_for_collection(
parameters.aperture_request,
parameters.detector_distance_mm,
Expand All @@ -45,9 +44,30 @@ def setup_eh2_serial_collection(
devices.diffractometer,
)
# Set up sample stage
LOGGER.info("Move phi to start")
yield from setup_sample_stage(
parameters.panda_rotation_params, devices.serial_stages
)
# Read energy and wavelength from dcm to then set up eiger
LOGGER.info("Set up and prepare the eiger for collection")
energ_in_kev = yield from bps.rd(devices.energy_device.energy_in_kev)
wavelength_in_a = yield from bps.rd(devices.energy_device.wavelength_in_a)
yield from set_eiger_params(
parameters, energ_in_kev, wavelength_in_a, devices.eiger
)
# Set ntriggers
# See https://github.com/bluesky/ophyd-async/issues/1288
yield from bps.abs_set(
devices.eiger.detector.ntrigger, parameters.total_num_images, wait=True
)
trigger_info = TriggerInfo(
collections_per_event=1,
number_of_events=1,
trigger=DetectorTrigger.EXTERNAL_EDGE,
livetime=parameters.exposure_time_s,
)
# Prepare
yield from bps.prepare(devices.eiger, trigger_info, wait=True)


def setup_beamline_for_collection(
Expand Down
21 changes: 12 additions & 9 deletions tests/unit_tests/serial/device_setup_plans/test_eiger_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
from ophyd_async.fastcs.eiger import EigerDetector

from i19_bluesky.parameters.serial_parameters import SerialExperimentEh2
from i19_bluesky.serial.device_setup_plans.eiger_metadata import (
from i19_bluesky.serial.device_setup_plans.eiger_setup_plans import (
_convert_beam_centre_to_pixels,
_read_converter_lut,
calculate_beam_centre_from_lut,
write_eiger_params,
set_eiger_params,
)

LUT_FILE = """
Expand All @@ -34,7 +34,7 @@ def test_convert_bc_to_pix(parameters):
assert beam_y == pytest.approx(133.33, 1e-2)


@patch("i19_bluesky.serial.device_setup_plans.eiger_metadata.get_config_client")
@patch("i19_bluesky.serial.device_setup_plans.eiger_setup_plans.get_config_client")
def test_read_converter_lut(mock_config_client: MagicMock):
file_contents = DetectorXYLookupTable.from_contents(LUT_FILE)
mock_config_client.return_value.get_file_contents.return_value = file_contents
Expand All @@ -43,7 +43,7 @@ def test_read_converter_lut(mock_config_client: MagicMock):
assert cols == lut_columns


@patch("i19_bluesky.serial.device_setup_plans.eiger_metadata._read_converter_lut")
@patch("i19_bluesky.serial.device_setup_plans.eiger_setup_plans._read_converter_lut")
def test_calculate_beam_centre_from_lut(
mock_read_lut: MagicMock, parameters: SerialExperimentEh2
):
Expand All @@ -59,11 +59,11 @@ def test_calculate_beam_centre_from_lut(


@pytest.mark.parametrize("wait", [(False, True)])
@patch("i19_bluesky.serial.device_setup_plans.eiger_metadata.bps.wait")
@patch("i19_bluesky.serial.device_setup_plans.eiger_setup_plans.bps.wait")
@patch(
"i19_bluesky.serial.device_setup_plans.eiger_metadata.calculate_beam_centre_from_lut"
"i19_bluesky.serial.device_setup_plans.eiger_setup_plans.calculate_beam_centre_from_lut"
)
async def test_write_eiger_params(
async def test_set_eiger_params(
mock_bc_from_lut: MagicMock,
mock_bps_wait: MagicMock,
eh2_eiger: EigerDetector,
Expand All @@ -74,14 +74,17 @@ async def test_write_eiger_params(
mock_bc_from_lut.return_value = (100, 200)

RE(
write_eiger_params(
set_eiger_params(
parameters,
17,
0.6,
eh2_eiger,
wait=wait,
)
)
assert await eh2_eiger.od.acquisition_id.get_value() == ""
assert await eh2_eiger.od.file_path.get_value() == "/tmp/i19-2/cm12345-1/foo"
assert await eh2_eiger.od.file_prefix.get_value() == "bar_01"
assert await eh2_eiger.detector.detector_distance.get_value() == 320
assert await eh2_eiger.detector.beam_center_x.get_value() == 100
assert await eh2_eiger.detector.beam_center_y.get_value() == 200
Expand All @@ -97,4 +100,4 @@ async def test_write_eiger_params(
assert await eh2_eiger.detector.kappa_start.get_value() == 0 # type:ignore
assert await eh2_eiger.detector.kappa_increment.get_value() == 0 # type:ignore
if wait:
mock_bps_wait.assert_called_once_with("eiger_metadata")
mock_bps_wait.assert_called_once_with("eiger_setup")
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async def test_reset_panda(mock_panda: HDFPanda, RE: RunEngine):

assert (
await mock_panda.outenc[1].val.get_value() # type: ignore
== "INENC1.VAL"
== "INENC3.VAL"
)
assert (
await mock_panda.outenc[2].val.get_value() # type: ignore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ async def test_setup_outenc_vals(mock_panda: HDFPanda, RE: RunEngine):
RE(setup_outenc_vals(mock_panda, group="setup_outenc_vals"))

assert await mock_panda.outenc[1].val.get_value() == PandaBitMux.ZERO # type: ignore
assert await mock_panda.outenc[2].val.get_value() == "INENC1.VAL" # type: ignore
assert await mock_panda.outenc[2].val.get_value() == "INENC3.VAL" # type: ignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
)


@patch("i19_bluesky.serial.run_panda_plans.panda_serial_collection.bps.trigger")
@patch("i19_bluesky.serial.run_panda_plans.panda_serial_collection.bps.complete")
@patch("i19_bluesky.serial.run_panda_plans.panda_serial_collection.bps.kickoff")
@patch("i19_bluesky.serial.run_panda_plans.panda_serial_collection.bps.abs_set")
@patch("i19_bluesky.serial.run_panda_plans.panda_serial_collection.move_stage_x_and_z")
@patch("i19_bluesky.serial.run_panda_plans.panda_serial_collection.arm_panda")
Expand All @@ -21,7 +22,8 @@ def test_trigger_panda_call_order(
mock_arm_panda: MagicMock,
mock_move_stage_x_and_z: MagicMock,
mock_set_value_for_params: MagicMock,
mock_arm_or_disarm: MagicMock,
mock_kickoff: MagicMock,
mock_complete: MagicMock,
parameters: SerialExperimentEh2,
devices: SerialCollectionEh2PandaComposite,
RE: RunEngine,
Expand All @@ -35,17 +37,19 @@ def test_trigger_panda_call_order(
mock_setup_panda_for_rotation, "mock_setup_panda_for_rotation"
)
parent_mock.attach_mock(mock_arm_panda, "mock_arm_panda")
parent_mock.attach_mock(mock_arm_or_disarm, "mock_arm_or_disarm")
parent_mock.attach_mock(mock_kickoff, "mock_kickoff")
parent_mock.attach_mock(mock_complete, "mock_complete")
RE(trigger_panda_collection(parameters, devices))
expected_calls = [
call.mock_setup_panda_for_rotation(
parameters.panda_rotation_params, devices.panda
),
call.mock_arm_panda(devices.panda),
call.mock_arm_or_disarm(devices.eiger.detector.arm),
call.mock_kickoff(devices.eiger, wait=True),
call.mock_move_stage_x_and_z(0, 0, devices.serial_stages),
call.mock_move_stage_x_and_z(1, 0, devices.serial_stages),
call.mock_set_value_for_params(devices.diffractometer.phi, 6.0, wait=True),
call.mock_set_value_for_params(devices.diffractometer.phi, 5.0, wait=True),
call.mock_complete(devices.eiger, wait=True),
]
parent_mock.assert_has_calls(expected_calls, any_order=True)
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,17 @@ async def test_main_collection_plan(
mock_trigger_panda.assert_called_once_with(parameters, devices)


@patch("i19_bluesky.serial.run_panda_plans.run_serial_with_panda.bps.trigger")
@patch("i19_bluesky.serial.run_panda_plans.run_serial_with_panda.bps.unstage")
@patch("i19_bluesky.serial.run_panda_plans.run_serial_with_panda.disarm_panda")
async def test_run_on_collection_abort(
mock_disarm_panda: MagicMock,
mock_disarm_eiger: MagicMock,
mock_unstage_eiger: MagicMock,
RE: RunEngine,
devices: SerialCollectionEh2PandaComposite,
):
RE(run_on_collection_abort(devices.panda, devices.eiger, devices.diffractometer))
get_mock_put(devices.diffractometer.phi.motor_stop).assert_called_once_with(1)
mock_disarm_eiger.assert_called_once_with(devices.eiger.detector.disarm)
mock_unstage_eiger.assert_called_once_with(devices.eiger, wait=True)
mock_disarm_panda.assert_called_once_with(devices.panda)


Expand All @@ -73,11 +73,11 @@ async def test_run_on_collection_abort(
@patch(
"i19_bluesky.serial.run_panda_plans.run_serial_with_panda.move_sample_stage_back"
)
@patch("i19_bluesky.serial.run_panda_plans.run_serial_with_panda.bps.trigger")
@patch("i19_bluesky.serial.run_panda_plans.run_serial_with_panda.bps.unstage")
@patch("i19_bluesky.serial.run_panda_plans.run_serial_with_panda.disarm_panda")
async def test_end_run(
mock_disarm_panda: MagicMock,
mock_disarm_eiger: MagicMock,
mock_unstage_eiger: MagicMock,
mock_move_sample_stage_back: MagicMock,
mock_reset_panda: MagicMock,
mock_close_shutter: MagicMock,
Expand All @@ -94,7 +94,7 @@ async def test_end_run(
devices.shutter,
)
)
mock_disarm_eiger.assert_called_once_with(devices.eiger.detector.disarm)
mock_unstage_eiger.assert_called_once_with(devices.eiger, wait=True)
mock_move_sample_stage_back.assert_called_once_with(devices.serial_stages, 0)
mock_disarm_panda.assert_called_once_with(devices.panda)
mock_reset_panda.assert_called_once_with(devices.panda)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from dodal.devices.beamlines.i19.pin_col_stages import (
PinColRequest,
)
from ophyd_async.core import set_mock_value
from ophyd_async.core import DetectorTrigger, TriggerInfo, set_mock_value

from i19_bluesky.parameters.devices_composites import SerialCollectionEh2PandaComposite
from i19_bluesky.parameters.serial_parameters import SerialExperimentEh2
Expand Down Expand Up @@ -72,17 +72,19 @@ async def test_setup_beamline_for_collection(
)


@patch("i19_bluesky.serial.setup_beamline_plans.setup_beamline.write_eiger_params")
@patch("i19_bluesky.serial.setup_beamline_plans.setup_beamline.set_eiger_params")
@patch("i19_bluesky.serial.setup_beamline_plans.setup_beamline.setup_sample_stage")
@patch(
"i19_bluesky.serial.setup_beamline_plans.setup_beamline.setup_beamline_for_collection"
)
@patch("i19_bluesky.serial.setup_beamline_plans.setup_beamline.open_experiment_shutter")
def test_setup_eh2_serial_collection(
@patch("i19_bluesky.serial.setup_beamline_plans.setup_beamline.bps.prepare")
async def test_setup_eh2_serial_collection(
mock_prepare: MagicMock,
mock_open_shutter: MagicMock,
mock_setup: MagicMock,
mock_stage: MagicMock,
mock_write_eiger_params: MagicMock,
mock_set_eiger_params: MagicMock,
parameters: SerialExperimentEh2,
devices: SerialCollectionEh2PandaComposite,
RE: RunEngine,
Expand All @@ -92,12 +94,23 @@ def test_setup_eh2_serial_collection(
RE(setup_eh2_serial_collection(parameters, devices))

mock_open_shutter.assert_called_once_with(devices.shutter)
mock_write_eiger_params.assert_called_once_with(
parameters, 17.9, 0.6, devices.eiger
)
mock_set_eiger_params.assert_called_once_with(parameters, 17.9, 0.6, devices.eiger)
mock_setup.assert_called_once_with(
"100um", 320, 0, devices.backlight, devices.pincol, devices.diffractometer
)
mock_stage.assert_called_once_with(
parameters.panda_rotation_params, devices.serial_stages
)
assert (
await devices.eiger.detector.ntrigger.get_value() == parameters.total_num_images
)
mock_prepare.assert_called_once_with(
devices.eiger,
TriggerInfo(
collections_per_event=1,
number_of_events=1,
trigger=DetectorTrigger.EXTERNAL_EDGE,
livetime=parameters.exposure_time_s,
),
wait=True,
)
Loading