def test_slope_against_qgis_cpu(): # slope by xrspatial agg_numpy = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) xrspatial_slope_numpy = slope(agg_numpy, name='slope_numpy') general_output_checks(agg_numpy, xrspatial_slope_numpy) assert xrspatial_slope_numpy.name == 'slope_numpy' agg_dask = xr.DataArray(da.from_array(elevation, chunks=(3, 3)), attrs={'res': (10.0, 10.0)}) xrspatial_slope_dask = slope(agg_dask, name='slope_dask') general_output_checks(agg_dask, xrspatial_slope_dask) assert xrspatial_slope_dask.name == 'slope_dask' # numpy and dask case produce same results np.testing.assert_allclose(xrspatial_slope_numpy.data, xrspatial_slope_dask.compute().data, equal_nan=True) # nan border edges xrspatial_edges = [ xrspatial_slope_numpy.data[0, :], xrspatial_slope_numpy.data[-1, :], xrspatial_slope_numpy.data[:, 0], xrspatial_slope_numpy.data[:, -1], ] for edge in xrspatial_edges: np.testing.assert_allclose(edge, np.full(edge.shape, np.nan), equal_nan=True) # test against QGIS xrspatial_vals = xrspatial_slope_numpy.values[1:-1, 1:-1] qgis_vals = qgis_slope[1:-1, 1:-1] np.testing.assert_allclose(xrspatial_vals, qgis_vals, equal_nan=True)
def test_slope_transfer_function(): """ Assert slope transfer function """ da = xr.DataArray(data_gaussian, attrs={'res': 1}) da_slope = slope(da) assert da_slope.dims == da.dims assert da_slope.coords == da.coords assert da_slope.attrs == da.attrs assert da.shape == da_slope.shape assert da_slope.sum() > 0 # In the middle of the array, there is the maximum of the gaussian; # And there the slope must be zero. _imax = np.where(da == da.max()) assert da_slope[_imax] == 0 # same result when cellsize_x = cellsize_y = 1 da = xr.DataArray(data_gaussian, attrs={'res': (1.0, 1.0)}) da_slope = slope(da) assert da_slope.dims == da.dims assert da_slope.coords == da.coords assert da_slope.attrs == da.attrs assert da.shape == da_slope.shape assert da_slope.sum() > 0 # In the middle of the array, there is the maximum of the gaussian; # And there the slope must be zero. _imax = np.where(da == da.max()) assert da_slope[_imax] == 0
def test_slope_gpu_equals_cpu(): import cupy small_da = xr.DataArray(elevation2, attrs={'res': (10.0, 10.0)}) cpu = slope(small_da, name='numpy_result') small_da_cupy = xr.DataArray(cupy.asarray(elevation2), attrs={'res': (10.0, 10.0)}) gpu = slope(small_da_cupy, name='cupy_result') assert isinstance(gpu.data, cupy.ndarray) assert np.isclose(cpu, gpu, equal_nan=True).all()
def test_slope_numpy_equals_dask(): small_numpy_based_data_array = xr.DataArray(elevation2, attrs={'res': (10.0, 10.0)}) small_das_based_data_array = xr.DataArray(da.from_array(elevation2, chunks=(3, 3)), attrs={'res': (10.0, 10.0)}) numpy_slope = slope(small_numpy_based_data_array, name='numpy_slope') dask_slope = slope(small_das_based_data_array, name='dask_slope') assert isinstance(dask_slope.data, da.Array) dask_slope.data = dask_slope.data.compute() assert np.isclose(numpy_slope, dask_slope, equal_nan=True).all()
def test_slope_with_dask_array(): import dask.array as da data = da.from_array(elevation, chunks=(3, 3)) small_da = xr.DataArray(data, attrs={'res': (10.0, 10.0)}) # slope by xrspatial xrspatial_slope = slope(small_da, name='slope_agg') xrspatial_slope.data = xrspatial_slope.data.compute() # validate output attributes assert xrspatial_slope.dims == small_da.dims assert xrspatial_slope.attrs == small_da.attrs assert xrspatial_slope.shape == small_da.shape assert xrspatial_slope.name == 'slope_agg' for coord in small_da.coords: assert np.all(xrspatial_slope[coord] == small_da[coord]) # validate output values # ignore border edges xrspatial_vals = xrspatial_slope.values[1:-1, 1:-1] qgis_vals = qgis_slope[1:-1, 1:-1] assert (np.isclose(xrspatial_vals, qgis_vals, equal_nan=True).all() | ( np.isnan(xrspatial_vals) & np.isnan(qgis_vals))).all()
def _dask_cupy_equals_numpy_cpu(): # 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 import cupy cupy_data = cupy.asarray(elevation2) dask_cupy_data = da.from_array(cupy_data, chunks=(3, 3)) small_da = xr.DataArray(elevation2, attrs={'res': (10.0, 10.0)}) cpu = slope(small_da, name='numpy_result') small_dask_cupy = xr.DataArray(dask_cupy_data, attrs={'res': (10.0, 10.0)}) gpu = slope(small_dask_cupy, name='cupy_result') assert np.isclose(cpu, gpu, equal_nan=True).all()
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_numpy_equals_qgis(qgis_output): # slope by xrspatial numpy_agg = input_data(backend='numpy') xrspatial_slope_numpy = slope(numpy_agg, name='slope_numpy') general_output_checks(numpy_agg, xrspatial_slope_numpy) assert xrspatial_slope_numpy.name == 'slope_numpy' xrspatial_vals = xrspatial_slope_numpy.data[1:-1, 1:-1] qgis_vals = qgis_output[1:-1, 1:-1] np.testing.assert_allclose(xrspatial_vals, qgis_vals, equal_nan=True) # nan border edges assert_nan_edges_effect(xrspatial_slope_numpy)
def test_invalid_res_attr(): """ Assert 'res' attribute of input xarray """ da = xr.DataArray(data_gaussian, attrs={}) with pytest.raises(ValueError) as e_info: da_slope = slope(da) assert e_info da = xr.DataArray(data_gaussian, attrs={'res': 'any_string'}) with pytest.raises(ValueError) as e_info: da_slope = slope(da) assert e_info da = xr.DataArray(data_gaussian, attrs={'res': ('str_tuple', 'str_tuple')}) with pytest.raises(ValueError) as e_info: da_slope = slope(da) assert e_info da = xr.DataArray(data_gaussian, attrs={'res': (1, 2, 3)}) with pytest.raises(ValueError) as e_info: da_slope = slope(da) assert e_info
def test_slope_against_qgis_gpu(): import cupy # slope by xrspatial agg_cupy = xr.DataArray(cupy.asarray(elevation), attrs={'res': (10.0, 10.0)}) xrspatial_slope_gpu = slope(agg_cupy, name='slope_cupy') general_output_checks(agg_cupy, xrspatial_slope_gpu) assert xrspatial_slope_gpu.name == 'slope_cupy' agg_numpy = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) xrspatial_slope_cpu = slope(agg_numpy, name='slope_numpy') # both cpu and gpu produce same results np.testing.assert_allclose(xrspatial_slope_cpu.data, xrspatial_slope_gpu.data.get(), equal_nan=True) # test against QGIS # nan border edges xrspatial_vals = xrspatial_slope_gpu.data[1:-1, 1:-1].get() qgis_vals = qgis_slope[1:-1, 1:-1] np.testing.assert_allclose(xrspatial_vals, qgis_vals, equal_nan=True)
def test_slope_against_qgis(): # input data data = np.asarray( [[1432.6542, 1432.4764, 1432.4764, 1432.1207, 1431.9429, np.nan], [1432.6542, 1432.6542, 1432.4764, 1432.2986, 1432.1207, np.nan], [1432.832, 1432.6542, 1432.4764, 1432.2986, 1432.1207, np.nan], [1432.832, 1432.6542, 1432.4764, 1432.4764, 1432.1207, np.nan], [1432.832, 1432.6542, 1432.6542, 1432.4764, 1432.2986, np.nan], [1432.832, 1432.6542, 1432.6542, 1432.4764, 1432.2986, np.nan], [1432.832, 1432.832, 1432.6542, 1432.4764, 1432.4764, np.nan]], dtype=np.float32) small_da = xr.DataArray(data, attrs={'res': (10.0, 10.0)}) # slope by QGIS qgis_slope = np.asarray( [[0.8052942, 0.742317, 1.1390567, 1.3716657, np.nan, np.nan], [0.74258685, 0.742317, 1.0500116, 1.2082565, np.nan, np.nan], [0.56964326, 0.9002944, 0.9002944, 1.0502871, np.nan, np.nan], [0.5095078, 0.9003686, 0.742317, 1.1390567, np.nan, np.nan], [0.6494868, 0.64938396, 0.5692523, 1.0500116, np.nan, np.nan], [0.80557066, 0.56964326, 0.64914393, 0.9002944, np.nan, np.nan], [0.6494868, 0.56964326, 0.8052942, 0.742317, np.nan, np.nan]], dtype=np.float32) # slope by xrspatial xrspatial_slope = slope(small_da, name='slope_agg') # validate output attributes assert xrspatial_slope.dims == small_da.dims assert xrspatial_slope.attrs == small_da.attrs assert xrspatial_slope.shape == small_da.shape assert xrspatial_slope.name == 'slope_agg' for coord in small_da.coords: assert np.all(xrspatial_slope[coord] == small_da[coord]) # validate output values # ignore border edges xrspatial_vals = xrspatial_slope.values[1:-1, 1:-1] qgis_vals = qgis_slope[1:-1, 1:-1] assert ((xrspatial_vals == qgis_vals) | (np.isnan(xrspatial_vals) & np.isnan(qgis_vals))).all()
def test_slope_against_qgis_gpu(): import cupy small_da = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) small_da_cupy = xr.DataArray(cupy.asarray(elevation), attrs={'res': (10.0, 10.0)}) xrspatial_slope = slope(small_da_cupy, name='slope_cupy') # validate output attributes assert xrspatial_slope.dims == small_da.dims assert xrspatial_slope.attrs == small_da.attrs assert xrspatial_slope.shape == small_da.shape for coord in small_da.coords: assert np.all(xrspatial_slope[coord] == small_da[coord]) # validate output values # ignore border edges xrspatial_vals = xrspatial_slope.values[1:-1, 1:-1] qgis_vals = qgis_slope[1:-1, 1:-1] assert (np.isclose(xrspatial_vals, qgis_vals, equal_nan=True).all() | ( np.isnan(xrspatial_vals) & np.isnan(qgis_vals))).all()
def test_slope_against_qgis(): small_da = xr.DataArray(elevation, attrs={'res': (10.0, 10.0)}) # add crs for tests small_da = _add_EPSG4326_crs_to_da(small_da) # slope by xrspatial xrspatial_slope = slope(small_da, name='slope_agg') # validate output attributes and coords, including crs preservation assert xrspatial_slope.dims == small_da.dims assert xrspatial_slope.attrs == small_da.attrs assert xrspatial_slope.shape == small_da.shape assert xrspatial_slope.name == 'slope_agg' for coord in small_da.coords: assert np.all(xrspatial_slope[coord] == small_da[coord]) # validate output values # ignore border edges xrspatial_vals = xrspatial_slope.values[1:-1, 1:-1] qgis_vals = qgis_slope[1:-1, 1:-1] assert (np.isclose(xrspatial_vals, qgis_vals, equal_nan=True).all() | ( np.isnan(xrspatial_vals) & np.isnan(qgis_vals))).all()
def time_slope(self, nx, type): slope(self.xr)
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