def test_curvature_gpu_equals_cpu(): import cupy agg_numpy = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) cpu = curvature(agg_numpy, name='numpy_result') agg_cupy = xr.DataArray(cupy.asarray(elevation), attrs={'res': (10.0, 10.0)}) gpu = curvature(agg_cupy, name='cupy_result') general_output_checks(agg_cupy, gpu) np.testing.assert_allclose(cpu.data, gpu.data.get(), equal_nan=True)
def test_curvature_numpy_equals_dask(): agg_numpy = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) numpy_curvature = curvature(agg_numpy, name='numpy_curvature') agg_dask = xr.DataArray(da.from_array(elevation, chunks=(3, 3)), attrs={'res': (10.0, 10.0)}) dask_curvature = curvature(agg_dask, name='dask_curvature') general_output_checks(agg_dask, dask_curvature) # both produce same results np.testing.assert_allclose(numpy_curvature.data, dask_curvature.data.compute(), equal_nan=True)
def test_curvature_gpu_equals_cpu(): import cupy small_da = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) cpu = curvature(small_da, name='numpy_result') small_da_cupy = xr.DataArray(cupy.asarray(elevation), attrs={'res': (10.0, 10.0)}) gpu = curvature(small_da_cupy, name='cupy_result') assert isinstance(gpu.data, cupy.ndarray) assert np.isclose(cpu, gpu, equal_nan=True).all()
def test_curvature_on_flat_surface(): # flat surface test_arr1 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) test_raster1 = xr.DataArray(test_arr1) # add crs for tests test_raster1 = _add_EPSG4326_crs_to_da(test_raster1, res=(1, 1)) curv = curvature(test_raster1) # output must be an xarray DataArray assert isinstance(curv, xr.DataArray) assert isinstance(curv.values, np.ndarray) # shape, dims, coords, attr preserved, including crs assert test_raster1.shape == curv.shape assert test_raster1.dims == curv.dims assert test_raster1.attrs == curv.attrs for coord in test_raster1.coords: assert np.all(test_raster1[coord] == curv[coord]) # border edges are all nans assert np.isnan(curv.values[0, :]).all() assert np.isnan(curv.values[-1, :]).all() assert np.isnan(curv.values[:, 0]).all() assert np.isnan(curv.values[:, -1]).all() # curvature of a flat surface is all 0s # exclude border edges assert np.unique(curv.values[1:-1, 1:-1]) == [0]
def test_curvature_numpy_equals_dask(): small_numpy_based_data_array = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) small_das_based_data_array = xr.DataArray(da.from_array(elevation, chunks=(3, 3)), attrs={'res': (10.0, 10.0)}) numpy_curvature = curvature(small_numpy_based_data_array, name='numpy_curvature') dask_curvature = curvature(small_das_based_data_array, name='dask_curvature') assert isinstance(dask_curvature.data, da.Array) dask_curvature.data = dask_curvature.data.compute() assert np.isclose(numpy_curvature, dask_curvature, equal_nan=True).all()
def test_curvature_on_concave_surface(concave_surface): concave_data, expected_result = concave_surface numpy_agg = create_test_raster(concave_data, attrs={'res': (1, 1)}) numpy_result = curvature(numpy_agg) general_output_checks(numpy_agg, numpy_result, expected_result, verify_dtype=True)
def test_curvature_on_concave_surface(): # concave test_arr3 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) expected_results = np.asarray([[np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, 0., -100., 0., np.nan], [np.nan, -100., 400., -100., np.nan], [np.nan, 0., -100., 0., np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan]]) test_raster3 = xr.DataArray(test_arr3, attrs={'res': (1, 1)}) curv = curvature(test_raster3) general_output_checks(test_raster3, curv, expected_results)
def test_curvature_on_convex_surface(): # convex test_arr2 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, -1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) expected_results = np.asarray([[np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, 0., 100., 0., np.nan], [np.nan, 100., -400., 100., np.nan], [np.nan, 0., 100., 0., np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan]]) test_raster2 = xr.DataArray(test_arr2, attrs={'res': (1, 1)}) curv = curvature(test_raster2) general_output_checks(test_raster2, curv, expected_results)
def test_curvature_on_flat_surface(): # flat surface test_arr1 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) expected_results = np.array([[np.nan, np.nan, np.nan, np.nan, np.nan], [np.nan, 0, 0, 0, np.nan], [np.nan, 0, 0, 0, np.nan], [np.nan, 0, 0, 0, np.nan], [np.nan, np.nan, np.nan, np.nan, np.nan]]) test_raster1 = xr.DataArray(test_arr1, attrs={'res': (1, 1)}) curv = curvature(test_raster1) general_output_checks(test_raster1, curv, expected_results)
def test_summarize_terrain(random_data): test_terrain = create_test_raster(random_data, name='myterrain') summarized_ds = summarize_terrain(test_terrain) variables = [v for v in summarized_ds] should_have = ['myterrain', 'myterrain-slope', 'myterrain-curvature', 'myterrain-aspect'] assert variables == should_have np.testing.assert_allclose(summarized_ds['myterrain-slope'], slope(test_terrain)) np.testing.assert_allclose(summarized_ds['myterrain-curvature'], curvature(test_terrain)) np.testing.assert_allclose(summarized_ds['myterrain-aspect'], aspect(test_terrain))
def test_curvature_on_convex_surface(): # convex test_arr2 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, -1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) test_raster2 = xr.DataArray(test_arr2, attrs={'res': (1, 1)}) curv = curvature(test_raster2) # output must be an xarray DataArray assert isinstance(curv, xr.DataArray) assert isinstance(curv.values, np.ndarray) # shape, dims, coords, attr preserved assert test_raster2.shape == curv.shape assert test_raster2.dims == curv.dims assert test_raster2.attrs == curv.attrs for coord in test_raster2.coords: assert np.all(test_raster2[coord] == curv[coord]) # curvature at a cell (i, j) only considers 4 cells: # (i-1, j), (i+1, j), (i, j-1), (i, j+1) # id of bottom of the convex shape in the raster i, j = (2, 2) # The 4 surrounding values should be the same assert curv.values[i-1, j] == curv.values[i+1, j]\ == curv.values[i, j-1] == curv.values[i, j+1] # Positive curvature indicates the surface is upwardly convex at that cell assert curv.values[i-1, j] > 0 # Negative curvature indicates the surface is upwardly concave at that cell assert curv.values[i, j] < 0 # A value of 0 indicates the surface is flat. # exclude border edges for ri in range(1, curv.shape[0] - 1): for rj in range(1, curv.shape[1] - 1): if ri not in (i-1, i, i+1) and rj not in (j-1, j, j+1): assert curv.values[ri, rj] == 0 # border edges are all nans assert np.isnan(curv.values[0, :]).all() assert np.isnan(curv.values[-1, :]).all() assert np.isnan(curv.values[:, 0]).all() assert np.isnan(curv.values[:, -1]).all()
def test_curvature_on_flat_surface(): # flat surface test_arr1 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) test_raster1 = xr.DataArray(test_arr1) curv = curvature(test_raster1) # output must be an xarray DataArray assert isinstance(curv, xr.DataArray) assert isinstance(curv.values, np.ndarray) # shape, dims, coords, attr preserved assert test_raster1.shape == curv.shape assert test_raster1.dims == curv.dims assert test_raster1.attrs == curv.attrs assert test_raster1.coords == curv.coords # curvature of a flat surface is all 0s assert np.unique(curv.values) == [0]
def test_curvature_invalid_input_raster(): invalid_raster_type = np.array([0, 1, 2, 3]) with pytest.raises(Exception) as e_info: curvature(invalid_raster_type) assert e_info invalid_raster_dtype = xr.DataArray(np.array([['cat', 'dog']])) with pytest.raises(Exception) as e_info: curvature(invalid_raster_dtype) assert e_info invalid_raster_shape = xr.DataArray(np.array([0, 0])) with pytest.raises(Exception) as e_info: curvature(invalid_raster_shape) assert e_info
def test_curvature_on_concave_surface(): # concave test_arr3 = np.array([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]) test_raster3 = xr.DataArray(test_arr3) curv = curvature(test_raster3) # output must be an xarray DataArray assert isinstance(curv, xr.DataArray) assert isinstance(curv.values, np.ndarray) # shape, dims, coords, attr preserved assert test_raster3.shape == curv.shape assert test_raster3.dims == curv.dims assert test_raster3.attrs == curv.attrs for coord in test_raster3.coords: assert np.all(test_raster3[coord] == curv[coord]) # curvature at a cell (i, j) only considers 4 cells: # (i-1, j), (i+1, j), (i, j-1), (i, j+1) # id of bottom of the convex shape in the raster i, j = (2, 2) # The 4 surrounding values should be the same assert curv.values[i-1, j] == curv.values[i+1, j]\ == curv.values[i, j-1] == curv.values[i, j+1] # Negative curvature indicates the surface is upwardly concave at that cell assert curv.values[i - 1, j] < 0 # Positive curvature indicates the surface is upwardly convex at that cell assert curv.values[i, j] > 0 # A value of 0 indicates the surface is flat. for ri in range(curv.shape[0]): for rj in range(curv.shape[1]): if ri not in (i - 1, i, i + 1) and rj not in (j - 1, j, j + 1): assert curv.values[ri, rj] == 0
def summarize_terrain(terrain: xr.DataArray): """ Calculates slope, aspect, and curvature of an elevation terrain and return a dataset of the computed data. Parameters ---------- terrain: xarray.DataArray 2D NumPy, CuPy, or Dask with NumPy-backed xarray DataArray of elevation values. Returns ------- summarized_terrain: xarray.Dataset Dataset with slope, aspect, curvature variables with a naming convention of `terrain.name-variable_name` Examples -------- .. sourcecode:: python >>> import numpy as np >>> import xarray as xr >>> from xrspatial.analytics import summarize_terrain >>> data = np.array([ [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, -1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]], dtype=np.float64) >>> raster = xr.DataArray(data, name='myraster', attrs={'res': (1, 1)}) >>> summarized_terrain = summarize_terrain(raster) >>> summarized_terrain <xarray.Dataset> Dimensions: (dim_0: 5, dim_1: 8) Dimensions without coordinates: dim_0, dim_1 Data variables: myraster (dim_0, dim_1) float64 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 myraster-slope (dim_0, dim_1) float32 nan nan nan nan ... nan nan nan myraster-curvature (dim_0, dim_1) float64 nan nan nan nan ... nan nan nan myraster-aspect (dim_0, dim_1) float32 nan nan nan nan ... nan nan nan >>> summarized_terrain['myraster-slope'] <xarray.DataArray 'myraster-slope' (dim_0: 5, dim_1: 8)> array([[ nan, nan, nan, nan, nan, nan, nan, nan], [ nan, 10.024988, 14.036243, 10.024988, 10.024988, 14.036243, 10.024988, nan], [ nan, 14.036243, 0. , 14.036243, 14.036243, 0. , 14.036243, nan], [ nan, 10.024988, 14.036243, 10.024988, 10.024988, 14.036243, 10.024988, nan], [ nan, nan, nan, nan, nan, nan, nan, nan]], dtype=float32) # noqa Dimensions without coordinates: dim_0, dim_1 Attributes: res: (1, 1) >>> summarized_terrain['myraster-curvature'] <xarray.DataArray 'myraster-curvature' (dim_0: 5, dim_1: 8)> array([[ nan, nan, nan, nan, nan, nan, nan, nan], [ nan, -0., -100., -0., -0., 100., -0., nan], [ nan, -100., 400., -100., 100., -400., 100., nan], [ nan, -0., -100., -0., -0., 100., -0., nan], [ nan, nan, nan, nan, nan, nan, nan, nan]]) Dimensions without coordinates: dim_0, dim_1 Attributes: res: (1, 1) >>> summarized_terrain['myraster-aspect'] <xarray.DataArray 'myraster-aspect' (dim_0: 5, dim_1: 8)> array([[ nan, nan, nan, nan, nan, nan, nan, nan], [ nan, 315., 0., 45., 135., 180., 225., nan], [ nan, 270., -1., 90., 90., -1., 270., nan], [ nan, 225., 180., 135., 45., 0., 315., nan], [ nan, nan, nan, nan, nan, nan, nan, nan]], dtype=float32) Dimensions without coordinates: dim_0, dim_1 Attributes: res: (1, 1) """ if terrain.name is None: raise NameError('Requires xr.DataArray.name property to be set') ds = terrain.to_dataset() ds[f'{terrain.name}-slope'] = slope(terrain) ds[f'{terrain.name}-curvature'] = curvature(terrain) ds[f'{terrain.name}-aspect'] = aspect(terrain) return ds