landlab.components.flow_director.flow_director_mfd¶
flow_director_mfd.py: provides the component FlowDirectorMFD.
This components finds the steepest single-path steepest descent flow directions. It is equivalent to D4 method in the special case of a raster grid in that it does not consider diagonal links between nodes. For that capability, use FlowDirectorD8.
- class FlowDirectorMFD[source]¶
Bases:
_FlowDirectorToMany
Multiple-path flow direction with or without out diagonals.
Directs flow by the multiple flow direction method. Each node is assigned multiple flow directions, toward all of the N neighboring nodes that are lower than it. If none of the neighboring nodes are lower, the location is identified as a pit. Flow proportions can be calculated as proportional to slope or proportional to the square root of slope, which is the solution to a steady kinematic wave.
Specifically, it stores as ModelGrid fields:
Node array of receivers (nodes that receive flow), or ITS OWN ID if there is no receiver: ‘flow__receiver_node’. This array is 2D, and is of dimension (number of nodes x max number of receivers).
Node array of flow proportions: ‘flow__receiver_proportions’. This array is 2D, and is of dimension (number of nodes x max number of receivers).
Node array of links carrying flow: ‘flow__link_to_receiver_node’. This array is 2D, and is of dimension (number of nodes x max number of receivers).
Node array of downhill slopes corresponding to each receiver.: ‘topographic__steepest_slope’ This array is 2D, and is of dimension (number of nodes x max number of receivers). If the slope is uphill or flat, the value is assigned zero.
Boolean node array of all local lows: ‘flow__sink_flag’
Link array identifing if flow goes with (1) or against (-1) the link direction: ‘flow__link_direction’
The primary method of this class is
run_one_step
.Examples
This method works for both raster and irregular grids. First we will look at a raster example, and then an irregular example.
>>> import numpy as numpy >>> from landlab import RasterModelGrid >>> from landlab.components import FlowDirectorMFD >>> mg = RasterModelGrid((3, 3), xy_spacing=(1, 1)) >>> mg.set_closed_boundaries_at_grid_edges(True, True, True, False) >>> _ = mg.add_field( ... "topographic__elevation", ... mg.node_x + mg.node_y, ... at="node", ... )
The MFD flow director can be uses for raster and irregular grids. For raster grids, use of diagonal links is specified with the keyword diagonals (default is False).
>>> fd = FlowDirectorMFD(mg, "topographic__elevation", diagonals=True) >>> fd.surface_values array([0., 1., 2., 1., 2., 3., 2., 3., 4.]) >>> fd.run_one_step()
Unlike flow directors that only direct flow to one node, FlowDirectorMFD directs flow to all downstream nodes. It stores the receiver information is a (number of nodes x maximum number or receivers) shape field at nodes.
>>> mg.at_node["flow__receiver_node"] array([[ 0, -1, -1, -1, -1, -1, -1, -1], [ 1, -1, -1, -1, -1, -1, -1, -1], [ 2, -1, -1, -1, -1, -1, -1, -1], [ 3, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, 1, -1, -1, 0, -1], [ 5, -1, -1, -1, -1, -1, -1, -1], [ 6, -1, -1, -1, -1, -1, -1, -1], [ 7, -1, -1, -1, -1, -1, -1, -1], [ 8, -1, -1, -1, -1, -1, -1, -1]])
It also stores the proportions of flow going to each receiver, the link on which the flow moves in at node arrays, and the slope of each link.
>>> mg.at_node["flow__receiver_proportions"] array([[1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.41421356, 0. , 0. , 0.58578644, 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]]) >>> mg.at_node["flow__link_to_receiver_node"] array([[-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, 3, -1, -1, 12, -1], [-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1]]) >>> mg.at_node["topographic__steepest_slope"] 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. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 1. , 0. , 0. , 1.41421356, 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. ], [0. , 0. , 0. , 0. , 0. , 0. , 0. , 0. ]])
Finally, FlowDirectorMFD identifies sinks, or local lows.
>>> mg.at_node["flow__sink_flag"].astype(int) array([1, 1, 1, 1, 0, 1, 1, 1, 1])
The flow directors also have the ability to return the flow receiver nodes. For this example, we will turn the diagonals off. This is the default value.
>>> mg = RasterModelGrid((3, 3), xy_spacing=(1, 1)) >>> mg.set_closed_boundaries_at_grid_edges(True, True, True, False) >>> _ = mg.add_field( ... "topographic__elevation", ... mg.node_x + mg.node_y, ... at="node", ... ) >>> fd = FlowDirectorMFD(mg, "topographic__elevation") >>> fd.run_one_step() >>> receivers, proportions = fd.direct_flow() >>> receivers array([[ 0, -1, -1, -1], [ 1, -1, -1, -1], [ 2, -1, -1, -1], [ 3, -1, -1, -1], [-1, -1, -1, 1], [ 5, -1, -1, -1], [ 6, -1, -1, -1], [ 7, -1, -1, -1], [ 8, -1, -1, -1]]) >>> proportions array([[1., 0., 0., 0.], [1., 0., 0., 0.], [1., 0., 0., 0.], [1., 0., 0., 0.], [0., 0., 0., 1.], [1., 0., 0., 0.], [1., 0., 0., 0.], [1., 0., 0., 0.], [1., 0., 0., 0.]])
For each donor node (represented by each row) the proportions should sum to one.
>>> proportions.sum(axis=1) array([1., 1., 1., 1., 1., 1., 1., 1., 1.])
For the second example we will use a Hexagonal Model Grid, a special type of Voroni Grid that has regularly spaced hexagonal cells. FlowDirectorMFD has multiple ways to partition flow based on slope. The default method is based on the slope angle. A secondary methods is to partion based on the square root of slope. This represents the solution to a steady kinematic wave.
>>> from landlab import HexModelGrid >>> mg = HexModelGrid((5, 3)) >>> _ = mg.add_field( ... "topographic__elevation", ... mg.node_x + numpy.round(mg.node_y), ... at="node", ... ) >>> fd = FlowDirectorMFD( ... mg, "topographic__elevation", partition_method="square_root_of_slope" ... ) >>> fd.surface_values array([1. , 2. , 3. , 1.5, 2.5, 3.5, 4.5, 2. , 3. , 4. , 5. , 6. , 3.5, 4.5, 5.5, 6.5, 4. , 5. , 6. ]) >>> fd.run_one_step() >>> mg.at_node["flow__receiver_node"] array([[ 0, -1, -1, -1, -1, -1], [ 1, -1, -1, -1, -1, -1], [ 2, -1, -1, -1, -1, -1], [ 3, -1, -1, -1, -1, -1], [-1, -1, -1, 3, 0, 1], [-1, -1, -1, 4, 1, 2], [ 6, -1, -1, -1, -1, -1], [ 7, -1, -1, -1, -1, -1], [-1, -1, -1, 7, 3, 4], [-1, -1, -1, 8, 4, 5], [-1, -1, -1, 9, 5, 6], [11, -1, -1, -1, -1, -1], [12, -1, -1, -1, -1, -1], [-1, -1, 16, 12, 8, 9], [-1, -1, 17, 13, 9, 10], [15, -1, -1, -1, -1, -1], [16, -1, -1, -1, -1, -1], [17, -1, -1, -1, -1, -1], [18, -1, -1, -1, -1, -1]]) >>> mg.at_node["flow__receiver_proportions"] array([[1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.34108138, 0.41773767, 0.24118095], [0. , 0. , 0. , 0.34108138, 0.41773767, 0.24118095], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.34108138, 0.41773767, 0.24118095], [0. , 0. , 0. , 0.34108138, 0.41773767, 0.24118095], [0. , 0. , 0. , 0.34108138, 0.41773767, 0.24118095], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0.19431571, 0.27480391, 0.33656468, 0.19431571], [0. , 0. , 0.19431571, 0.27480391, 0.33656468, 0.19431571], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ], [1. , 0. , 0. , 0. , 0. , 0. ]]) >>> mg.at_node["flow__link_to_receiver_node"] array([[-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, 8, 3, 4], [-1, -1, -1, 9, 5, 6], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, 19, 12, 13], [-1, -1, -1, 20, 14, 15], [-1, -1, -1, 21, 16, 17], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, 35, 31, 25, 26], [-1, -1, 37, 32, 27, 28], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1]]) >>> mg.at_node["topographic__steepest_slope"] 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. , 0. , 0. , 1. , 1.5, 0.5], [0. , 0. , 0. , 1. , 1.5, 0.5], [0. , 0. , 1. , 0. , 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 1. , 1.5, 0.5], [0. , 0. , 0. , 1. , 1.5, 0.5], [0. , 0. , 0. , 1. , 1.5, 0.5], [0. , 1. , 0. , 0. , 0. , 0. ], [0. , 0. , 0. , 0.5, 0. , 0. ], [0. , 0. , 0.5, 1. , 1.5, 0.5], [0. , 0. , 0.5, 1. , 1.5, 0.5], [0. , 1. , 1.5, 0. , 0. , 0. ], [0. , 0. , 0. , 0. , 0. , 0. ], [0. , 0. , 0.5, 0. , 0. , 0. ], [0. , 0.5, 0. , 0. , 0. , 0. ]]) >>> mg.at_node["flow__sink_flag"].astype(int) array([1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1])
References
Required Software Citation(s) Specific to this Component
None Listed
Additional References
Freeman, T. (1991). Calculating catchment area with divergent flow based on a regular grid. Computers and Geosciences 17(3), 413 - 422. https://dx.doi.org/10.1016/0098-3004(91)90048-i
Quinn, P., Beven, K., Chevallier, P., Planchon, O. (1991). The prediction of hillslope flow paths for distributed hydrological modelling using digital terrain models Hydrological Processes 5(1), 59-79. https://dx.doi.org/10.1002/hyp.3360050106
- Parameters:
grid (ModelGrid) – A grid.
surface (field name at node or array of length node, optional) – The surface to direct flow across, default is field at node: topographic__elevation.
partition_method (string, optional) – Method for partitioning flow. Options include ‘slope’ (default) and ‘square_root_of_slope’.
- __init__(grid, surface='topographic__elevation', **kwargs)[source]¶
- Parameters:
grid (ModelGrid) – A grid.
surface (field name at node or array of length node, optional) – The surface to direct flow across, default is field at node: topographic__elevation.
partition_method (string, optional) – Method for partitioning flow. Options include ‘slope’ (default) and ‘square_root_of_slope’.
- static __new__(cls, *args, **kwds)¶
- cite_as = ''¶
- property coords¶
Return the coordinates of nodes on grid attached to the component.
- property current_time¶
Current time.
Some components may keep track of the current time. In this case, the
current_time
attribute is incremented. Otherwise it is set to None.- Return type:
current_time
- definitions = (('flow__link_to_receiver_node', 'ID of link downstream of each node, which carries the discharge'), ('flow__receiver_node', 'Node array of receivers (node that receives flow from current node)'), ('flow__receiver_proportions', 'Node array of proportion of flow sent to each receiver.'), ('flow__sink_flag', 'Boolean array, True at local lows'), ('topographic__elevation', 'Land surface topographic elevation'), ('topographic__steepest_slope', 'The steepest *downhill* slope'))¶
- direct_flow()[source]¶
Find flow directions, save to the model grid, and return receivers.
direct_flow() checks for updated boundary conditions, calculates slopes on links, finds basself._surface_valuesel nodes based on the status at node, calculates flow directions, saves results to the grid, and returns a at-node array of receiver nodes. This array is stored in the grid at: grid[‘node’][‘flow__receiver_nodes’]
An alternative to direct_flow() is run_one_step() which does the same things but also returns a at-node array of receiver nodes. This array is stored in the grid at: grid[‘node’][‘flow__receiver_nodes’]
- classmethod from_path(grid, path)¶
Create a component from an input file.
- property grid¶
Return the grid attached to the component.
- initialize_optional_output_fields()¶
Create fields for a component based on its optional field outputs, if declared in _optional_var_names.
This method will create new fields (without overwrite) for any fields output by the component as optional. New fields are initialized to zero. New fields are created as arrays of floats, unless the component also contains the specifying property _var_type.
- initialize_output_fields(values_per_element=None)¶
Create fields for a component based on its input and output var names.
This method will create new fields (without overwrite) for any fields output by, but not supplied to, the component. New fields are initialized to zero. Ignores optional fields. New fields are created as arrays of floats, unless the component specifies the variable type.
- Parameters:
values_per_element (int (optional)) – On occasion, it is necessary to create a field that is of size (n_grid_elements, values_per_element) instead of the default size (n_grid_elements,). Use this keyword argument to acomplish this task.
- input_var_names = ()¶
- property link_to_flow_receiving_node¶
Return the link id along the link transporting flow.
- name = 'FlowDirectorMFD'¶
- property node_receiving_flow¶
Return the node ids of the nodes receiving flow.
- property node_steepest_slope¶
Return the steepest link slope at a node.
- optional_var_names = ('topographic__elevation',)¶
- output_var_names = ('flow__link_to_receiver_node', 'flow__receiver_node', 'flow__receiver_proportions', 'flow__sink_flag', 'topographic__steepest_slope')¶
- property proportions_of_flow¶
Return the proportions of flow going to recievers.
- run_one_step()[source]¶
Find flow directions and save to the model grid.
run_one_step() checks for updated boundary conditions, calculates slopes on links, finds basself._surface_valuesel nodes based on the status at node, calculates flow directions, and saves results to the grid.
An alternative to run_one_step() is direct_flow() which does the same things but also returns the receiver nodes not return values.
- property shape¶
Return the grid shape attached to the component, if defined.
- property sink_flag¶
Return the array with sink flags.
- property surface_values¶
Values of the surface over which flow is directed.
- unit_agnostic = True¶
- units = (('flow__link_to_receiver_node', '-'), ('flow__receiver_node', '-'), ('flow__receiver_proportions', '-'), ('flow__sink_flag', '-'), ('topographic__elevation', 'm'), ('topographic__steepest_slope', '-'))¶
- updated_boundary_conditions()[source]¶
Method to update FlowDirectorMFD when boundary conditions change.
Call this if boundary conditions on the grid are updated after the component is instantiated.
- classmethod var_definition(name)¶
Get a description of a particular field.
- Parameters:
name (str) – A field name.
- Returns:
A description of each field.
- Return type:
tuple of (name, *description*)
- classmethod var_help(name)¶
Print a help message for a particular field.
- Parameters:
name (str) – A field name.
- classmethod var_loc(name)¶
Location where a particular variable is defined.
- var_mapping = (('flow__link_to_receiver_node', 'node'), ('flow__receiver_node', 'node'), ('flow__receiver_proportions', 'node'), ('flow__sink_flag', 'node'), ('topographic__elevation', 'node'), ('topographic__steepest_slope', 'node'))¶