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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,4 @@ dmypy.json

# airspeed velocity
.asv/
xrspatial-examples/
11 changes: 9 additions & 2 deletions xrspatial/aspect.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
from __future__ import annotations

from functools import partial
from math import atan2
from typing import Optional

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None


import numpy as np
import xarray as xr
from numba import cuda

from xrspatial.utils import ArrayTypeFunctionMapping, cuda_args, ngjit, not_implemented_func
from xrspatial.utils import ArrayTypeFunctionMapping, cuda_args, ngjit

# 3rd-party
try:
Expand Down
8 changes: 7 additions & 1 deletion xrspatial/classify.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import warnings
from functools import partial
from typing import List, Optional
Expand All @@ -12,7 +14,11 @@
class cupy(object):
ndarray = False

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

import numba as nb
import numpy as np

Expand Down
8 changes: 7 additions & 1 deletion xrspatial/curvature.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# std lib
from functools import partial
from typing import Optional, Union
Expand All @@ -9,7 +11,11 @@
class cupy(object):
ndarray = False

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

import numpy as np
import xarray as xr
from numba import cuda
Expand Down
10 changes: 9 additions & 1 deletion xrspatial/datasets/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import os

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

import datashader as ds
import noise
import numpy as np
Expand Down Expand Up @@ -76,6 +80,10 @@ def make_terrain(
terrain : xarray.DataArray
2D array of generated terrain values.
"""

if da is None:
raise Exception("make terrain requires dask.Array (pip install dask)")

def _func(arr, block_id=None):
block_ystart = block_id[0] * arr.shape[0]
block_xstart = block_id[1] * arr.shape[1]
Expand Down
12 changes: 11 additions & 1 deletion xrspatial/focal.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
from __future__ import annotations


import copy
from functools import partial
from math import isnan
import math

import dask.array as da
import numba as nb
import numpy as np
import pandas as pd
import xarray as xr

from numba import cuda, prange
from xarray import DataArray


try:
import dask.array as da
except ImportError:
da = None


try:
import cupy
except ImportError:
Expand Down
11 changes: 8 additions & 3 deletions xrspatial/hillshade.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@
from functools import partial
from typing import Optional

import dask.array as da
import numpy as np

try:
import dask.array as da
except ImportError:
da = None

import xarray as xr
from numba import cuda

Expand Down Expand Up @@ -178,12 +183,12 @@ def hillshade(agg: xr.DataArray,
out = _run_cupy(agg.data, azimuth, angle_altitude)

# dask + cupy case
elif (has_cuda_and_cupy() and isinstance(agg.data, da.Array) and
elif (has_cuda_and_cupy() and da is not None and isinstance(agg.data, da.Array) and
is_cupy_backed(agg)):
raise NotImplementedError("Dask/CuPy hillshade not implemented")

# dask + numpy case
elif isinstance(agg.data, da.Array):
elif da is not None and isinstance(agg.data, da.Array):
out = _run_dask_numpy(agg.data, azimuth, angle_altitude)

else:
Expand Down
8 changes: 7 additions & 1 deletion xrspatial/multispectral.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from __future__ import annotations

import warnings
from math import sqrt

import dask.array as da
import numba as nb
import numpy as np
import xarray as xr
Expand All @@ -18,6 +19,11 @@
class cupy(object):
ndarray = False

try:
import dask.array as da
except ImportError:
da = None


@ngjit
def _arvi_cpu(nir_data, red_data, blue_data):
Expand Down
8 changes: 7 additions & 1 deletion xrspatial/perlin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# std lib
from functools import partial

Expand All @@ -11,7 +13,11 @@
class cupy(object):
ndarray = False

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

import numba as nb
from numba import cuda, jit

Expand Down
8 changes: 6 additions & 2 deletions xrspatial/proximity.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from math import sqrt

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

import numpy as np
import xarray as xr
from numba import prange
Expand Down Expand Up @@ -619,7 +623,7 @@ def _process_dask(raster, xs, ys):
# numpy case
result = _process_numpy(raster.data, xs, ys)

elif isinstance(raster.data, da.Array):
elif da is not None and isinstance(raster.data, da.Array):
# dask + numpy case
xs = da.from_array(xs, chunks=(raster.chunks))
ys = da.from_array(ys, chunks=(raster.chunks))
Expand Down
13 changes: 9 additions & 4 deletions xrspatial/slope.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# std lib
from functools import partial
from math import atan
Expand All @@ -10,14 +12,17 @@
class cupy(object):
ndarray = False

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

import numpy as np
import xarray as xr
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 @@ -64,6 +69,7 @@ def _run_dask_numpy(data: da.Array,
meta=np.array(()))
return out


def _run_dask_cupy(data: da.Array,
cellsize_x: Union[int, float],
cellsize_y: Union[int, float]) -> da.Array:
Expand All @@ -79,7 +85,6 @@ def _run_dask_cupy(data: da.Array,
return out



@cuda.jit(device=True)
def _gpu(arr, cellsize_x, cellsize_y):
a = arr[2, 0]
Expand Down
7 changes: 6 additions & 1 deletion xrspatial/terrain.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

# std lib
from functools import partial
from typing import List, Optional, Tuple, Union
Expand All @@ -14,7 +16,10 @@
class cupy(object):
ndarray = False

import dask.array as da
try:
import dask.array as da
except ImportError:
da = None

# local modules
from xrspatial.utils import (ArrayTypeFunctionMapping, cuda_args, get_dataarray_resolution,
Expand Down
33 changes: 25 additions & 8 deletions xrspatial/tests/general_checks.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import dask.array as da
from __future__ import annotations
try:
import dask.array as da
except ImportError:
da = None

import numpy as np
import pytest
import xarray as xr

from xrspatial.utils import ArrayTypeFunctionMapping, has_cuda_and_cupy
from xrspatial.utils import ArrayTypeFunctionMapping
from xrspatial.utils import has_cuda_and_cupy
from xrspatial.utils import has_dask_array
from xrspatial.utils import has_dask_dataframe

# Use this as a decorator to skip tests if do not have both CUDA and CuPy available.
cuda_and_cupy_available = pytest.mark.skipif(
not has_cuda_and_cupy(), reason="Requires CUDA and CuPy")


# Use this as a decorator to skip tests if do not have dask array
dask_array_available = pytest.mark.skipif(
not has_dask_array(), reason="Requires dask.Array")

# Use this as a decorator to skip tests if do not have dask array
dask_dataframe_available = pytest.mark.skipif(
not has_dask_dataframe(), reason="Requires dask.DataFrame")


def create_test_raster(
data,
backend='numpy',
Expand All @@ -36,7 +53,7 @@ def create_test_raster(
import cupy
raster.data = cupy.asarray(raster.data)

if 'dask' in backend:
if 'dask' in backend and has_dask_array():
raster.data = da.from_array(raster.data, chunks=chunks)

return raster
Expand All @@ -52,7 +69,7 @@ def general_output_checks(input_agg: xr.DataArray,
# type of output is the same as of input
assert isinstance(output_agg.data, type(input_agg.data))

if isinstance(input_agg.data, da.Array):
if has_dask_array() and isinstance(input_agg.data, da.Array):
# dask case
assert isinstance(
output_agg.data.compute(), type(input_agg.data.compute()))
Expand Down Expand Up @@ -123,13 +140,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, atol=0, rtol=1e-7):
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, atol=atol, rtol=rtol
)
np.testing.assert_allclose(numpy_result.data, dask_cupy_result.data.compute().get(),
equal_nan=True, atol=atol, rtol=rtol)
7 changes: 6 additions & 1 deletion xrspatial/tests/test_aspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
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,
assert_numpy_equals_dask_numpy,
dask_array_available,
create_test_raster,
cuda_and_cupy_available, general_output_checks)


Expand Down Expand Up @@ -45,13 +47,15 @@ def test_numpy_equals_qgis(elevation_raster, qgis_aspect):
assert_nan_edges_effect(xrspatial_aspect)


@dask_array_available
def test_numpy_equals_dask_qgis_data(elevation_raster):
# compare using the data run through QGIS
numpy_agg = input_data(elevation_raster, 'numpy')
dask_agg = input_data(elevation_raster, 'dask+numpy')
assert_numpy_equals_dask_numpy(numpy_agg, dask_agg, aspect)


@dask_array_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])
Expand Down Expand Up @@ -79,6 +83,7 @@ def test_numpy_equals_cupy_random_data(random_data):
assert_numpy_equals_cupy(numpy_agg, cupy_agg, aspect, atol=1e-6, rtol=1e-6)


@dask_array_available
@cuda_and_cupy_available
@pytest.mark.parametrize("size", [(2, 4), (10, 15)])
@pytest.mark.parametrize(
Expand Down
Loading