Ejemplo n.º 1
0
def test_zslice():
    testvars = ["salt", "u", "v", "z_w"]
    for testvar in testvars:
        varin = ds[testvar]
        depths = np.asarray(ds[testvar].cf["vertical"][0, :, 0, 0].values)
        varout = xroms.isoslice(varin, depths, grid, axis="Z")
        assert np.allclose(varout.cf.isel(T=0, Y=0, X=0),
                           varin.cf.isel(T=0, Y=0, X=0))
Ejemplo n.º 2
0
    def isoslice(self, iso_values, iso_array=None, axis="Z"):
        """Interpolate var to iso_values.

        This wraps `xgcm` `transform` function for slice interpolation,
        though `transform` has additional functionality.

        Inputs
        ------
        iso_values: list, ndarray
            Values to interpolate to. If calculating var at fixed depths,
            iso_values are the fixed depths, which should be negative if
            below mean sea level. If input as array, should be 1D.
        iso_array: DataArray, optional
            Array that var is interpolated onto (e.g., z coordinates or
            density). If calculating var on fixed depth slices, iso_array
            contains the depths [m] associated with var. In that case and
            if None, will use z coordinate attached to var. Also use this
            option if you want to interpolate with z depths constant in
            time and input the appropriate z coordinate.
        dim: str, optional
            Dimension over which to calculate isoslice. If calculating var
            onto fixed depths, `dim='Z'`. Options are 'Z', 'Y', and 'X'.

        Returns
        -------
        DataArray of var interpolated to iso_values. Dimensionality will be the
        same as var except with dim dimension of size of iso_values.

        Notes
        -----
        var cannot have chunks in the dimension dim.

        cf-xarray should still be usable after calling this function.

        Example usage
        -------------
        To calculate temperature onto fixed depths:
        >>> xroms.isoslice(ds.temp, np.linspace(0, -30, 50))

        To calculate temperature onto salinity:
        >>> xroms.isoslice(ds.temp, np.arange(0, 36), iso_array=ds.salt, axis='Z')

        Calculate lat-z slice of salinity along a constant longitude value (-91.5):
        >>> xroms.isoslice(ds.salt, -91.5, iso_array=ds.lon_rho, axis='X')

        Calculate slice of salt at 28 deg latitude
        >>> xroms.isoslice(ds.salt, 28, iso_array=ds.lat_rho, axis='Y')

        Interpolate temp to salinity values between 0 and 36 in the X direction
        >>> xroms.isoslice(ds.temp, np.linspace(0, 36, 50), iso_array=ds.salt, axis='X')

        Interpolate temp to salinity values between 0 and 36 in the Z direction
        >>> xroms.isoslice(ds.temp, np.linspace(0, 36, 50), iso_array=ds.salt, axis='Z')

        Calculate the depth of a specific isohaline (33):
        >>> xroms.isoslice(ds.salt, 33, iso_array=ds.z_rho, axis='Z')

        Calculate dye 10 meters above seabed. Either do this on the vertical
        rho grid, or first change to the w grid and then use `isoslice`. You may prefer
        to do the latter if there is a possibility that the distance above the seabed you are
        interpolating to (10 m) could be below the deepest rho grid depth.
        * on rho grid directly:
        >>> height_from_seabed = ds.z_rho + ds.h
        >>> height_from_seabed.name = 'z_rho'
        >>> xroms.isoslice(ds.dye_01, 10, iso_array=height_from_seabed, axis='Z')
        * on w grid:
        >>> var_w = ds.dye_01.xroms.to_grid(scoord='w').chunk({'s_w': -1})
        >>> ds['dye_01_w'] = var_w  # currently this is the easiest way to reattached coords xgcm variables
        >>> height_from_seabed = ds.z_w + ds.h
        >>> height_from_seabed.name = 'z_w'
        >>> xroms.isoslice(ds['dye_01_w'], 10, iso_array=height_from_seabed, axis='Z')
        """

        return xroms.isoslice(
            self.da,
            iso_values,
            grid=self.da.attrs["grid"],
            iso_array=iso_array,
            axis=axis,
        )
Ejemplo n.º 3
0
def mld(sig0, h, mask, z=None, thresh=0.03):
    """Calculate the mixed layer depth [m].

    Inputs
    ------
    sig0: DataArray
        Potential density [kg/m^3]
    h: DataArray, ndarray
        Depths [m].
    mask: DataArray, ndarray
        mask to match sig0
    z: DataArray, ndarray, optional
        The vertical depths associated with sig0. Should be on 'rho'
        grid horizontally and vertically. Use z coords associated with DataArray sig0
        if not input.
    thresh: float, optional
        For detection of mixed layer [kg/m^3]

    Returns
    -------
    DataArray of mixed layer depth on rho horizontal grid.
    Output is `[T,Y,X]`.

    Notes
    -----
    Mixed layer depth is based on the fixed Potential Density (PD) threshold.

    Converted to xroms by K. Thyng Aug 2020 from:

    Update history:
    v1.0 DL 2020Jun07

    References:
    ncl mixed_layer_depth function at https://github.com/NCAR/ncl/blob/ed6016bf579f8c8e8f77341503daef3c532f1069/ni/src/lib/nfpfort/ocean.f
    de Boyer Montégut, C., Madec, G., Fischer, A. S., Lazar, A., & Iudicone, D. (2004). Mixed layer depth over the global ocean: An examination of profile data and a profile‐based climatology. Journal of  Geophysical Research: Oceans, 109(C12).

    Example usage
    -------------
    >>> xroms.mld(sig0, h, mask)
    """

    if h.mean() > 0:  # if depths are positive, change to negative
        h = -h

    # xisoslice will operate over the relevant s dimension
    skey = sig0.dims[[dim[:2] == "s_" for dim in sig0.dims].index(True)]

    if z is None:
        z = sig0.z_rho

    # the mixed layer depth is the isosurface of depth where the potential density equals the surface - a threshold
    mld = xroms.isoslice(
        z,
        0.0,
        sig0.attrs["grid"],
        iso_array=sig0 - sig0.isel(s_rho=-1) - thresh,
        axis="Z",
    )
    #     mld = xroms.xisoslice(sig0 - sig0.isel(s_rho=-1) - thresh, 0.0, z, skey)

    # Replace nan's that are not masked with the depth of the water column.
    cond = (mld.isnull()) & (mask == 1)
    mld = mld.where(~cond, h)

    mld.attrs["name"] = "mld"
    mld.attrs["long_name"] = "mixed layer depth"
    mld.attrs["units"] = "m"
    if "grid" in sig0.attrs:
        mld.attrs["grid"] = sig0.attrs["grid"]
    mld.name = mld.attrs["name"]

    return mld.squeeze()