Skip to content

Commit

Permalink
fix for ophyd (#65)
Browse files Browse the repository at this point in the history
* fix for ophyd

* droping 3.10 as soft ioc no longer support it.

* make fast scan always take at least one reading
  • Loading branch information
Relm-Arrowny authored Dec 20, 2024
1 parent 5c162e4 commit 33022e0
Show file tree
Hide file tree
Showing 24 changed files with 1,349 additions and 1,410 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
runs-on: ["ubuntu-latest"] # can add windows-latest, macos-latest
python-version: ["3.10", "3.11"]
python-version: ["3.11", "3.12"]
include:
# Include one that runs in the dev environment
- runs-on: "ubuntu-latest"
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The devcontainer should use the developer target and run as root with podman
# or docker with user namespaces.
ARG PYTHON_VERSION=3.11
ARG PYTHON_VERSION=3.12
FROM python:${PYTHON_VERSION} as developer

# Add any system dependencies for the developer/build environment here
Expand Down
16 changes: 9 additions & 7 deletions src/p99_bluesky/devices/epics/andor2_controller.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import asyncio

from ophyd_async.core import DetectorControl, DetectorTrigger
from ophyd_async.core import DetectorController, DetectorTrigger
from ophyd_async.core._detector import TriggerInfo
from ophyd_async.epics import adcore
from ophyd_async.epics.adcore import (
Expand All @@ -16,16 +16,16 @@
)


class Andor2Controller(DetectorControl):
class Andor2Controller(DetectorController):
"""
Andor 2 controller
"""

_supported_trigger_types = {
DetectorTrigger.internal: Andor2TriggerMode.internal,
DetectorTrigger.constant_gate: Andor2TriggerMode.ext_trigger,
DetectorTrigger.variable_gate: Andor2TriggerMode.ext_FVP,
DetectorTrigger.INTERNAL: Andor2TriggerMode.INTERNAL,
DetectorTrigger.CONSTANT_GATE: Andor2TriggerMode.EXT_TRIGGER,
DetectorTrigger.VARIABLE_GATE: Andor2TriggerMode.EXT_FVP,
}

def __init__(
Expand All @@ -51,9 +51,11 @@ async def prepare(self, trigger_info: TriggerInfo):
await asyncio.gather(
self._drv.trigger_mode.set(self._get_trigger_mode(trigger_info.trigger)),
self._drv.num_images.set(
999_999 if trigger_info.number == 0 else trigger_info.number
999_999
if trigger_info.total_number_of_triggers == 0
else trigger_info.total_number_of_triggers
),
self._drv.image_mode.set(ImageMode.multiple),
self._drv.image_mode.set(ImageMode.MULTIPLE),
)

async def arm(self) -> None:
Expand Down
16 changes: 9 additions & 7 deletions src/p99_bluesky/devices/epics/andor3_controller.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import asyncio

from ophyd_async.core import (
DetectorControl,
DetectorController,
DetectorTrigger,
)
from ophyd_async.core._detector import TriggerInfo
Expand All @@ -19,16 +19,16 @@
)


class Andor3Controller(DetectorControl):
class Andor3Controller(DetectorController):
"""
Andor 3 controller
"""

_supported_trigger_types = {
DetectorTrigger.internal: Andor3TriggerMode.internal,
DetectorTrigger.constant_gate: Andor3TriggerMode.ext_trigger,
DetectorTrigger.variable_gate: Andor3TriggerMode.ext_exposure,
DetectorTrigger.INTERNAL: Andor3TriggerMode.INTERNAL,
DetectorTrigger.CONSTANT_GATE: Andor3TriggerMode.EXT_TRIGGER,
DetectorTrigger.VARIABLE_GATE: Andor3TriggerMode.EXT_EXPOSURE,
}

def __init__(
Expand All @@ -54,9 +54,11 @@ async def prepare(self, trigger_info: TriggerInfo):
await asyncio.gather(
self._drv.trigger_mode.set(self._get_trigger_mode(trigger_info.trigger)),
self._drv.num_images.set(
999_999 if trigger_info.number == 0 else trigger_info.number
999_999
if trigger_info.total_number_of_triggers == 0
else trigger_info.total_number_of_triggers
),
self._drv.image_mode.set(ImageMode.fixed),
self._drv.image_mode.set(ImageMode.FIXED),
)

async def arm(self) -> None:
Expand Down
54 changes: 24 additions & 30 deletions src/p99_bluesky/devices/epics/drivers/andor2_driver.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,34 @@
from enum import Enum

from ophyd_async.core import StrictEnum
from ophyd_async.epics.adcore._core_io import ADBaseIO
from ophyd_async.epics.signal import (
from ophyd_async.epics.core import (
epics_signal_r,
epics_signal_rw,
epics_signal_rw_rbv,
)


class Andor2TriggerMode(str, Enum):
internal = "Internal"
ext_trigger = "External"
ext_start = "External Start"
ext_exposure = "External Exposure"
ext_FVP = "External FVP"
soft = "Software"


class ImageMode(str, Enum):
single = "Single"
multiple = "Multiple"
continuous = "Continuous"
fast_kinetics = "Fast Kinetics"


class ADBaseDataType(str, Enum):
UInt16 = "UInt16"
UInt32 = "UInt32"
b1 = ""
b2 = ""
b3 = ""
b4 = ""
b5 = ""
b6 = ""
Float32 = "Float32"
Float64 = "Float64"
class Andor2TriggerMode(StrictEnum):
INTERNAL = "Internal"
EXT_TRIGGER = "External"
EXT_START = "External Start"
EXT_EXPOSURE = "External Exposure"
EXT_FVP = "External FVP"
SOFT = "Software"


class ImageMode(StrictEnum):
SINGLE = "Single"
MULTIPLE = "Multiple"
CONTINUOUS = "Continuous"
FAST_KINETICS = "Fast Kinetics"


class ADBaseDataType(StrictEnum):
UINT16 = "UInt16"
UINT32 = "UInt32"
B1 = ""
FLOAT32 = "Float32"
FLOAT64 = "Float64"


class Andor2DriverIO(ADBaseIO):
Expand Down
23 changes: 11 additions & 12 deletions src/p99_bluesky/devices/epics/drivers/andor3_driver.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
from enum import Enum

from ophyd_async.core import StrictEnum
from ophyd_async.epics.adcore._core_io import ADBaseIO
from ophyd_async.epics.signal import epics_signal_rw, epics_signal_rw_rbv
from ophyd_async.epics.core import epics_signal_rw, epics_signal_rw_rbv


class Andor3TriggerMode(str, Enum):
internal = "Internal"
ext_start = "External Start"
ext_exposure = "External Exposure"
soft = "Software"
ext_trigger = "External"
class Andor3TriggerMode(StrictEnum):
INTERNAL = "Internal"
EXT_START = "External Start"
EXT_EXPOSURE = "External Exposure"
SOFT = "Software"
EXT_TRIGGER = "External"


class ImageMode(str, Enum):
fixed = "Fixed"
continuous = "Continuous"
class ImageMode(StrictEnum):
FIXED = "Fixed"
CONTINUOUS = "Continuous"


class Andor3DriverIO(ADBaseIO):
Expand Down
40 changes: 19 additions & 21 deletions src/p99_bluesky/devices/p99/sample_stage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
from enum import Enum

from ophyd_async.core import Device
from ophyd_async.epics.signal import epics_signal_rw
from ophyd_async.core import Device, StrictEnum
from ophyd_async.epics.core import epics_signal_rw


class SampleAngleStage(Device):
Expand All @@ -16,23 +14,23 @@ def __init__(self, prefix: str, name: str):
super().__init__(name=name)


class p99StageSelections(str, Enum):
Empty = "Empty"
Mn5um = "Mn 5um"
Fe = "Fe (empty)"
Co5um = "Co 5um"
Ni5um = "Ni 5um"
Cu5um = "Cu 5um"
Zn5um = "Zn 5um"
Zr = "Zr (empty)"
Mo = "Mo (empty)"
Rh = "Rh (empty)"
Pd = "Pd (empty)"
Ag = "Ag (empty)"
Cd25um = "Cd 25um"
W = "W (empty)"
Pt = "Pt (empty)"
User = "User"
class p99StageSelections(StrictEnum):
EMPTY = "EMPTY"
MN5UM = "MN 5UM"
FE = "FE (EMPTY)"
CO5UM = "CO 5UM"
NI5UM = "NI 5UM"
CU5UM = "CU 5UM"
ZN5UM = "ZN 5UM"
ZR = "ZR (EMPTY)"
MO = "MO (EMPTY)"
RH = "RH (EMPTY)"
PD = "PD (EMPTY)"
AG = "AG (EMPTY)"
CD25UM = "CD 25UM"
W = "W (EMPTY)"
PT = "PT (EMPTY)"
USER = "USER"


class FilterMotor(Device):
Expand Down
4 changes: 2 additions & 2 deletions src/p99_bluesky/plans/ad_plans.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def takeImg(
det: Andor2Ad | Andor3Ad,
exposure: float,
n_img: int = 1,
det_trig: DetectorTrigger = DetectorTrigger.internal,
det_trig: DetectorTrigger = DetectorTrigger.INTERNAL,
) -> MsgGenerator:
"""
Bare minimum to take an image using prepare plan with full detector control
Expand All @@ -20,7 +20,7 @@ def takeImg(
grp = short_uid("prepare")
deadtime: float = det.controller.get_deadtime(exposure)
tigger_info = TriggerInfo(
number=n_img,
number_of_triggers=n_img,
trigger=det_trig,
deadtime=deadtime,
livetime=exposure,
Expand Down
4 changes: 2 additions & 2 deletions src/p99_bluesky/plans/fast_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,9 @@ def inner_fast_scan_1d(
yield from bps.prepare(motor, fly_info, group=grp, wait=True)
yield from bps.wait(group=grp)
yield from bps.kickoff(motor, group=grp, wait=True)

done = yield from bps.complete(motor)
LOGGER.info(f"flying motor = {motor.name} at speed = {motor_speed}")
done = yield from bps.complete(motor)
yield from bps.trigger_and_read(dets + [motor])
while not done.done:
yield from bps.trigger_and_read(dets + [motor])
yield from bps.checkpoint()
Expand Down
3 changes: 1 addition & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
FilenameProvider,
StaticFilenameProvider,
StaticPathProvider,
callback_on_mock_put,
set_mock_value,
)
from ophyd_async.testing import callback_on_mock_put, set_mock_value
from super_state_machine.errors import TransitionError

from p99_bluesky.devices import Andor2Ad, Andor3Ad
Expand Down
32 changes: 16 additions & 16 deletions tests/epics/soft_ioc/softsignal.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@ def soft_mbb(prefix: str, name: str, *option):
# temp = builder.mbbIn(readback_name, initial_value=0)
builder.mbbOut(
name,
"Empty",
"Mn 5um",
"Fe (empty)",
"Co 5um",
"Ni 5um",
"Cu 5um",
"Zn 5um",
"Zr (empty)",
"Mo (empty)",
"Rh (empty)",
"Pd (empty)",
"Ag (empty)",
"Cd 25um",
"W (empty)",
"Pt (empty)",
"User",
"EMPTY",
"MN 5UM",
"FE (EMPTY)",
"CO 5UM",
"NI 5UM",
"CU 5UM",
"ZN 5UM",
"ZR (EMPTY)",
"MO (EMPTY)",
"RH (EMPTY)",
"PD (EMPTY)",
"AG (EMPTY)",
"CD 25UM",
"W (EMPTY)",
"PT (EMPTY)",
"USER",
)


Expand Down
12 changes: 7 additions & 5 deletions tests/epics/test_andor2_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
DetectorTrigger,
DeviceCollector,
TriggerInfo,
set_mock_value,
)
from ophyd_async.epics.adcore import ImageMode
from ophyd_async.testing import set_mock_value

from p99_bluesky.devices.epics.andor2_controller import Andor2Controller
from p99_bluesky.devices.epics.drivers.andor2_driver import (
Expand All @@ -27,15 +27,17 @@ async def Andor(RE) -> Andor2Controller:

async def test_Andor_controller(RE, Andor: Andor2Controller):
with patch("ophyd_async.core.wait_for_value", return_value=None):
await Andor.prepare(trigger_info=TriggerInfo(number=1, livetime=0.002))
await Andor.prepare(
trigger_info=TriggerInfo(number_of_triggers=1, livetime=0.002)
)
await Andor.arm()

driver = Andor._drv

set_mock_value(driver.accumulate_period, 1)
assert await driver.num_images.get_value() == 1
assert await driver.image_mode.get_value() == ImageMode.multiple
assert await driver.trigger_mode.get_value() == Andor2TriggerMode.internal
assert await driver.image_mode.get_value() == ImageMode.MULTIPLE
assert await driver.trigger_mode.get_value() == Andor2TriggerMode.INTERNAL
assert await driver.acquire.get_value() is True
assert await driver.acquire_time.get_value() == 0.002
assert Andor.get_deadtime(2) == 2 + 0.1
Expand All @@ -49,6 +51,6 @@ async def test_Andor_controller(RE, Andor: Andor2Controller):
with patch("ophyd_async.core.wait_for_value", return_value=None):
await Andor.disarm()
with pytest.raises(ValueError):
Andor._get_trigger_mode(DetectorTrigger.edge_trigger)
Andor._get_trigger_mode(DetectorTrigger.EDGE_TRIGGER)

assert await driver.acquire.get_value() is False
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,16 @@ async def Andor(RE) -> Andor3Controller:

async def test_Andor3_controller(RE, Andor: Andor3Controller):
with patch("ophyd_async.core.wait_for_value", return_value=None):
await Andor.prepare(trigger_info=TriggerInfo(number=1, livetime=0.002))
await Andor.prepare(
trigger_info=TriggerInfo(number_of_triggers=1, livetime=0.002)
)
await Andor.arm()

driver = Andor._drv

assert await driver.num_images.get_value() == 1
assert await driver.image_mode.get_value() == ImageMode.fixed
assert await driver.trigger_mode.get_value() == Andor3TriggerMode.internal
assert await driver.image_mode.get_value() == ImageMode.FIXED
assert await driver.trigger_mode.get_value() == Andor3TriggerMode.INTERNAL
assert await driver.acquire.get_value() is True
assert await driver.acquire_time.get_value() == 0.002
assert Andor.get_deadtime(2) == 2 + 0.1
Expand All @@ -42,6 +44,6 @@ async def test_Andor3_controller(RE, Andor: Andor3Controller):
with patch("ophyd_async.core.wait_for_value", return_value=None):
await Andor.disarm()
with pytest.raises(ValueError):
Andor._get_trigger_mode(DetectorTrigger.edge_trigger)
Andor._get_trigger_mode(DetectorTrigger.EDGE_TRIGGER)

assert await driver.acquire.get_value() is False
Loading

0 comments on commit 33022e0

Please sign in to comment.