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
37 changes: 9 additions & 28 deletions doc/devices/dae.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ suitable; instead the [`Dae`](ibex_bluesky_core.devices.dae.Dae) class should be
```python

from ibex_bluesky_core.utils import get_pv_prefix
from ibex_bluesky_core.devices.simpledae import SimpleDae, RunPerPointController, GoodFramesWaiter, GoodFramesNormalizer
from ibex_bluesky_core.devices.simpledae import SimpleDae, RunPerPointController, PeriodGoodFramesWaiter, PeriodGoodFramesNormalizer
prefix = get_pv_prefix()
# One DAE run for each scan point, save the runs after each point.
controller = RunPerPointController(save_run=True)
# Wait for 500 good frames on each run
waiter = GoodFramesWaiter(500)
# Wait for 500 good frames on each run.
# Note despite using RunPerPointController here we are still using PeriodGoodFramesWaiter and PeriodGoodFramesNormalizer.
waiter = PeriodGoodFramesWaiter(500)
# Sum spectra 1..99 inclusive, then normalize by total good frames
reducer = GoodFramesNormalizer(
reducer = PeriodGoodFramesNormalizer(
prefix=prefix,
detector_spectra=[i for i in range(1, 100)],
)
Expand Down Expand Up @@ -161,22 +162,11 @@ DAE signals. For example, normalizing intensities are implemented as a reducer.

A reducer may produce any number of reduced signals.

### {py:obj}`GoodFramesNormalizer<ibex_bluesky_core.devices.simpledae.GoodFramesNormalizer>`

This normalizer sums a set of user-defined detector spectra, and then divides by the number
of good frames.

Published signals:
- `simpledae.good_frames` - the number of good frames reported by the DAE
- `reducer.det_counts` - summed detector counts for all of the user-provided spectra
- `reducer.intensity` - normalized intensity (`det_counts / good_frames`)
- `reducer.det_counts_stddev` - uncertainty (standard deviation) of the summed detector counts
- `reducer.intensity_stddev` - uncertainty (standard deviation) of the normalised intensity

### {py:obj}`PeriodGoodFramesNormalizer<ibex_bluesky_core.devices.simpledae.PeriodGoodFramesNormalizer>`

Equivalent to the `GoodFramesNormalizer` above, but uses good frames only from the current
period. This should be used if a controller which counts into multiple periods is being used.
Uses good frames only from the current period.
This should be used if a controller which counts into multiple periods is being used OR if a
controller counts into multiple runs.

Published signals:
- `simpledae.period.good_frames` - the number of good frames reported by the DAE
Expand Down Expand Up @@ -345,20 +335,11 @@ Waits for a user-specified number of microamp-hours.
Published signals:
- `simpledae.good_uah` - actual good uAh for this run.

### GoodFramesWaiter

[`GoodFramesWaiter`](ibex_bluesky_core.devices.simpledae.GoodFramesWaiter)

Waits for a user-specified number of good frames (in total for the entire run)

Published signals:
- `simpledae.good_frames` - actual good frames for this run.

### PeriodGoodFramesWaiter

[`PeriodGoodFramesWaiter`](ibex_bluesky_core.devices.simpledae.PeriodGoodFramesWaiter)

Waits for a user-specified number of good frames (in the current period)
Waits for a user-specified number of good frames (in the current period) - this should be used even if the controller is splitting up points into separate runs.

Published signals:
- `simpledae.period.good_frames` - actual period good frames for this run.
Expand Down
8 changes: 4 additions & 4 deletions manual_system_tests/dae_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from ibex_bluesky_core.callbacks import ISISCallbacks
from ibex_bluesky_core.devices.block import block_rw_rbv
from ibex_bluesky_core.devices.simpledae import (
GoodFramesNormalizer,
GoodFramesWaiter,
PeriodGoodFramesNormalizer,
PeriodGoodFramesWaiter,
RunPerPointController,
SimpleDae,
)
Expand Down Expand Up @@ -47,8 +47,8 @@ def dae_scan_plan() -> Generator[Msg, None, None]:
block = block_rw_rbv(float, "mot")

controller = RunPerPointController(save_run=True)
waiter = GoodFramesWaiter(500)
reducer = GoodFramesNormalizer(
waiter = PeriodGoodFramesWaiter(500)
reducer = PeriodGoodFramesNormalizer(
prefix=prefix,
detector_spectra=[i for i in range(1, 100)],
)
Expand Down
11 changes: 7 additions & 4 deletions src/ibex_bluesky_core/devices/simpledae/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from ibex_bluesky_core.devices.simpledae._reducers import (
VARIANCE_ADDITION,
DSpacingMappingReducer,
GoodFramesNormalizer,
MonitorNormalizer,
PeriodGoodFramesNormalizer,
PeriodSpecIntegralsReducer,
Expand All @@ -35,7 +34,6 @@
Waiter,
)
from ibex_bluesky_core.devices.simpledae._waiters import (
GoodFramesWaiter,
GoodUahWaiter,
MEventsWaiter,
PeriodGoodFramesWaiter,
Expand All @@ -44,6 +42,11 @@
)
from ibex_bluesky_core.utils import get_pv_prefix

# For backwards compatibility.
# These were removed in https://github.com/ISISComputingGroup/ibex_bluesky_core/issues/136
GoodFramesWaiter = PeriodGoodFramesWaiter
GoodFramesNormalizer = PeriodGoodFramesNormalizer

logger = logging.getLogger(__name__)

__all__ = [
Expand Down Expand Up @@ -182,12 +185,12 @@ def monitor_normalising_dae(
"""
prefix = get_pv_prefix()

waiter = PeriodGoodFramesWaiter(frames)

if periods:
controller = PeriodPerPointController(save_run=save_run)
waiter = PeriodGoodFramesWaiter(frames)
else:
controller = RunPerPointController(save_run=save_run)
waiter = GoodFramesWaiter(frames)

reducer = MonitorNormalizer(
prefix=prefix,
Expand Down
8 changes: 0 additions & 8 deletions src/ibex_bluesky_core/devices/simpledae/_reducers.py
Original file line number Diff line number Diff line change
Expand Up @@ -278,14 +278,6 @@ def denominator(self, dae: "SimpleDae") -> SignalR[int]:
return dae.period.good_frames


class GoodFramesNormalizer(ScalarNormalizer):
"""Sum a set of user-specified spectra, then normalize by total good frames."""

def denominator(self, dae: "SimpleDae") -> SignalR[int]:
"""Get normalization denominator (total good frames)."""
return dae.good_frames


class MonitorNormalizer(Reducer, StandardReadable):
"""Normalize a set of user-specified detector spectra by user-specified monitor spectra."""

Expand Down
8 changes: 0 additions & 8 deletions src/ibex_bluesky_core/devices/simpledae/_waiters.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,6 @@ def get_signal(self, dae: "SimpleDae") -> SignalR[int]:
return dae.period.good_frames


class GoodFramesWaiter(SimpleWaiter[int]):
"""Wait for good frames to reach a user-specified value."""

def get_signal(self, dae: "SimpleDae") -> SignalR[int]:
"""Wait for good frames."""
return dae.good_frames


class GoodUahWaiter(SimpleWaiter[float]):
"""Wait for good microamp-hours to reach a user-specified value."""

Expand Down
27 changes: 4 additions & 23 deletions tests/devices/simpledae/test_reducers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

from ibex_bluesky_core.devices.simpledae import (
VARIANCE_ADDITION,
GoodFramesNormalizer,
MonitorNormalizer,
PeriodGoodFramesNormalizer,
PeriodSpecIntegralsReducer,
Expand All @@ -30,13 +29,6 @@ async def period_good_frames_reducer() -> PeriodGoodFramesNormalizer:
return reducer


@pytest.fixture
async def good_frames_reducer() -> GoodFramesNormalizer:
reducer = GoodFramesNormalizer(prefix="", detector_spectra=[1, 2])
await reducer.connect(mock=True)
return reducer


# detector summer sum_spectra/default, monitor summer sum_spectra/default 1, 1
@pytest.fixture
async def monitor_normalizer() -> MonitorNormalizer:
Expand Down Expand Up @@ -340,24 +332,13 @@ def test_period_good_frames_normalizer_publishes_period_good_frames(
assert period_good_frames_reducer.denominator(fake_dae) == fake_dae.period.good_frames


def test_good_frames_normalizer_publishes_good_frames(
good_frames_reducer: GoodFramesNormalizer,
):
fake_dae: SimpleDae = FakeDae() # type: ignore
readables = good_frames_reducer.additional_readable_signals(fake_dae)
assert fake_dae.good_uah not in readables
assert fake_dae.good_frames in readables

assert good_frames_reducer.denominator(fake_dae) == fake_dae.good_frames


def test_scalar_normalizer_publishes_uncertainties(
simpledae: SimpleDae,
good_frames_reducer: GoodFramesNormalizer,
period_good_frames_reducer: PeriodGoodFramesNormalizer,
):
readables = good_frames_reducer.additional_readable_signals(simpledae)
assert good_frames_reducer.intensity_stddev in readables
assert good_frames_reducer.det_counts_stddev in readables
readables = period_good_frames_reducer.additional_readable_signals(simpledae)
assert period_good_frames_reducer.intensity_stddev in readables
assert period_good_frames_reducer.det_counts_stddev in readables


async def test_period_good_frames_normalizer(
Expand Down
11 changes: 6 additions & 5 deletions tests/devices/simpledae/test_simpledae.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@
from ibex_bluesky_core.devices.dae import DaeCheckingSignal
from ibex_bluesky_core.devices.simpledae import (
Controller,
GoodFramesNormalizer,
GoodFramesWaiter,
GoodUahWaiter,
MonitorNormalizer,
PeriodGoodFramesNormalizer,
PeriodGoodFramesWaiter,
PeriodPerPointController,
Expand Down Expand Up @@ -181,15 +182,15 @@ def test_check_dae():
check_dae_strategies(dae, expected_controller=RunPerPointController)

with pytest.raises(
TypeError, match=r"DAE waiter must be of type GoodFramesWaiter, got PeriodGoodFramesWaiter"
TypeError, match=r"DAE waiter must be of type GoodUahWaiter, got PeriodGoodFramesWaiter"
):
check_dae_strategies(dae, expected_waiter=GoodFramesWaiter)
check_dae_strategies(dae, expected_waiter=GoodUahWaiter)

with pytest.raises(
TypeError,
match=r"DAE reducer must be of type GoodFramesNormalizer, got PeriodGoodFramesNormalizer",
match=r"DAE reducer must be of type MonitorNormalizer, got PeriodGoodFramesNormalizer",
):
check_dae_strategies(dae, expected_reducer=GoodFramesNormalizer)
check_dae_strategies(dae, expected_reducer=MonitorNormalizer)

# Should not raise
check_dae_strategies(
Expand Down
18 changes: 0 additions & 18 deletions tests/devices/simpledae/test_waiters.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from ophyd_async.testing import set_mock_value

from ibex_bluesky_core.devices.simpledae import (
GoodFramesWaiter,
GoodUahWaiter,
MEventsWaiter,
PeriodGoodFramesWaiter,
Expand Down Expand Up @@ -49,23 +48,6 @@ async def test_period_good_frames_waiter(simpledae: "SimpleDae"):
assert waiter.get_signal(simpledae) == simpledae.period.good_frames


async def test_good_frames_waiter(simpledae: "SimpleDae"):
waiter = GoodFramesWaiter(5000)

set_mock_value(simpledae.good_frames, 4999)

with pytest.raises(asyncio.TimeoutError):
await asyncio.wait_for(waiter.wait(simpledae), timeout=SHORT_TIMEOUT)

set_mock_value(simpledae.good_frames, 5000)

# Check this returns - will raise a timeout error if not.
await asyncio.wait_for(waiter.wait(simpledae), timeout=SHORT_TIMEOUT)

assert waiter.additional_readable_signals(simpledae) == [simpledae.good_frames]
assert waiter.get_signal(simpledae) == simpledae.good_frames


async def test_mevents_waiter(simpledae: "SimpleDae"):
waiter = MEventsWaiter(5000)

Expand Down