11# pyright: reportMissingParameterType=false
22import math
3+ import re
34from unittest .mock import AsyncMock
45
56import numpy as np
910
1011from ibex_bluesky_core .devices .simpledae import SimpleDae
1112from ibex_bluesky_core .devices .simpledae .reducers import (
13+ VARIANCE_ADDITION ,
1214 GoodFramesNormalizer ,
1315 MonitorNormalizer ,
1416 PeriodGoodFramesNormalizer ,
@@ -256,6 +258,7 @@ def spectra_bins_easy_to_test() -> sc.DataArray:
256258 data = sc .Variable (
257259 dims = ["tof" ],
258260 values = [1000.0 , 2000.0 , 3000.0 , 2000.0 , 1000.0 ],
261+ variances = [1000.0 , 2000.0 , 3000.0 , 2000.0 , 1000.0 ],
259262 unit = sc .units .counts ,
260263 dtype = "float64" ,
261264 ),
@@ -273,6 +276,7 @@ def spectra_bins_tof_convert_to_wavelength_easy() -> sc.DataArray:
273276 data = sc .Variable (
274277 dims = ["tof" ],
275278 values = [1000.0 , 2000.0 , 3000.0 , 2000.0 , 1000.0 ],
279+ variances = [1000.0 , 2000.0 , 3000.0 , 2000.0 , 1000.0 ],
276280 unit = sc .units .counts ,
277281 dtype = "float64" ,
278282 ),
@@ -293,6 +297,7 @@ def spectra_bins_tof_convert_to_wavelength_easy_copy() -> sc.DataArray:
293297 data = sc .Variable (
294298 dims = ["tof" ],
295299 values = [1000.0 , 2000.0 , 3000.0 , 2000.0 , 1000.0 ],
300+ variances = [1000.0 , 2000.0 , 3000.0 , 2000.0 , 1000.0 ],
296301 unit = sc .units .counts ,
297302 dtype = "float64" ,
298303 ),
@@ -361,13 +366,23 @@ async def test_period_good_frames_normalizer(
361366
362367 period_good_frames_reducer .detectors [1 ].read_spectrum_dataarray = AsyncMock (
363368 return_value = sc .DataArray (
364- data = sc .Variable (dims = ["tof" ], values = [1000.0 , 2000.0 , 3000.0 ], unit = sc .units .counts ),
369+ data = sc .Variable (
370+ dims = ["tof" ],
371+ values = [1000.0 , 2000.0 , 3000.0 ],
372+ variances = [1000.0 , 2000.0 , 3000.0 ],
373+ unit = sc .units .counts ,
374+ ),
365375 coords = {"tof" : sc .array (dims = ["tof" ], values = [0 , 1 , 2 , 3 ])},
366376 )
367377 )
368378 period_good_frames_reducer .detectors [2 ].read_spectrum_dataarray = AsyncMock (
369379 return_value = sc .DataArray (
370- data = sc .Variable (dims = ["tof" ], values = [4000.0 , 5000.0 , 6000.0 ], unit = sc .units .counts ),
380+ data = sc .Variable (
381+ dims = ["tof" ],
382+ values = [4000.0 , 5000.0 , 6000.0 ],
383+ variances = [1000.0 , 2000.0 , 3000.0 ],
384+ unit = sc .units .counts ,
385+ ),
371386 coords = {"tof" : sc .array (dims = ["tof" ], values = [0 , 1 , 2 , 3 ])},
372387 )
373388 )
@@ -395,6 +410,7 @@ async def test_period_good_frames_normalizer_uncertainties(
395410 values = [1000.0 , 2000.0 , 3000.0 ],
396411 variances = [1000.0 , 2000.0 , 3000.0 ],
397412 unit = sc .units .counts ,
413+ dtype = "float64" ,
398414 ),
399415 coords = {"tof" : sc .array (dims = ["tof" ], values = [0 , 1 , 2 , 3 ])},
400416 )
@@ -406,6 +422,7 @@ async def test_period_good_frames_normalizer_uncertainties(
406422 values = [4000.0 , 5000.0 , 6000.0 ],
407423 variances = [4000.0 , 5000.0 , 6000.0 ],
408424 unit = sc .units .counts ,
425+ dtype = "float64" ,
409426 ),
410427 coords = {
411428 "tof" : sc .array (
@@ -420,8 +437,10 @@ async def test_period_good_frames_normalizer_uncertainties(
420437 det_counts_stddev = await period_good_frames_reducer .det_counts_stddev .get_value ()
421438 intensity_stddev = await period_good_frames_reducer .intensity_stddev .get_value ()
422439
423- assert det_counts_stddev == math .sqrt (21000 )
424- assert intensity_stddev == pytest .approx (math .sqrt ((21000 + (123 ** 2 / 21000 )) / 123 ** 2 ), 1e-4 )
440+ assert det_counts_stddev == math .sqrt (21000 + VARIANCE_ADDITION )
441+ assert intensity_stddev == pytest .approx (
442+ math .sqrt ((21000 + VARIANCE_ADDITION ) / (123 ** 2 )), 1e-4
443+ )
425444
426445
427446async def test_period_good_frames_normalizer_zero_counts (
@@ -458,13 +477,11 @@ async def test_period_good_frames_normalizer_zero_counts(
458477 )
459478 )
460479
461- await period_good_frames_reducer .reduce_data (simpledae )
462-
463- det_counts_stddev = await period_good_frames_reducer .det_counts_stddev .get_value ()
464- intensity_stddev = await period_good_frames_reducer .intensity_stddev .get_value ()
465-
466- assert det_counts_stddev == 0
467- assert intensity_stddev == 0
480+ with pytest .raises (
481+ ValueError ,
482+ match = re .escape ("Cannot normalize; denominator is zero. Check beamline configuration." ),
483+ ):
484+ await period_good_frames_reducer .reduce_data (simpledae )
468485
469486
470487async def test_scalar_normalizer_tof_bounded_zero_to_one_half (
@@ -542,13 +559,23 @@ async def test_monitor_normalizer(
542559): # 1, 1
543560 monitor_normalizer .detectors [1 ].read_spectrum_dataarray = AsyncMock (
544561 return_value = sc .DataArray (
545- data = sc .Variable (dims = ["tof" ], values = [1000.0 , 2000.0 , 3000.0 ], unit = sc .units .counts ),
562+ data = sc .Variable (
563+ dims = ["tof" ],
564+ values = [1000.0 , 2000.0 , 3000.0 ],
565+ variances = [1000.0 , 2000.0 , 3000.0 ],
566+ unit = sc .units .counts ,
567+ ),
546568 coords = {"tof" : sc .array (dims = ["tof" ], values = [0 , 1 , 2 , 3 ])},
547569 )
548570 )
549571 monitor_normalizer .monitors [2 ].read_spectrum_dataarray = AsyncMock (
550572 return_value = sc .DataArray (
551- data = sc .Variable (dims = ["tof" ], values = [4000.0 , 5000.0 , 6000.0 ], unit = sc .units .counts ),
573+ data = sc .Variable (
574+ dims = ["tof" ],
575+ values = [4000.0 , 5000.0 , 6000.0 ],
576+ variances = [4000.0 , 5000.0 , 6000.0 ],
577+ unit = sc .units .counts ,
578+ ),
552579 coords = {"tof" : sc .array (dims = ["tof" ], values = [0 , 1 , 2 , 3 ])},
553580 )
554581 )
@@ -590,15 +617,11 @@ async def test_monitor_normalizer_zero_counts(
590617 )
591618 )
592619
593- await monitor_normalizer .reduce_data (simpledae )
594-
595- det_counts_stddev = await monitor_normalizer .det_counts_stddev .get_value ()
596- mon_counts_stddev = await monitor_normalizer .mon_counts_stddev .get_value ()
597- intensity_stddev = await monitor_normalizer .intensity_stddev .get_value ()
598-
599- assert det_counts_stddev == 0
600- assert mon_counts_stddev == 0
601- assert intensity_stddev == 0
620+ with pytest .raises (
621+ ValueError ,
622+ match = re .escape ("Cannot normalize; got zero monitor counts. Check beamline configuration." ),
623+ ):
624+ await monitor_normalizer .reduce_data (simpledae )
602625
603626
604627async def test_monitor_normalizer_uncertainties (
@@ -633,9 +656,11 @@ async def test_monitor_normalizer_uncertainties(
633656 mon_counts_stddev = await monitor_normalizer .mon_counts_stddev .get_value ()
634657 intensity_stddev = await monitor_normalizer .intensity_stddev .get_value ()
635658
636- assert det_counts_stddev == math .sqrt (6000 )
659+ assert det_counts_stddev == math .sqrt (6000 + VARIANCE_ADDITION )
637660 assert mon_counts_stddev == math .sqrt (15000 )
638- assert intensity_stddev == pytest .approx (math .sqrt ((6000 + (6000 ** 2 / 15000 )) / 15000 ** 2 ), 1e-4 )
661+ assert intensity_stddev == pytest .approx (
662+ (6000 / 15000 ) * math .sqrt ((6000.5 / 6000 ** 2 ) + (15000 / 15000 ** 2 )), 1e-8
663+ )
639664
640665
641666def test_monitor_normalizer_publishes_raw_and_normalized_counts (
@@ -658,7 +683,7 @@ def test_monitor_normalizer_publishes_raw_and_normalized_count_uncertainties(
658683 assert monitor_normalizer .mon_counts_stddev in readables
659684
660685
661- async def test_monitor_normalizer_det_sum_normal_mon_sum_tof_bound_ ( # 1, 2
686+ async def test_monitor_normalizer_det_sum_normal_mon_sum_tof_bound ( # 1, 2
662687 simpledae : SimpleDae ,
663688 monitor_normalizer_zero_to_one_half_det_norm_mon_tof : MonitorNormalizer ,
664689 spectra_bins_easy_to_test : sc .DataArray ,
0 commit comments