コード例 #1
0
ファイル: sed_flux_dep_incision.py プロジェクト: stgl/landlab
    def get_sed_flux_function(self, rel_sed_flux):
        """Get the sediment flux function.

        Parameters
        ----------
        rel_sed_flux
        """
        if self._type == "generalized_humped":
            """Returns K*f(qs,qc)"""
            sed_flux_fn = (self._kappa * (rel_sed_flux**self._nu + self._c) *
                           np.exp(-self._phi * rel_sed_flux))
        elif self._type == "linear_decline":
            sed_flux_fn = 1.0 - rel_sed_flux
        elif self._type == "parabolic":
            raise MissingKeyError(
                "Pure parabolic (where intersect at zero flux is exactly " +
                "zero) is currently not supported, sorry. Try " +
                "almost_parabolic instead?")
            sed_flux_fn = 1.0 - 4.0 * (rel_sed_flux - 0.5)**2.0
        elif self._type == "almost_parabolic":
            sed_flux_fn = np.where(
                rel_sed_flux > 0.1,
                1.0 - 4.0 * (rel_sed_flux - 0.5)**2.0,
                2.6 * rel_sed_flux + 0.1,
            )
        elif self._type == "None":
            sed_flux_fn = 1.0
        else:
            raise MissingKeyError(
                "Provided sed flux sensitivity type in input file was not " +
                "recognised!")
        return sed_flux_fn
コード例 #2
0
    def get_sed_flux_function_pseudoimplicit(
        self, sed_in, trans_cap_vol_out, prefactor_for_volume, prefactor_for_dz
    ):
        """Get the pseudoimplicit sediment flux function.

        Parameters
        ----------
        sed_in
        trans_cap_vol_out
        prefactor_for_volume
        prefactor_for_dz
        """
        rel_sed_flux_in = sed_in / trans_cap_vol_out
        rel_sed_flux = rel_sed_flux_in

        if self._type == "generalized_humped":
            """Returns K*f(qs,qc)"""

            def sed_flux_fn_gen(rel_sed_flux_in):
                return (
                    self._kappa
                    * (rel_sed_flux_in ** self._nu + self._c)
                    * np.exp(-self._phi * rel_sed_flux_in)
                )

        elif self._type == "linear_decline":

            def sed_flux_fn_gen(rel_sed_flux_in):
                return 1.0 - rel_sed_flux_in

        elif self._type == "parabolic":
            raise MissingKeyError(
                "Pure parabolic (where intersect at zero flux is exactly "
                + "zero) is currently not supported, sorry. Try "
                + "almost_parabolic instead?"
            )

            def sed_flux_fn_gen(rel_sed_flux_in):
                return 1.0 - 4.0 * (rel_sed_flux_in - 0.5) ** 2.0

        elif self._type == "almost_parabolic":

            def sed_flux_fn_gen(rel_sed_flux_in):
                return np.where(
                    rel_sed_flux_in > 0.1,
                    1.0 - 4.0 * (rel_sed_flux_in - 0.5) ** 2.0,
                    2.6 * rel_sed_flux_in + 0.1,
                )

        elif self._type == "None":

            def sed_flux_fn_gen(rel_sed_flux_in):
                return 1.0

        else:
            raise MissingKeyError(
                "Provided sed flux sensitivity type in input file was not "
                + "recognised!"
            )

        for i in range(self._pseudoimplicit_repeats):
            sed_flux_fn = sed_flux_fn_gen(rel_sed_flux)
            sed_vol_added = prefactor_for_volume * sed_flux_fn
            rel_sed_flux = rel_sed_flux_in + sed_vol_added / trans_cap_vol_out
            # print rel_sed_flux
            if rel_sed_flux >= 1.0:
                rel_sed_flux = 1.0
                break
            if rel_sed_flux < 0.0:
                rel_sed_flux = 0.0
                break
        last_sed_flux_fn = sed_flux_fn
        sed_flux_fn = sed_flux_fn_gen(rel_sed_flux)
        # this error could alternatively be used to break the loop
        error_in_sed_flux_fn = sed_flux_fn - last_sed_flux_fn
        dz = prefactor_for_dz * sed_flux_fn
        sed_flux_out = rel_sed_flux * trans_cap_vol_out
        return dz, sed_flux_out, rel_sed_flux, error_in_sed_flux_fn
コード例 #3
0
ファイル: stream_power.py プロジェクト: pfeiffea/landlab
    def __init__(
        self,
        grid,
        K_sp=0.001,
        threshold_sp=0.0,
        sp_type="set_mn",
        m_sp=0.5,
        n_sp=1.0,
        a_sp=None,
        b_sp=None,
        c_sp=None,
        channel_width_field=1.0,
        discharge_field="drainage_area",
        erode_flooded_nodes=True,
    ):
        """Initialize the StreamPowerEroder.

        Parameters
        ----------
        grid : ModelGrid
            A grid.
        K_sp : float, array, or field name
            K in the stream power equation (units vary with other parameters).
        threshold_sp : positive float, array, or field name, optional
            The threshold stream power, below which no erosion occurs. This
            threshold is assumed to be in "stream power" units, i.e., if
            sp_type is 'Shear_stress', the value should be tau**a.
        sp_type : {'set_mn', 'Total', 'Unit', 'Shear_stress'}
            Controls how the law is implemented. If 'set_mn', use the supplied
            values of m_sp and n_sp. Else, component will derive values of m and n
            from supplied values of a_sp, b_sp, and c_sp, following Whipple and
            Tucker:

            *  If ``'Total'``, ``m = a * c``, ``n = a``.
            *  If ``'Unit'``, ``m = a * c *(1 - b)``, ``n = a``.
            *  If ``'Shear_stress'``, ``m = 2 * a * c * (1 - b) / 3``,
               ``n = 2 * a / 3``.

        m_sp : float, optional
            m in the stream power equation (power on drainage area). Overridden if
            a_sp, b_sp, and c_sp are supplied.
        n_sp : float, optional, ~ 0.5<n_sp<4.
            n in the stream power equation (power on slope). Overridden if
            a_sp, b_sp, and c_sp are supplied.
        a_sp : float, optional
            The power on the SP/shear term to get the erosion rate; the "erosional
            process" term. Only used if sp_type is not 'set_mn'.
        b_sp : float, optional
            The power on discharge to get width; the "hydraulic geometry" term.
            Only used if sp_type in ('Unit', 'Shear_stress').
        c_sp : float, optional
            The power on area to get discharge; the "basin hydology" term. Only
            used if sp_type is not 'set_mn'.
        channel_width_field : None, float, array, or field name, optional
            If not None, component will look for node-centered data describing
            channel width or if an array, will take the array as the channel
            widths. It will use the widths to implement incision ~ stream power
            per unit width. If sp_type is 'set_mn', follows the equation given
            above. If sp_type in ('Unit', 'Shear_stress'), the width value will
            be implemented directly. W has no effect if sp_type is 'Total'.
        discharge_field : float, field name, or array, optional
            Discharge [L^2/T]. The default is to use the grid field
            'drainage_area'. To use custom spatially/temporally varying
            rainfall, use 'water__unit_flux_in' to specify water input to the
            FlowAccumulator and use "surface_water__discharge" for this
            keyword argument.
        erode_flooded_nodes : bool (optional)
            Whether erosion occurs in flooded nodes identified by a
            depression/lake mapper (e.g., DepressionFinderAndRouter). When set
            to false, the field *flood_status_code* must be present on the grid
            (this is created by the DepressionFinderAndRouter). Default True.
        """
        super().__init__(grid)

        if "flow__receiver_node" in grid.at_node:
            if grid.at_node["flow__receiver_node"].size != grid.size("node"):
                msg = (
                    "A route-to-multiple flow director has been "
                    "run on this grid. The landlab development team has not "
                    "verified that StreamPowerEroder is compatible with "
                    "route-to-multiple methods. Please open a GitHub Issue "
                    "to start this process.")
                raise NotImplementedError(msg)

        if not erode_flooded_nodes:
            if "flood_status_code" not in self._grid.at_node:
                msg = (
                    "In order to not erode flooded nodes another component "
                    "must create the field *flood_status_code*. You want to "
                    "run a lake mapper/depression finder.")
                raise ValueError(msg)

        self._erode_flooded_nodes = erode_flooded_nodes

        self._A = return_array_at_node(grid, discharge_field)
        self._elevs = return_array_at_node(grid, "topographic__elevation")
        self._sp_crit = return_array_at_node(grid, threshold_sp)

        # use setter for K defined below
        self.K = K_sp

        assert np.all(self._sp_crit >= 0.0)

        if discharge_field == "drainage_area":
            self._use_Q = False
        else:
            self._use_Q = True

        if channel_width_field is None:
            self._use_W = False
        else:
            self._use_W = True
            self._W = return_array_at_node(grid, channel_width_field)

        if np.any(threshold_sp != 0.0):
            self._set_threshold = True
            # ^flag for sed_flux_dep_incision to see if the threshold was
            # manually set.
        else:
            self._set_threshold = False

        self._type = sp_type
        if sp_type == "set_mn":
            assert (float(m_sp) >= 0.0) and (float(n_sp) >=
                                             0.0), "m and n must be positive"
            self._m = float(m_sp)
            self._n = float(n_sp)
            assert (
                (a_sp is None) and (b_sp is None) and (c_sp is None)
            ), "If sp_type is 'set_mn', do not pass values for a, b, or c!"
        else:
            assert sp_type in ("Total", "Unit", "Shear_stress"), (
                "sp_type not recognised. It must be 'set_mn', 'Total', " +
                "'Unit', or 'Shear_stress'.")
            assert (m_sp == 0.5 and n_sp
                    == 1.0), "Do not set m and n if sp_type is not 'set_mn'!"
            assert float(a_sp) >= 0.0, "a must be positive"
            self._a = float(a_sp)
            if b_sp is not None:
                assert float(b_sp) >= 0.0, "b must be positive"
                self._b = float(b_sp)
            else:
                assert self._use_W, "b was not set"
                self._b = 0.0
            if c_sp is not None:
                assert float(c_sp) >= 0.0, "c must be positive"
                self._c = float(c_sp)
            else:
                assert self._use_Q, "c was not set"
                self._c = 1.0
            if self._type == "Total":
                self._n = self._a
                self._m = self._a * self._c  # ==_a if use_Q
            elif self._type == "Unit":
                self._n = self._a
                self._m = self._a * self._c * (1.0 - self._b)
                # ^ ==_a iff use_Q&use_W etc
            elif self._type == "Shear_stress":
                self._m = 2.0 * self._a * self._c * (1.0 - self._b) / 3.0
                self._n = 2.0 * self._a / 3.0
            else:
                raise MissingKeyError(
                    "Not enough information was provided on the exponents to use!"
                )

        # m and n will always be set, but care needs to be taken to include Q
        # and W directly if appropriate

        self._stream_power_erosion = self._grid.zeros(centering="node")
        self._alpha = self._grid.zeros("node")