Esempio n. 1
0
def test_latitude_masks(get_test_ds):
    """run through lats, and ensure we're grabbing the closest
    "south-grid-cell-location" (whether that's in the x or y direction!)
    to each latitude value"""

    ds = get_test_ds

    grid = get_llc_grid(ds)
    yW = grid.interp(ds['YC'], 'X', boundary='fill')
    yS = grid.interp(ds['YC'], 'Y', boundary='fill')
    wetW = ds['maskW'].isel(k=0)
    wetS = ds['maskS'].isel(k=0)

    dLat = 0.5  # is this robust?
    nx = 90

    for lat in np.arange(-89, 89, 10):
        print('lat: ', lat)
        maskW, maskS = vector_calc.get_latitude_masks(lat, ds['YC'], grid)

        maskW = maskW.where((maskW != 0) & wetW, 0.)
        maskS = maskS.where((maskS != 0) & wetS, 0.)

        arctic = int((len(maskW.tile) - 1) / 2)
        assert not (maskW > 0).sel(tile=slice(arctic + 1, None)).any()
        assert not (maskS < 0).sel(tile=slice(arctic - 1)).any()

        assert (yW - lat < dLat).where(ds['maskW'].isel(k=0)
                                       & (maskW != 0)).all().values
        assert (yS - lat < dLat).where(ds['maskS'].isel(k=0)
                                       & (maskS != 0)).all().values
Esempio n. 2
0
def test_3d(get_global_ds):
    """check that vertical coordinate"""

    ds = get_global_ds
    grid = ecco_v4_py.get_llc_grid(ds)
    maskK = ds['maskC']
    maskL = grid.interp(maskK, 'Z', to='left', boundary='fill')
    maskU = grid.interp(maskK, 'Z', to='right', boundary='fill')
    maskKp1 = ds.maskC.isel(k=0).broadcast_like(ds.k_p1)
    for mask in [maskK, maskL, maskU, maskKp1]:
        ecco_v4_py.get_basin_mask('atl', mask)
Esempio n. 3
0
def test_optional_grid(get_test_ds):
    """simple, make sure we can optionally provide grid..."""

    ds = get_test_ds
    grid = get_llc_grid(ds)

    uX = xr.ones_like(ds['U'].isel(k=0)).load()
    vY = xr.ones_like(ds['V'].isel(k=0)).load()

    u1, v1 = vector_calc.UEVNfromUXVY(uX, vY, ds)
    u2, v2 = vector_calc.UEVNfromUXVY(uX, vY, ds, grid)
    assert (u1 == u2).all()
    assert (v1 == v2).all()
Esempio n. 4
0
def test_separate_coords(get_test_ds, myfunc, myarg):
    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    ds = ds.rename({'U': 'UVELMASS', 'V': 'VVELMASS'})

    myarg['grid'] = grid
    expected = myfunc(ds, **myarg)
    coords = ds.coords.to_dataset().reset_coords()
    ds = ds.reset_coords(drop=True)

    test = myfunc(ds, coords=coords, **myarg)
    xr.testing.assert_allclose(test['psi_moc'].reset_coords(drop=True),
                               expected['psi_moc'].reset_coords(drop=True))
Esempio n. 5
0
def test_separate_coords(get_test_ds, myfunc, fld, xflds, yflds, lat):
    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    for fx, fy in zip(xflds, yflds):
        ds[fx] = ds['U'].copy()
        ds[fy] = ds['V'].copy()

    expected = myfunc(ds, lat, grid=grid)
    coords = ds.coords.to_dataset().reset_coords()
    ds = ds.reset_coords(drop=True)

    test = myfunc(ds, lat, coords=coords, grid=grid)
    xr.testing.assert_equal(test[fld].reset_coords(drop=True),
                            expected[fld].reset_coords(drop=True))
Esempio n. 6
0
def test_meridional_stf(get_test_ds, lats, basin, doFlip):
    """compute a meridional streamfunction"""

    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    ds = ds.rename({'U': 'UVELMASS', 'V': 'VVELMASS'})

    if basin is None or len(ds.tile) == 13:
        trsp = ecco_v4_py.calc_meridional_stf(ds,
                                              lats,
                                              doFlip=doFlip,
                                              basin_name=basin,
                                              grid=grid)

        basinW = ds['maskW']
        basinS = ds['maskS']
        if basin is not None:
            basinW = ecco_v4_py.get_basin_mask(basin, basinW)
            basinS = ecco_v4_py.get_basin_mask(basin, basinS)

        lats = [lats] if np.isscalar(lats) else lats
        for lat in lats:
            maskW, maskS = ecco_v4_py.vector_calc.get_latitude_masks(
                lat, ds['YC'], grid)

            trspx = (ds['drF'] * ds['dyG'] *
                     np.abs(maskW)).where(basinW).sum(dim=['i_g', 'j', 'tile'])
            trspy = (ds['drF'] * ds['dxG'] *
                     np.abs(maskS)).where(basinS).sum(dim=['i', 'j_g', 'tile'])
            test = trsp.sel(lat=lat).psi_moc.squeeze().reset_coords(drop=True)
            expected = (1e-6 * (trspx + trspy)).reset_coords(drop=True)
            if doFlip:
                expected = expected.isel(k=slice(None, None, -1))
            expected = expected.cumsum(dim='k')
            if doFlip:
                expected = -1 * expected.isel(k=slice(None, None, -1))
            xr.testing.assert_allclose(test, expected)
    else:
        with pytest.raises(NotImplementedError):
            trsp = ecco_v4_py.calc_meridional_stf(ds,
                                                  lats,
                                                  doFlip=doFlip,
                                                  basin_name=basin,
                                                  grid=grid)
Esempio n. 7
0
def test_trsp_masking(get_test_ds, lat):
    """make sure internal masking is legit"""

    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    ds['U'] = ds['U'].where(ds['maskW'], 0.)
    ds['V'] = ds['V'].where(ds['maskS'], 0.)

    expected = ecco_v4_py.meridional_trsp_at_depth(ds['U'], ds['V'], lat, ds)
    coords = ds[['Z', 'YC', 'XC', 'dyG', 'dxG', 'time']].copy()
    coords.attrs = ds.attrs.copy()
    ds = ds.reset_coords(drop=True)
    test = ecco_v4_py.meridional_trsp_at_depth(ds['U'], ds['V'], lat, coords)

    xr.testing.assert_equal(test['trsp_z'].reset_coords(drop=True),
                            expected['trsp_z'].reset_coords(drop=True))
Esempio n. 8
0
def test_section_trsp(get_test_ds, myfunc, tfld, xflds, yflds, factor, args,
                      mask, error):
    """compute a volume transport,
    within the lat/lon portion of the domain"""

    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    for fx, fy in zip(xflds, yflds):
        ds[fx] = ds['U'].copy()
        ds[fy] = ds['V'].copy()

    myargs = args.copy()
    if mask:
        myargs['maskW'], myargs[
            'maskS'] = ecco_v4_py.vector_calc.get_latitude_masks(
                30, ds['YC'], grid)
    else:
        myargs['maskW'] = None
        myargs['maskS'] = None

    if error is None:
        trsp = myfunc(ds, grid=grid, **myargs)

        maskW, maskS = ecco_v4_py.calc_section_trsp._parse_section_trsp_inputs(
            ds, grid=grid, **myargs)

        expx = (ds['drF'] * ds['dyG']).copy(
        ) if tfld == 'vol_trsp_z' else 2. * xr.ones_like(ds['hFacW'])
        expy = (ds['drF'] * ds['dxG']).copy(
        ) if tfld == 'vol_trsp_z' else 2. * xr.ones_like(ds['hFacS'])
        trspx = (expx * np.abs(maskW)).where(
            ds['maskW']).sum(dim=['i_g', 'j', 'tile'])
        trspy = (expy * np.abs(maskS)).where(
            ds['maskS']).sum(dim=['i', 'j_g', 'tile'])

        test = trsp[tfld].squeeze().reset_coords(drop=True)
        expected = (factor * (trspx + trspy)).reset_coords(drop=True)
        xr.testing.assert_equal(test, expected)

    else:
        with pytest.raises(error):
            trsp = myfunc(ds, **myargs)
Esempio n. 9
0
def test_section_stf(get_test_ds, args, mask, error, doFlip):
    """compute streamfunction across section"""

    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    ds = ds.rename({'U': 'UVELMASS', 'V': 'VVELMASS'})

    myargs = args.copy()
    if mask:
        myargs['maskW'], myargs[
            'maskS'] = ecco_v4_py.vector_calc.get_latitude_masks(
                30, ds['YC'], grid)
    else:
        myargs['maskW'] = None
        myargs['maskS'] = None

    if error is None:
        trsp = ecco_v4_py.calc_section_stf(ds,
                                           doFlip=doFlip,
                                           grid=grid,
                                           **myargs)

        maskW, maskS = ecco_v4_py.calc_section_trsp._parse_section_trsp_inputs(
            ds, **myargs)

        trspx = (ds['drF'] * ds['dyG'] * np.abs(maskW)).where(
            ds['maskW']).sum(dim=['i_g', 'j', 'tile'])
        trspy = (ds['drF'] * ds['dxG'] * np.abs(maskS)).where(
            ds['maskS']).sum(dim=['i', 'j_g', 'tile'])

        test = trsp.psi_moc.squeeze().reset_coords(drop=True)
        expected = (1e-6 * (trspx + trspy)).reset_coords(drop=True)
        if doFlip:
            expected = expected.isel(k=slice(None, None, -1))
        expected = expected.cumsum(dim='k')
        if doFlip:
            expected = -1 * expected.isel(k=slice(None, None, -1))
        xr.testing.assert_allclose(test, expected)

    else:
        with pytest.raises(error):
            trsp = ecco_v4_py.calc_section_stf(ds, **myargs)
Esempio n. 10
0
def test_latitude_mask(get_test_ds):
    """run through lats, and ensure we're grabbing the closest
    "south-grid-cell-location" (whether that's in the x or y direction!)
    to each latitude value"""

    ds = get_test_ds

    grid = get_llc_grid(ds)
    wetC = ds['maskC'].isel(k=0)

    dLat = 0.5  # is this robust?
    nx = 90

    for lat in np.arange(-89, 89, 10):
        print('lat: ', lat)
        maskC = scalar_calc.get_latitude_mask(lat, ds['YC'], grid)

        maskC = maskC.where((maskC != 0) & wetC, 0.)

        assert (ds['YC'] - lat < dLat).where((maskC != 0)).all().values
Esempio n. 11
0
def test_trsp_masking(get_test_ds, section_name):
    """make sure internal masking is legit"""

    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    ds['U'] = ds['U'].where(ds['maskW'], 0.)
    ds['V'] = ds['V'].where(ds['maskS'], 0.)

    pt1, pt2 = ecco_v4_py.get_section_endpoints(section_name)
    _, maskW, maskS = ecco_v4_py.get_section_line_masks(pt1, pt2, ds)

    expected = ecco_v4_py.section_trsp_at_depth(ds['U'], ds['V'], maskW, maskS,
                                                ds)

    ds = ds.drop_vars(['maskW', 'maskS'])
    test = ecco_v4_py.section_trsp_at_depth(ds['U'], ds['V'], maskW, maskS)

    xr.testing.assert_equal(test['trsp_z'].reset_coords(drop=True),
                            expected['trsp_z'].reset_coords(drop=True))
Esempio n. 12
0
def test_meridional_trsp(get_test_ds, myfunc, tfld, xflds, yflds, factor, lats,
                         basin):
    """compute a transport"""

    ds = get_test_ds
    grid = ecco_v4_py.get_llc_grid(ds)

    ds['U'], ds['V'] = get_fake_vectors(ds['U'], ds['V'])
    for fx, fy in zip(xflds, yflds):
        ds[fx] = ds['U'].copy()
        ds[fy] = ds['V'].copy()

    if basin is None or len(ds.tile) == 13:
        trsp = myfunc(ds, lats, basin_name=basin, grid=grid)
        basinW = ds['maskW']
        basinS = ds['maskS']
        if basin is not None:
            basinW = ecco_v4_py.get_basin_mask(basin, basinW)
            basinS = ecco_v4_py.get_basin_mask(basin, basinS)

        lats = [lats] if np.isscalar(lats) else lats
        expx = (ds['drF'] * ds['dyG']).copy(
        ) if tfld == 'vol_trsp_z' else 2. * xr.ones_like(ds['hFacW'])
        expy = (ds['drF'] * ds['dxG']).copy(
        ) if tfld == 'vol_trsp_z' else 2. * xr.ones_like(ds['hFacS'])
        for lat in lats:
            maskW, maskS = ecco_v4_py.vector_calc.get_latitude_masks(
                lat, ds['YC'], grid)

            trspx = (expx *
                     np.abs(maskW)).where(basinW).sum(dim=['i_g', 'j', 'tile'])
            trspy = (expy *
                     np.abs(maskS)).where(basinS).sum(dim=['i', 'j_g', 'tile'])

            test = trsp.sel(lat=lat)[tfld].squeeze().reset_coords(drop=True)
            expected = (factor * (trspx + trspy)).reset_coords(drop=True)
            xr.testing.assert_allclose(test, expected)
    else:
        with pytest.raises(NotImplementedError):
            trsp = myfunc(ds, lats, basin_name=basin, grid=grid)
Esempio n. 13
0
print(ecco_monthly_mean.time.isel(time=[0, -1]).values)

# In[11]:

# each monthly mean record is bookended by a snapshot.
#we should have one more snapshot than monthly mean record
print('number of monthly mean records: ', len(ecco_monthly_mean.time))
print('number of monthly snapshot records: ', len(ecco_monthly_snaps.time))

# ## Create the xgcm 'grid' object
#
# the xgcm grid object makes it easy to make flux divergence calculations across different tiles of the lat-lon-cap grid.

# In[12]:

ecco_xgcm_grid = ecco.get_llc_grid(ecco_grid)
ecco_xgcm_grid

# ## Calculate LHS: $\eta$ time tendency: $G_{\text{total tendency}}$
#
# We calculate the monthly-averaged time tendency of ``ETAN`` by differencing monthly ``ETAN`` snapshots.
# Subtract the numpy arrays $\eta(t+1)$ - $\eta(t)$.  This operation gives us $\Delta$ ``ETAN`` $/ \Delta$ t (month) records.

# In[13]:

num_months = len(ecco_monthly_snaps.time)
G_total_tendency_month = ecco_monthly_snaps.ETAN.isel(
    time=range(1, num_months)).values - ecco_monthly_snaps.ETAN.isel(
        time=range(0, num_months - 1)).values

# The result is a numpy array of 264 months
# Recall that for tiles 7-12, the y-dimension actually runs East-West.
# Therefore, we want to compute a finite difference in the x-dimension on these tiles to get the latitude band at 26$^\circ$N.
# For tiles 1-5, we clearly want to difference in the y-dimension.
# Things get more complicated on tile 6.

# Here we make the [xgcm Grid object](https://xgcm.readthedocs.io/en/latest/api.html#grid) which allows us to compute finite differences in simple one liners.
# This object understands how each of the tiles on the LLC grid connect, because we provide that information.
# To see under the hood, checkout the utility function [get_llc_grid](https://github.com/ECCO-GROUP/ECCOv4-py/blob/master/ecco_v4_py/ecco_utils.py) where these connections are defined.

# In[10]:

ecco_ds

# In[11]:

grid = ecco.get_llc_grid(ecco_ds)

# In[12]:

lat_maskW = grid.diff(dome_maskC, 'X', boundary='fill')
lat_maskS = grid.diff(dome_maskC, 'Y', boundary='fill')

# In[13]:

plt.figure(figsize=(12, 6))
ecco.plot_tiles(lat_maskW + maskW.isel(k=0), cmap='viridis')
plt.show()

# In[14]:

plt.figure(figsize=(12, 6))
Esempio n. 15
0
def test_get_grid(get_test_ds):
    """make sure we can make a grid ... that's it"""

    grid = ecco_v4_py.get_llc_grid(get_test_ds)
        'THETA': 'THETA_snp'
    })
])

# ### Create the xgcm 'grid' object
#
# The `xgcm` 'grid' object is used to calculate the flux divergences across different tiles of the lat-lon-cap grid and the time derivatives from ``THETA`` snapshots

# In[17]:

# Change time axis of the snapshot variables
ds.time_snp.attrs['c_grid_axis_shift'] = 0.5

# In[18]:

grid = ecco.get_llc_grid(ds)

# ### Number of seconds in each month
# The xgcm `grid` object includes information on the time axis, such that we can use it to get $\Delta t$, which is the time span between the beginning and end of each month (in seconds).

# In[19]:

delta_t = grid.diff(ds.time_snp, 'T', boundary='fill', fill_value=np.nan)

# Convert to seconds
delta_t = delta_t.astype('f4') / 1e9

# ## Calculate total tendency of $\theta$ ($G^{\theta}_\textrm{total}$)
#
# We calculate the monthly-averaged time tendency of ``THETA`` by differencing monthly ``THETA`` snapshots. Remember  that we need to include a scaling factor due to the nonlinear free surface formulation. Thus, we need to use snapshots of both `ETAN` and `THETA`  to evaluate $s^*\theta$.
                                               dask_chunk=True)
date_last_record = \
    ecco.extract_yyyy_mm_dd_hh_mm_ss_from_datetime64(ds_ecco_monthly_snaps.time[-1].values)

# load monthly mean data
ds_ecco_monthly_mean = \
    ecco.recursive_load_ecco_var_from_years_nc(dir_monthly,\
                                               vars_to_load=['ETAN',\
                                                             'oceFWflx',\
                                                             'UVELMASS',\
                                                             'VVELMASS',\
                                                             'WVELMASS'],\
                                               years_to_load='all',\
                                               dask_chunk=True)

grid_ecco_xgcm = ecco.get_llc_grid(ds_grid)

# calculte total tendency
num_months = len(ds_ecco_monthly_mean.time)
G_total_tendency_month = ds_ecco_monthly_mean.ETAN.isel(time=range(1,num_months)).values - ds_ecco_monthly_mean.ETAN.isel(time=range(0,num_months-1)).values
tmp = ds_ecco_monthly_mean.ETAN.isel(time=range(0,num_months-1)).copy(deep=True)
tmp.name = 'G_total_tendency_month'
tmp.values = G_total_tendency_month
G_total_tendency_month = tmp

t = []
for year in range(year_start,year_end+1):
    for month in range(1,13):
        t = np.append(t,date(year,month,1).toordinal())

seconds_per_month = 3600 * 24 * (t[1:]-t[0:len(t)-1])