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
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 @@ -111,6 +111,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 @@ -131,7 +132,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 @@ -4,13 +4,18 @@
from unittest.mock import ANY, MagicMock, patch

import bluesky.plan_stubs as bps
import numpy
import numpy as np
import pytest
from bluesky.run_engine import RunEngine
from bluesky.simulators import RunEngineSimulator, assert_message_and_return_remaining
from bluesky.utils import Msg
from ophyd.sim import NullStatus

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.parameters.gridscan import GridScanWithEdgeDetect
Expand All @@ -19,7 +24,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 @@ -30,39 +34,46 @@
from mx_bluesky.hyperion.parameters.gridscan import (
HyperionThreeDGridScan,
)
from tests.conftest import pin_tip_edge_data

from ..conftest import OavGridSnapshotTestEvents
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])


def _fake_generator_array(values):
return [_fake_generator(value) for value in values]


def _fake_generator(value):
yield from bps.null()
return value

# Try to move all this into conftest, so that other tests can use it
# refactor the other tests in test_load_centre_collect_full_plan.py to also use
# (where I pinched this code from)
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
):
with patch.object(ophyd_pin_tip_detection, "trigger", side_effect=find_a_pin(ophyd_pin_tip_detection)):
yield ophyd_pin_tip_detection


def test_full_grid_scan(
test_fgs_params: HyperionThreeDGridScan, test_config_files: dict[str, str]
):
Expand All @@ -84,24 +95,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 +117,13 @@ 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()
# Don't assert this - instead verify that the flyscan was called with the expected
# parameters of the grid that we detected. In fact this check is the same as the
# test_when_full_grid_scan_run_then_parameters_sent_to_fgs_as_expected
# so you may as well just remove this assert completely
# mock_pre_centring_setup_oav.assert_called_once()

# Check backlight was moved OUT
get_mock_put(composite.backlight.position).assert_called_once_with(
Expand Down Expand Up @@ -141,25 +151,22 @@ 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
test_full_grid_scan_params.grid_width_um = 200
shihab-dls marked this conversation as resolved.
Show resolved Hide resolved

RE(
ispyb_activation_wrapper(
detect_grid_and_do_gridscan(
Expand All @@ -173,8 +180,9 @@ def test_when_full_grid_scan_run_then_parameters_sent_to_fgs_as_expected(

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

# Need to twiddle these values, or the values in the pin_tip_detection_with_found_pin
# fixture, so that they match up
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)

Expand Down Expand Up @@ -241,22 +249,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 +271,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
Loading