Skip to content

Commit

Permalink
Move to ophyd async (#33)
Browse files Browse the repository at this point in the history
* Convert devices to ophyd-async

* Small fix

* update dependancy

* linting

* Convert detector fully

* more linting

* Changes to get plans working on test rigs

* Fix for latest ophyd-async

* Fix docs

* Fix lint

---------

Co-authored-by: Oliver Silvester <oliver.silvester@diamond.ac.uk>
  • Loading branch information
callumforrester and olliesilvester authored Aug 12, 2024
1 parent 20096cf commit e0051a4
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 63 deletions.
2 changes: 2 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@
("py:class", "htss_rig_bluesky.devices.SampleStage"),
("py:class", "SampleStage"),
("py:class", "htss_rig_bluesky.plans.detector.Roi"),
("py:class", "ophyd_async.epics.areadetector.aravis.AravisDetector"),
("py:class", "AravisDetector"),
("py:class", "NoneType"),
("py:class", "'str'"),
("py:class", "'float'"),
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies = [
"pandablocks",
"scipy",
"tiled==0.1.0a91",
"ophyd_async>=0.3.4",
]
dynamic = ["version"]
license.file = "LICENSE"
Expand Down
74 changes: 47 additions & 27 deletions src/htss_rig_bluesky/devices.py
Original file line number Diff line number Diff line change
@@ -1,62 +1,82 @@
from enum import Enum
from pathlib import Path

import epics
from bluesky.protocols import Status
from dodal.devices.areadetector import AdAravisDetector
from ophyd import Component, Device, EpicsMotor, EpicsSignalWithRBV, MotorBundle
from ophyd_async.core import (
AsyncStatus,
AutoIncrementFilenameProvider,
Device,
StaticPathProvider,
)
from ophyd_async.epics.areadetector.aravis import AravisDetector
from ophyd_async.epics.motion import Motor
from ophyd_async.epics.signal import epics_signal_rw

from .names import pv_prefix


class SampleStage(MotorBundle):
x: EpicsMotor = Component(EpicsMotor, "X")
theta: EpicsMotor = Component(EpicsMotor, "A")
class SampleStage(Device):
def __init__(self, prefix: str, name: str):
self.x = Motor(prefix + "X")
self.theta = Motor(prefix + "A")
super().__init__(name)


class Backlight(Device):
on: EpicsSignalWithRBV = Component(EpicsSignalWithRBV, "State")
class BacklightPower(str, Enum):
ON = "On"
OFF = "Off"

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.on.put_complete = True

def set(self, value) -> Status:
# Shortcut so that bps.abs_set(beam.on, True) is the same
# as bps.abs_set(beam, True)
return self.on.set(value)
class Backlight(Device):
def __init__(self, prefix: str, name: str = ""):
self.power = epics_signal_rw(BacklightPower, prefix + "State")
super().__init__(name)

@AsyncStatus.wrap
async def set(self, position: BacklightPower):
"""This setter will turn the backlight on when we move it in to the beam and off
when we move it out."""
await self.power.set(position)


def sample(name: str = "sample_stage") -> SampleStage:
"""
Create sample stage Ophyd device
Create sample stage ophyd-async device
Args:
name: Name for this device for reference in events.
Defaults to "sample_stage".
Returns:
SampleStage: A new Ophyd Device
SampleStage: A new ophyd-async Device
"""

return SampleStage(name=name, prefix=f"{pv_prefix()}-MO-MAP-01:STAGE:")


def det(name: str = "det") -> AdAravisDetector:
def det(name: str = "det") -> AravisDetector:
"""
Create detector stage Ophyd device
Create detector stage ophyd-async device
Args:
name: Name for this device for reference in events.
Defaults to "det".
Returns:
SampleStage: A new Ophyd Device
AravisDetector: A new ophyd-async Device
"""

det = AdAravisDetector(name=name, prefix=f"{pv_prefix()}-EA-DET-01:")
det.read_attrs += ["cam"]
det.cam.read_attrs += ["acquire_time", "acquire_period"]
det.hdf.reg_root = "/exports/mybeamline/data"
det.hdf.write_path_template = "%Y"
return det
dir_prov = StaticPathProvider(
AutoIncrementFilenameProvider(),
Path("/exports/mybeamline/data"),
)
return AravisDetector(
name=name,
prefix=f"{pv_prefix()}-EA-DET-01:",
path_provider=dir_prov,
hdf_suffix="HDF5:",
drv_suffix="DET:",
)


def beam(name: str = "beam") -> Backlight:
Expand All @@ -68,7 +88,7 @@ def beam(name: str = "beam") -> Backlight:
Defaults to "beam".
Backlight:
SampleStage: A new Ophyd Device
Backlight: A new ophyd-async Device
"""

return Backlight(name=name, prefix=f"{pv_prefix()}-EA-BEAM-01:")
Expand Down
20 changes: 10 additions & 10 deletions src/htss_rig_bluesky/plans/calibration.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import bluesky.plan_stubs as bps
import bluesky.plans as bp

from htss_rig_bluesky.devices import AdAravisDetector, SampleStage
from htss_rig_bluesky.devices import AravisDetector, SampleStage


def scan_center(
det: AdAravisDetector,
det: AravisDetector,
sample: SampleStage,
min_x: float | None = None,
max_x: float | None = None,
Expand Down Expand Up @@ -42,15 +42,15 @@ def scan_center(
Plan
"""

x_range = abs(sample.x.high_limit - sample.x.low_limit)
x_range = abs(sample.x.high_limit_travel - sample.x.low_limit_travel)
limit_margin = x_range * 0.01
min_x = min_x or sample.x.low_limit + limit_margin
max_x = max_x or sample.x.high_limit - limit_margin
min_x = min_x or sample.x.low_limit_travel + limit_margin
max_x = max_x or sample.x.high_limit_travel - limit_margin

yield from bps.mv(
det.cam.num_images,
det.drv.num_images,
images_per_side,
det.cam.acquire_time,
det.drv.acquire_time,
exposure_time,
)
yield from bp.grid_scan(
Expand All @@ -68,7 +68,7 @@ def scan_center(


def scan_exposure(
det: AdAravisDetector,
det: AravisDetector,
min_exposure: float = 0.01,
max_exposure: float = 0.2,
exposure_steps: int = 10,
Expand All @@ -85,8 +85,8 @@ def scan_exposure(
Yields:
Plan
"""
exposure_time = det.cam.acquire_time
yield from bps.abs_set(det.cam.acquire_period, max_exposure + 0.1)
exposure_time = det.drv.acquire_time
yield from bps.abs_set(det.drv.acquire_period, max_exposure + 0.1)
yield from bp.scan(
[det],
exposure_time,
Expand Down
31 changes: 12 additions & 19 deletions src/htss_rig_bluesky/plans/detector.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
from dataclasses import dataclass

import bluesky.plan_stubs as bps

from htss_rig_bluesky.devices import AdAravisDetector
from ophyd_async.epics.areadetector.aravis import AravisDetector


@dataclass
Expand All @@ -30,7 +29,7 @@ def max_y(self) -> int:
return self.min_y + (self.size_y or 0)


def ensure_detector_ready(det: AdAravisDetector) -> Generator:
def ensure_detector_ready(det: AravisDetector) -> Generator:
"""
Setup detector for exercises
Expand All @@ -40,20 +39,20 @@ def ensure_detector_ready(det: AdAravisDetector) -> Generator:
Yields:
Plan
"""

# TODO: need num exposures too?
yield from bps.mv(
det.cam.num_exposures,
det.drv.num_images,
1,
det.cam.num_images,
1,
det.cam.acquire_period,
det.drv.acquire_period,
0.1,
det.cam.acquire_time,
det.drv.acquire_time,
0.15,
det.hdf.nd_array_port,
"DET.CAM",
)


def set_roi(det: AdAravisDetector, roi: Roi) -> Generator:
def set_roi(det: AravisDetector, roi: Roi) -> Generator:
"""
Setup detector ROI and frame size
Expand All @@ -64,16 +63,10 @@ def set_roi(det: AdAravisDetector, roi: Roi) -> Generator:
Yields:
Plan
"""
# Ophyd Async AravisDetector doesn't appear to have signal for max sizes
# eg DET:MaxSizeX_RBVDET:MaxSizeX_RBV

max_x = yield from bps.rd(det.cam.max_size.max_size_x)
max_y = yield from bps.rd(det.cam.max_size.max_size_y)

sets = {
det.cam.min_x: roi.min_x,
det.cam.min_y: roi.min_y,
det.cam.size.size_x: roi.size_x or max_x,
det.cam.size.size_y: roi.size_y or max_y,
}
sets = {det.drv.array_size_x: roi.size_x, det.drv.array_size_y: roi.size_y}

for signal, value in sets.items():
yield from bps.abs_set(signal, value)
Expand Down
10 changes: 5 additions & 5 deletions src/htss_rig_bluesky/plans/exercise.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@
import bluesky.plans as bp
from ophyd import PositionerBase

from htss_rig_bluesky.devices import AdAravisDetector, SampleStage
from htss_rig_bluesky.devices import AravisDetector, SampleStage

from .detector import ensure_detector_ready


def exercise_beamline(det: AdAravisDetector, sample: SampleStage) -> Generator:
def exercise_beamline(det: AravisDetector, sample: SampleStage) -> Generator:
"""
Perform all beamline exercise plans sequentially.
Expand Down Expand Up @@ -48,7 +48,7 @@ def exercise_motors(sample: SampleStage) -> Generator:
)


def exercise_detector(det: AdAravisDetector) -> Generator:
def exercise_detector(det: AravisDetector) -> Generator:
"""
exercise the detector by taking a frame.
Expand All @@ -64,12 +64,12 @@ def exercise_detector(det: AdAravisDetector) -> Generator:
yield from bp.count([det])


def exercise_scan(det: AdAravisDetector, sample: SampleStage) -> Generator:
def exercise_scan(det: AravisDetector, sample: SampleStage) -> Generator:
"""
Perform a short scan to exercise the test rig.
Args:
det (AdAravisDetector): Detector
det (AravisDetector): Detector
sample (SampleStage): Sample stage
Yields:
Expand Down
7 changes: 5 additions & 2 deletions src/htss_rig_bluesky/startup.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@
import matplotlib
import matplotlib.pyplot as plt # noqa: F401
import numpy as np # noqa: F401
from bluesky import RunEngine
from bluesky.callbacks.best_effort import BestEffortCallback
from bluesky.run_engine import RunEngine
from dodal.utils import make_all_devices
from ophyd_async.core import DeviceCollector # noqa: F401

import htss_rig_bluesky.devices as devices
from htss_rig_bluesky.devices import beam, det, sample # noqa: F401
from htss_rig_bluesky.plans.calibration import scan_center, scan_exposure # noqa: F401
from htss_rig_bluesky.plans.detector import ( # noqa: F401
Roi,
Expand Down Expand Up @@ -46,6 +48,8 @@

matplotlib.use("QtAgg")

RE = RunEngine()

successful_devices, errors = make_all_devices(devices)
if len(errors) > 0:
print(f"The following devices failed to connect{errors}")
Expand All @@ -54,7 +58,6 @@

bec = BestEffortCallback()

RE = RunEngine()
RE.subscribe(bec)

if os.environ.get("MINIMAL", False):
Expand Down

0 comments on commit e0051a4

Please sign in to comment.