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
115 changes: 77 additions & 38 deletions src/test_rig_bluesky/plans.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import math
from dataclasses import dataclass
import os
from typing import Any

from bluesky import plan_stubs as bps
Expand All @@ -10,25 +10,51 @@
from dodal.devices.motors import XYZStage
from dodal.plan_stubs.data_session import attach_data_session_metadata_decorator
from dodal.plans import spec_scan
from ophyd_async.core import TriggerInfo
from ophyd_async.core import Device, Settings, TriggerInfo, YamlSettingsProvider
from ophyd_async.epics.adaravis import AravisDetector
from ophyd_async.epics.adcore import NDAttributePv, NDAttributePvDbrType
from ophyd_async.epics.adcore._core_io import NDROIStatNIO
from ophyd_async.plan_stubs import setup_ndattributes
from ophyd_async.plan_stubs import (
apply_settings,
apply_settings_if_different,
retrieve_settings,
setup_ndattributes,
store_settings,
)
from scanspec.specs import Line, Spec

imaging_detector = inject("imaging_detector")
spectroscopy_detector = inject("spectroscopy_detector")
sample_stage = inject("sample_stage")


@dataclass
class ROI:
channel: int
name: str
start_x: int
start_y: int
size: int
def save_settings(
device: Device,
design_name: str,
design_directory: str = os.path.abspath("./src/test_rig_bluesky/"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm still not thrilled about letting the user configure this, makes it harder for us to swap it out for a database in the future. I won't block merge over it though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added it back in to allow the settings for testing to be saved in the testing directory. I'm sure there's a better way to do it but I'm not sure what that way is

) -> MsgGenerator[None]:
provider = YamlSettingsProvider(design_directory)
yield from store_settings(provider, design_name, device)


def load_settings(
device: Device,
design_name: str,
design_directory: str = os.path.abspath("./src/test_rig_bluesky/"),
whitelist_pvs: list[str] | None = None,
) -> MsgGenerator[None]:
provider = YamlSettingsProvider(design_directory)
settings = yield from retrieve_settings(provider, design_name, device)
if whitelist_pvs is None:
settings_to_set = settings
else:
signal_values = {
signal: value
for signal, value in settings.items()
if signal.name.replace(f"{device.name}-", "") in whitelist_pvs
}
settings_to_set = Settings(settings.device, signal_values)
yield from apply_settings_if_different(settings_to_set, apply_settings)


@attach_data_session_metadata_decorator()
Expand All @@ -52,49 +78,62 @@ def spectroscopy(
yield from bps.prepare(
spectroscopy_detector, TriggerInfo(livetime=exposure_time), wait=True
)
# TODO: This would be nicer if NDArrayBaseIO had a PortName signal
yield from bps.abs_set(
spectroscopy_detector.fileio.nd_array_port, "D2.roistat", wait=True
)

rois = [
ROI(2, "Green", 880, 605, 150),
ROI(3, "Blue", 1665, 600, 150),
ROI(1, "Red", 95, 610, 150),
]
yield from load_settings(
device=spectroscopy_detector,
design_name="spectroscopy_detector_baseline",
whitelist_pvs=[
"fileio.nd_array_port",
"roistat-channels-array_counter",
"roistat-channels-1-min_x",
"roistat-channels-1-min_y",
"roistat-channels-1-name_",
"roistat-channels-1-size_x",
"roistat-channels-1-size_y",
"roistat-channels-1-use",
"roistat-channels-2-min_x",
"roistat-channels-2-min_y",
"roistat-channels-2-name_",
"roistat-channels-2-size_x",
"roistat-channels-2-size_y",
"roistat-channels-2-use",
"roistat-channels-3-min_x",
"roistat-channels-3-min_y",
"roistat-channels-3-name_",
"roistat-channels-3-size_x",
"roistat-channels-3-size_y",
"roistat-channels-3-use",
],
)

params: list[NDAttributePv] = []
for roi in rois:
roistatn = spectroscopy_detector.roistat.channels[roi.channel] # type: ignore
for channel in list(spectroscopy_detector.roistat.channels.keys()): # type: ignore
roistatn = spectroscopy_detector.roistat.channels[channel] # type: ignore
assert isinstance(roistatn, NDROIStatNIO)

yield from bps.mv(
*(roistatn.name_, roi.name),
*(roistatn.min_x, roi.start_x),
*(roistatn.min_y, roi.start_y),
*(roistatn.size_x, roi.size),
*(roistatn.size_y, roi.size),
*(roistatn.use, True),
wait=True,
)
channel_name = yield from bps.rd(roistatn.name_)

params.append(
NDAttributePv(
name=f"{roi.name}Total",
name=f"{channel_name}Total",
signal=roistatn.total,
dbrtype=NDAttributePvDbrType.DBR_LONG,
description=f"Sum of {roi.name} channel",
description=f"Sum of {channel_name} channel",
)
)

yield from setup_ndattributes(spectroscopy_detector.roistat, params) # type: ignore

for motor in [sample_stage.x, sample_stage.y]:
yield from bps.mv(
*(motor.acceleration_time, 0.001),
*(motor.velocity, 100),
wait=True,
)
yield from load_settings(
device=sample_stage,
design_name="sample_stage_baseline",
whitelist_pvs=[
"x-acceleration_time",
"x-velocity",
"y-acceleration_time",
"y-velocity",
],
)

spec = spec or Line(sample_stage.x, 0, 5, 5)

Expand Down
24 changes: 24 additions & 0 deletions src/test_rig_bluesky/sample_stage_baseline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
x.acceleration_time: 0.001
x.high_limit_travel: 14.5
x.low_limit_travel: -14.5
x.offset: 0.0
x.offset_freeze_switch: Variable
x.set_use_switch: Use
x.user_setpoint: 5.00004
x.velocity: 100.0
y.acceleration_time: 0.001
y.high_limit_travel: 14.5
y.low_limit_travel: -14.5
y.offset: 0.0
y.offset_freeze_switch: Variable
y.set_use_switch: Use
y.user_setpoint: 4.99999
y.velocity: 100.0
z.acceleration_time: 0.5
z.high_limit_travel: 14.5
z.low_limit_travel: -14.5
z.offset: 0.0
z.offset_freeze_switch: Variable
z.set_use_switch: Use
z.user_setpoint: 7.000030000000001
z.velocity: 50.0
71 changes: 71 additions & 0 deletions src/test_rig_bluesky/spectroscopy_detector_baseline.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
driver.acquire: false
driver.acquire_period: 0.021815
driver.acquire_time: 0.10000
driver.array_counter: 3
driver.image_mode: Multiple
driver.nd_attributes_file: ''
driver.num_images: 1
driver.trigger_mode: 'Off'
driver.trigger_source: Freerun
driver.wait_for_plugins: false
fileio.acquire: false
fileio.array_counter: 3
fileio.auto_increment: true
fileio.capture: false
fileio.chunk_size_auto: true
fileio.compression: None
fileio.create_directory: 0
fileio.enable_callbacks: Enable
fileio.file_name: 5073260b-9688-4283-84d1-204955e423aa
fileio.file_number: 1
fileio.file_path: /tmp/
fileio.file_template: '%s%s.h5'
fileio.file_write_mode: Stream
fileio.flush_now: false
fileio.lazy_open: true
fileio.nd_array_address: 0
fileio.nd_array_port: D2.roistat
fileio.nd_attributes_file: ''
fileio.num_capture: 0
fileio.num_extra_dims: 0
fileio.num_frames_chunks: 1
fileio.position_mode: false
fileio.queue_size: 2
fileio.swmr_mode: true
fileio.wait_for_plugins: false
fileio.xml_file_name: ''
roistat.acquire: false
roistat.array_counter: 3
roistat.channels.1.min_x: 95
roistat.channels.1.min_y: 610
roistat.channels.1.name_: Red
roistat.channels.1.size_x: 150
roistat.channels.1.size_y: 150
roistat.channels.1.use: true
roistat.channels.2.min_x: 880
roistat.channels.2.min_y: 605
roistat.channels.2.name_: Green
roistat.channels.2.size_x: 150
roistat.channels.2.size_y: 150
roistat.channels.2.use: true
roistat.channels.3.min_x: 1665
roistat.channels.3.min_y: 600
roistat.channels.3.name_: Blue
roistat.channels.3.size_x: 150
roistat.channels.3.size_y: 150
roistat.channels.3.use: true
roistat.enable_callbacks: Enable
roistat.nd_array_address: 0
roistat.nd_array_port: D2.CAM
roistat.nd_attributes_file: <Attributes><Attribute name="&lt;ophyd_async.core._signal.SignalRW
object at 0x7ff2db389990&gt;Total" type="EPICS_PV" source="BL01C-DI-DCAM-02:ROISTAT:1:Total_RBV"
dbrtype="DBR_LONG" description="Sum of &lt;ophyd_async.core._signal.SignalRW object
at 0x7ff2db389990&gt; channel" /><Attribute name="&lt;ophyd_async.core._signal.SignalRW
object at 0x7ff2db38bb10&gt;Total" type="EPICS_PV" source="BL01C-DI-DCAM-02:ROISTAT:2:Total_RBV"
dbrtype="DBR_LONG" description="Sum of &lt;ophyd_async.core._signal.SignalRW object
at 0x7ff2db38bb10&gt; channel" /><Attribute name="&lt;ophyd_async.core._signal.SignalRW
object at 0x7ff2db39d3d0&gt;Total" type="EPICS_PV" source="BL01C-DI-DCAM-02:ROISTAT:3:Total_RBV"
dbrtype="DBR_LONG" description="Sum of &lt;ophyd_async.core._signal.SignalRW object
at 0x7ff2db39d3d0&gt; channel" /></Attributes>
roistat.queue_size: 2
roistat.wait_for_plugins: false
56 changes: 55 additions & 1 deletion tests/unit_tests/test_plans.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import os
import unittest.mock
from collections import defaultdict

Expand All @@ -10,7 +11,13 @@
from ophyd_async.testing import assert_emitted, callback_on_mock_put, set_mock_value
from scanspec.specs import Line

from test_rig_bluesky.plans import demo_spectroscopy, snapshot, spectroscopy
from test_rig_bluesky.plans import (
demo_spectroscopy,
load_settings,
save_settings,
snapshot,
spectroscopy,
)


@pytest.fixture
Expand Down Expand Up @@ -61,6 +68,53 @@ async def on_acquire(acquire: bool, wait: bool) -> None:
callback_on_mock_put(detector.driver.acquire, on_acquire)


def test_save_settings(
run_engine: RunEngine,
_spectroscopy_detector: AravisDetector,
):
run_engine(
save_settings(
_spectroscopy_detector, design_name="test", design_directory="/tmp"
)
)

assert os.path.isfile("/tmp/test.yaml")


async def test_load_subset_of_settings(
run_engine: RunEngine,
_spectroscopy_detector: AravisDetector,
):
run_engine(
load_settings(
_spectroscopy_detector,
design_name="test_settings",
design_directory=os.path.abspath("./tests/unit_tests/"),
whitelist_pvs=["driver-acquire_time"],
)
)

assert await _spectroscopy_detector.driver.acquire_time.get_value() == 0.5
assert await _spectroscopy_detector.roistat.channels[1].min_x.get_value() == 0 # type:ignore


async def test_load_settings(
run_engine: RunEngine,
_spectroscopy_detector: AravisDetector,
):
run_engine(
load_settings(
_spectroscopy_detector,
design_name="test_settings",
design_directory=os.path.abspath("./tests/unit_tests/"),
)
)

assert await _spectroscopy_detector.driver.acquire_period.get_value() == 1.0
assert await _spectroscopy_detector.driver.num_images.get_value() == 2
assert await _spectroscopy_detector.roistat.channels[1].min_x.get_value() == 95 # type:ignore


def test_snapshot(
run_engine: RunEngine,
_imaging_detector: AravisDetector,
Expand Down
62 changes: 62 additions & 0 deletions tests/unit_tests/test_settings.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
driver.acquire: false
driver.acquire_period: 1.0
driver.acquire_time: 0.5
driver.array_counter: 5
driver.image_mode: Single
driver.nd_attributes_file: ""
driver.num_images: 2
driver.trigger_mode: "On"
driver.trigger_source: Line1
driver.wait_for_plugins: false
fileio.acquire: false
fileio.array_counter: 0
fileio.auto_increment: false
fileio.capture: false
fileio.chunk_size_auto: false
fileio.compression: None
fileio.create_directory: 0
fileio.enable_callbacks: Enable
fileio.file_name: ""
fileio.file_number: 0
fileio.file_path: ""
fileio.file_template: ""
fileio.file_write_mode: Single
fileio.flush_now: false
fileio.lazy_open: false
fileio.nd_array_address: 0
fileio.nd_array_port: ""
fileio.nd_attributes_file: ""
fileio.num_capture: 0
fileio.num_extra_dims: 0
fileio.num_frames_chunks: 0
fileio.position_mode: false
fileio.queue_size: 0
fileio.swmr_mode: false
fileio.wait_for_plugins: false
fileio.xml_file_name: ""
roistat.acquire: false
roistat.array_counter: 3
roistat.channels.1.min_x: 95
roistat.channels.1.min_y: 610
roistat.channels.1.name_: Red
roistat.channels.1.size_x: 150
roistat.channels.1.size_y: 150
roistat.channels.1.use: true
roistat.channels.2.min_x: 880
roistat.channels.2.min_y: 605
roistat.channels.2.name_: Green
roistat.channels.2.size_x: 150
roistat.channels.2.size_y: 150
roistat.channels.2.use: true
roistat.channels.3.min_x: 1665
roistat.channels.3.min_y: 600
roistat.channels.3.name_: Blue
roistat.channels.3.size_x: 150
roistat.channels.3.size_y: 150
roistat.channels.3.use: true
roistat.enable_callbacks: Enable
roistat.nd_array_address: 0
roistat.nd_array_port: ""
roistat.nd_attributes_file: ""
roistat.queue_size: 0
roistat.wait_for_plugins: false