Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
## Xarray-Spatial Changelog
-----------

### Version 0.5.0 - 2025-12-15
- Python 3.14 is now supported!
- Fixed bug in curvature dask+cupy args and added unit test for curvature(#824)
- Added dask cupy test for slope func (#824)
- Added dask cupy test for aspect func (#824)
- Added in dask-cupy convolve_2d test (#823)
- Now ensures the hash value fits into an unsigned 64-bit integer for NumPy 2.0.0 (#805)
- Added dask and pyarrow to setup.cfg test area (#822)
- Allow Negative Target Height in Viewshed Analysis (viewshed.py) (#812)
- Small Fixes while testing Cuda 13 (#818)
- Support for certain Dask+Cupy (#815)
- Update docstring for viewshed (#807)


### Version 0.4.0 - 2024-04-25
- Python 3.12 is now supported!
- Python 3.9 & 3.8 are no longer supported.
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,10 +208,10 @@ In the GIS world, rasters are used for representing continuous phenomena (e.g. e

| Name | NumPy xr.DataArray | Dask xr.DataArray | CuPy GPU xr.DataArray | Dask GPU xr.DataArray |
|:----------:|:----------------------:|:--------------------:|:-------------------:|:------:|
| [Aspect](xrspatial/aspect.py) | ✅️ | ✅️ | ✅️ | ️ |
| [Curvature](xrspatial/curvature.py) | ✅️ | | | ⚠️ |
| [Aspect](xrspatial/aspect.py) | ✅️ | ✅️ | ✅️ | ️ |
| [Curvature](xrspatial/curvature.py) | ✅️ |⚠️✅️ |⚠️✅️ | ⚠️✅️ |
| [Hillshade](xrspatial/hillshade.py) | ✅️ | ✅️ | | |
| [Slope](xrspatial/slope.py) | ✅️ | ✅️ | ✅️ | ⚠️ |
| [Slope](xrspatial/slope.py) | ✅️ | ✅️ | ✅️ | ⚠️✅️ |
| [Terrain Generation](xrspatial/terrain.py) | ✅️ | ✅️ | ✅️ | |
| [Viewshed](xrspatial/viewshed.py) | ✅️ | | | |
| [Perlin Noise](xrspatial/perlin.py) | ✅️ | ✅️ | ✅️ | |
Expand Down
11 changes: 7 additions & 4 deletions xrspatial/curvature.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ class cupy(object):
from numba import cuda

# local modules
from xrspatial.utils import (ArrayTypeFunctionMapping, cuda_args, get_dataarray_resolution, ngjit,
not_implemented_func)
from xrspatial.utils import (ArrayTypeFunctionMapping, cuda_args, get_dataarray_resolution, ngjit)


@ngjit
Expand Down Expand Up @@ -84,10 +83,14 @@ def _run_cupy(data: cupy.ndarray,

return out


def _run_dask_cupy(data: da.Array,
cellsize: Union[int, float]) -> da.Array:
cellsize: Union[int, float]) -> da.Array:
data = data.astype(cupy.float32)
_func = partial(_cpu, cellsize=cellsize)
cellsize_arr = cupy.array([float(cellsize)], dtype='f4')

_func = partial(_run_cupy, cellsize=cellsize_arr)

out = data.map_overlap(_func,
depth=(1, 1),
boundary=cupy.nan,
Expand Down
4 changes: 2 additions & 2 deletions xrspatial/tests/general_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,13 @@ def assert_numpy_equals_cupy(numpy_agg, cupy_agg, func, nan_edges=True, atol=0,
numpy_result.data, cupy_result.data.get(), equal_nan=True, atol=atol, rtol=rtol)


def assert_numpy_equals_dask_cupy(numpy_agg, dask_cupy_agg, func, nan_edges=True):
def assert_numpy_equals_dask_cupy(numpy_agg, dask_cupy_agg, func, nan_edges=True, atol=0, rtol=1e-7):
numpy_result = func(numpy_agg)
if nan_edges:
assert_nan_edges_effect(numpy_result)

dask_cupy_result = func(dask_cupy_agg)
general_output_checks(dask_cupy_agg, dask_cupy_result)
np.testing.assert_allclose(
numpy_result.data, dask_cupy_result.data.compute().get(), equal_nan=True
numpy_result.data, dask_cupy_result.data.compute().get(), equal_nan=True, atol=atol, rtol=rtol
)
14 changes: 13 additions & 1 deletion xrspatial/tests/test_aspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
import pytest

from xrspatial import aspect
from xrspatial.tests.general_checks import (assert_nan_edges_effect, assert_numpy_equals_cupy,
from xrspatial.tests.general_checks import (assert_nan_edges_effect,
assert_numpy_equals_cupy,
assert_numpy_equals_dask_cupy,
assert_numpy_equals_dask_numpy, create_test_raster,
cuda_and_cupy_available, general_output_checks)

Expand Down Expand Up @@ -75,3 +77,13 @@ def test_numpy_equals_cupy_random_data(random_data):
numpy_agg = create_test_raster(random_data, backend='numpy')
cupy_agg = create_test_raster(random_data, backend='cupy')
assert_numpy_equals_cupy(numpy_agg, cupy_agg, aspect, atol=1e-6, rtol=1e-6)


@cuda_and_cupy_available
@pytest.mark.parametrize("size", [(2, 4), (10, 15)])
@pytest.mark.parametrize(
"dtype", [np.int32, np.int64, np.uint32, np.uint64, np.float32, np.float64])
def test_numpy_equals_dask_cupy_random_data(random_data):
numpy_agg = create_test_raster(random_data, backend='numpy')
dask_cupy_agg = create_test_raster(random_data, backend='dask+cupy')
assert_numpy_equals_dask_cupy(numpy_agg, dask_cupy_agg, aspect, atol=1e-6, rtol=1e-6)
14 changes: 11 additions & 3 deletions xrspatial/tests/test_curvature.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from xrspatial import curvature
from xrspatial.tests.general_checks import (assert_numpy_equals_cupy,
assert_numpy_equals_dask_cupy,
assert_numpy_equals_dask_numpy, create_test_raster,
cuda_and_cupy_available, general_output_checks)

Expand Down Expand Up @@ -87,9 +88,6 @@ def test_numpy_equals_cupy_random_data(random_data):
numpy_agg = create_test_raster(random_data, backend='numpy')
cupy_agg = create_test_raster(random_data, backend='cupy')
assert_numpy_equals_cupy(numpy_agg, cupy_agg, curvature)
# NOTE: Dask + GPU code paths don't currently work because of
# dask casting cupy arrays to numpy arrays during
# https://github.com/dask/dask/issues/4842


@pytest.mark.parametrize("size", [(2, 4), (10, 15)])
Expand All @@ -99,3 +97,13 @@ def test_numpy_equals_dask_random_data(random_data):
numpy_agg = create_test_raster(random_data, backend='numpy')
dask_agg = create_test_raster(random_data, backend='dask')
assert_numpy_equals_dask_numpy(numpy_agg, dask_agg, curvature)


@cuda_and_cupy_available
@pytest.mark.parametrize("size", [(2, 4), (10, 15)])
@pytest.mark.parametrize(
"dtype", [np.int32, np.int64, np.uint32, np.uint64, np.float32, np.float64])
def test_numpy_equals_dask_cupy_random_data(random_data):
numpy_agg = create_test_raster(random_data, backend='numpy')
dask_cupy_agg = create_test_raster(random_data, backend='dask+cupy')
assert_numpy_equals_dask_cupy(numpy_agg, dask_cupy_agg, curvature, atol=1e-6, rtol=1e-6)
11 changes: 11 additions & 0 deletions xrspatial/tests/test_slope.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from xrspatial import slope
from xrspatial.tests.general_checks import (assert_nan_edges_effect, assert_numpy_equals_cupy,
assert_numpy_equals_dask_cupy,
assert_numpy_equals_dask_numpy, create_test_raster,
cuda_and_cupy_available, general_output_checks)

Expand Down Expand Up @@ -63,3 +64,13 @@ def test_numpy_equals_cupy_qgis_data(elevation_raster):
numpy_agg = input_data(elevation_raster, 'numpy')
cupy_agg = input_data(elevation_raster, 'cupy')
assert_numpy_equals_cupy(numpy_agg, cupy_agg, slope)


@cuda_and_cupy_available
@pytest.mark.parametrize("size", [(2, 4), (10, 15)])
@pytest.mark.parametrize(
"dtype", [np.int32, np.int64, np.uint32, np.uint64, np.float32, np.float64])
def test_numpy_equals_dask_cupy_random_data(random_data):
numpy_agg = create_test_raster(random_data, backend='numpy')
dask_cupy_agg = create_test_raster(random_data, backend='dask+cupy')
assert_numpy_equals_dask_cupy(numpy_agg, dask_cupy_agg, slope, atol=1e-6, rtol=1e-6)