Skip to content

Commit 7bc8b4a

Browse files
committed
Fix coverage
1 parent 45dd8a1 commit 7bc8b4a

File tree

2 files changed

+101
-88
lines changed

2 files changed

+101
-88
lines changed

src/ibex_bluesky_core/devices/muon.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def damped_oscillator(
3636
return B + A_0 * np.cos(omega_0 * t + phi_0) * np.exp(-t * lambda_0)
3737

3838

39-
def damped_oscillator_multiple( # noqa: PLR0913 PLR0917 (model is just this complex)
39+
def double_damped_oscillator( # noqa: PLR0913 PLR0917 (model is just this complex)
4040
t: NDArray[np.floating],
4141
B: float, # noqa: N803
4242
A_0: float, # noqa: N803

tests/devices/test_muon.py

Lines changed: 100 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pyright: reportMissingParameterType=false
2-
from unittest.mock import AsyncMock, patch
2+
import re
3+
from unittest.mock import AsyncMock, MagicMock, patch
34

45
import lmfit
56
import numpy as np
@@ -10,7 +11,7 @@
1011
from ibex_bluesky_core.devices.muon import (
1112
MuonAsymmetryReducer,
1213
damped_oscillator,
13-
damped_oscillator_multiple,
14+
double_damped_oscillator,
1415
)
1516
from ibex_bluesky_core.devices.simpledae import MEventsWaiter, PeriodPerPointController, SimpleDae
1617

@@ -23,19 +24,6 @@
2324
damped_oscillator_params.add("phi_0", 0.0)
2425
damped_oscillator_params.add("lambda_0", 0.001)
2526

26-
multi_damped_oscillator_model = lmfit.Model(damped_oscillator_multiple)
27-
28-
multi_damped_oscillator_params = lmfit.Parameters()
29-
multi_damped_oscillator_params.add("B", 0.0)
30-
multi_damped_oscillator_params.add("A_0", 0.1, min=0)
31-
multi_damped_oscillator_params.add("omega_0", 0.1, min=0)
32-
multi_damped_oscillator_params.add("phi_0", 0.0)
33-
multi_damped_oscillator_params.add("lambda_0", 0.001)
34-
multi_damped_oscillator_params.add("A_1", 0.1, min=0)
35-
multi_damped_oscillator_params.add("omega_1", 0.1, min=0)
36-
multi_damped_oscillator_params.add("phi_1", 0.0)
37-
multi_damped_oscillator_params.add("lambda_1", 0.001)
38-
3927

4028
@pytest.fixture
4129
def asymmetry_reducer():
@@ -61,18 +49,7 @@ def rebinning_asymmetry_reducer():
6149

6250

6351
@pytest.fixture
64-
def multi_damped_oscillator_asymmetry_reducer():
65-
return MuonAsymmetryReducer(
66-
forward_detectors=np.array([1]),
67-
backward_detectors=np.array([2]),
68-
prefix="UNITTEST:",
69-
model=multi_damped_oscillator_model,
70-
fit_parameters=multi_damped_oscillator_params,
71-
)
72-
73-
74-
@pytest.fixture
75-
async def simpledae_single_oscillator(rebinning_asymmetry_reducer):
52+
async def simpledae(rebinning_asymmetry_reducer):
7653
dae = SimpleDae(
7754
prefix="UNITTEST:",
7855
reducer=rebinning_asymmetry_reducer,
@@ -83,63 +60,50 @@ async def simpledae_single_oscillator(rebinning_asymmetry_reducer):
8360
return dae
8461

8562

86-
@pytest.fixture
87-
async def simpledae_multi_oscillator(multi_damped_oscillator_asymmetry_reducer):
88-
dae = SimpleDae(
89-
prefix="UNITTEST:",
90-
reducer=multi_damped_oscillator_asymmetry_reducer,
91-
waiter=MEventsWaiter(5000),
92-
controller=PeriodPerPointController(save_run=False),
63+
def test_damped_oscillator():
64+
np.testing.assert_allclose(
65+
damped_oscillator(
66+
t=np.array([0, 1, 2, 3, 4, 5], dtype=np.float64),
67+
B=1,
68+
A_0=0.0,
69+
phi_0=0.0,
70+
omega_0=0.0,
71+
lambda_0=0.0,
72+
),
73+
np.array([1, 1, 1, 1, 1, 1], dtype=np.float64),
9374
)
94-
await dae.connect(mock=True)
95-
return dae
9675

9776

98-
def test_asymmetry_reducer_readable_signals_single_oscillator(
99-
simpledae_single_oscillator, rebinning_asymmetry_reducer
100-
):
101-
assert set(
102-
rebinning_asymmetry_reducer.additional_readable_signals(simpledae_single_oscillator)
103-
) == {
104-
simpledae_single_oscillator.reducer.B,
105-
simpledae_single_oscillator.reducer.B_err,
106-
simpledae_single_oscillator.reducer.A_0,
107-
simpledae_single_oscillator.reducer.A_0_err,
108-
simpledae_single_oscillator.reducer.omega_0,
109-
simpledae_single_oscillator.reducer.omega_0_err,
110-
simpledae_single_oscillator.reducer.phi_0,
111-
simpledae_single_oscillator.reducer.phi_0_err,
112-
simpledae_single_oscillator.reducer.lambda_0,
113-
simpledae_single_oscillator.reducer.lambda_0_err,
114-
}
77+
def test_double_damped_oscillator():
78+
np.testing.assert_allclose(
79+
double_damped_oscillator(
80+
t=np.array([0, 1, 2, 3, 4, 5], dtype=np.float64),
81+
B=1,
82+
A_0=0.0,
83+
phi_0=0.0,
84+
omega_0=0.0,
85+
lambda_0=0.0,
86+
A_1=0.0,
87+
phi_1=0.0,
88+
omega_1=0.0,
89+
lambda_1=0.0,
90+
),
91+
np.array([1, 1, 1, 1, 1, 1], dtype=np.float64),
92+
)
11593

11694

117-
def test_asymmetry_reducer_readable_signals_multiple_oscillator(
118-
simpledae_multi_oscillator, multi_damped_oscillator_asymmetry_reducer
119-
):
120-
assert set(
121-
multi_damped_oscillator_asymmetry_reducer.additional_readable_signals(
122-
simpledae_multi_oscillator
123-
)
124-
) == {
125-
simpledae_multi_oscillator.reducer.B,
126-
simpledae_multi_oscillator.reducer.B_err,
127-
simpledae_multi_oscillator.reducer.A_0,
128-
simpledae_multi_oscillator.reducer.A_0_err,
129-
simpledae_multi_oscillator.reducer.omega_0,
130-
simpledae_multi_oscillator.reducer.omega_0_err,
131-
simpledae_multi_oscillator.reducer.phi_0,
132-
simpledae_multi_oscillator.reducer.phi_0_err,
133-
simpledae_multi_oscillator.reducer.lambda_0,
134-
simpledae_multi_oscillator.reducer.lambda_0_err,
135-
simpledae_multi_oscillator.reducer.A_1,
136-
simpledae_multi_oscillator.reducer.A_1_err,
137-
simpledae_multi_oscillator.reducer.omega_1,
138-
simpledae_multi_oscillator.reducer.omega_1_err,
139-
simpledae_multi_oscillator.reducer.phi_1,
140-
simpledae_multi_oscillator.reducer.phi_1_err,
141-
simpledae_multi_oscillator.reducer.lambda_1,
142-
simpledae_multi_oscillator.reducer.lambda_1_err,
95+
def test_asymmetry_reducer_readable_signals(simpledae, rebinning_asymmetry_reducer):
96+
assert set(rebinning_asymmetry_reducer.additional_readable_signals(simpledae)) == {
97+
simpledae.reducer.B,
98+
simpledae.reducer.B_err,
99+
simpledae.reducer.A_0,
100+
simpledae.reducer.A_0_err,
101+
simpledae.reducer.omega_0,
102+
simpledae.reducer.omega_0_err,
103+
simpledae.reducer.phi_0,
104+
simpledae.reducer.phi_0_err,
105+
simpledae.reducer.lambda_0,
106+
simpledae.reducer.lambda_0_err,
143107
}
144108

145109

@@ -193,11 +157,9 @@ def test_rebin_and_sum_with_no_rebinning(asymmetry_reducer):
193157
scipp.testing.assert_allclose(result.coords["tof"], time)
194158

195159

196-
async def test_asymmetry_reducer(simpledae_single_oscillator):
197-
simpledae_single_oscillator.trigger_and_get_specdata = AsyncMock(return_value=None)
198-
simpledae_single_oscillator.reducer._first_det.read_spectrum_dataarray = AsyncMock(
199-
return_value=None
200-
)
160+
async def test_asymmetry_reducer(simpledae):
161+
simpledae.trigger_and_get_specdata = AsyncMock(return_value=None)
162+
simpledae.reducer._first_det.read_spectrum_dataarray = AsyncMock(return_value=None)
201163

202164
with patch(
203165
"ibex_bluesky_core.devices.muon.MuonAsymmetryReducer._calculate_asymmetry",
@@ -215,10 +177,10 @@ async def test_asymmetry_reducer(simpledae_single_oscillator):
215177
},
216178
)
217179

218-
await simpledae_single_oscillator.reducer.reduce_data(simpledae_single_oscillator)
180+
await simpledae.reducer.reduce_data(simpledae)
219181

220-
assert await simpledae_single_oscillator.reducer.B.get_value() == pytest.approx(0.0, abs=1e-8)
221-
assert await simpledae_single_oscillator.reducer.A_0.get_value() == pytest.approx(0.0, abs=1e-8)
182+
assert await simpledae.reducer.B.get_value() == pytest.approx(0.0, abs=1e-8)
183+
assert await simpledae.reducer.A_0.get_value() == pytest.approx(0.0, abs=1e-8)
222184

223185

224186
async def test_asymmetry_reducer_real_data():
@@ -281,3 +243,54 @@ async def test_asymmetry_reducer_real_data():
281243
assert await dae.reducer.omega_0.get_value() == pytest.approx(omega_0, abs=1e-3)
282244
assert await dae.reducer.phi_0.get_value() == pytest.approx(phi_0, abs=1e-3)
283245
assert await dae.reducer.lambda_0.get_value() == pytest.approx(lambda_0, abs=1e-3)
246+
247+
248+
def test_missing_parameters():
249+
with pytest.raises(ValueError, match=r"Missing parameters: .*"):
250+
MuonAsymmetryReducer(
251+
forward_detectors=np.array([1]),
252+
backward_detectors=np.array([2]),
253+
time_bin_edges=sc.linspace("tof", 0, 5, num=20, unit=sc.units.ns, dtype="float64"),
254+
prefix="UNITTEST:",
255+
model=damped_oscillator_model,
256+
fit_parameters=lmfit.Parameters(),
257+
)
258+
259+
260+
def test_calculate_asymmetry(asymmetry_reducer):
261+
with (
262+
patch.object(asymmetry_reducer, "_rebin_and_sum") as rebin_sum_mock,
263+
patch("ibex_bluesky_core.devices.muon.calculate_polarisation") as calculate_asymmetry_mock,
264+
):
265+
fake_da = MagicMock(spec=sc.DataArray)
266+
rebin_sum_mock.return_value = sc.scalar(value=5.0, variance=10.0)
267+
asymmetry_reducer._calculate_asymmetry(
268+
np.array([[0], [0], [0]]), first_spec_dataarray=fake_da
269+
)
270+
271+
calculate_asymmetry_mock.assert_called_with(
272+
sc.scalar(value=5.0, variance=10.5),
273+
sc.scalar(value=5.0, variance=10.5),
274+
asymmetry_reducer._alpha,
275+
)
276+
277+
278+
async def test_if_fit_fails_then_get_error(asymmetry_reducer, simpledae):
279+
await asymmetry_reducer.connect(mock=True)
280+
281+
with (
282+
patch.object(asymmetry_reducer, "_calculate_asymmetry"),
283+
patch.object(asymmetry_reducer, "_fit_data") as fit_data_mock,
284+
patch.object(simpledae, "trigger_and_get_specdata"),
285+
patch.object(asymmetry_reducer._first_det, "read_spectrum_dataarray"),
286+
):
287+
fit_data_mock.return_value = None
288+
289+
with pytest.raises(
290+
ValueError,
291+
match=re.escape(
292+
"MuonAsymmetryReducer failed to fit asymmetry model to muon data.\n"
293+
"Check beamline setup."
294+
),
295+
):
296+
await asymmetry_reducer.reduce_data(simpledae)

0 commit comments

Comments
 (0)