Skip to content

Commit 8184755

Browse files
committed
fix test blending utils
1 parent d7f84fb commit 8184755

File tree

3 files changed

+91
-133
lines changed

3 files changed

+91
-133
lines changed

pysteps/blending/utils.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -47,46 +47,6 @@
4747
CV2_IMPORTED = False
4848

4949

50-
def stack_cascades(R_d, donorm=True):
51-
"""Stack the given cascades into a larger array.
52-
53-
Parameters
54-
----------
55-
R_d : dict
56-
Dictionary containing a list of cascades obtained by calling a method
57-
implemented in pysteps.cascade.decomposition.
58-
donorm : bool
59-
If True, normalize the cascade levels before stacking.
60-
61-
Returns
62-
-------
63-
out : tuple
64-
A three-element tuple containing a four-dimensional array of stacked
65-
cascade levels and arrays of mean values and standard deviations for each
66-
cascade level.
67-
"""
68-
R_c = []
69-
mu_c = []
70-
sigma_c = []
71-
72-
for cascade in R_d:
73-
R_ = []
74-
R_i = cascade["cascade_levels"]
75-
n_levels = R_i.shape[0]
76-
mu_ = np.asarray(cascade["means"])
77-
sigma_ = np.asarray(cascade["stds"])
78-
if donorm:
79-
for j in range(n_levels):
80-
R__ = (R_i[j, :, :] - mu_[j]) / sigma_[j]
81-
R_.append(R__)
82-
else:
83-
R_ = R_i
84-
R_c.append(np.stack(R_))
85-
mu_c.append(mu_)
86-
sigma_c.append(sigma_)
87-
return np.stack(R_c), np.stack(mu_c), np.stack(sigma_c)
88-
89-
9050
def blend_cascades(cascades_norm, weights):
9151
"""Calculate blended normalized cascades using STEPS weights following eq.
9252
10 in :cite:`BPS2006`.

pysteps/io/importers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@
215215
from pysteps.decorators import postprocess_import
216216
from pysteps.exceptions import DataModelError, MissingOptionalDependency
217217
from pysteps.utils import aggregate_fields
218+
from pysteps.xarray_helpers import convert_input_to_xarray_dataset
218219

219220
try:
220221
from osgeo import gdal, gdalconst, osr
@@ -550,7 +551,7 @@ def _import_mrms_grib(filename, extent=None, window_size=4, **kwargs):
550551
cartesian_unit="degrees",
551552
)
552553

553-
return precip, None, metadata
554+
return convert_input_to_xarray_dataset(precip, None, metadata)
554555

555556

556557
@postprocess_import()

pysteps/tests/test_blending_utils.py

Lines changed: 89 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,7 @@
1313
blend_optical_flows,
1414
compute_smooth_dilated_mask,
1515
preprocess_and_store_nwp_data,
16-
decompose_NWP,
17-
load_NWP,
1816
recompose_cascade,
19-
stack_cascades,
2017
)
2118
from pysteps.utils.check_norain import check_norain
2219
from pysteps.xarray_helpers import convert_input_to_xarray_dataset
@@ -100,27 +97,11 @@
10097

10198
# Set the testing arguments
10299
# Test function arguments
103-
utils_arg_names = (
104-
"precip_nwp_dataset",
105-
"nwp_model",
106-
"issue_times",
107-
"timestep",
108-
"n_timesteps",
109-
"shape",
110-
"weights",
111-
)
100+
utils_arg_names = ("precip_nwp_dataset", "nwp_model", "issue_times", "weights")
112101

113102
# Test function values
114103
utils_arg_values = [
115-
(
116-
precip_nwp_dataset,
117-
"test",
118-
[issue_time_first, issue_time_second],
119-
5.0,
120-
3,
121-
precip_nwp_dataset[nwp_precip_var].values.shape[1:],
122-
weights,
123-
)
104+
(precip_nwp_dataset, "test", [issue_time_first, issue_time_second], weights)
124105
]
125106

126107
smoothing_arg_names = (
@@ -145,15 +126,7 @@
145126
###
146127
@pytest.mark.parametrize(utils_arg_names, utils_arg_values)
147128
# The test function to be used
148-
def test_blending_utils(
149-
precip_nwp_dataset,
150-
nwp_model,
151-
issue_times,
152-
timestep,
153-
n_timesteps,
154-
shape,
155-
weights,
156-
):
129+
def test_blending_utils(precip_nwp_dataset, nwp_model, issue_times, weights):
157130
"""Tests if all blending utils functions behave correctly."""
158131

159132
# First, make the output path if it does not exist yet
@@ -204,87 +177,110 @@ def test_blending_utils(
204177
###
205178
# Now check if files load correctly for two different issue times
206179
###
207-
with xr.open_dataset(preprocessed_file) as nwp_file:
208-
precip_decomposed_nwp_first, v_nwp_first = load_NWP(
209-
input_nc_path_decomp=os.path.join(decomp_file),
210-
input_path_velocities=os.path.join(preprocessed_file),
211-
start_time=issue_times[0],
212-
n_timesteps=n_timesteps,
213-
)
214-
215-
precip_decomposed_nwp_second, v_nwp_second = load_NWP(
216-
input_nc_path_decomp=os.path.join(decomp_file),
217-
input_path_velocities=os.path.join(preprocessed_file),
218-
start_time=issue_times[1],
219-
n_timesteps=n_timesteps,
220-
)
180+
with xr.open_dataset(preprocessed_file) as nwp_file_dataset:
181+
nwp_file_dataset_first = nwp_file_dataset.sel(time=issue_times[0])
182+
nwp_file_dataset_second = nwp_file_dataset.sel(time=issue_times[1])
183+
precip_var = nwp_file_dataset.attrs["precip_var"]
221184

222185
# Check, for a sample, if the stored motion fields are as expected
223186
assert_array_almost_equal(
224-
v_nwp_first[1],
225-
oflow_method(precip_nwp_dataset[0:2, :, :]),
187+
nwp_file_dataset_first.velocity_x.values,
188+
oflow_method(precip_nwp_dataset.isel(time=slice(0, 2))).velocity_x.values,
226189
decimal=3,
227190
err_msg="Stored motion field of first forecast not equal to expected motion field",
228191
)
229192
assert_array_almost_equal(
230-
v_nwp_second[1],
231-
oflow_method(precip_nwp_dataset[3:5, :, :]),
193+
nwp_file_dataset_first.velocity_y.values,
194+
oflow_method(precip_nwp_dataset.isel(time=slice(0, 2))).velocity_y.values,
232195
decimal=3,
233-
err_msg="Stored motion field of second forecast not equal to expected motion field",
196+
err_msg="Stored motion field of first forecast not equal to expected motion field",
234197
)
235-
236-
###
237-
# Stack the cascades
238-
###
239-
precip_decomposed_first_stack, mu_first_stack, sigma_first_stack = (
240-
stack_cascades(R_d=precip_decomposed_nwp_first, donorm=False)
198+
assert_array_almost_equal(
199+
nwp_file_dataset_second.velocity_x.values,
200+
oflow_method(precip_nwp_dataset.isel(time=slice(3, 5))).velocity_x.values,
201+
decimal=3,
202+
err_msg="Stored motion field of second forecast not equal to expected motion field",
241203
)
242-
243-
print(precip_decomposed_nwp_first)
244-
print(precip_decomposed_first_stack)
245-
print(mu_first_stack)
246-
247-
(
248-
precip_decomposed_second_stack,
249-
mu_second_stack,
250-
sigma_second_stack,
251-
) = stack_cascades(R_d=precip_decomposed_nwp_second, donorm=False)
252-
253-
# Check if the array shapes are still correct
254-
assert precip_decomposed_first_stack.shape == (
255-
n_timesteps + 1,
256-
8,
257-
shape[0],
258-
shape[1],
204+
assert_array_almost_equal(
205+
nwp_file_dataset_second.velocity_y.values,
206+
oflow_method(precip_nwp_dataset.isel(time=slice(3, 5))).velocity_y.values,
207+
decimal=3,
208+
err_msg="Stored motion field of second forecast not equal to expected motion field",
259209
)
260-
assert mu_first_stack.shape == (n_timesteps + 1, 8)
261-
assert sigma_first_stack.shape == (n_timesteps + 1, 8)
262210

263211
###
264212
# Blend the cascades
265213
###
266214
precip_decomposed_blended = blend_cascades(
267215
cascades_norm=np.stack(
268-
(precip_decomposed_first_stack[0], precip_decomposed_second_stack[0])
216+
(
217+
nwp_file_dataset_first[precip_var].values,
218+
nwp_file_dataset_second[precip_var].values,
219+
)
269220
),
270221
weights=weights,
271222
)
272223

273-
assert precip_decomposed_blended.shape == precip_decomposed_first_stack[0].shape
224+
assert (
225+
precip_decomposed_blended.shape
226+
== nwp_file_dataset_first[precip_var].values.shape
227+
)
274228

275229
###
276230
# Blend the optical flow fields
277231
###
278232
v_nwp_blended = blend_optical_flows(
279-
flows=np.stack((v_nwp_first[1], v_nwp_second[1])), weights=weights[:, 1]
233+
flows=np.stack(
234+
(
235+
np.array(
236+
[
237+
nwp_file_dataset_first.velocity_x.values,
238+
nwp_file_dataset_first.velocity_y.values,
239+
]
240+
),
241+
np.array(
242+
[
243+
nwp_file_dataset_second.velocity_x.values,
244+
nwp_file_dataset_second.velocity_y.values,
245+
]
246+
),
247+
)
248+
),
249+
weights=weights[:, 1],
280250
)
281251

282-
assert v_nwp_blended.shape == v_nwp_first[1].shape
252+
assert (
253+
v_nwp_blended.shape
254+
== np.array(
255+
[
256+
nwp_file_dataset_first.velocity_x.values,
257+
nwp_file_dataset_first.velocity_y.values,
258+
]
259+
).shape
260+
)
261+
assert_array_almost_equal(
262+
v_nwp_blended[0],
263+
(
264+
oflow_method(
265+
precip_nwp_dataset.isel(time=slice(0, 2))
266+
).velocity_x.values
267+
+ oflow_method(
268+
precip_nwp_dataset.isel(time=slice(3, 5))
269+
).velocity_x.values
270+
)
271+
/ 2,
272+
decimal=3,
273+
err_msg="Blended motion field does not equal average of the two motion fields",
274+
)
283275
assert_array_almost_equal(
284-
v_nwp_blended,
276+
v_nwp_blended[1],
285277
(
286-
oflow_method(precip_nwp_dataset[0:2, :, :])
287-
+ oflow_method(precip_nwp_dataset[3:5, :, :])
278+
oflow_method(
279+
precip_nwp_dataset.isel(time=slice(0, 2))
280+
).velocity_y.values
281+
+ oflow_method(
282+
precip_nwp_dataset.isel(time=slice(3, 5))
283+
).velocity_y.values
288284
)
289285
/ 2,
290286
decimal=3,
@@ -295,30 +291,30 @@ def test_blending_utils(
295291
# Recompose the fields (the non-blended fields are used for this here)
296292
###
297293
precip_recomposed_first = recompose_cascade(
298-
combined_cascade=precip_decomposed_first_stack[0],
299-
combined_mean=mu_first_stack[0],
300-
combined_sigma=sigma_first_stack[0],
294+
combined_cascade=nwp_file_dataset_first[precip_var].values,
295+
combined_mean=nwp_file_dataset_first["means"].values,
296+
combined_sigma=nwp_file_dataset_first["stds"].values,
301297
)
302298
precip_recomposed_second = recompose_cascade(
303-
combined_cascade=precip_decomposed_second_stack[0],
304-
combined_mean=mu_second_stack[0],
305-
combined_sigma=sigma_second_stack[0],
299+
combined_cascade=nwp_file_dataset_second[precip_var].values,
300+
combined_mean=nwp_file_dataset_second["means"].values,
301+
combined_sigma=nwp_file_dataset_second["stds"].values,
306302
)
307303

308304
assert_array_almost_equal(
309305
precip_recomposed_first,
310-
precip_nwp_dataset[0, :, :],
306+
precip_nwp_dataset.isel(time=0)[nwp_precip_var].values,
311307
decimal=3,
312308
err_msg="Recomposed field of first forecast does not equal original field",
313309
)
314310
assert_array_almost_equal(
315311
precip_recomposed_second,
316-
precip_nwp_dataset[3, :, :],
312+
precip_nwp_dataset.isel(time=3)[nwp_precip_var].values,
317313
decimal=3,
318314
err_msg="Recomposed field of second forecast does not equal original field",
319315
)
320316

321-
precip_arr = precip_nwp_dataset
317+
precip_arr = precip_nwp_dataset[nwp_precip_var].values
322318
# rainy fraction is 0.005847
323319
assert not check_norain(precip_arr, win_fun=None)
324320
assert not check_norain(
@@ -364,8 +360,9 @@ def test_blending_smoothing_utils(
364360
non_linear_growth_kernel_sizes,
365361
):
366362
# First add some nans to indicate a mask
367-
precip_nwp_dataset[:, 0:100, 0:100] = np.nan
368-
nan_indices = np.isnan(precip_nwp_dataset[0])
363+
nwp_precip_var = precip_nwp_dataset.attrs["precip_var"]
364+
precip_nwp_dataset[nwp_precip_var].data[:, 0:100, 0:100] = np.nan
365+
nan_indices = np.isnan(precip_nwp_dataset[nwp_precip_var].values[0])
369366
new_mask = compute_smooth_dilated_mask(
370367
nan_indices,
371368
max_padding_size_in_px=max_padding_size_in_px,

0 commit comments

Comments
 (0)