From 8cda35fab4b0f320cb59a3c954c0d58ecf2a4436 Mon Sep 17 00:00:00 2001 From: Brendan Collins Date: Thu, 30 Apr 2026 22:01:17 -0700 Subject: [PATCH] Use sized slice in dask morph chunk writeback (#1399) `result[hy:-hy, hx:-hx] = interior` becomes the empty slice `0:-0` when hy or hx is 0, so 1xN and Nx1 kernels raised ValueError on the dask backends while numpy and cupy paths handled them. Switch both _morph_chunk_numpy and _morph_chunk_cupy to `result[hy:hy + rows, hx:hx + cols] = interior`, and add parametrized 1x3 / 3x1 dask regression tests. --- xrspatial/morphology.py | 4 ++-- xrspatial/tests/test_morphology.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/xrspatial/morphology.py b/xrspatial/morphology.py index 086fd383..63691e3f 100644 --- a/xrspatial/morphology.py +++ b/xrspatial/morphology.py @@ -334,7 +334,7 @@ def _morph_chunk_numpy(chunk, kernel, op, block_info=None): else: interior = _dilate_kernel_numpy(chunk, kernel, rows, cols, ky, kx) result = chunk.copy() - result[hy:-hy, hx:-hx] = interior + result[hy:hy + rows, hx:hx + cols] = interior return result @@ -388,7 +388,7 @@ def _morph_chunk_cupy(chunk, kernel, op, block_info=None): else: _dilate_gpu[bpg, tpb](chunk, kern_dev, out, hy, hx, ky, kx) result = chunk.copy() - result[hy:-hy, hx:-hx] = out + result[hy:hy + rows, hx:hx + cols] = out return result diff --git a/xrspatial/tests/test_morphology.py b/xrspatial/tests/test_morphology.py index 40ab27c8..7ded3b07 100644 --- a/xrspatial/tests/test_morphology.py +++ b/xrspatial/tests/test_morphology.py @@ -284,6 +284,30 @@ def test_closing_dask_equals_numpy(): assert_numpy_equals_dask_numpy(numpy_agg, dask_agg, morph_closing, nan_edges=True) +@dask_array_available +@pytest.mark.parametrize("kernel", [ + np.array([[1, 1, 1]], dtype=np.uint8), + np.array([[1], [1], [1]], dtype=np.uint8), +]) +def test_erode_dask_1d_kernel_matches_numpy(kernel): + numpy_agg = create_test_raster(_DATA, backend='numpy') + dask_agg = create_test_raster(_DATA, backend='dask') + fn = partial(morph_erode, kernel=kernel) + assert_numpy_equals_dask_numpy(numpy_agg, dask_agg, fn, nan_edges=False) + + +@dask_array_available +@pytest.mark.parametrize("kernel", [ + np.array([[1, 1, 1]], dtype=np.uint8), + np.array([[1], [1], [1]], dtype=np.uint8), +]) +def test_dilate_dask_1d_kernel_matches_numpy(kernel): + numpy_agg = create_test_raster(_DATA, backend='numpy') + dask_agg = create_test_raster(_DATA, backend='dask') + fn = partial(morph_dilate, kernel=kernel) + assert_numpy_equals_dask_numpy(numpy_agg, dask_agg, fn, nan_edges=False) + + # --------------------------------------------------------------------------- # CuPy backend # ---------------------------------------------------------------------------