Source code for landlab.grid.mappers

#! /usr/bin/env python
"""Map values from one grid element to another.

Grid mapping functions
+++++++++++++++++++++++

.. autosummary::

    ~landlab.grid.mappers.map_link_head_node_to_link
    ~landlab.grid.mappers.map_link_tail_node_to_link
    ~landlab.grid.mappers.map_min_of_link_nodes_to_link
    ~landlab.grid.mappers.map_max_of_link_nodes_to_link
    ~landlab.grid.mappers.map_mean_of_link_nodes_to_link
    ~landlab.grid.mappers.map_value_at_min_node_to_link
    ~landlab.grid.mappers.map_value_at_max_node_to_link
    ~landlab.grid.mappers.map_node_to_cell
    ~landlab.grid.mappers.map_min_of_node_links_to_node
    ~landlab.grid.mappers.map_max_of_node_links_to_node
    ~landlab.grid.mappers.map_upwind_node_link_max_to_node
    ~landlab.grid.mappers.map_downwind_node_link_max_to_node
    ~landlab.grid.mappers.map_upwind_node_link_mean_to_node
    ~landlab.grid.mappers.map_downwind_node_link_mean_to_node
    ~landlab.grid.mappers.map_value_at_upwind_node_link_max_to_node
    ~landlab.grid.mappers.map_value_at_downwind_node_link_max_to_node
    ~landlab.grid.mappers.map_link_vector_components_to_node
    ~landlab.grid.mappers.map_node_to_link_linear_upwind
    ~landlab.grid.mappers.map_node_to_link_lax_wendroff

Each link has a *tail* and *head* node. The *tail* nodes are located at the
start of a link, while the head nodes are located at end of a link.

Below, the numbering scheme for links in :class:`~.RasterModelGrid` is illustrated
with an example of a four-row by five column grid (4x5). In this example,
each ``*`` (or ``X``) is a node, the lines represent links, and the ``^`` and ``>`` symbols
indicate the direction and *head* of each link. Link heads in the
:class:`~.RasterModelGrid` always point in the cardinal directions North (N) or East
(E).::

    *--27-->*--28-->*--29-->*--30-->*
    ^       ^       ^       ^       ^
   22      23      24      25      26
    |       |       |       |       |
    *--18-->*--19-->*--20-->*--21-->*
    ^       ^       ^       ^       ^
    13      14      15      16     17
    |       |       |       |       |
    *---9-->*--10-->X--11-->*--12-->*
    ^       ^       ^       ^       ^
    4       5       6       7       8
    |       |       |       |       |
    *--0--->*---1-->*--2--->*---3-->*

For example, node ``X`` has four link-neighbors. From south and going clockwise,
these neighbors are ``[6, 10, 15, 11]``. Both link 6 and link 10 have node ``X`` as
their *head* node, while links 15 and 11 have node ``X`` as their *tail* node.
"""

import numpy as np


[docs] def cartesian_to_polar(x, y): """Return 2d polar coordinates (r, theta) equivalent to given cartesian coordinates (x, y). Examples -------- >>> r, theta = cartesian_to_polar(1.0, 1.0) >>> int(r * 1000) 1414 >>> int(theta * 1000) 785 """ return np.sqrt(x**2 + y**2), np.arctan2(y, x) # r, theta
[docs] def map_node_to_cell(grid, var_name, out=None): """Map values for nodes to cells. map_node_to_cell iterates across the grid and identifies the all node values of 'var_name'. This function takes node values of 'var_name' and mapes that value to the corresponding cell area for each node. Parameters ---------- grid : ModelGrid A landlab ModelGrid. var_name : array or field name Values defined at nodes. out : ndarray, optional Buffer to place mapped values into or `None` to create a new array. Returns ------- ndarray Mapped values at cells. Examples -------- >>> import numpy as np >>> from landlab.grid.mappers import map_node_to_cell >>> from landlab import RasterModelGrid >>> rmg = RasterModelGrid((3, 4)) >>> _ = rmg.add_field("z", np.arange(12.0), at="node") >>> map_node_to_cell(rmg, "z") array([ 5., 6.]) >>> values_at_cells = rmg.empty(at="cell") >>> rtn = map_node_to_cell(rmg, "z", out=values_at_cells) >>> values_at_cells array([ 5., 6.]) >>> rtn is values_at_cells True :meta landlab: info-cell, info-node, map """ if out is None: out = grid.empty(at="cell") if type(var_name) is str: var_name = grid.at_node[var_name] out[:] = var_name[grid.node_at_cell] return out
[docs] def map_mean_of_patch_nodes_to_patch( grid, var_name, ignore_closed_nodes=True, out=None ): """Map the mean value of nodes around a patch to the patch. Parameters ---------- grid : ModelGrid A landlab ModelGrid. var_name : array or field name Values defined at nodes. ignore_closed_nodes : bool If True, do not incorporate closed nodes into calc. If all nodes are masked at a patch, record zero if out is None or leave the existing value if out. out : ndarray, optional Buffer to place mapped values into or `None` to create a new array. Returns ------- ndarray Mapped values at patches. Examples -------- >>> import numpy as np >>> from landlab.grid.mappers import map_mean_of_patch_nodes_to_patch >>> from landlab import RasterModelGrid >>> rmg = RasterModelGrid((3, 4)) >>> rmg.at_node["vals"] = [ ... [5.0, 4.0, 3.0, 2.0], ... [5.0, 4.0, 3.0, 2.0], ... [3.0, 2.0, 1.0, 0.0], ... ] >>> map_mean_of_patch_nodes_to_patch(rmg, "vals") array([ 4.5, 3.5, 2.5, 3.5, 2.5, 1.5]) >>> rmg.at_node["vals"] = [ ... [5.0, 4.0, 3.0, 2.0], ... [5.0, 4.0, 3.0, 2.0], ... [3.0, 2.0, 1.0, 0.0], ... ] >>> rmg.status_at_node[rmg.node_x > 1.5] = rmg.BC_NODE_IS_CLOSED >>> ans = np.zeros(6, dtype=float) >>> _ = map_mean_of_patch_nodes_to_patch(rmg, "vals", out=ans) >>> ans array([ 4.5, 4. , 0. , 3.5, 3. , 0. ]) :meta landlab: info-patch, info-node, map """ if out is None: out = np.zeros(grid.number_of_patches, dtype=float) if type(var_name) is str: var_name = grid.at_node[var_name] values_at_nodes = var_name[grid.nodes_at_patch] if ignore_closed_nodes: values_at_nodes = np.ma.masked_where( grid.status_at_node[grid.nodes_at_patch] == grid.BC_NODE_IS_CLOSED, values_at_nodes, copy=False, ) meanvals = np.mean(values_at_nodes, axis=1) if type(meanvals.mask) is not np.bool_: gooddata = np.logical_not(meanvals.mask) out[gooddata] = meanvals.data[gooddata] else: if not meanvals.mask: out[:] = meanvals.data else: np.mean(values_at_nodes, axis=1, out=out) return out
[docs] def map_max_of_patch_nodes_to_patch(grid, var_name, ignore_closed_nodes=True, out=None): """Map the maximum value of nodes around a patch to the patch. Parameters ---------- grid : ModelGrid A landlab ModelGrid. var_name : array or field name Values defined at nodes. ignore_closed_nodes : bool If True, do not incorporate closed nodes into calc. If all nodes are masked at a patch, record zero if out is None or leave the existing value if out. out : ndarray, optional Buffer to place mapped values into or `None` to create a new array. Returns ------- ndarray Mapped values at patches. Examples -------- >>> import numpy as np >>> from landlab.grid.mappers import map_max_of_patch_nodes_to_patch >>> from landlab import RasterModelGrid >>> rmg = RasterModelGrid((3, 4)) >>> rmg.at_node["vals"] = [ ... [5.0, 4.0, 3.0, 2.0], ... [3.0, 4.0, 3.0, 2.0], ... [3.0, 2.0, 1.0, 0.0], ... ] >>> map_max_of_patch_nodes_to_patch(rmg, "vals") array([ 5., 4., 3., 4., 4., 3.]) >>> rmg.at_node["vals"] = [ ... [5.0, 4.0, 3.0, 2.0], ... [3.0, 4.0, 3.0, 2.0], ... [3.0, 2.0, 1.0, 0.0], ... ] >>> rmg.status_at_node[rmg.node_x > 1.5] = rmg.BC_NODE_IS_CLOSED >>> ans = np.zeros(6, dtype=float) >>> _ = map_max_of_patch_nodes_to_patch(rmg, "vals", out=ans) >>> ans array([ 5., 4., 0., 4., 4., 0.]) :meta landlab: info-patch, info-node, map """ if out is None: out = np.zeros(grid.number_of_patches, dtype=float) if type(var_name) is str: var_name = grid.at_node[var_name] values_at_nodes = var_name[grid.nodes_at_patch] if ignore_closed_nodes: values_at_nodes = np.ma.masked_where( grid.status_at_node[grid.nodes_at_patch] == grid.BC_NODE_IS_CLOSED, values_at_nodes, copy=False, ) maxvals = values_at_nodes.max(axis=1) if type(maxvals.mask) is not np.bool_: gooddata = np.logical_not(maxvals.mask) out[gooddata] = maxvals.data[gooddata] else: if not maxvals.mask: out[:] = maxvals.data else: np.amax(values_at_nodes, axis=1, out=out) return out
[docs] def map_min_of_patch_nodes_to_patch(grid, var_name, ignore_closed_nodes=True, out=None): """Map the minimum value of nodes around a patch to the patch. Parameters ---------- grid : ModelGrid A landlab ModelGrid. var_name : array or field name Values defined at nodes. ignore_closed_nodes : bool If True, do not incorporate closed nodes into calc. If all nodes are masked at a patch, record zero if out is None or leave the existing value if out. out : ndarray, optional Buffer to place mapped values into or `None` to create a new array. Returns ------- ndarray Mapped values at patches. Examples -------- >>> import numpy as np >>> from landlab.grid.mappers import map_min_of_patch_nodes_to_patch >>> from landlab import RasterModelGrid >>> rmg = RasterModelGrid((3, 4)) >>> rmg.at_node["vals"] = [ ... [5.0, 4.0, 3.0, 2.0], ... [5.0, 4.0, 3.0, 2.0], ... [3.0, 2.0, 1.0, 0.0], ... ] >>> map_min_of_patch_nodes_to_patch(rmg, "vals") array([ 4., 3., 2., 2., 1., 0.]) >>> rmg.at_node["vals"] = [ ... [5.0, 4.0, 3.0, 2.0], ... [5.0, 4.0, 3.0, 2.0], ... [3.0, 2.0, 1.0, 0.0], ... ] >>> rmg.status_at_node[rmg.node_x > 1.5] = rmg.BC_NODE_IS_CLOSED >>> ans = np.zeros(6, dtype=float) >>> _ = map_min_of_patch_nodes_to_patch(rmg, "vals", out=ans) >>> ans array([ 4., 4., 0., 2., 2., 0.]) :meta landlab: info-patch, info-node, map """ if out is None: out = np.zeros(grid.number_of_patches, dtype=float) if type(var_name) is str: var_name = grid.at_node[var_name] values_at_nodes = var_name[grid.nodes_at_patch] if ignore_closed_nodes: values_at_nodes = np.ma.masked_where( grid.status_at_node[grid.nodes_at_patch] == grid.BC_NODE_IS_CLOSED, values_at_nodes, copy=False, ) minvals = values_at_nodes.min(axis=1) if type(minvals.mask) is not np.bool_: gooddata = np.logical_not(minvals.mask) out[gooddata] = minvals.data[gooddata] else: if not minvals.mask: out[:] = minvals.data else: np.amin(values_at_nodes, axis=1, out=out) return out