def calc_aspect_at_node( grid, slope_component_tuple=None, elevs="topographic__elevation", unit="degrees", ignore_closed_nodes=True, ): """Get array of aspect of a surface. Calculates at returns the aspect of a surface. Aspect is returned as radians clockwise of north, unless input parameter units is set to 'degrees'. If slope_component_tuple is provided, i.e., (slope_x, slope_y), 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. If ignore_closed_nodes is False, all proximal elevation values will be used in the calculation. If True, only unclosed nodes are used. Parameters ---------- grid : ModelGrid A ModelGrid. slope_component_tuple : (slope_x_array, slope_y_array) (optional) Tuple of components of slope in the x and y directions, defined on nodes, if already known. If not, provide *elevs*. elevs : str or array (optional) Node field name or node array of elevations. If *slope_component_tuple* is not provided, must be set, but unused otherwise. unit : {'degrees', 'radians'} Controls the unit that the aspect is returned as. ignore_closed_nodes : bool If True, do not incorporate values at closed nodes into the calc. Examples -------- >>> from landlab import RasterModelGrid >>> mg = RasterModelGrid((4, 4)) >>> z = mg.node_x ** 2 + mg.node_y ** 2 >>> mg.calc_aspect_at_node(elevs=z) array([ 225. , 240.16585039, 255.2796318 , 258.69006753, 209.83414961, 225. , 243.54632481, 248.77808974, 194.7203682 , 206.45367519, 225. , 231.94498651, 191.30993247, 201.22191026, 218.05501349, 225. ]) >>> z = z.max() - z >>> mg.calc_aspect_at_node(elevs=z) array([ 45. , 60.16585039, 75.2796318 , 78.69006753, 29.83414961, 45. , 63.54632481, 68.77808974, 14.7203682 , 26.45367519, 45. , 51.94498651, 11.30993247, 21.22191026, 38.05501349, 45. ]) >>> mg = RasterModelGrid((4, 4), xy_spacing=(3., 2.)) >>> z = mg.node_x ** 2 + mg.node_y ** 2 >>> mg.calc_aspect_at_node(elevs=z) array([ 236.30993247, 247.52001262, 259.97326008, 262.40535663, 220.75264634, 234.41577266, 251.13402374, 255.29210302, 201.54258265, 215.47930877, 235.73541937, 242.24162456, 196.69924423, 209.43534223, 229.19345757, 236.30993247]) Note that a small amount of asymmetry arises at the grid edges due to the "missing" nodes beyond the edge of the grid. LLCATS: NINF SURF """ if slope_component_tuple: if not isinstance(slope_component_tuple, (tuple, list)): raise TypeError("slope_component_tuple must be tuple") if len(slope_component_tuple) != 2: raise ValueError("slope_component_tuple must be of length 2") else: try: elev_array = grid.at_node[elevs] except (KeyError, TypeError): assert elevs.size == grid.number_of_nodes elev_array = elevs _, slope_component_tuple = grid.calc_slope_at_node( elevs=elev_array, ignore_closed_nodes=ignore_closed_nodes, return_components=True, ) angle_from_x_ccw = np.arctan2(-slope_component_tuple[1], -slope_component_tuple[0]) if unit == "degrees": return radians_to_degrees(angle_from_x_ccw) elif unit == "radians": angle_from_north_cw = (5. * np.pi / 2. - angle_from_x_ccw) % (2. * np.pi) return angle_from_north_cw else: raise TypeError("unit must be 'degrees' or 'radians'")
def calc_aspect_at_node( grid, slope_component_tuple=None, elevs="topographic__elevation", unit="degrees", ignore_closed_nodes=True, ): """Get array of aspect of a surface. Calculates at returns the aspect of a surface. Aspect is returned as radians clockwise of north, unless input parameter units is set to 'degrees'. If slope_component_tuple is provided, i.e., (slope_x, slope_y), 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. If ignore_closed_nodes is False, all proximal elevation values will be used in the calculation. If True, only unclosed nodes are used. Parameters ---------- grid : ModelGrid A ModelGrid. slope_component_tuple : (slope_x_array, slope_y_array) (optional) Tuple of components of slope in the x and y directions, defined on nodes, if already known. If not, provide *elevs*. elevs : str or array (optional) Node field name or node array of elevations. If *slope_component_tuple* is not provided, must be set, but unused otherwise. unit : {'degrees', 'radians'} Controls the unit that the aspect is returned as. ignore_closed_nodes : bool If True, do not incorporate values at closed nodes into the calc. Examples -------- >>> from landlab import RasterModelGrid >>> mg = RasterModelGrid((4, 4)) >>> z = mg.node_x ** 2 + mg.node_y ** 2 >>> mg.calc_aspect_at_node(elevs=z) array([ 225. , 240.16585039, 255.2796318 , 258.69006753, 209.83414961, 225. , 243.54632481, 248.77808974, 194.7203682 , 206.45367519, 225. , 231.94498651, 191.30993247, 201.22191026, 218.05501349, 225. ]) >>> z = z.max() - z >>> mg.calc_aspect_at_node(elevs=z) array([ 45. , 60.16585039, 75.2796318 , 78.69006753, 29.83414961, 45. , 63.54632481, 68.77808974, 14.7203682 , 26.45367519, 45. , 51.94498651, 11.30993247, 21.22191026, 38.05501349, 45. ]) >>> mg = RasterModelGrid((4, 4), xy_spacing=(3., 2.)) >>> z = mg.node_x ** 2 + mg.node_y ** 2 >>> mg.calc_aspect_at_node(elevs=z) array([ 236.30993247, 247.52001262, 259.97326008, 262.40535663, 220.75264634, 234.41577266, 251.13402374, 255.29210302, 201.54258265, 215.47930877, 235.73541937, 242.24162456, 196.69924423, 209.43534223, 229.19345757, 236.30993247]) Note that a small amount of asymmetry arises at the grid edges due to the "missing" nodes beyond the edge of the grid. LLCATS: NINF SURF """ if slope_component_tuple: if not isinstance(slope_component_tuple, (tuple, list)): raise TypeError("slope_component_tuple must be tuple") if len(slope_component_tuple) != 2: raise ValueError("slope_component_tuple must be of length 2") else: try: elev_array = grid.at_node[elevs] except (KeyError, TypeError): assert elevs.size == grid.number_of_nodes elev_array = elevs _, slope_component_tuple = grid.calc_slope_at_node( elevs=elev_array, ignore_closed_nodes=ignore_closed_nodes, return_components=True, ) angle_from_x_ccw = np.arctan2(-slope_component_tuple[1], -slope_component_tuple[0]) if unit == "degrees": return radians_to_degrees(angle_from_x_ccw) elif unit == "radians": angle_from_north_cw = (5.0 * np.pi / 2.0 - angle_from_x_ccw) % (2.0 * np.pi) return angle_from_north_cw else: raise TypeError("unit must be 'degrees' or 'radians'")