Skip to content

Commit d4ac4c0

Browse files
Fixes to linear and saliency based blending (#466)
* Fix: ensure linear blending can also handle multiple input timesteps and ensure linear blending can deal with nans. * add new release --------- Co-authored-by: mats-knmi <145579783+mats-knmi@users.noreply.github.com>
1 parent bc54616 commit d4ac4c0

File tree

4 files changed

+173
-34
lines changed

4 files changed

+173
-34
lines changed

PKG-INFO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 1.2
22
Name: pysteps
3-
Version: 1.16.0
3+
Version: 1.17.0
44
Summary: Python framework for short-term ensemble prediction systems
55
Home-page: http://pypi.python.org/pypi/pysteps/
66
License: LICENSE

pysteps/blending/linear_blending.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ def forecast(
105105
if nowcast_kwargs is None:
106106
nowcast_kwargs = dict()
107107

108+
# Ensure that only the most recent precip timestep is used
109+
if len(precip.shape) == 3:
110+
precip = precip[-1, :, :]
111+
108112
# Calculate the nowcasts
109113
nowcast_method_func = nowcasts.get_method(nowcast_method)
110114
precip_nowcast = nowcast_method_func(
@@ -173,6 +177,17 @@ def forecast(
173177
precip_nwp.shape, precip_nowcast.shape
174178
)
175179

180+
# Ensure we are not working with nans in the bleding.
181+
# Check if the NWP data contains any nans. If so, fill them with 0.0.
182+
precip_nwp = np.nan_to_num(precip_nwp, nan=0.0)
183+
184+
# Fill nans in precip_nowcast
185+
nan_mask = np.isnan(precip_nowcast)
186+
if fill_nwp:
187+
precip_nowcast[nan_mask] = precip_nwp[nan_mask]
188+
else:
189+
precip_nowcast[nan_mask] = 0.0
190+
176191
# Initialise output
177192
precip_blended = np.zeros_like(precip_nowcast)
178193

@@ -224,10 +239,6 @@ def forecast(
224239
+ weight_nowcast * precip_nowcast[slc_id]
225240
)
226241

227-
# Find where the NaN values are and replace them with NWP data
228-
if fill_nwp:
229-
nan_indices = np.isnan(precip_blended)
230-
precip_blended[nan_indices] = precip_nwp[nan_indices]
231242
else:
232243
# If no NWP data is given, the blended field is simply equal to the nowcast field
233244
precip_blended = precip_nowcast

pysteps/tests/test_blending_linear_blending.py

Lines changed: 156 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,155 @@
88

99
# Test function arguments
1010
linear_arg_values = [
11-
(5, 30, 60, 20, 45, "eulerian", None, 1, False, True),
12-
(5, 30, 60, 20, 45, "eulerian", None, 2, False, False),
13-
(5, 30, 60, 20, 45, "eulerian", None, 0, False, False),
14-
(4, 23, 33, 9, 28, "eulerian", None, 1, False, False),
15-
(3, 18, 36, 13, 27, "eulerian", None, 1, False, False),
16-
(7, 30, 68, 11, 49, "eulerian", None, 1, False, False),
17-
(10, 100, 160, 25, 130, "eulerian", None, 1, False, False),
18-
(6, 60, 180, 22, 120, "eulerian", None, 1, False, False),
19-
(5, 100, 200, 40, 150, "eulerian", None, 1, False, False),
20-
(5, 30, 60, 20, 45, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
21-
(4, 23, 33, 9, 28, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
22-
(3, 18, 36, 13, 27, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
23-
(7, 30, 68, 11, 49, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
24-
(10, 100, 160, 25, 130, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
25-
(6, 60, 180, 22, 120, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
26-
(5, 100, 200, 40, 150, "extrapolation", np.zeros((2, 200, 200)), 1, False, False),
27-
(5, 30, 60, 20, 45, "eulerian", None, 1, True, True),
28-
(5, 30, 60, 20, 45, "eulerian", None, 2, True, False),
29-
(5, 30, 60, 20, 45, "eulerian", None, 0, True, False),
30-
(5, 30, 60, 20, 45, "extrapolation", np.zeros((2, 200, 200)), 1, True, False),
31-
(4, 23, 33, 9, 28, "extrapolation", np.zeros((2, 200, 200)), 1, True, False),
32-
(3, 18, 36, 13, 27, "extrapolation", np.zeros((2, 200, 200)), 1, True, False),
11+
(5, 30, 60, 20, 45, "eulerian", None, 1, False, True, False),
12+
(5, 30, 60, 20, 45, "eulerian", None, 2, False, False, False),
13+
(5, 30, 60, 20, 45, "eulerian", None, 0, False, False, False),
14+
(4, 23, 33, 9, 28, "eulerian", None, 1, False, False, False),
15+
(3, 18, 36, 13, 27, "eulerian", None, 1, False, False, False),
16+
(7, 30, 68, 11, 49, "eulerian", None, 1, False, False, False),
17+
(7, 30, 68, 11, 49, "eulerian", None, 1, False, False, True),
18+
(10, 100, 160, 25, 130, "eulerian", None, 1, False, False, False),
19+
(6, 60, 180, 22, 120, "eulerian", None, 1, False, False, False),
20+
(5, 100, 200, 40, 150, "eulerian", None, 1, False, False, False),
21+
(
22+
5,
23+
30,
24+
60,
25+
20,
26+
45,
27+
"extrapolation",
28+
np.zeros((2, 200, 200)),
29+
1,
30+
False,
31+
False,
32+
False,
33+
),
34+
(
35+
4,
36+
23,
37+
33,
38+
9,
39+
28,
40+
"extrapolation",
41+
np.zeros((2, 200, 200)),
42+
1,
43+
False,
44+
False,
45+
False,
46+
),
47+
(
48+
3,
49+
18,
50+
36,
51+
13,
52+
27,
53+
"extrapolation",
54+
np.zeros((2, 200, 200)),
55+
1,
56+
False,
57+
False,
58+
False,
59+
),
60+
(
61+
7,
62+
30,
63+
68,
64+
11,
65+
49,
66+
"extrapolation",
67+
np.zeros((2, 200, 200)),
68+
1,
69+
False,
70+
False,
71+
False,
72+
),
73+
(
74+
10,
75+
100,
76+
160,
77+
25,
78+
130,
79+
"extrapolation",
80+
np.zeros((2, 200, 200)),
81+
1,
82+
False,
83+
False,
84+
False,
85+
),
86+
(
87+
6,
88+
60,
89+
180,
90+
22,
91+
120,
92+
"extrapolation",
93+
np.zeros((2, 200, 200)),
94+
1,
95+
False,
96+
False,
97+
False,
98+
),
99+
(
100+
5,
101+
100,
102+
200,
103+
40,
104+
150,
105+
"extrapolation",
106+
np.zeros((2, 200, 200)),
107+
1,
108+
False,
109+
False,
110+
False,
111+
),
112+
(
113+
5,
114+
100,
115+
200,
116+
40,
117+
150,
118+
"extrapolation",
119+
np.zeros((2, 200, 200)),
120+
1,
121+
False,
122+
False,
123+
True,
124+
),
125+
(5, 30, 60, 20, 45, "eulerian", None, 1, True, True, False),
126+
(5, 30, 60, 20, 45, "eulerian", None, 2, True, False, False),
127+
(5, 30, 60, 20, 45, "eulerian", None, 0, True, False, False),
128+
(
129+
5,
130+
30,
131+
60,
132+
20,
133+
45,
134+
"extrapolation",
135+
np.zeros((2, 200, 200)),
136+
1,
137+
True,
138+
False,
139+
False,
140+
),
141+
(4, 23, 33, 9, 28, "extrapolation", np.zeros((2, 200, 200)), 1, True, False, False),
142+
(
143+
3,
144+
18,
145+
36,
146+
13,
147+
27,
148+
"extrapolation",
149+
np.zeros((2, 200, 200)),
150+
1,
151+
True,
152+
False,
153+
False,
154+
),
33155
]
34156

35157

36158
@pytest.mark.parametrize(
37-
"timestep, start_blending, end_blending, n_timesteps, controltime, nowcast_method, V, n_models, salient_blending, squeeze_nwp_array",
159+
"timestep, start_blending, end_blending, n_timesteps, controltime, nowcast_method, V, n_models, salient_blending, squeeze_nwp_array, fill_nwp",
38160
linear_arg_values,
39161
)
40162
def test_linear_blending(
@@ -48,6 +170,7 @@ def test_linear_blending(
48170
n_models,
49171
salient_blending,
50172
squeeze_nwp_array,
173+
fill_nwp,
51174
):
52175
"""Tests if the linear blending function is correct. For the nowcast data a precipitation field
53176
which is constant over time is taken. One half of the field has no rain and the other half
@@ -89,11 +212,15 @@ def test_linear_blending(
89212
if squeeze_nwp_array:
90213
r_nwp = np.squeeze(r_nwp)
91214

92-
# Define nowcast input data
93-
r_input = np.zeros((200, 200))
94-
95-
for i in range(100, 200):
96-
r_input[i, :] = 11.0
215+
# Define nowcast input data (alternate between 2D and 3D arrays for testing)
216+
if timestep % 2 == 0:
217+
r_input = np.zeros((4, 200, 200))
218+
for i in range(100, 200):
219+
r_input[:, i, :] = 11.0
220+
else:
221+
r_input = np.zeros((200, 200))
222+
for i in range(100, 200):
223+
r_input[i, :] = 11.0
97224

98225
# Transform from mm/h to dB
99226
r_input, _ = transformation.dB_transform(
@@ -112,6 +239,7 @@ def test_linear_blending(
112239
dict({"unit": "mm/h", "transform": None}),
113240
start_blending=start_blending,
114241
end_blending=end_blending,
242+
fill_nwp=fill_nwp,
115243
saliency=salient_blending,
116244
)
117245

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070

7171
setup(
7272
name="pysteps",
73-
version="1.16.0",
73+
version="1.17.0",
7474
author="PySteps developers",
7575
packages=find_packages(),
7676
license="LICENSE",

0 commit comments

Comments
 (0)