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))
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, )
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()