Coverage for tests/categorical/test_binary.py: 100%
57 statements
« prev ^ index » next coverage.py v7.3.2, created at 2024-02-28 12:51 +1100
« prev ^ index » next coverage.py v7.3.2, created at 2024-02-28 12:51 +1100
1"""
2Tests scores.categorical.binary
3"""
4import dask
5import dask.array
6import numpy as np
7import pytest
8import xarray as xr
10from scores.categorical import probability_of_detection, probability_of_false_detection
12fcst0 = xr.DataArray(data=[[0, 0], [0, np.nan]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
13fcst1 = xr.DataArray(data=[[1, 1], [1, np.nan]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
14fcst_mix = xr.DataArray(data=[[0, 1], [1, np.nan]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
15obs0 = xr.DataArray(data=[[0, 0], [0, 0]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
16obs1 = xr.DataArray(data=[[1, 1], [1, 1]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
17obs_mix = xr.DataArray(data=[[0, 1], [1, np.nan]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
18fcst_bad = xr.DataArray(data=[[0, 0.2], [0, np.nan]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
19obs_bad = xr.DataArray(data=[[0, 3], [0, np.nan]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
20weight_array = xr.DataArray(data=[[2, 1], [1, 1]], dims=["a", "b"], coords={"a": [100, 200], "b": [500, 600]})
22expected_pod0 = xr.DataArray(data=np.nan, name="ctable_probability_of_detection")
23expected_pod1 = xr.DataArray(data=1, name="ctable_probability_of_detection")
24expected_pod2 = xr.DataArray(data=0, name="ctable_probability_of_detection")
25expected_pod3 = xr.DataArray(data=2 / 3, name="ctable_probability_of_detection")
26expected_poda = xr.DataArray(data=[0.5, 1], dims="b", coords={"b": [500, 600]}, name="ctable_probability_of_detection")
27expected_pod_weighted = xr.DataArray(data=1 / 2, name="ctable_probability_of_detection")
30expected_pofd0 = xr.DataArray(data=0, name="ctable_probability_of_false_detection")
31expected_pofd1 = xr.DataArray(data=np.nan, name="ctable_probability_of_false_detection")
32expected_pofd2 = xr.DataArray(data=1, name="ctable_probability_of_false_detection")
33expected_pofd3 = xr.DataArray(data=2 / 3, name="ctable_probability_of_false_detection")
34expected_pofda = xr.DataArray(
35 data=[0.5, 1], dims="b", coords={"b": [500, 600]}, name="ctable_probability_of_false_detection"
36)
37expected_pofd_weighted = xr.DataArray(data=1 / 2, name="ctable_probability_of_detection")
40@pytest.mark.parametrize(
41 ("fcst", "obs", "reduce_dims", "check_args", "weights", "expected"),
42 [
43 (fcst0, obs0, None, True, None, expected_pod0), # Fcst zeros, obs zeros
44 (fcst1, obs1, None, True, None, expected_pod1), # Fcst ones, obs ones
45 (fcst1, obs0, None, True, None, expected_pod0), # Fcst ones, obs zeros
46 (fcst0, obs1, None, True, None, expected_pod2), # Fcst zeros, obs ones
47 (fcst_mix, obs1, None, True, None, expected_pod3), # Fcst mixed, obs ones
48 (fcst1, obs_mix, None, True, None, expected_pod1), # Fcst ones, obs mixed
49 (fcst_mix, obs1, "a", True, None, expected_poda), # Fcst mix, obs ones, only reduce one dim
50 (fcst_bad, obs0, None, False, None, expected_pod0), # Don't check for bad data
51 (fcst_mix, obs1, None, True, weight_array, expected_pod_weighted), # Fcst mixed, obs ones, with weights
52 (
53 xr.Dataset({"array1": fcst0, "array2": fcst1}),
54 xr.Dataset({"array1": obs0, "array2": obs1}),
55 None,
56 True,
57 None,
58 xr.Dataset({"array1": expected_pod0, "array2": expected_pod1}),
59 ), # Test with DataSet for inputs
60 ],
61)
62def test_probability_of_detection(fcst, obs, reduce_dims, check_args, weights, expected):
63 """Tests probability_of_detection"""
64 result = probability_of_detection(fcst, obs, reduce_dims=reduce_dims, weights=weights, check_args=check_args)
65 xr.testing.assert_equal(result, expected)
68def test_pod_dask():
69 "Tests that probability_of_detection works with dask"
70 result = probability_of_detection(fcst_mix.chunk(), obs1.chunk())
71 assert isinstance(result.data, dask.array.Array)
72 result = result.compute()
73 assert isinstance(result.data, np.ndarray)
74 xr.testing.assert_equal(result, expected_pod3)
77@pytest.mark.parametrize(
78 ("fcst", "obs", "error_msg"),
79 [
80 (fcst_bad, obs0, "`fcst` contains values that are not in the set {0, 1, np.nan}"),
81 (fcst0, obs_bad, "`obs` contains values that are not in the set {0, 1, np.nan}"),
82 ],
83)
84def test_probability_of_detection_raises(fcst, obs, error_msg):
85 """test probability_of_detection raises"""
86 with pytest.raises(ValueError) as exc:
87 probability_of_detection(fcst, obs)
88 assert error_msg in str(exc.value)
91@pytest.mark.parametrize(
92 ("fcst", "obs", "reduce_dims", "check_args", "weights", "expected"),
93 [
94 (fcst0, obs0, None, True, None, expected_pofd0), # Fcst zeros, obs zeros
95 (fcst1, obs1, None, True, None, expected_pofd1), # Fcst ones, obs ones
96 (fcst1, obs0, None, True, None, expected_pofd2), # Fcst ones, obs zeros
97 (fcst0, obs1, None, True, None, expected_pofd1), # Fcst zeros, obs ones
98 (fcst_mix, obs0, None, True, None, expected_pofd3), # Fcst ones, obs mixed
99 (fcst_mix, obs0, "a", True, None, expected_poda), # Fcst mix, obs ones, only reduce one dim
100 (fcst_bad, obs0, None, False, None, expected_pofd0), # Don't check for bad data
101 (fcst_mix, obs0, None, True, weight_array, expected_pofd_weighted), # Fcst mixed, obs ones, with weights
102 (
103 xr.Dataset({"array1": fcst0, "array2": fcst1}),
104 xr.Dataset({"array1": obs0, "array2": obs1}),
105 None,
106 True,
107 None,
108 xr.Dataset({"array1": expected_pofd0, "array2": expected_pofd1}),
109 ), # Test with DataSet for inputs
110 ],
111)
112def test_probability_of_false_detection(fcst, obs, reduce_dims, check_args, weights, expected):
113 """Tests probability_of_false_detection"""
114 result = probability_of_false_detection(fcst, obs, reduce_dims=reduce_dims, weights=weights, check_args=check_args)
115 xr.testing.assert_equal(result, expected)
118def test_pofd_dask():
119 "Tests that probability_of_false_detection works with dask"
120 result = probability_of_false_detection(fcst_mix.chunk(), obs0.chunk())
121 assert isinstance(result.data, dask.array.Array)
122 result = result.compute()
123 assert isinstance(result.data, np.ndarray)
124 xr.testing.assert_equal(result, expected_pofd3)
127@pytest.mark.parametrize(
128 ("fcst", "obs", "error_msg"),
129 [
130 (fcst_bad, obs0, "`fcst` contains values that are not in the set {0, 1, np.nan}"),
131 (fcst0, obs_bad, "`obs` contains values that are not in the set {0, 1, np.nan}"),
132 ],
133)
134def test_probability_of_false_detection_raises(fcst, obs, error_msg):
135 """test probability_of_false_detection raises"""
136 with pytest.raises(ValueError) as exc:
137 probability_of_false_detection(fcst, obs)
138 assert error_msg in str(exc.value)