landlab.components.flow_accum.flow_accum_bw

flow_accum_bw.py: Implementation of the Braun & Willet (2012) stack alorithm.

Implementation of Braun & Willett (2012) algorithm for calculating drainage area and (optionally) water discharge. Assumes each node has only one downstream receiver. If water discharge is calculated, the result assumes steady flow (that is, hydrologic equilibrium).

The main public function is:

a, q, s = flow_accumulation(r)

which takes an array of receiver-node IDs, r (the nodes that “receive” the flow from a each node; this array would be returned by the flow_routing component’s calc_flowdirs() method). It returns Numpy arrays with the drainage area (a) and discharge (q) at each node, along with an array (s) that contains the IDs of the nodes in downstream-to-upstream order.

If you simply want the ordered list by itself, use:

s = make_ordered_node_array(r)

Created: GT Nov 2013

find_drainage_area_and_discharge(s, r, node_cell_area=1.0, runoff=1.0, boundary_nodes=None)[source]

Calculate the drainage area and water discharge at each node.

Parameters:
  • s (ndarray of int) – Ordered (downstream to upstream) array of node IDs

  • r (ndarray of int) – Receiver IDs for each node

  • node_cell_area (float or ndarray) – Cell surface areas for each node. If it’s an array, must have same length as s (that is, the number of nodes).

  • runoff (float or ndarray) – Local runoff rate at each cell (in water depth per time). If it’s an array, must have same length as s (that is, the number of nodes).

  • boundary_nodes (list, optional) – Array of boundary nodes to have discharge and drainage area set to zero. Default value is None.

Returns:

drainage area and discharge

Return type:

tuple of ndarray

Notes

  • If node_cell_area not given, the output drainage area is equivalent to the number of nodes/cells draining through each point, including the local node itself.

  • Give node_cell_area as a scalar when using a regular raster grid.

  • If runoff is not given, the discharge returned will be the same as drainage area (i.e., drainage area times unit runoff rate).

  • If using an unstructured Landlab grid, make sure that the input argument for node_cell_area is the cell area at each NODE rather than just at each CELL. This means you need to include entries for the perimeter nodes too. They can be zeros.

Examples

>>> import numpy as np
>>> from landlab.components.flow_accum import find_drainage_area_and_discharge
>>> r = np.array([2, 5, 2, 7, 5, 5, 6, 5, 7, 8]) - 1
>>> s = np.array([4, 1, 0, 2, 5, 6, 3, 8, 7, 9])
>>> a, q = find_drainage_area_and_discharge(s, r)
>>> a
array([  1.,   3.,   1.,   1.,  10.,   4.,   3.,   2.,   1.,   1.])
>>> q
array([  1.,   3.,   1.,   1.,  10.,   4.,   3.,   2.,   1.,   1.])
find_drainage_area_and_discharge_lossy(s, r, link_to_receiver, loss_function, grid, node_cell_area=1.0, runoff=1.0, boundary_nodes=None)[source]

Calculate the drainage area and water discharge at each node, permitting discharge to fall (or gain) as it moves downstream according to some function. Note that only transmission creates loss, so water sourced locally within a cell is always retained. The loss on each link is recorded in the ‘surface_water__discharge_loss’ link field on the grid; ensure this exists before running the function.

Parameters:
  • s (ndarray of int) – Ordered (downstream to upstream) array of node IDs

  • r (ndarray of int) – Receiver node IDs for each node

  • link_to_receiver (ndarray of int) – Link to receiver node IDs for each node

  • loss_function (Python function(Qw, nodeID, linkID, grid)) – Function dictating how to modify the discharge as it leaves each node. nodeID is the current node; linkID is the downstream link, grid is a ModelGrid. Returns a float.

  • grid (Landlab ModelGrid (or None)) – A grid to enable spatially variable parameters to be used in the loss function. If no spatially resolved parameters are needed, this can be a dummy variable, e.g., None.

  • node_cell_area (float or ndarray) – Cell surface areas for each node. If it’s an array, must have same length as s (that is, the number of nodes).

  • runoff (float or ndarray) – Local runoff rate at each cell (in water depth per time). If it’s an array, must have same length as s (that is, the number of nodes).

  • boundary_nodes (list, optional) – Array of boundary nodes to have discharge and drainage area set to zero. Default value is None.

Returns:

drainage area and discharge

Return type:

tuple of ndarray

Notes

  • If node_cell_area not given, the output drainage area is equivalent to the number of nodes/cells draining through each point, including the local node itself.

  • Give node_cell_area as a scalar when using a regular raster grid.

  • If runoff is not given, the discharge returned will be the same as drainage area (i.e., drainage area times unit runoff rate).

  • If using an unstructured Landlab grid, make sure that the input argument for node_cell_area is the cell area at each NODE rather than just at each CELL. This means you need to include entries for the perimeter nodes too. They can be zeros.

  • Loss cannot go negative.

Examples

>>> import numpy as np
>>> from landlab import RasterModelGrid
>>> from landlab.components.flow_accum import find_drainage_area_and_discharge
>>> r = np.array([2, 5, 2, 7, 5, 5, 6, 5, 7, 8]) - 1
>>> s = np.array([4, 1, 0, 2, 5, 6, 3, 8, 7, 9])
>>> l = np.ones(10, dtype=int)  # dummy
>>> nodes_wo_outlet = np.array([0, 1, 2, 3, 5, 6, 7, 8, 9])
>>> def lossfunc(Qw, dummyn, dummyl, dummygrid):
...     return 0.5 * Qw
...
>>> mg = RasterModelGrid((3, 4))  # some grid big enough to make go
>>> _ = mg.add_zeros("node", "surface_water__discharge_loss", dtype=float)
>>> a, q = find_drainage_area_and_discharge_lossy(s, r, l, lossfunc, mg)
>>> a
array([ 1.,  3.,  1.,  1., 10.,  4.,  3.,  2.,  1.,  1.])
>>> q
array([1.  , 2.  , 1.  , 1.  , 3.75, 2.  , 2.  , 1.5 , 1.  , 1.  ])
>>> np.allclose(
...     mg.at_node["surface_water__discharge_loss"][nodes_wo_outlet],
...     0.5 * q[nodes_wo_outlet],
... )
True
>>> np.isclose(mg.at_node["surface_water__discharge_loss"][4], 0.0)
True
>>> lossfield = mg.add_ones("loss_field", at="node", dtype=float)
>>> lossfield *= 0.5
>>> def lossfunc2(Qw, nodeID, dummyl, grid):
...     return grid.at_node["loss_field"][nodeID] * Qw
...
>>> a, q = find_drainage_area_and_discharge_lossy(s, r, l, lossfunc2, mg)
>>> a
array([ 1.,  3.,  1.,  1., 10.,  4.,  3.,  2.,  1.,  1.])
>>> q
array([1.  , 2.  , 1.  , 1.  , 3.75, 2.  , 2.  , 1.5 , 1.  , 1.  ])
>>> np.allclose(
...     mg.at_node["surface_water__discharge_loss"][nodes_wo_outlet],
...     lossfield[nodes_wo_outlet] * q[nodes_wo_outlet],
... )
True
>>> def lossfunc3(Qw, nodeID, dummyl, dummygrid):
...     return Qw - 100.0  # a huge loss
...
>>> a, q = find_drainage_area_and_discharge_lossy(s, r, l, lossfunc3, mg)
>>> a
array([ 1.,  3.,  1.,  1., 10.,  4.,  3.,  2.,  1.,  1.])
>>> q
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])
flow_accumulation(receiver_nodes, node_cell_area=1.0, runoff_rate=1.0, boundary_nodes=None)[source]

Calculate drainage area and (steady) discharge.

Calculates and returns the drainage area and (steady) discharge at each node, along with a downstream-to-upstream ordered list (array) of node IDs.

Examples

>>> import numpy as np
>>> from landlab.components.flow_accum import flow_accumulation
>>> r = np.array([2, 5, 2, 7, 5, 5, 6, 5, 7, 8]) - 1
>>> a, q, s = flow_accumulation(r)
>>> a
array([  1.,   3.,   1.,   1.,  10.,   4.,   3.,   2.,   1.,   1.])
>>> q
array([  1.,   3.,   1.,   1.,  10.,   4.,   3.,   2.,   1.,   1.])
>>> s
array([4, 1, 0, 2, 5, 6, 3, 8, 7, 9])
make_ordered_node_array(receiver_nodes, nd=None, delta=None, D=None)[source]

Create an array of node IDs that is arranged in order from.

Creates and returns an array of node IDs that is arranged in order from downstream to upstream.

The lack of a leading underscore is meant to signal that this operation could be useful outside of this module!

Examples

>>> import numpy as np
>>> from landlab.components.flow_accum import make_ordered_node_array
>>> r = np.array([2, 5, 2, 7, 5, 5, 6, 5, 7, 8]) - 1
>>> s = make_ordered_node_array(r)
>>> s
array([4, 1, 0, 2, 5, 6, 3, 8, 7, 9])