Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
496a22e
temp storing changes to work on another ticket
danielmaclaren Jul 21, 2025
81fdf27
Merge remote-tracking branch 'origin/main' into ticket164wrapper
danielmaclaren Sep 4, 2025
1d2636e
three wrappers, tests and documentation
danielmaclaren Oct 13, 2025
f10dedb
fixed incorrect path within dae_table test
danielmaclaren Oct 13, 2025
27aff24
Merge branch 'main' into ticket164wrapper
danielmaclaren Oct 13, 2025
ffd43aa
ruff checks
danielmaclaren Oct 13, 2025
1228094
Merge branch 'ticket164wrapper' of https://github.com/IsisComputingGr…
danielmaclaren Oct 13, 2025
67b5670
deleted files
danielmaclaren Oct 13, 2025
3ff0cf6
ruff format changes
danielmaclaren Oct 13, 2025
42a49cd
updated dae parameters in wrapper
danielmaclaren Oct 13, 2025
d8dabb3
ruff check and format
danielmaclaren Oct 13, 2025
fd772c1
ruff --fix
danielmaclaren Oct 13, 2025
36805b1
removed if statement
danielmaclaren Oct 13, 2025
9151497
updates that aren't working
danielmaclaren Oct 28, 2025
7e03513
fix num_periods test
rerpha Oct 28, 2025
0865761
updated tests for wrappers
danielmaclaren Oct 29, 2025
dba1ce2
updated wrapper tests
danielmaclaren Oct 29, 2025
23affff
refactoring of tests
danielmaclaren Oct 29, 2025
4432835
ruff checks
danielmaclaren Oct 29, 2025
161818e
ruff checks
danielmaclaren Oct 29, 2025
c31c388
exposed wrapper files to __all__
danielmaclaren Oct 29, 2025
d8fb08b
ruff fixes
danielmaclaren Oct 29, 2025
b028f81
Merge remote-tracking branch 'origin/ticket164wrapper' into ticket164…
danielmaclaren Oct 29, 2025
be7125d
ruff fixes (plan stubs)
danielmaclaren Oct 29, 2025
04cb045
corrected the rest of the comments
danielmaclaren Oct 30, 2025
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
79 changes: 79 additions & 0 deletions doc/plan_stubs/plan_wrappers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Plan Wrappers

Plan wrappers that temporarily modify [DAE (Data Acquisition Electronics)](https://isiscomputinggroup.github.io/ibex_bluesky_core/devices/dae.html#dae-data-acquisition-electronics) settings during a plan, automatically restoring the original values afterwards. This ensures that your experiments don't permanently change instrument configuration.

## Available Wrappers

### DAE Table

:py:obj:`dae_table_wrapper <ibex_bluesky_core.plan_stubs.dae_table_wrapper>`

```python
RE(
_with_dae_tables(
bps.null(),
dae=dae,
new_settings=modified_settings
)
)
```

Where `modified_settings` is a dataset in the form :py:obj:`DaeSettingsData < ibex_bluesky_core.devices.dae.DaeSettingsData>`

A function that wraps a plan to temporarily modify the DAE table.

### Num Periods
:py:obj:`num_periods_wrapper <ibex_bluesky_core.plan_stubs.num_periods_wrapper>`

```python
RE(
_with_num_periods(
bps.null(),
dae=dae,
number_of_periods=1000
)
)
```
A function that wraps a plan to temporarily modify the number of periods.

### Time Channels
:py:obj:`time_channels_wrapper <ibex_bluesky_core.plan_stubs.time_channels_wrapper>`:

```python
RE(
_with_time_channels(
bps.null(),
dae=dae,
new_settings=modified_settings
)
)
```
Where `modified_settings` is a dataset in the form :py:obj:`DaeTCBSettingsData < ibex_bluesky_core.devices.dae.DaeTCBSettingsData>`

A function that wraps a plan to temporarily modify the time channels boundaries.

## Usage

To use these wrappers, the plan written by the user must be wrapped by the function within the RunEngine:

``` python

from bluesky import RunEngine
from ibex_bluesky_core.plan_stubs import _with_num_periods
from ibex_bluesky_core.devices.simpledae import SimpleDae

dae = SimpleDae() # Give your DAE options here
RE = RunEngine()

RE(
_with_num_periods(
bps.null(), # Default plan to run
dae=dae,
number_of_periods=1000 # Temporary number of periods to run
)
)

```

the plan with the modified DAE settings, restoring the original settings afterwards.

6 changes: 4 additions & 2 deletions src/ibex_bluesky_core/devices/dae/_period_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from xml.etree.ElementTree import tostring

from bluesky.protocols import Locatable, Location, Movable
from ophyd_async.core import AsyncStatus, Device, SignalRW
from ophyd_async.core import AsyncStatus, SignalRW, StandardReadable

from ibex_bluesky_core.devices import (
isis_epics_signal_rw,
Expand Down Expand Up @@ -108,7 +108,9 @@ def _convert_period_settings_to_xml(current_xml: str, value: DaePeriodSettingsDa
return tostring(root, encoding="unicode")


class DaePeriodSettings(Device, Locatable[DaePeriodSettingsData], Movable[DaePeriodSettingsData]):
class DaePeriodSettings(
StandardReadable, Locatable[DaePeriodSettingsData], Movable[DaePeriodSettingsData]
):
"""Subdevice for the DAE hardware period settings."""

def __init__(self, dae_prefix: str, name: str = "") -> None:
Expand Down
4 changes: 2 additions & 2 deletions src/ibex_bluesky_core/devices/dae/_tcb_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from xml.etree.ElementTree import tostring

from bluesky.protocols import Locatable, Location, Movable
from ophyd_async.core import AsyncStatus, Device, SignalRW
from ophyd_async.core import AsyncStatus, SignalRW, StandardReadable

from ibex_bluesky_core.devices import (
compress_and_hex,
Expand Down Expand Up @@ -120,7 +120,7 @@ def _convert_tcb_settings_to_xml(current_xml: str, settings: DaeTCBSettingsData)
return tostring(root, encoding="unicode")


class DaeTCBSettings(Device, Locatable[DaeTCBSettingsData], Movable[DaeTCBSettingsData]):
class DaeTCBSettings(StandardReadable, Locatable[DaeTCBSettingsData], Movable[DaeTCBSettingsData]):
"""Subdevice for the DAE time channel settings."""

def __init__(self, dae_prefix: str, name: str = "") -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
from ophyd_async.epics.motor import Motor, UseSetMode

from ibex_bluesky_core.devices.reflectometry import ReflParameter
from ibex_bluesky_core.plan_stubs.dae_table_wrapper import _with_dae_tables
from ibex_bluesky_core.plan_stubs.num_periods_wrapper import _with_num_periods
from ibex_bluesky_core.plan_stubs.time_channels_wrapper import _with_time_channels
from ibex_bluesky_core.utils import NamedReadableAndMovable

logger = logging.getLogger(__name__)
Expand All @@ -25,6 +28,9 @@


__all__ = [
"_with_dae_tables",
"_with_num_periods",
"_with_time_channels",
"call_qt_aware",
"call_sync",
"polling_plan",
Expand Down
43 changes: 43 additions & 0 deletions src/ibex_bluesky_core/plan_stubs/dae_table_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Wrap a plan with temporary modification to DAE Settings."""

from collections.abc import Generator

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
from bluesky.utils import Msg
from ophyd_async.plan_stubs import ensure_connected

from ibex_bluesky_core.devices.dae import Dae, DaeSettingsData


def _with_dae_tables(
plan: Generator[Msg, None, None], dae: Dae, new_settings: DaeSettingsData
) -> Generator[Msg, None, None]:
"""Wrap a plan with temporary modification to DAE Settings.

Args:
plan: The plan to wrap.
dae: The Dae instance.
new_settings: The new DAE Settings to apply temporarily.

Returns:
A generator which runs the plan with the modified DAE settings, restoring the original
settings afterwards.

"""
yield from ensure_connected(dae)

original_dae_setting = None

def _inner() -> Generator[Msg, None, None]:
nonlocal original_dae_setting
original_dae_setting = yield from bps.rd(dae.dae_settings)

yield from bps.mv(dae.dae_settings, new_settings)

yield from plan

def _cleanup() -> Generator[Msg, None, None]:
yield from bps.mv(dae.dae_settings, original_dae_setting)

return (yield from bpp.finalize_wrapper(_inner(), _cleanup()))
42 changes: 42 additions & 0 deletions src/ibex_bluesky_core/plan_stubs/num_periods_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
"""Wrap a plan with temporary modification to Periods Settings."""

from collections.abc import Generator

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
from bluesky.utils import Msg
from ophyd_async.plan_stubs import ensure_connected

from ibex_bluesky_core.devices.dae import Dae


def _with_num_periods(
plan: Generator[Msg, None, None], dae: Dae, number_of_periods: int
) -> Generator[Msg, None, None]:
"""Wrap a plan with temporary modification to Periods Settings.

Args:
plan: The plan to wrap.
dae: The Dae instance.
number_of_periods: The number of periods to set to temporarily.

Returns:
A generator which runs the plan with the modified number of periods, restoring the original
number of periods afterwards.

"""
original_num_periods = None

def _inner() -> Generator[Msg, None, None]:
yield from ensure_connected(dae)
nonlocal original_num_periods
original_num_periods = yield from bps.rd(dae.number_of_periods)

yield from bps.mv(dae.number_of_periods, number_of_periods)

yield from plan

def _cleanup() -> Generator[Msg, None, None]:
yield from bps.mv(dae.number_of_periods, original_num_periods)

return (yield from bpp.finalize_wrapper(_inner(), _cleanup()))
43 changes: 43 additions & 0 deletions src/ibex_bluesky_core/plan_stubs/time_channels_wrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Wrap a plan with temporary modification to Time Channel Settings."""

from collections.abc import Generator

import bluesky.plan_stubs as bps
import bluesky.preprocessors as bpp
from bluesky.utils import Msg
from ophyd_async.plan_stubs import ensure_connected

from ibex_bluesky_core.devices.dae import Dae, DaeTCBSettingsData


def _with_time_channels(
plan: Generator[Msg, None, None], dae: Dae, new_tcb_settings: DaeTCBSettingsData
) -> Generator[Msg, None, None]:
"""Wrap a plan with temporary modification to Time Channel Settings.

Args:
plan: The plan to wrap.
dae: The Dae instance.
new_tcb_settings: The time channel settings to apply temporarily.

Returns:
A generator which runs the plan with the modified TCB settings, restoring the original
settings afterwards.

"""
yield from ensure_connected(dae)

original_time_channels = None

def _inner() -> Generator[Msg, None, None]:
nonlocal original_time_channels
original_time_channels = yield from bps.rd(dae.tcb_settings)

yield from bps.mv(dae.tcb_settings, new_tcb_settings)

yield from plan

def _cleanup() -> Generator[Msg, None, None]:
yield from bps.mv(dae.tcb_settings, original_time_channels)

return (yield from bpp.finalize_wrapper(_inner(), _cleanup()))
8 changes: 8 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pytest
from bluesky.run_engine import RunEngine

from ibex_bluesky_core.devices.dae import Dae
from ibex_bluesky_core.devices.simpledae import Controller, Reducer, SimpleDae, Waiter
from ibex_bluesky_core.run_engine import get_run_engine

Expand Down Expand Up @@ -36,3 +37,10 @@ async def simpledae() -> SimpleDae:
)
await dae.connect(mock=True)
return dae


@pytest.fixture
async def dae() -> Dae:
dae = Dae("UNITTEST:MOCK:")
await dae.connect(mock=True)
return dae
7 changes: 0 additions & 7 deletions tests/devices/test_dae.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,6 @@
)


@pytest.fixture
async def dae() -> Dae:
dae = Dae("UNITTEST:MOCK:")
await dae.connect(mock=True)
return dae


@pytest.fixture
async def spectrum() -> DaeSpectra:
spectrum = DaeSpectra(dae_prefix="UNITTEST:MOCK:", spectra=1, period=1)
Expand Down
Loading