Skip to content

Commit 85b2e73

Browse files
authored
Fix vet padding bug #163 (PR #164)
This PR fixes issue #163. - Fix the issue with the pysteps.motion.vet function's padding argument when MaskedArrays are used as input. - Add a short test to check that pysteps.motion.vet correctly pad Masked and Non-Masked input images.
1 parent 48edbfd commit 85b2e73

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

pysteps/motion/vet.py

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -513,20 +513,25 @@ def debug_print(*args, **kwargs):
513513
+ "Supported values: {0}".format(str(valid_indexing))
514514
)
515515

516-
# Get mask
517-
if isinstance(input_images, MaskedArray):
518-
mask = numpy.ma.getmaskarray(input_images)
519-
else:
520-
# Mask invalid data
521-
if padding > 0:
522-
padding_tuple = ((0, 0), (padding, padding), (padding, padding))
516+
# Convert input_images to a MaskedArray if it is a regular ndarray
517+
if not isinstance(input_images, MaskedArray):
518+
input_images = numpy.ma.masked_invalid(input_images)
523519

524-
input_images = numpy.pad(
525-
input_images, padding_tuple, "constant", constant_values=numpy.nan
526-
)
520+
mask = numpy.ma.getmaskarray(input_images)
527521

528-
input_images = numpy.ma.masked_invalid(input_images)
529-
mask = numpy.ma.getmaskarray(input_images)
522+
if padding > 0:
523+
padding_tuple = ((0, 0), (padding, padding), (padding, padding))
524+
525+
input_images_data = numpy.pad(
526+
numpy.ma.getdata(input_images),
527+
padding_tuple,
528+
"constant",
529+
constant_values=numpy.nan,
530+
)
531+
532+
mask = numpy.pad(mask, padding_tuple, "constant", constant_values=True)
533+
534+
input_images = numpy.ma.MaskedArray(data=input_images_data, mask=mask)
530535

531536
input_images.data[mask] = 0 # Remove any Nan from the raw data
532537

pysteps/tests/test_motion.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import numpy as np
2323
import pytest
24+
from functools import partial
2425
from scipy.ndimage import uniform_filter
2526

2627
import pysteps as stp
@@ -324,6 +325,40 @@ def test_input_shape_checks(
324325
motion_method(np.zeros((frames, image_size, image_size)), verbose=False)
325326

326327

328+
def test_vet_padding():
329+
"""
330+
Test that the padding functionality in vet works correctly with ndarrays and
331+
masked arrays.
332+
"""
333+
334+
_, precip_obs = _create_observations(
335+
reference_field.copy(), "linear_y", num_times=2
336+
)
337+
338+
# Use a small region to speed up the test
339+
precip_obs = precip_obs[:, 200:427, 250:456]
340+
# precip_obs.shape == (227 , 206)
341+
# 227 is a prime number ; 206 = 2*103
342+
# Using this shape will force vet to internally pad the input array for the sector's
343+
# blocks to divide exactly the input shape.
344+
# NOTE: This "internal padding" is different from the padding keyword being test next.
345+
346+
for padding in [0, 3, 10]:
347+
# No padding
348+
vet_method = partial(
349+
motion.get_method("vet"),
350+
verbose=False,
351+
sectors=((16, 4, 2), (16, 4, 2)),
352+
options=dict(maxiter=5),
353+
padding=padding
354+
# We use only a few iterations since
355+
# we don't care about convergence in this test
356+
)
357+
358+
assert precip_obs.shape == vet_method(precip_obs).shape
359+
assert precip_obs.shape == vet_method(np.ma.masked_invalid(precip_obs)).shape
360+
361+
327362
def test_vet_cost_function():
328363
"""
329364
Test that the vet cost_function computation gives always the same result

0 commit comments

Comments
 (0)