Calculate gradients on a raster grid.
calc_grad_at_link (grid, vals, \*args, \*\*kwds) |
Calculate gradients in node_values at links. |
calc_grad_at_active_link (grid, vals, \*args, ...) |
Calculate gradients over active links. |
calc_grad_across_cell_faces (grid, vals, ...) |
Get gradients across the faces of a cell. |
calc_grad_across_cell_corners (grid, vals, ...) |
Get gradients to diagonally opposite nodes. |
landlab.grid.raster_gradients.alculate_gradient_along_node_links |
calc_aspect_at_cell_subtriangles
(grid, elevs='topographic__elevation', subtriangle_unit_normals=None, unit='degrees')[source]¶Get tuple of arrays of aspect of each of the eight cell subtriangles.
Aspect is returned as radians clockwise of north, unless input parameter units is set to ‘degrees’.
If subtriangle_unit_normals is provided the aspect will be calculated from these data.
If it is not, it will be derived from elevation data at the nodes, which can either be a string referring to a grid field (default: ‘topographic__elevation’), or an nnodes-long numpy array of the values themselves.
Parameters: | grid : ModelGrid
elevs : str or array (optional)
subtriangle_unit_normals : tuple of 8 (ncels, 3) arrays (optional)
unit : {‘degrees’, ‘radians’}
|
---|---|
Returns: | (a_ENE, a_NNE, a_NNW, a_WNW, a_WSW, a_SSW, a_SSE, a_ESE) :
|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> mg = RasterModelGrid((3, 3))
>>> z = np.array([1., 0., 1., 0., 0., 0., 1., 0., 1.])
>>> eight_tris = mg.calc_unit_normals_at_cell_subtriangles(z)
>>> A = mg.calc_aspect_at_cell_subtriangles(z, eight_tris)
>>> A0 = mg.calc_aspect_at_cell_subtriangles(z)
>>> np.allclose(A, A0)
True
>>> type(A) is tuple
True
>>> len(A)
8
>>> len(A[0]) == mg.number_of_cells
True
>>> A0
(array([ 180.]), array([ 270.]), array([ 90.]), array([ 180.]),
array([ 0.]), array([ 90.]), array([ 270.]), array([ 0.]))
LLCATS: CINF SURF
calc_grad_across_cell_corners
(grid, vals, *args, **kwds)[source]¶Get gradients to diagonally opposite nodes.
Calculate gradient of the value field provided by node_values to the values at diagonally opposite nodes. The returned gradients are ordered as upper-right, upper-left, lower-left and lower-right.
Construction:
grid.calc_grad_across_cell_corners(node_values, [cell_ids],
out=None)
Parameters: | node_values : array_like or field name
cell_ids : array_like, optional
out : array_like, optional
|
---|---|
Returns: | (N, 4) ndarray
|
Examples
Create a grid with two cells.
>>> from landlab import RasterModelGrid
>>> grid = RasterModelGrid(3, 4)
>>> x = np.array([1., 0., 0., 1.,
... 0., 0., 1., 1.,
... 3., 3., 3., 3.])
A decrease in quantity to a diagonal node is a negative gradient.
>>> from math import sqrt
>>> grid.calc_grad_across_cell_corners(x) * sqrt(2.)
array([[ 3., 3., 1., 0.],
[ 2., 2., -1., 0.]])
>>> grid = RasterModelGrid((3, 4), spacing=(3, 4))
>>> grid.calc_grad_across_cell_corners(x)
array([[ 0.6, 0.6, 0.2, 0. ],
[ 0.4, 0.4, -0.2, 0. ]])
LLCATS: CNINF GRAD
calc_grad_across_cell_faces
(grid, vals, *args, **kwds)[source]¶Get gradients across the faces of a cell.
Calculate gradient of the value field provided by node_values across each of the faces of the cells of a grid. The returned gradients are ordered as right, top, left, and bottom.
Note that the returned gradients are masked to exclude neighbor nodes which are closed. Beneath the mask is the value -1.
Construction:
grid.calc_grad_across_cell_faces(node_values, [cell_ids],
out=None)
Parameters: | node_values : array_like or field name
cell_ids : array_like, optional
out : array_like, optional
|
---|---|
Returns: | (N, 4) Masked ndarray
|
Examples
Create a grid with two cells.
>>> from landlab import RasterModelGrid
>>> grid = RasterModelGrid(3, 4)
>>> x = np.array([0., 0., 0., 0.,
... 0., 0., 1., 1.,
... 3., 3., 3., 3.])
A decrease in quantity across a face is a negative gradient.
>>> grid.calc_grad_across_cell_faces(x)
masked_array(data =
[[ 1. 3. 0. 0.]
[ 0. 2. -1. -1.]],
mask =
False,
fill_value = 1e+20)
>>> grid = RasterModelGrid((3, 4), spacing=(2, 1))
>>> grid.calc_grad_across_cell_faces(x)
masked_array(data =
[[ 1. 1.5 0. 0. ]
[ 0. 1. -1. -0.5]],
mask =
False,
fill_value = 1e+20)
LLCATS: FINF GRAD
calc_grad_along_node_links
(grid, vals, *args, **kwds)[source]¶Get gradients along links touching a node.
Calculate gradient of the value field provided by node_values across each of the faces of the nodes of a grid. The returned gradients are ordered as right, top, left, and bottom. All returned values follow our standard sign convention, where a link pointing N or E and increasing in value is positive, a link pointing S or W and increasing in value is negative.
Note that the returned gradients are masked to exclude neighbor nodes which are closed. Beneath the mask is the value -1.
Construction:
grid.calc_grad_along_node_links(node_values, [cell_ids],
out=None)
Parameters: | node_values : array_like or field name
node_ids : array_like, optional
out : array_like, optional
|
---|---|
Returns: | (N, 4) Masked ndarray
|
Examples
Create a grid with nine nodes.
>>> from landlab import RasterModelGrid
>>> grid = RasterModelGrid(3, 3)
>>> x = np.array([0., 0., 0.,
... 0., 1., 2.,
... 2., 2., 2.])
A decrease in quantity across a face is a negative gradient.
>>> grid.calc_grad_along_node_links(x)
masked_array(data =
[[-- -- -- --]
[-- 1.0 -- --]
[-- -- -- --]
[1.0 -- -- --]
[1.0 1.0 1.0 1.0]
[-- -- 1.0 --]
[-- -- -- --]
[-- -- -- 1.0]
[-- -- -- --]],
mask =
[[ True True True True]
[ True False True True]
[ True True True True]
[False True True True]
[False False False False]
[ True True False True]
[ True True True True]
[ True True True False]
[ True True True True]],
fill_value = 1e+20)
>>> grid = RasterModelGrid((3, 3), spacing=(2, 4))
>>> grid.calc_grad_along_node_links(x)
masked_array(data =
[[-- -- -- --]
[-- 0.5 -- --]
[-- -- -- --]
[0.25 -- -- --]
[0.25 0.5 0.25 0.5]
[-- -- 0.25 --]
[-- -- -- --]
[-- -- -- 0.5]
[-- -- -- --]],
mask =
[[ True True True True]
[ True False True True]
[ True True True True]
[False True True True]
[False False False False]
[ True True False True]
[ True True True True]
[ True True True False]
[ True True True True]],
fill_value = 1e+20)
LLCATS: NINF LINF GRAD
calc_grad_at_active_link
(grid, vals, *args, **kwds)[source]¶Calculate gradients over active links.
Deprecated since version 0.1: Use calc_grad_across_cell_faces()
or calc_grad_across_cell_corners()
instead
Calculates the gradient in quantity s at each active link in the grid. This is nearly identical to the method of the same name in ModelGrid, except that it uses a constant node spacing for link length to improve efficiency.
Note that a negative gradient corresponds to a lower node in the direction of the link.
Returns: | ndarray
|
---|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> grid = RasterModelGrid(4, 5, 1.0)
>>> u = [0., 1., 2., 3., 0.,
... 1., 2., 3., 2., 3.,
... 0., 1., 2., 1., 2.,
... 0., 0., 2., 2., 0.]
>>> grad = grid.calc_grad_at_active_link(u)
>>> grad
array([ 1., 1., -1.,
1., 1., -1., 1.,
-1., -1., -1.,
1., 1., -1., 1.,
-1., 0., 1.])
For greater speed, sending a pre-created numpy array as an argument avoids having to create a new one with each call:
>>> grad = np.empty(grid.number_of_active_links)
>>> rtn = grid.calc_grad_at_active_link(u, out=grad)
>>> grad
array([ 1., 1., -1.,
1., 1., -1., 1.,
-1., -1., -1.,
1., 1., -1., 1.,
-1., 0., 1.])
>>> rtn is grad
True
>>> grid = RasterModelGrid((3, 3), spacing=(1, 2))
>>> node_values = [0., 0., 0.,
... 1., 3., 1.,
... 2., 2., 2.]
>>> grid.calc_grad_at_active_link(node_values)
array([ 3., 1., -1., -1.])
This function is deprecated. Instead, use calc_grad_at_link
.
>>> grid = RasterModelGrid((3, 3), spacing=(1, 2))
>>> node_values = [0., 0., 0.,
... 1., 3., 1.,
... 2., 2., 2.]
>>> grid.calc_grad_at_link(node_values)[grid.active_links]
array([ 3., 1., -1., -1.])
LLCATS: LINF GRAD
calc_grad_at_link
(grid, vals, *args, **kwds)[source]¶Calculate gradients in node_values at links.
Construction:
calc_grad_at_link(grid, node_values, out=None)
Parameters: | grid : RasterModelGrid
node_values : array_like or field name
out : ndarray, optional
|
---|---|
Returns: | ndarray
|
Examples
>>> from landlab import RasterModelGrid
>>> grid = RasterModelGrid((3, 3))
>>> node_values = [0., 0., 0.,
... 1., 3., 1.,
... 2., 2., 2.]
>>> grid.calc_grad_at_link(node_values)
array([ 0., 0., 1., 3., 1., 2., -2., 1., -1., 1., 0., 0.])
>>> out = np.empty(grid.number_of_links, dtype=float)
>>> rtn = grid.calc_grad_at_link(node_values, out=out)
>>> rtn is out
True
>>> out
array([ 0., 0., 1., 3., 1., 2., -2., 1., -1., 1., 0., 0.])
>>> grid = RasterModelGrid((3, 3), spacing=(1, 2))
>>> grid.calc_grad_at_link(node_values)
array([ 0., 0., 1., 3., 1., 1., -1., 1., -1., 1., 0., 0.])
>>> _ = grid.add_field('node', 'elevation', node_values)
>>> grid.calc_grad_at_link('elevation')
array([ 0., 0., 1., 3., 1., 1., -1., 1., -1., 1., 0., 0.])
LLCATS: LINF GRAD
calc_grad_at_patch
(grid, elevs='topographic__elevation', ignore_closed_nodes=True, subtriangle_unit_normals=None, slope_magnitude=None)[source]¶Calculate the components of the gradient of each raster patch.
Returns the mean gradient of the four possible patch subtriangles, in radians.
If ignore_closed_nodes is True, closed nodes do not affect gradient calculations. If more than one closed node is present in a patch, the patch gradients in both x and y directions are set to zero.
Parameters: | grid : RasterModelGrid
elevs : str or ndarray, optional
ignore_closed_nodes : bool
subtriangle_unit_normals : tuple of 4 (npatches, 3) arrays (optional)
slope_magnitude : array with size num_patches (optional)
|
---|---|
Returns: | gradient_tuple : (x_component_at_patch, y_component_at_patch)
|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> mg = RasterModelGrid((4, 5))
>>> z = mg.node_y
>>> (x_grad, y_grad) = mg.calc_grad_at_patch(elevs=z)
>>> np.allclose(y_grad, np.pi/4.)
True
>>> np.allclose(x_grad, 0.)
True
>>> from landlab import CLOSED_BOUNDARY, FIXED_VALUE_BOUNDARY
>>> z = mg.node_x.copy()
>>> mg.set_closed_boundaries_at_grid_edges(True, True, True, True)
>>> mg.status_at_node[11] = CLOSED_BOUNDARY
>>> mg.status_at_node[[9, 2]] = FIXED_VALUE_BOUNDARY
>>> z[11] = 100. # this should get ignored now
>>> z[9] = 2. # this should be felt by patch 7 only
>>> z[2] = 1. # should be felt by patches 1 and 2
>>> xgrad, ygrad = mg.calc_grad_at_patch(
... elevs=z, ignore_closed_nodes=True)
>>> (xgrad.reshape((3, 4)) * 4./np.pi)[1, 1:]
array([ 1., 1., -1.])
>>> np.allclose(ygrad[1:3], xgrad[1:3])
True
LLCATS: PINF GRAD
calc_slope_at_cell_subtriangles
(grid, elevs='topographic__elevation', subtriangle_unit_normals=None)[source]¶Calculate the slope (positive magnitude of gradient) at each of the eight cell subtriangles.
Parameters: | grid : RasterModelGrid
elevs : str or ndarray, optional
subtriangle_unit_normals : tuple of 8 (ncells, 3) arrays (optional)
|
---|---|
Returns: | (s_ENE, s_NNE, s_NNW, s_WNW, s_WSW, s_SSW, s_SSE, s_ESE) :
|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> mg = RasterModelGrid((3, 3))
>>> z = np.array([np.sqrt(3.), 0., 4./3.,
... 0., 0., 0.,
... 1., 0., 1./np.sqrt(3.)])
>>> eight_tris = mg.calc_unit_normals_at_cell_subtriangles(z)
>>> S = mg.calc_slope_at_cell_subtriangles(z, eight_tris)
>>> S0 = mg.calc_slope_at_cell_subtriangles(z)
>>> np.allclose(S, S0)
True
>>> type(S) is tuple
True
>>> len(S)
8
>>> len(S[0]) == mg.number_of_cells
True
>>> np.allclose(S[0], S[1])
True
>>> np.allclose(S[2], S[3])
True
>>> np.allclose(S[4], S[5])
True
>>> np.allclose(S[6], S[7])
True
>>> np.allclose(np.rad2deg(S[0])[0], 30.)
True
>>> np.allclose(np.rad2deg(S[2])[0], 45.)
True
>>> np.allclose(np.rad2deg(S[4])[0], 60.)
True
>>> np.allclose(np.cos(S[6])[0], 3./5.)
True
LLCATS: CINF GRAD
calc_slope_at_node
(grid, elevs='topographic__elevation', method='patch_mean', ignore_closed_nodes=True, return_components=False)[source]¶Array of slopes at nodes, averaged over neighboring patches.
Produces a value for node slope (i.e., mean gradient magnitude) at each node in a manner analogous to a GIS-style slope map. If method==’patch_mean’, it averages the gradient on each of the patches surrounding the node; if method==’Horn’, it returns the resolved slope direction. Directional information can still be returned through use of the return_components keyword. All values are returned in radians, including the components; take the tan to recover the rise/run.
Note that under these definitions, it is not always true that:
mag, cmp = mg.calc_slope_at_node(z)
mag**2 == cmp[0]**2 + cmp[1]**2 # only if method=='Horn'
If ignore_closed_nodes is False, all proximal elevation values will be used in the calculation. If True, only unclosed nodes are used.
This is a verion of this code specialized for a raster. It subdivides the four square patches around each node into subtriangles, in order to ensure more correct solutions that incorporate equally weighted information from all surrounding nodes on rough surfaces.
Parameters: | elevs : str or ndarray, optional
method : {‘patch_mean’, ‘Horn’}
ignore_closed_nodes : bool
return_components : bool
|
---|---|
Returns: | float array or length-2 tuple of float arrays
|
Examples
>>> import numpy as np
>>> from landlab import RadialModelGrid, RasterModelGrid
>>> mg = RasterModelGrid((5, 5), 1.)
>>> z = mg.node_x
>>> slopes = mg.calc_slope_at_node(elevs=z)
>>> np.allclose(slopes, np.pi / 4.)
True
>>> mg = RasterModelGrid((4, 5), 2.)
>>> z = - mg.node_y
>>> slope_mag, cmp = mg.calc_slope_at_node(elevs=z,
... return_components=True)
>>> np.allclose(slope_mag, np.pi / 4.)
True
>>> np.allclose(cmp[0], 0.)
True
>>> np.allclose(cmp[1], - np.pi / 4.)
True
>>> mg = RasterModelGrid((4, 4))
>>> z = mg.node_x ** 2 + mg.node_y ** 2
>>> slopes, cmp = mg.calc_slope_at_node(z, return_components=True)
>>> slopes
array([ 0.95531662, 1.10991779, 1.32082849, 1.37713803, 1.10991779,
1.20591837, 1.3454815 , 1.38904403, 1.32082849, 1.3454815 ,
1.39288142, 1.41562833, 1.37713803, 1.38904403, 1.41562833,
1.43030663])
>>> np.allclose(cmp[0].reshape((4, 4))[:, 0],
... cmp[1].reshape((4, 4))[0, :]) # test radial symmetry
True
LLCATS: NINF GRAD SURF
calc_slope_at_patch
(grid, elevs='topographic__elevation', ignore_closed_nodes=True, subtriangle_unit_normals=None)[source]¶Calculate the slope (positive magnitude of gradient) at raster patches.
Returns the mean of the slopes of the four possible patch subtriangles.
If ignore_closed_nodes is True, closed nodes do not affect slope calculations. If more than one closed node is present in a patch, the patch slope is set to zero.
Parameters: | grid : RasterModelGrid
elevs : str or ndarray, optional
ignore_closed_nodes : bool
subtriangle_unit_normals : tuple of 4 (npatches, 3) arrays (optional)
|
---|---|
Returns: | slopes_at_patch : n_patches-long array
|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> mg = RasterModelGrid((4, 5))
>>> z = mg.node_x
>>> S = mg.calc_slope_at_patch(elevs=z)
>>> S.size == mg.number_of_patches
True
>>> np.allclose(S, np.pi/4.)
True
>>> z = mg.node_y**2
>>> mg.calc_slope_at_patch(elevs=z).reshape((3, 4))
array([[ 0.78539816, 0.78539816, 0.78539816, 0.78539816],
[ 1.24904577, 1.24904577, 1.24904577, 1.24904577],
[ 1.37340077, 1.37340077, 1.37340077, 1.37340077]])
>>> from landlab import CLOSED_BOUNDARY, FIXED_VALUE_BOUNDARY
>>> z = mg.node_x.copy()
>>> mg.set_closed_boundaries_at_grid_edges(True, True, True, True)
>>> mg.status_at_node[11] = CLOSED_BOUNDARY
>>> mg.status_at_node[9] = FIXED_VALUE_BOUNDARY
>>> z[11] = 100. # this should get ignored now
>>> z[9] = 2. # this should be felt by patch 7 only
>>> mg.calc_slope_at_patch(elevs=z, ignore_closed_nodes=True).reshape(
... (3, 4)) * 4./np.pi
array([[ 0., 0., 0., 0.],
[ 0., 1., 1., 1.],
[ 0., 0., 0., 0.]])
LLCATS: PINF GRAD
calc_unit_normals_at_cell_subtriangles
(grid, elevs='topographic__elevation')[source]¶Calculate unit normals on a cell.
Calculate the eight unit normal vectors <a, b, c> to the eight subtriangles of a four-cornered (raster) cell.
Parameters: | grid : RasterModelGrid
elevs : str or ndarray, optional
|
---|---|
Returns: | (n_ENE, n_NNE, n_NNW, n_WNW, n_WSW, n_SSW, n_SSE, n_ESE) :
|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> mg = RasterModelGrid((3, 3))
>>> z = mg.node_x ** 2
>>> eight_tris = mg.calc_unit_normals_at_cell_subtriangles(z)
>>> type(eight_tris) is tuple
True
>>> len(eight_tris)
8
>>> eight_tris[0].shape == (mg.number_of_cells, 3)
True
>>> eight_tris
(array([[-0.9486833 , 0. , 0.31622777]]),
array([[-0.9486833 , 0. , 0.31622777]]),
array([[-0.70710678, 0. , 0.70710678]]),
array([[-0.70710678, 0. , 0.70710678]]),
array([[-0.70710678, 0. , 0.70710678]]),
array([[-0.70710678, 0. , 0.70710678]]),
array([[-0.9486833 , 0. , 0.31622777]]),
array([[-0.9486833 , 0. , 0.31622777]]))
LLCATS: CINF GRAD
calc_unit_normals_at_patch_subtriangles
(grid, elevs='topographic__elevation')[source]¶Calculate unit normals on a patch.
Calculate the four unit normal vectors <a, b, c> to the four possible subtriangles of a four-cornered (raster) patch.
Parameters: | grid : RasterModelGrid
elevs : str or ndarray, optional
|
---|---|
Returns: | (n_TR, n_TL, n_BL, n_BR) : each a num-patches x length-3 array
|
Examples
>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> mg = RasterModelGrid((4, 5))
>>> z = mg.node_x ** 2
>>> four_tris = mg.calc_unit_normals_at_patch_subtriangles(z)
>>> type(four_tris) is tuple
True
>>> len(four_tris)
4
>>> np.allclose(four_tris[0], four_tris[1])
True
>>> np.allclose(four_tris[2], four_tris[3])
True
>>> np.allclose(four_tris[0], four_tris[2])
True
>>> np.allclose(np.square(four_tris[0]).sum(axis=1), 1.)
True
>>> four_tris[0]
array([[-0.70710678, 0. , 0.70710678],
[-0.9486833 , 0. , 0.31622777],
[-0.98058068, 0. , 0.19611614],
[-0.98994949, 0. , 0.14142136],
[-0.70710678, 0. , 0.70710678],
[-0.9486833 , 0. , 0.31622777],
[-0.98058068, 0. , 0.19611614],
[-0.98994949, 0. , 0.14142136],
[-0.70710678, 0. , 0.70710678],
[-0.9486833 , 0. , 0.31622777],
[-0.98058068, 0. , 0.19611614],
[-0.98994949, 0. , 0.14142136]])
LLCATS: PINF GRAD