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 production grid detection plan in unit tests #721

Merged
merged 12 commits into from
Jan 8, 2025
22 changes: 22 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
from dodal.devices.i03.beamstop import Beamstop, BeamstopPositions
from dodal.devices.oav.oav_detector import OAV, OAVConfig
from dodal.devices.oav.oav_parameters import OAVParameters
from dodal.devices.oav.pin_image_recognition import PinTipDetection
from dodal.devices.robot import BartRobot
from dodal.devices.s4_slit_gaps import S4SlitGaps
from dodal.devices.smargon import Smargon
Expand Down Expand Up @@ -998,6 +999,27 @@ def pin_tip_edge_data():
return tip_x_px, tip_y_px, top_edge_array, bottom_edge_array


def find_a_pin(pin_tip_detection):
def set_good_position():
x, y, top_edge_array, bottom_edge_array = pin_tip_edge_data()
set_mock_value(pin_tip_detection.triggered_tip, numpy.array([x, y]))
set_mock_value(pin_tip_detection.triggered_top_edge, top_edge_array)
set_mock_value(pin_tip_detection.triggered_bottom_edge, bottom_edge_array)
return NullStatus()

return set_good_position


@pytest.fixture
def pin_tip_detection_with_found_pin(ophyd_pin_tip_detection: PinTipDetection):
with patch.object(
ophyd_pin_tip_detection,
"trigger",
side_effect=find_a_pin(ophyd_pin_tip_detection),
):
yield ophyd_pin_tip_detection


# Prevent pytest from catching exceptions when debugging in vscode so that break on
# exception works correctly (see: https://github.com/pytest-dev/pytest/issues/7409)
if os.getenv("PYTEST_RAISE", "0") == "1":
Expand Down
3 changes: 2 additions & 1 deletion tests/unit_tests/hyperion/experiment_plans/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def grid_detect_devices(
eiger: EigerDetector,
smargon: Smargon,
oav: OAV,
ophyd_pin_tip_detection: PinTipDetection,
zocalo: ZocaloResults,
synchrotron: Synchrotron,
fast_grid_scan: ZebraFastGridScan,
Expand All @@ -134,7 +135,7 @@ def grid_detect_devices(
zebra_fast_grid_scan=fast_grid_scan,
flux=MagicMock(spec=Flux),
oav=oav,
pin_tip_detection=MagicMock(spec=PinTipDetection),
pin_tip_detection=ophyd_pin_tip_detection,
smargon=smargon,
synchrotron=synchrotron,
s4_slit_gaps=MagicMock(spec=S4SlitGaps),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from dodal.devices.aperturescatterguard import ApertureValue
from dodal.devices.backlight import BacklightPosition
from dodal.devices.oav.oav_parameters import OAVParameters
from dodal.devices.oav.pin_image_recognition import PinTipDetection
from ophyd_async.testing import get_mock_put, set_mock_value

from mx_bluesky.common.external_interaction.callbacks.xray_centre.ispyb_callback import (
Expand All @@ -22,7 +23,6 @@
)
from mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan import (
GridDetectThenXRayCentreComposite,
OavGridDetectionComposite,
detect_grid_and_do_gridscan,
grid_detect_then_xray_centre,
)
Expand All @@ -35,31 +35,7 @@
from .conftest import FLYSCAN_RESULT_LOW, FLYSCAN_RESULT_MED, sim_fire_event_on_open_run


def _fake_grid_detection(
devices: OavGridDetectionComposite,
parameters: OAVParameters,
snapshot_template: str,
snapshot_dir: str,
grid_width_microns: float = 0,
box_size_um: float = 0.0,
):
oav = devices.oav
set_mock_value(oav.grid_snapshot.box_width, 635)
# first grid detection: x * y
set_mock_value(oav.grid_snapshot.num_boxes_x, 10)
set_mock_value(oav.grid_snapshot.num_boxes_y, 4)
yield from bps.create(CONST.DESCRIPTORS.OAV_GRID_SNAPSHOT_TRIGGERED)
yield from bps.read(oav) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
yield from bps.read(devices.smargon)
yield from bps.save()

# second grid detection: x * z, so num_boxes_y refers to smargon z
set_mock_value(oav.grid_snapshot.num_boxes_x, 10)
set_mock_value(oav.grid_snapshot.num_boxes_y, 1)
yield from bps.create(CONST.DESCRIPTORS.OAV_GRID_SNAPSHOT_TRIGGERED)
yield from bps.read(oav) # type: ignore # See: https://github.com/bluesky/bluesky/issues/1809
yield from bps.read(devices.smargon)
yield from bps.save()
def _fake_flyscan(*args):
yield from _fire_xray_centre_result_event([FLYSCAN_RESULT_MED, FLYSCAN_RESULT_LOW])


Expand All @@ -84,24 +60,18 @@ def grid_detect_devices_with_oav_config_params(
return grid_detect_devices


@patch(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.grid_detection_plan",
autospec=True,
)
@patch(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.flyscan_xray_centre_no_move",
autospec=True,
)
async def test_detect_grid_and_do_gridscan(
mock_flyscan: MagicMock,
mock_grid_detection_plan: MagicMock,
pin_tip_detection_with_found_pin: PinTipDetection,
grid_detect_devices_with_oav_config_params: GridDetectThenXRayCentreComposite,
RE: RunEngine,
test_full_grid_scan_params: GridScanWithEdgeDetect,
test_config_files: dict,
):
mock_grid_detection_plan.side_effect = _fake_grid_detection

composite = grid_detect_devices_with_oav_config_params

RE(
Expand All @@ -112,8 +82,6 @@ async def test_detect_grid_and_do_gridscan(
test_full_grid_scan_params,
)
)
# Verify we called the grid detection plan
mock_grid_detection_plan.assert_called_once()

# Check backlight was moved OUT
get_mock_put(composite.backlight.position).assert_called_once_with(
Expand Down Expand Up @@ -141,25 +109,20 @@ def _do_detect_grid_and_gridscan_then_wait_for_backlight(
yield from bps.wait(CONST.WAIT.GRID_READY_FOR_DC)


@patch(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.grid_detection_plan",
autospec=True,
)
@patch(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.flyscan_xray_centre_no_move",
autospec=True,
)
def test_when_full_grid_scan_run_then_parameters_sent_to_fgs_as_expected(
mock_flyscan: MagicMock,
mock_grid_detection_plan: MagicMock,
grid_detect_devices_with_oav_config_params: GridDetectThenXRayCentreComposite,
RE: RunEngine,
test_full_grid_scan_params: GridScanWithEdgeDetect,
test_config_files: dict,
pin_tip_detection_with_found_pin: PinTipDetection,
):
oav_params = OAVParameters("xrayCentring", test_config_files["oav_config_json"])

mock_grid_detection_plan.side_effect = _fake_grid_detection
RE(
ispyb_activation_wrapper(
detect_grid_and_do_gridscan(
Expand All @@ -173,10 +136,9 @@ def test_when_full_grid_scan_run_then_parameters_sent_to_fgs_as_expected(

params: HyperionThreeDGridScan = mock_flyscan.call_args[0][1]

assert params.detector_params.num_triggers == 50

assert params.FGS_params.x_axis.full_steps == 10
assert params.FGS_params.y_axis.end == pytest.approx(1.511, 0.001)
assert params.detector_params.num_triggers == 180
assert params.FGS_params.x_axis.full_steps == 15
assert params.FGS_params.y_axis.end == pytest.approx(-0.0649, 0.001)

# Parameters can be serialized
params.model_dump_json()
Expand Down Expand Up @@ -241,22 +203,18 @@ def test_detect_grid_and_do_gridscan_does_not_activate_ispyb_callback(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.change_aperture_then_move_to_xtal",
autospec=True,
)
@patch(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.grid_detection_plan",
autospec=True,
side_effect=_fake_grid_detection,
)
@patch(
"mx_bluesky.hyperion.experiment_plans.grid_detect_then_xray_centre_plan.flyscan_xray_centre_no_move",
autospec=True,
side_effect=_fake_flyscan,
)
def test_grid_detect_then_xray_centre_centres_on_the_first_flyscan_result(
mock_flyscan: MagicMock,
mock_grid_detection_plan: MagicMock,
mock_change_aperture_then_move_to_xtal: MagicMock,
grid_detect_devices_with_oav_config_params: GridDetectThenXRayCentreComposite,
test_full_grid_scan_params: GridScanWithEdgeDetect,
test_config_files: dict[str, str],
pin_tip_detection_with_found_pin: PinTipDetection,
RE: RunEngine,
):
RE(
Expand All @@ -267,6 +225,7 @@ def test_grid_detect_then_xray_centre_centres_on_the_first_flyscan_result(
)
)
mock_change_aperture_then_move_to_xtal.assert_called_once()

assert (
mock_change_aperture_then_move_to_xtal.mock_calls[0].args[0]
== FLYSCAN_RESULT_MED
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ def set_good_position():

@pytest.fixture
def composite(
robot_load_composite, fake_create_rotation_devices, sim_run_engine
robot_load_composite,
fake_create_rotation_devices,
pin_tip_detection_with_found_pin,
sim_run_engine,
) -> LoadCentreCollectComposite:
rlaec_args = {
field.name: getattr(robot_load_composite, field.name)
Expand All @@ -72,6 +75,7 @@ def composite(
}

composite = LoadCentreCollectComposite(**(rlaec_args | rotation_args))
composite.pin_tip_detection = pin_tip_detection_with_found_pin
minaxis = Location(setpoint=-2, readback=-2)
maxaxis = Location(setpoint=2, readback=2)
tip_x_px, tip_y_px, top_edge_array, bottom_edge_array = pin_tip_edge_data()
Expand Down Expand Up @@ -114,9 +118,6 @@ def composite(
sim_run_engine.add_read_handler_for(
composite.pin_tip_detection.triggered_tip, (tip_x_px, tip_y_px)
)
composite.pin_tip_detection.trigger = MagicMock(
side_effect=find_a_pin(composite.pin_tip_detection)
)
return composite


Expand Down
Loading