Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -3,7 +3,7 @@
from bluesky.callbacks import CallbackBase
from dodal.log import LOGGER
from event_model.documents import RunStart, RunStop
from heliotrapi.client import AnalysisClient
from heliotrapi.client import AnalysisClient, AnalysisResult

I15_1_ANALYSIS_URL = "https://i15-1-analysis.diamond.ac.uk"

Expand Down Expand Up @@ -47,9 +47,9 @@ def stop(self, doc: RunStop) -> RunStop | None:
)
LOGGER.info(f"Submitted analysis request {self.request_id}")

def wait_on_and_retrieve_result(self):
def wait_on_and_retrieve_result(self) -> AnalysisResult:
if not self.request_id:
raise ValueError("Results requested but analysis has not been triggered")
result = self._client.get_request_id_result(self.request_id)
LOGGER.info(f"Received result from analysis {result} for {self.request_id}")
return result.result
return result
4 changes: 3 additions & 1 deletion src/crystallography_bluesky/i15_1/plans/centre_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,13 @@ def per_step():
)

analysis_result = analysis_callback.wait_on_and_retrieve_result()
centre = analysis_result["centre"]
centre = analysis_result.result["centre"]
assert (start_z < centre < end_z) or (start_z > centre > end_z), (
f"Analysis result {centre} is not within the bounds of the scan: "
+ f"({start_z, end_z})"
)
LOGGER.info(f"Got {centre} from analysis, moving there now")

yield from bps.mv(hexapod.z, centre)

return analysis_result
3 changes: 3 additions & 0 deletions src/crystallography_bluesky/i15_1/plans/generic_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from dodal.common import inject
from dodal.common.beamlines.beamline_utils import get_config_client
from dodal.devices.beamlines.i15_1.attenuators import FastAttenuator, SlowAttenuator
from dodal.devices.beamlines.i15_1.hexapod import Hexapod
from dodal.devices.beamlines.i15_1.laue import LaueMonochrometer
from dodal.devices.beamlines.i15_1.robot import Robot
from dodal.devices.synchrotron import Synchrotron
Expand Down Expand Up @@ -63,6 +64,7 @@ class GenericCollectionDevices:
fast_attenuator: FastAttenuator
slow_attenuator: SlowAttenuator
synchrotron: Synchrotron
hexapod: Hexapod


def get_default_baseline_devices(all_devices: GenericCollectionDevices):
Expand All @@ -72,6 +74,7 @@ def get_default_baseline_devices(all_devices: GenericCollectionDevices):
all_devices.tth,
all_devices.fast_attenuator,
all_devices.slow_attenuator,
all_devices.hexapod,
]


Expand Down
2 changes: 1 addition & 1 deletion tests/unit_tests/i15_1/callbacks/test_analysis_callback.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def test_wait_on_and_retrieve_result(mock_client_cls):
callback = TriggerAnalysisCallback("url", "analysis")
callback.request_id = MagicMock()

assert callback.wait_on_and_retrieve_result() == 42
assert callback.wait_on_and_retrieve_result().result == 42
mock_client.get_request_id_result.assert_called_once()


Expand Down
8 changes: 5 additions & 3 deletions tests/unit_tests/i15_1/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
from dodal.devices.beamlines.i15_1.attenuators import FastAttenuator, SlowAttenuator
from dodal.devices.beamlines.i15_1.beam_health import BeamHealth
from dodal.devices.beamlines.i15_1.blower import Blower
from dodal.devices.beamlines.i15_1.hexapod import Hexapod
from dodal.devices.beamlines.i15_1.cobra import Cobra
from dodal.devices.beamlines.i15_1.laue import LaueMonochrometer
from dodal.devices.beamlines.i15_1.robot import Robot
from dodal.devices.motors import XYZStage
from dodal.devices.synchrotron import Synchrotron
from dodal.devices.tetramm import SummingTetrammDetector
from dodal.devices.zebra.zebra import Zebra, ZebraMapping
Expand Down Expand Up @@ -115,9 +115,9 @@ async def fast_shutter() -> ZebraFastShutter:


@pytest.fixture
async def hexapod() -> XYZStage:
async def hexapod() -> Hexapod:
async with init_devices(mock=True):
hexapod = XYZStage("")
hexapod = Hexapod("", "")
return hexapod


Expand Down Expand Up @@ -154,6 +154,7 @@ async def common_collection_devices(
slow_attenuator: SlowAttenuator,
fast_attenuator: FastAttenuator,
synchrotron: Synchrotron,
hexapod: Hexapod,
) -> GenericCollectionDevices:
return GenericCollectionDevices(
eiger,
Expand All @@ -166,6 +167,7 @@ async def common_collection_devices(
fast_attenuator,
slow_attenuator,
synchrotron,
hexapod,
)


Expand Down
24 changes: 18 additions & 6 deletions tests/unit_tests/i15_1/test_centre_sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
import pytest
from bluesky.run_engine import RunEngine
from bluesky.run_engine import RunEngine, RunEngineResult
from bluesky.simulators import RunEngineSimulator, assert_message_and_return_remaining
from dodal.devices.motors import XYZStage
from heliotrapi.models import AnalysisResult
Expand All @@ -24,7 +24,7 @@
@pytest.fixture
def blueapi_run_engine():
# This adds the info the blueapi will add in prod
RE = RunEngine()
RE = RunEngine(call_returns_result=True)
RE.md["data_session_directory"] = "/dls/i15-1/data/2026/cm44163-3"
RE.md["scan_file"] = "i15-1-95557"
return RE
Expand All @@ -36,7 +36,9 @@ def mock_analysis_callback():
"crystallography_bluesky.i15_1.plans.centre_sample.TriggerAnalysisCallback"
) as patch_analysis_callback:
instance = patch_analysis_callback.return_value
instance.wait_on_and_retrieve_result.return_value = {"centre": 15}
instance.wait_on_and_retrieve_result.return_value = AnalysisResult(
result={"centre": 15}, status="completed", analysis_name="centring"
)
yield patch_analysis_callback


Expand All @@ -50,7 +52,7 @@ def mock_analysis_client():
analysis_name="fake_sample_alignment_i15_1",
result={"centre": 17},
status="completed",
created_at=datetime.now(),
created_at=datetime(2026, 10, 20, 14, 35, 46, 96041),
)

yield mock_client
Expand Down Expand Up @@ -261,7 +263,7 @@ def test_centre_sample_moved_to_start_before_stage(


@patch("crystallography_bluesky.i15_1.plans.centre_sample.generic_per_step_collection")
def test_centre_sample_calls_analysis_and_retrieves_result(
def test_centre_sample_calls_analysis_and_retrieves_and_returns_result(
mock_generic_collection: MagicMock,
mock_analysis_client: MagicMock,
hexapod: XYZStage,
Expand All @@ -276,12 +278,22 @@ def my_plan(*_, **__):
yield from bps.null()

mock_generic_collection.side_effect = my_plan
blueapi_run_engine(
result = blueapi_run_engine(
centre_sample(10, 20, 10, 0.01, generic_collection_devices, hexapod)
)

mock_analysis_client.submit.assert_called_once()
mock_analysis_client.get_request_id_result.assert_called_once()
assert isinstance(result, RunEngineResult) and result.plan_result == AnalysisResult(
request_id=None,
status="completed",
analysis_name="fake_sample_alignment_i15_1",
inputs=None,
result={"centre": 17},
created_at=datetime(2026, 10, 20, 14, 35, 46, 96041),
finished_at=None,
version="0.3.3",
)


@patch("crystallography_bluesky.i15_1.plans.centre_sample.generic_per_step_collection")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def fake_setup(*_, **__):
common_collection_devices.xtal,
common_collection_devices.fast_attenuator,
common_collection_devices.slow_attenuator,
common_collection_devices.hexapod,
]
+ baseline_devices
)
Expand Down
Loading