Skip to content

Commit cbffbaa

Browse files
committed
Add normalisation to PeriodSpecIntegralsReducer
1 parent 45c8e07 commit cbffbaa

File tree

3 files changed

+45
-8
lines changed

3 files changed

+45
-8
lines changed

doc/devices/dae.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,13 +191,16 @@ Published signals:
191191
### {py:obj}`PeriodSpecIntegralsReducer<ibex_bluesky_core.devices.simpledae.PeriodSpecIntegralsReducer>`
192192

193193
This reducer exposes the raw integrals of the configured detector and monitor spectra, as
194-
numpy arrays. By itself, this reducer is not useful in a scan, but is useful for downstream
195-
processing as performed by reflectometry detector-mapping alignment for
196-
example.
194+
numpy arrays. As a convenience, this reducer additionally publishes scalar sums of detector
195+
and monitor intensities, and an 'intensity' (detector sum divided by monitor sum).
197196

198197
Published signals:
199198
- `reducer.mon_integrals` - `numpy` array of integrated counts on each configured monitor pixel.
200199
- `reducer.det_integrals` - `numpy` array of integrated counts on each configured detector pixel.
200+
- `reducer.mon_sum` - scalar of integrated counts on each configured monitor.
201+
- `reducer.det_sum` - scalar of integrated counts on each configured detector pixel.
202+
- `reducer.intensity` - detector sum normalized by monitor sum.
203+
- `reducer.intensity_stddev` - standard deviation of normalized intensity.
201204

202205
### {py:obj}`DSpacingMappingReducer<ibex_bluesky_core.devices.simpledae.DSpacingMappingReducer>`
203206

src/ibex_bluesky_core/devices/simpledae/_reducers.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -321,12 +321,19 @@ def additional_readable_signals(self, dae: Dae) -> list[Device]:
321321
class PeriodSpecIntegralsReducer(Reducer, StandardReadable):
322322
"""A DAE Reducer which simultaneously exposes integrals of many spectra in the current period.
323323
324-
Two types of integrals are available: detectors and monitors. Other than defaults, their
325-
behaviour is identical. No normalization is performed in this reducer - exactly how the
326-
detector and monitor integrals are used is defined downstream.
324+
Two types of integrals are available: detectors and monitors.
327325
328-
By itself, the data from this reducer is not suitable for use in a scan - but it provides
329-
raw data which may be useful for further processing as part of callbacks (e.g. LiveDispatchers).
326+
The exposed signals are:
327+
328+
- det_integrals (1-dimensional array)
329+
- mon_integrals (1-dimensional array)
330+
331+
For convenience, three additional properties are also exposed:
332+
333+
- det_sum (scalar) - the sum of detector intensities across every detector.
334+
- mon_sum (scalar) - the sum of monitor intensities across every monitor.
335+
- intensity (scalar) - det_sum / mon_sum
336+
- intensity_stddev (scalar) - det_sum / mon_sum
330337
"""
331338

332339
def __init__(
@@ -354,6 +361,10 @@ def __init__(
354361
self.mon_integrals, self._mon_integrals_setter = soft_signal_r_and_setter(
355362
Array1D[np.int32], np.ndarray([], dtype=np.int32)
356363
)
364+
self.det_sum, self._det_sum_setter = soft_signal_r_and_setter(int, 0)
365+
self.mon_sum, self._mon_sum_setter = soft_signal_r_and_setter(int, 0)
366+
self.intensity, self._intensity_setter = soft_signal_r_and_setter(float, 0.0)
367+
self.intensity_stddev, self._intensity_stddev_setter = soft_signal_r_and_setter(float, 0.0)
357368

358369
super().__init__(name="")
359370

@@ -393,13 +404,28 @@ async def reduce_data(self, dae: Dae) -> None:
393404
self._det_integrals_setter(det_integrals)
394405
self._mon_integrals_setter(mon_integrals)
395406

407+
scalar_det_sum = det_integrals.sum()
408+
scalar_mon_sum = mon_integrals.sum()
409+
self._det_sum_setter(scalar_det_sum)
410+
self._mon_sum_setter(scalar_mon_sum)
411+
412+
normalized = sc.scalar(
413+
scalar_det_sum, variance=scalar_det_sum + VARIANCE_ADDITION, dtype="float64"
414+
) / sc.scalar(scalar_mon_sum, variance=scalar_mon_sum + VARIANCE_ADDITION, dtype="float64")
415+
self._intensity_setter(normalized.value)
416+
self._intensity_stddev_setter(normalized.variance**0.5)
417+
396418
logger.info("reduction complete")
397419

398420
def additional_readable_signals(self, dae: Dae) -> list[Device]:
399421
"""Publish interesting signals derived or used by this reducer."""
400422
return [
401423
self.mon_integrals,
402424
self.det_integrals,
425+
self.det_sum,
426+
self.mon_sum,
427+
self.intensity,
428+
self.intensity_stddev,
403429
]
404430

405431

tests/devices/simpledae/test_reducers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,14 @@ async def test_period_spec_integrals_reducer(
10121012
np.testing.assert_equal(await reducer.mon_integrals.get_value(), mon_integrals)
10131013
np.testing.assert_equal(await reducer.det_integrals.get_value(), det_integrals)
10141014

1015+
assert await reducer.mon_sum.get_value() == mon_integrals.sum()
1016+
assert await reducer.det_sum.get_value() == det_integrals.sum()
1017+
1018+
assert (
1019+
pytest.approx(await reducer.intensity.get_value())
1020+
== det_integrals.sum() / mon_integrals.sum()
1021+
)
1022+
10151023

10161024
def test_period_spec_integrals_reducer_publishes_signals(simpledae: SimpleDae):
10171025
reducer = PeriodSpecIntegralsReducer(detectors=np.array([]), monitors=np.array([]))

0 commit comments

Comments
 (0)