Using xgcm.transform to interpolate to isopycnal space#

%load_ext watermark

import numpy as np
import xarray as xr
import xgcm

import pop_tools

%watermark -iv
xgcm     : 0.8.1
pop_tools: 2023.3.0.post2+dirty
xarray   : 2023.6.0
numpy    : 1.24.4

Load data#

Read an existing sample dataset for the tropical pacific. Unfortunately, this particular subset does not have SALT, so for demonstration purposes we set SALT=35.

# open sample data
filepath = pop_tools.DATASETS.fetch('Pac_POP0.1_JRA_IAF_1993-12-6-test.nc')
ds = xr.open_dataset(filepath)

# get DZU and DZT, needed for operations later on
filepath_g = pop_tools.DATASETS.fetch("Pac_grid_pbc_1301x305x62.tx01_62l.2013-07-13.nc")
ds_g = xr.open_dataset(filepath_g)
ds.update(ds_g[["DZU", "DZT"]])

# There is no salinity, so let's  create a fake SALT variable
ds["SALT"] = 35 * xr.ones_like(ds.TEMP)
ds.SALT.attrs["grid_loc"] = ds.TEMP.attrs["grid_loc"]
ds
Downloading file 'Pac_POP0.1_JRA_IAF_1993-12-6-test.nc' from 'ftp://ftp.cgd.ucar.edu/archive/aletheia-data/cesm-data/ocn/Pac_POP0.1_JRA_IAF_1993-12-6-test.nc' to '/home/docs/.pop_tools/data'.
Downloading file 'Pac_grid_pbc_1301x305x62.tx01_62l.2013-07-13.nc' from 'ftp://ftp.cgd.ucar.edu/archive/aletheia-data/cesm-data/ocn/Pac_grid_pbc_1301x305x62.tx01_62l.2013-07-13.nc' to '/home/docs/.pop_tools/data'.
<xarray.Dataset>
Dimensions:         (time: 1, z_t: 62, nlat: 305, nlon: 1301, z_w_top: 62,
                     z_w: 62, z_w_bot: 62)
Coordinates:
  * time            (time) object 0036-12-07 00:00:00
  * z_t             (z_t) float32 500.0 1.5e+03 2.5e+03 ... 5.625e+05 5.875e+05
  * z_w             (z_w) float32 0.0 1e+03 2e+03 ... 5.25e+05 5.5e+05 5.75e+05
  * z_w_top         (z_w_top) float32 0.0 1e+03 2e+03 ... 5.5e+05 5.75e+05
  * z_w_bot         (z_w_bot) float32 1e+03 2e+03 3e+03 ... 5.75e+05 6e+05
    ULONG           (nlat, nlon) float64 ...
    ULAT            (nlat, nlon) float64 ...
    TLONG           (nlat, nlon) float64 ...
    TLAT            (nlat, nlon) float64 ...
Dimensions without coordinates: nlat, nlon
Data variables: (12/29)
    TEND_TEMP       (time, z_t, nlat, nlon) float32 ...
    UET             (time, z_t, nlat, nlon) float32 ...
    VNT             (time, z_t, nlat, nlon) float32 ...
    WTT             (time, z_w_top, nlat, nlon) float32 ...
    KPP_SRC_TEMP    (time, z_t, nlat, nlon) float32 ...
    UVEL            (time, z_t, nlat, nlon) float32 ...
    ...              ...
    DIA_IMPVF_TEMP  (time, z_w_bot, nlat, nlon) float32 ...
    SHF             (time, nlat, nlon) float32 ...
    SHF_QSW         (time, nlat, nlon) float32 ...
    DZU             (z_t, nlat, nlon) float32 ...
    DZT             (z_t, nlat, nlon) float32 ...
    SALT            (time, z_t, nlat, nlon) float32 35.0 35.0 35.0 ... 35.0 35.0
Attributes:
    title:             g.e20.G.TL319_t13.control.001_hfreq
    history:           none
    Conventions:       CF-1.0; http://www.cgd.ucar.edu/cms/eaton/netcdf/CF-cu...
    time_period_freq:  day_5
    model_doi_url:     https://doi.org/10.5065/D67H1H0V
    contents:          Diagnostic and Prognostic Variables
    source:            CCSM POP2, the CCSM Ocean Component
    revision:          $Id: tavg.F90 89091 2018-04-30 15:58:32Z altuntas@ucar...
    calendar:          All years have exactly  365 days.
    start_time:        This dataset was created on 2018-12-14 at 16:05:58.8
    cell_methods:      cell_methods = time: mean ==> the variable values are ...

Construct xgcm-compatible dataset and xgcm grid object#

metrics = {
    ("X",): ["DXU", "DXT"],  # X distances
    ("Y",): ["DYU", "DYT"],  # Y distances
    ("Z",): ["DZU", "DZT"],  # Z distances
    ("X", "Y"): ["UAREA", "TAREA"],
}

# here we get the xgcm compatible dataset
grid, xds = pop_tools.to_xgcm_grid_dataset(
    ds,
    periodic=False,
    metrics=metrics,
    boundary={"X": "extend", "Y": "extend", "Z": "extend"},
)

xds["rho"] = pop_tools.eos(xds.SALT, xds.TEMP, depth=xds.z_t * 1e-2)
xds
<xarray.Dataset>
Dimensions:         (time: 1, z_t: 62, nlat_t: 305, nlon_t: 1301, nlon_u: 1301,
                     nlat_u: 305, z_w_top: 62, z_w_bot: 62)
Coordinates:
  * time            (time) object 0036-12-07 00:00:00
  * z_t             (z_t) float32 500.0 1.5e+03 2.5e+03 ... 5.625e+05 5.875e+05
  * z_w_top         (z_w_top) float32 0.0 1e+03 2e+03 ... 5.5e+05 5.75e+05
  * z_w_bot         (z_w_bot) float32 1e+03 2e+03 3e+03 ... 5.75e+05 6e+05
    ULONG           (nlat_u, nlon_u) float64 160.0 160.1 160.2 ... -70.1 -70.0
    ULAT            (nlat_u, nlon_u) float64 -15.03 -15.03 ... 15.03 15.03
    TLONG           (nlat_t, nlon_t) float64 159.9 160.0 160.1 ... 289.9 290.0
    TLAT            (nlat_t, nlon_t) float64 -15.07 -15.07 ... 14.98 14.98
  * nlon_u          (nlon_u) int64 1 2 3 4 5 6 ... 1296 1297 1298 1299 1300 1301
  * nlat_u          (nlat_u) int64 1 2 3 4 5 6 7 ... 299 300 301 302 303 304 305
  * nlon_t          (nlon_t) float64 0.5 1.5 2.5 ... 1.298e+03 1.3e+03 1.3e+03
  * nlat_t          (nlat_t) float64 0.5 1.5 2.5 3.5 ... 301.5 302.5 303.5 304.5
Data variables: (12/30)
    TEND_TEMP       (time, z_t, nlat_t, nlon_t) float32 3.461e-08 ... nan
    UET             (time, z_t, nlat_t, nlon_u) float32 -0.0005898 ... 0.0
    VNT             (time, z_t, nlat_u, nlon_t) float32 0.0002135 ... 0.0
    WTT             (time, z_w_top, nlat_t, nlon_t) float32 0.0 0.0 ... nan nan
    KPP_SRC_TEMP    (time, z_t, nlat_t, nlon_t) float32 1.908e-06 ... nan
    UVEL            (time, z_t, nlat_u, nlon_u) float32 -23.85 -25.17 ... nan
    ...              ...
    SHF             (time, nlat_t, nlon_t) float32 94.64 96.18 ... -58.45 -58.65
    SHF_QSW         (time, nlat_t, nlon_t) float32 245.0 245.2 ... 204.0 203.9
    DZU             (z_t, nlat_u, nlon_u) float32 1e+03 1e+03 ... 2.5e+04
    DZT             (z_t, nlat_t, nlon_t) float32 1e+03 1e+03 ... 2.5e+04
    SALT            (time, z_t, nlat_t, nlon_t) float32 35.0 35.0 ... 35.0 35.0
    rho             (time, z_t, nlat_t, nlon_t) float64 1.023e+03 ... nan
Attributes:
    title:             g.e20.G.TL319_t13.control.001_hfreq
    history:           none
    Conventions:       CF-1.0; http://www.cgd.ucar.edu/cms/eaton/netcdf/CF-cu...
    time_period_freq:  day_5
    model_doi_url:     https://doi.org/10.5065/D67H1H0V
    contents:          Diagnostic and Prognostic Variables
    source:            CCSM POP2, the CCSM Ocean Component
    revision:          $Id: tavg.F90 89091 2018-04-30 15:58:32Z altuntas@ucar...
    calendar:          All years have exactly  365 days.
    start_time:        This dataset was created on 2018-12-14 at 16:05:58.8
    cell_methods:      cell_methods = time: mean ==> the variable values are ...

Visualize surface density field#

(xds.rho - 1000).isel(z_t=0).plot(robust=True)
<matplotlib.collections.QuadMesh at 0x7f7cdbf0fcd0>
../_images/6038f9680e3497c8d20e81e62a118d19aa19d848732797e702f1afbe667823b3.png

Regrid to density space using grid.transform#

See https://xgcm.readthedocs.io/en/latest/transform.html for more

regridded = grid.transform(
    xds.TEMP,
    axis="Z",
    target=np.arange(25, 30, 0.5),
    target_data=xds.rho - 1000,
    method="linear",
)
/home/docs/checkouts/readthedocs.org/user_builds/pop-tools/conda/latest/lib/python3.9/site-packages/xgcm/grid.py:989: FutureWarning: From version 0.8.0 the Axis computation methods will be removed, in favour of using the Grid computation methods instead. i.e. use `Grid.transform` instead of `Axis.transform`
  warnings.warn(
/home/docs/checkouts/readthedocs.org/user_builds/pop-tools/conda/latest/lib/python3.9/site-packages/numba/np/ufunc/gufunc.py:171: RuntimeWarning: invalid value encountered in _interp_1d_linear
  return self.ufunc(*args, **kwargs)

Visualize temperature on a single isopycnal surface#

regridded.isel(rho=5).plot(robust=True)
<matplotlib.collections.QuadMesh at 0x7f7cdb7632b0>
../_images/4f4c449857347c58709fc770fc6fc3a4b52392f9f150940e872c40c9f286ebe1.png

Find depth of isopycnal surface#

regridded.coords["z_t"] = grid.transform(
    xds.z_t.broadcast_like(xds.rho),
    axis="Z",
    target=np.arange(24, 30, 0.5),
    target_data=xds.rho - 1000,
    method="linear",
)
regridded.z_t.isel(rho=5).plot(robust=True)
<matplotlib.collections.QuadMesh at 0x7f7cdb6baa60>
../_images/f7edda609f1e6a58808a80d148d31620a3e958f9fe4ae4ac7af0182ef4ff4574.png