Coverage for tests/probabilty/test_functions.py: 100%

1"""

2 This module contains unit tests for scores.probability.functions

3"""

4 import numpy as np

5 import pytest

6 import xarray as xr

7

8 import scores.probability.checks

9 import scores.probability.functions

10 from tests import assertions

11 from tests.probabilty import cdf_test_data, crps_test_data

12 from tests.probabilty import functions_test_data as ftd

13

14

15 def test_round_values_exception():

16 """Test rounding throws the right exceptions"""

17 with pytest.raises(ValueError):

18 scores.probability.functions.round_values(xr.DataArray(), -1, 5)

19

20

21@pytest.mark.parametrize(

22 ("array", "rounding_precision", "expected"),

23 [

24 (ftd.DA_ROUND, 0, ftd.EXP_ROUND1),

25 (ftd.DA_ROUND, 0.2, ftd.EXP_ROUND2),

26 (ftd.DA_ROUND, 5, ftd.EXP_ROUND3),

27 ],

28)

29 def test_round_values(array, rounding_precision, expected):

30 """Tests `round_values` with a variety of inputs."""

31 output_as = scores.probability.functions.round_values(array, rounding_precision)

32 assertions.assert_dataarray_equal(output_as, expected, decimals=7)

33

34

35 def test_propagate_nan_error():

36 """Test propagating throws the right exceptions"""

37 faulty_array = xr.Dataset({"lertitude": [1, 2, np.NaN, 4], "longitude": [20, 21, 22, 23, 24]})

38 with pytest.raises(ValueError):

39 scores.probability.functions.propagate_nan(faulty_array, "latitude")

40

41

42@pytest.mark.parametrize(

43 ("dim", "expected"),

44 [

45 ("x", cdf_test_data.EXP_PROPNAN_X),

46 ("y", cdf_test_data.EXP_PROPNAN_Y),

47 ],

48)

49 def test_propagate_nan(dim, expected):

50 """Tests `propagate_nan` with a variety of inputs."""

51 result = scores.probability.functions.propagate_nan(cdf_test_data.DA_PROPNAN, dim)

52 assertions.assert_dataarray_equal(result, expected, decimals=7)

53

54

55 def test_observed_cdf_errors():

56 """Test `osbserved_cdf_errors` with a variety of inputs."""

57 obs = xr.DataArray.from_dict({"dims": "temp", "data": [np.NaN, np.NaN, np.NaN, np.NaN]})

58 threshold_dim = "irrelevant for test"

59 threshold_values = None

60 badprecision = -1

61

62 # Bad precision raises a value error

63 with pytest.raises(ValueError):

64 scores.probability.functions.observed_cdf(obs, threshold_dim, threshold_values, precision=badprecision)

65

66 # Null obs and a null threshold value raises a value error

67 with pytest.raises(ValueError):

68 scores.probability.functions.observed_cdf(obs, threshold_dim, threshold_values)

69

70

71@pytest.mark.parametrize(

72 ("function_values", "expected"),

73 [

74 (crps_test_data.DA_ISPL1, crps_test_data.EXP_ISPL1),

75 (crps_test_data.DA_ISPL2, crps_test_data.EXP_ISPL2),

76 (crps_test_data.DA_ISPL3, crps_test_data.EXP_ISPL3),

77 ],

78)

79 def test_integrate_square_piecewise_linear(function_values, expected):

80 """Tests `integrate_square_piecewise_linear` with a variety of inputs."""

81 result = scores.probability.functions.integrate_square_piecewise_linear(function_values, "x")

82 assertions.assert_dataarray_equal(result, expected, decimals=7)

83

84

85@pytest.mark.parametrize(

86 ("method", "min_nonnan", "expected"),

87 [

88 ("linear", 2, cdf_test_data.EXP_FILL_CDF1A),

89 ("step", 1, cdf_test_data.EXP_FILL_CDF1B),

90 ("step", 2, cdf_test_data.EXP_FILL_CDF1C),

91 ("forward", 1, cdf_test_data.EXP_FILL_CDF1D),

92 ("backward", 1, cdf_test_data.EXP_FILL_CDF1E),

93 ],

94)

95 def test_fill_cdf(method, min_nonnan, expected):

96 """Tests `fill_cdf` with a variety of inputs."""

97 output = scores.probability.functions.fill_cdf(cdf_test_data.DA_FILL_CDF1, "x", method, min_nonnan)

98 assertions.assert_dataarray_equal(output, expected, decimals=7)

99

100

101@pytest.mark.parametrize(

102 (

103 "cdf",

104 "threshold_dim",

105 "method",

106 "min_nonnan",

107 "error_class",

108 "error_msg_snippet",

109 ),

110 [

111 ( # cdf values outside [0,1]

112 cdf_test_data.DA_CDF_FROM_QUANTS4,

113 "q_level",

114 "linear",

115 2,

116 ValueError,

117 "Input CDF has some values less than 0 or greater than 1.",

118 ),

119 (

120 cdf_test_data.DA_FILL_CDF1,

121 "y",

122 "linear",

123 2,

124 ValueError,

125 "'y' is not a dimension of `cdf`",

126 ),

127 (

128 cdf_test_data.DA_FILL_CDF1,

129 "x",

130 "linear",

131 1,

132 ValueError,

133 "`min_nonnan` must be at least 2 when `method='linear'`",

134 ),

135 (

136 cdf_test_data.DA_FILL_CDF1,

137 "x",

138 "step",

139 0,

140 ValueError,

141 "`min_nonnan` must be at least 1 when `method='step'`",

142 ),

143 (

144 cdf_test_data.DA_FILL_CDF1,

145 "x",

146 "quad",

147 0,

148 ValueError,

149 "`method` must be 'linear', 'step', 'forward' or 'backward'",

150 ),

151 ],

152)

153# pylint: disable=too-many-arguments

154 def test_fill_cdf_raises(cdf, threshold_dim, method, min_nonnan, error_class, error_msg_snippet):

155 """`fill_cdf` raises an exception as expected."""

156 with pytest.raises(error_class, match=error_msg_snippet):

157 scores.probability.functions.fill_cdf(

158 cdf,

159 threshold_dim,

160 method,

161 min_nonnan,

162 )

163

164

165@pytest.mark.parametrize(

166 (

167 "cdf",

168 "threshold_dim",

169 "tolerance",

170 "error_msg_snippet",

171 ),

172 [

173 (

174 cdf_test_data.DA_DECREASING_CDFS1,

175 "y",

176 0,

177 "'y' is not a dimension of `cdf`",

178 ),

179 (

180 cdf_test_data.DA_DECREASING_CDFS1,

181 "x",

182 -1,

183 "`tolerance` must be nonnegative.",

184 ),

185 (

186 cdf_test_data.DA_CDF_ENVELOPE2,

187 "y",

188 0,

189 "'y' is not a dimension of `cdf`",

190 ),

191 (

192 cdf_test_data.DA_CDF_ENVELOPE1,

193 "x",

194 0,

195 "CDFs should have no NaNs or be all NaN along `threshold_dim`",

196 ),

197 (

198 cdf_test_data.DA_NAN_DECREASING_CDFS2,

199 "x",

200 0,

201 "Coordinates along 'x' dimension should be increasing.",

202 ),

203 ],

204)

205 def test_check_nan_decreasing_inputs(cdf, threshold_dim, tolerance, error_msg_snippet):

206 """Tests that `_check_nan_decreasing_inputs` raises an exception as expected."""

207 with pytest.raises(ValueError, match=error_msg_snippet):

208 scores.probability.checks.check_nan_decreasing_inputs(cdf, threshold_dim, tolerance)

209

210

211@pytest.mark.parametrize(

212 ("cdf"),

213 [

214 (cdf_test_data.DA_CDF_ENVELOPE1),

215 (cdf_test_data.DA_CDF_ENVELOPE2),

216 ],

217)

218 def test_cdf_envelope(cdf):

219 """Tests `cdf_envelope` with a variety of inputs."""

220 result = scores.probability.functions.cdf_envelope(cdf, "x")

221 assertions.assert_dataarray_equal(result, cdf_test_data.EXP_CDF_ENVELOPE1, decimals=7)

222

223

224 def test_cdf_envelope_raises():

225 """Tests that `cdf_envelope` raises the correct error."""

226 with pytest.raises(ValueError, match="'y' is not a dimension of `cdf`"):

227 scores.probability.functions.cdf_envelope(cdf_test_data.DA_CDF_ENVELOPE1, "y")