Skip to content

Commit

Permalink
Merge branch 'main' into mx_bluesky_634_fix_pin_tip_detect
Browse files Browse the repository at this point in the history
  • Loading branch information
olliesilvester authored Nov 11, 2024
2 parents 3553cac + fc296b5 commit 94e62c3
Show file tree
Hide file tree
Showing 22 changed files with 300 additions and 81 deletions.
27 changes: 14 additions & 13 deletions tests/conftest.py → conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
}

BANNED_PATHS = [Path("/dls"), Path("/dls_sw")]
environ["DODAL_TEST_MODE"] = "true"


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -155,19 +156,6 @@ async def static_path_provider(
return svpp


@pytest.fixture
async def RE():
RE = RunEngine()
# make sure the event loop is thoroughly up and running before we try to create
# any ophyd_async devices which might need it
timeout = time.monotonic() + 1
while not RE.loop.is_running():
await asyncio.sleep(0)
if time.monotonic() > timeout:
raise TimeoutError("This really shouldn't happen but just in case...")
yield RE


@pytest.fixture
def run_engine_documents(RE: RunEngine) -> Mapping[str, list[dict]]:
docs: dict[str, list[dict]] = {}
Expand All @@ -185,3 +173,16 @@ def failed_status(failure: Exception) -> Status:
status = Status()
status.set_exception(failure)
return status


@pytest.fixture
async def RE():
RE = RunEngine()
# make sure the event loop is thoroughly up and running before we try to create
# any ophyd_async devices which might need it
timeout = time.monotonic() + 1
while not RE.loop.is_running():
await asyncio.sleep(0)
if time.monotonic() > timeout:
raise TimeoutError("This really shouldn't happen but just in case...")
yield RE
14 changes: 14 additions & 0 deletions src/dodal/beamlines/i22.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from dodal.devices.synchrotron import Synchrotron
from dodal.devices.tetramm import TetrammDetector
from dodal.devices.undulator import Undulator
from dodal.devices.watsonmarlow323_pump import WatsonMarlow323Pump
from dodal.log import set_beamline as set_log_beamline
from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device

Expand Down Expand Up @@ -376,3 +377,16 @@ def linkam(
wait_for_connection,
fake_with_ophyd_sim,
)


def ppump(
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
) -> WatsonMarlow323Pump:
"""Sample Environment Peristaltic Pump"""
return device_instantiation(
WatsonMarlow323Pump,
"ppump",
"-EA-PUMP-01:",
wait_for_connection,
fake_with_ophyd_sim,
)
8 changes: 4 additions & 4 deletions src/dodal/beamlines/i24.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@
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.i24_vgonio import VGonio
from dodal.devices.i24.pmac import PMAC
from dodal.devices.i24.vgonio import VerticalGoniometer
from dodal.devices.oav.oav_detector import OAV
from dodal.devices.oav.oav_parameters import OAVConfig
from dodal.devices.zebra import Zebra
Expand Down Expand Up @@ -154,12 +154,12 @@ def oav(wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False) ->
@skip_device(lambda: BL == "s24")
def vgonio(
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = False
) -> VGonio:
"""Get the i24 vgonio device, instantiate it if it hasn't already been.
) -> VerticalGoniometer:
"""Get the i24 vertical goniometer device, instantiate it if it hasn't already been.
If this is called when already instantiated, it will return the existing object.
"""
return device_instantiation(
VGonio,
VerticalGoniometer,
"vgonio",
"-MO-VGON-01:",
wait_for_connection,
Expand Down
14 changes: 14 additions & 0 deletions src/dodal/beamlines/p38.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from dodal.devices.slits import Slits
from dodal.devices.tetramm import TetrammDetector
from dodal.devices.undulator import Undulator
from dodal.devices.watsonmarlow323_pump import WatsonMarlow323Pump
from dodal.log import set_beamline as set_log_beamline
from dodal.utils import BeamlinePrefix, get_beamline_name, skip_device

Expand Down Expand Up @@ -315,3 +316,16 @@ def linkam(
wait_for_connection,
fake_with_ophyd_sim,
)


def ppump(
wait_for_connection: bool = True, fake_with_ophyd_sim: bool = True
) -> WatsonMarlow323Pump:
"""Peristaltic Pump"""
return device_instantiation(
WatsonMarlow323Pump,
"ppump",
"-EA-PUMP-01:",
wait_for_connection,
fake_with_ophyd_sim,
)
17 changes: 0 additions & 17 deletions src/dodal/devices/i24/i24_vgonio.py

This file was deleted.

16 changes: 16 additions & 0 deletions src/dodal/devices/i24/vgonio.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from ophyd_async.core import StandardReadable
from ophyd_async.epics.motor import Motor


class VerticalGoniometer(StandardReadable):
def __init__(self, prefix: str, name: str = "") -> None:
self.x = Motor(prefix + "PINX")
self.z = Motor(prefix + "PINZ")
self.yh = Motor(prefix + "PINYH")
self.omega = Motor(prefix + "OMEGA")

self.real_x = Motor(prefix + "PINXS")
self.real_z = Motor(prefix + "PINZS")
self.fast_y = Motor(prefix + "PINYS")

super().__init__(name)
45 changes: 45 additions & 0 deletions src/dodal/devices/watsonmarlow323_pump.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from ophyd_async.core import ConfigSignal, StandardReadable, StrictEnum
from ophyd_async.epics.signal import epics_signal_rw


class WatsonMarlow323PumpEnable(StrictEnum):
DISABLED = "Disabled"
ENABLED = "Enabled"


class WatsonMarlow323PumpDirection(StrictEnum):
CLOCKWISE = "CW"
COUNTER_CLOCKWISE = "CCW"


class WatsonMarlow323PumpState(StrictEnum):
STOPPED = "STOP"
STARTED = "START"


class WatsonMarlow323Pump(StandardReadable):
"""Watson Marlow 323 Peristaltic Pump device"""

def __init__(self, prefix: str, name: str = "") -> None:
with self.add_children_as_readables():
self.direction = epics_signal_rw(
WatsonMarlow323PumpDirection,
read_pv=prefix + "INFO:DIR",
write_pv=prefix + "SET:DIR",
)
self.state = epics_signal_rw(
WatsonMarlow323PumpState,
read_pv=prefix + "INFO:RUN",
write_pv=prefix + "SET:RUN",
)
self.speed = epics_signal_rw(
float, read_pv=prefix + "INFO:SPD", write_pv=prefix + "SET:SPD"
)

with self.add_children_as_readables(ConfigSignal):
self.enabled = epics_signal_rw(
WatsonMarlow323PumpEnable,
prefix + "DISABLE",
)

super().__init__(name=name)
3 changes: 3 additions & 0 deletions src/dodal/devices/zocalo/zocalo_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from dodal.utils import is_test_mode

ZOCALO_ENV = "dev_bluesky" if is_test_mode() else "bluesky"
3 changes: 2 additions & 1 deletion src/dodal/devices/zocalo/zocalo_interaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import zocalo.configuration
from workflows.transport import lookup

from dodal.devices.zocalo.zocalo_constants import ZOCALO_ENV
from dodal.log import LOGGER


Expand Down Expand Up @@ -56,7 +57,7 @@ class ZocaloTrigger:
see https://github.com/DiamondLightSource/dodal/wiki/How-to-Interact-with-Zocalo"""

def __init__(self, environment: str = "artemis"):
def __init__(self, environment: str = ZOCALO_ENV):
self.zocalo_environment: str = environment

def _send_to_zocalo(self, parameters: dict):
Expand Down
3 changes: 2 additions & 1 deletion src/dodal/devices/zocalo/zocalo_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
)
from workflows.transport.common_transport import CommonTransport

from dodal.devices.zocalo.zocalo_constants import ZOCALO_ENV
from dodal.devices.zocalo.zocalo_interaction import _get_zocalo_connection
from dodal.log import LOGGER

Expand Down Expand Up @@ -115,7 +116,7 @@ class ZocaloResults(StandardReadable, Triggerable):
def __init__(
self,
name: str = "zocalo",
zocalo_environment: str = "dev_artemis",
zocalo_environment: str = ZOCALO_ENV,
channel: str = "xrc.i03",
sort_key: str = DEFAULT_SORT_KEY.value,
timeout_s: float = DEFAULT_TIMEOUT,
Expand Down
4 changes: 4 additions & 0 deletions src/dodal/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def get_beamline_name(default: str) -> str:
return environ.get("BEAMLINE") or default


def is_test_mode() -> bool:
return environ.get("DODAL_TEST_MODE") == "true"


def get_hostname() -> str:
return socket.gethostname().split(".")[0]

Expand Down
51 changes: 36 additions & 15 deletions system_tests/test_zocalo_results.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import asyncio
import os

import bluesky.plan_stubs as bps
import psutil
import pytest
from bluesky.preprocessors import stage_decorator
from bluesky.protocols import Reading
from bluesky.run_engine import RunEngine
from bluesky.utils import FailedStatus

Expand All @@ -16,6 +16,7 @@
ZocaloStartInfo,
ZocaloTrigger,
)
from dodal.devices.zocalo.zocalo_constants import ZOCALO_ENV

TEST_RESULT_LARGE: XrcResult = {
"centre_of_mass": [1, 2, 3],
Expand All @@ -26,6 +27,8 @@
"bounding_box": [[2, 2, 2], [8, 8, 7]],
}

DCID_WHICH_EXISTS_IN_DEV_ISPYB = 1000


@pytest.fixture
async def zocalo_device():
Expand All @@ -34,15 +37,35 @@ async def zocalo_device():
return zd


def convert_zocalo_device_reading_to_xrc_result(
zocalo_reading: dict[str, Reading],
) -> XrcResult:
com = zocalo_reading["zocalo-centre_of_mass"]["value"][0]
max_voxel = zocalo_reading["zocalo-max_voxel"]["value"][0]
max_count = zocalo_reading["zocalo-max_count"]["value"][0]
n_voxels = zocalo_reading["zocalo-n_voxels"]["value"][0]
total_count = zocalo_reading["zocalo-total_count"]["value"][0]
bounding_box = zocalo_reading["zocalo-bounding_box"]["value"][0]

return XrcResult(
centre_of_mass=com.tolist(),
max_voxel=max_voxel.tolist(),
max_count=int(max_count),
n_voxels=int(n_voxels),
total_count=int(total_count),
bounding_box=bounding_box.tolist(),
)


@pytest.mark.s03
async def test_read_results_from_fake_zocalo(
zocalo_device: ZocaloResults, RE: RunEngine
):
zocalo_device._subscribe_to_results()
zc = ZocaloTrigger("dev_artemis")
zc.run_start(ZocaloStartInfo(0, None, 0, 100, 0))
zc.run_end(0)
zocalo_device.timeout_s = 5
zc = ZocaloTrigger(ZOCALO_ENV)
zc.run_start(ZocaloStartInfo(DCID_WHICH_EXISTS_IN_DEV_ISPYB, None, 0, 100, 0))
zc.run_end(DCID_WHICH_EXISTS_IN_DEV_ISPYB)
zocalo_device.timeout_s = 15

def plan():
yield from bps.open_run()
Expand All @@ -52,21 +75,21 @@ def plan():
RE(plan())

results = await zocalo_device.read()
assert results["zocalo-results"]["value"][0] == TEST_RESULT_LARGE
assert convert_zocalo_device_reading_to_xrc_result(results) == TEST_RESULT_LARGE


@pytest.mark.s03
async def test_stage_unstage_controls_read_results_from_fake_zocalo(
zocalo_device: ZocaloResults, RE: RunEngine
):
dodal.devices.zocalo.zocalo_results.CLEAR_QUEUE_WAIT_S = 0.05
zc = ZocaloTrigger("dev_artemis")
zocalo_device.timeout_s = 5
zc = ZocaloTrigger(ZOCALO_ENV)
zocalo_device.timeout_s = 15

def plan():
yield from bps.open_run()
zc.run_start(ZocaloStartInfo(0, None, 0, 100, 0))
zc.run_end(0)
zc.run_start(ZocaloStartInfo(DCID_WHICH_EXISTS_IN_DEV_ISPYB, None, 0, 100, 0))
zc.run_end(DCID_WHICH_EXISTS_IN_DEV_ISPYB)
yield from bps.sleep(0.15)
yield from bps.trigger_and_read([zocalo_device])
yield from bps.close_run()
Expand All @@ -89,7 +112,7 @@ def plan_with_stage():
await asyncio.sleep(1)

results = await zocalo_device.read()
assert results["zocalo-results"]["value"][0] == TEST_RESULT_LARGE
assert convert_zocalo_device_reading_to_xrc_result(results) == TEST_RESULT_LARGE
await zocalo_device.unstage()

# Generating some more results leaves them at RMQ
Expand All @@ -104,16 +127,14 @@ def plan_with_stage():
async def test_stale_connections_closed_after_unstage(
zocalo_device: ZocaloResults, RE: RunEngine
):
this_process = psutil.Process(os.getpid())

connections_before = len(this_process.connections())
connections_before = len(psutil.net_connections())

def stage_unstage():
yield from bps.stage(zocalo_device)
yield from bps.unstage(zocalo_device)

RE(stage_unstage())

connections_after = len(this_process.connections())
connections_after = len(psutil.net_connections())

assert connections_before == connections_after
Loading

0 comments on commit 94e62c3

Please sign in to comment.