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

1""" 

2Tests scores.categorical.binary 

3""" 

4import dask 

5import dask.array 

6import numpy as np 

7import pytest 

8import xarray as xr 

9 

10from scores.categorical import probability_of_detection, probability_of_false_detection 

11 

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]}) 

21 

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") 

28 

29 

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") 

38 

39 

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) 

66 

67 

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) 

75 

76 

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) 

89 

90 

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) 

116 

117 

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) 

125 

126 

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)