Skip to content

Commit d6218d8

Browse files
Merge pull request #1052 from OceanParcels/partial_slip_field_interpolation
Partialslip and freeslip interpolation
2 parents 50a8f19 + a6043c3 commit d6218d8

7 files changed

Lines changed: 694 additions & 705 deletions

File tree

parcels/examples/documentation_unstuck_Agrid.ipynb

Lines changed: 186 additions & 692 deletions
Large diffs are not rendered by default.

parcels/field.py

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -884,7 +884,7 @@ def interpolator2D(self, ti, z, y, x, particle=None):
884884
xii = xi if xsi <= .5 else xi+1
885885
yii = yi if eta <= .5 else yi+1
886886
return self.data[ti, yii, xii]
887-
elif self.interp_method in ['linear', 'bgrid_velocity']:
887+
elif self.interp_method in ['linear', 'bgrid_velocity', 'partialslip', 'freeslip']:
888888
val = (1-xsi)*(1-eta) * self.data[ti, yi, xi] + \
889889
xsi*(1-eta) * self.data[ti, yi, xi+1] + \
890890
xsi*eta * self.data[ti, yi+1, xi+1] + \
@@ -972,7 +972,7 @@ def interpolator3D(self, ti, z, y, x, time, particle=None):
972972
xsi * eta * data[yi + 1, xi + 1] + \
973973
(1 - xsi) * eta * data[yi + 1, xi]
974974
return (1 - zeta) * f0 + zeta * f1
975-
elif self.interp_method in ['linear', 'bgrid_velocity', 'bgrid_w_velocity']:
975+
elif self.interp_method in ['linear', 'bgrid_velocity', 'bgrid_w_velocity', 'partialslip', 'freeslip']:
976976
if self.interp_method == 'bgrid_velocity':
977977
if self.gridindexingtype == 'mom5':
978978
zeta = 1.
@@ -1635,8 +1635,91 @@ def spatial_c_grid_interpolation3D(self, ti, z, y, x, time, particle=None):
16351635
w = self.W.units.to_target(w, x, y, z)
16361636
return (u, v, w)
16371637

1638+
def _is_land2D(self, di, yi, xi):
1639+
if self.U.data.ndim == 3:
1640+
if di < np.shape(self.U.data)[0]:
1641+
return np.isclose(self.U.data[di, yi, xi], 0.) and np.isclose(self.V.data[di, yi, xi], 0.)
1642+
else:
1643+
return True
1644+
else:
1645+
if di < self.U.grid.zdim and yi < np.shape(self.U.data)[-2] and xi < np.shape(self.U.data)[-1]:
1646+
return np.isclose(self.U.data[0, di, yi, xi], 0.) and np.isclose(self.V.data[0, di, yi, xi], 0.)
1647+
else:
1648+
return True
1649+
1650+
def spatial_slip_interpolation(self, ti, z, y, x, time, particle=None):
1651+
(xsi, eta, zeta, xi, yi, zi) = self.U.search_indices(x, y, z, ti, time, particle=particle)
1652+
di = ti if self.U.grid.zdim == 1 else zi # general third dimension
1653+
1654+
f_u, f_v, f_w = 1, 1, 1
1655+
if self._is_land2D(di, yi, xi) and self._is_land2D(di, yi, xi+1) and self._is_land2D(di+1, yi, xi) \
1656+
and self._is_land2D(di+1, yi, xi+1) and eta > 0:
1657+
if self.U.interp_method == 'partialslip':
1658+
f_u = f_u * (.5 + .5 * eta) / eta
1659+
if self.vector_type == '3D':
1660+
f_w = f_w * (.5 + .5 * eta) / eta
1661+
elif self.U.interp_method == 'freeslip':
1662+
f_u = f_u / eta
1663+
if self.vector_type == '3D':
1664+
f_w = f_w / eta
1665+
if self._is_land2D(di, yi+1, xi) and self._is_land2D(di, yi+1, xi+1) and self._is_land2D(di+1, yi+1, xi) \
1666+
and self._is_land2D(di+1, yi+1, xi+1) and eta < 1:
1667+
if self.U.interp_method == 'partialslip':
1668+
f_u = f_u * (1 - .5 * eta) / (1 - eta)
1669+
if self.vector_type == '3D':
1670+
f_w = f_w * (1 - .5 * eta) / (1 - eta)
1671+
elif self.U.interp_method == 'freeslip':
1672+
f_u = f_u / (1 - eta)
1673+
if self.vector_type == '3D':
1674+
f_w = f_w / (1 - eta)
1675+
if self._is_land2D(di, yi, xi) and self._is_land2D(di, yi+1, xi) and self._is_land2D(di+1, yi, xi) \
1676+
and self._is_land2D(di+1, yi+1, xi) and xsi > 0:
1677+
if self.U.interp_method == 'partialslip':
1678+
f_v = f_v * (.5 + .5 * xsi) / xsi
1679+
if self.vector_type == '3D':
1680+
f_w = f_w * (.5 + .5 * xsi) / xsi
1681+
elif self.U.interp_method == 'freeslip':
1682+
f_v = f_v / xsi
1683+
if self.vector_type == '3D':
1684+
f_w = f_w / xsi
1685+
if self._is_land2D(di, yi, xi+1) and self._is_land2D(di, yi+1, xi+1) and self._is_land2D(di+1, yi, xi+1) \
1686+
and self._is_land2D(di+1, yi+1, xi+1) and xsi < 1:
1687+
if self.U.interp_method == 'partialslip':
1688+
f_v = f_v * (1 - .5 * xsi) / (1 - xsi)
1689+
if self.vector_type == '3D':
1690+
f_w = f_w * (1 - .5 * xsi) / (1 - xsi)
1691+
elif self.U.interp_method == 'freeslip':
1692+
f_v = f_v / (1 - xsi)
1693+
if self.vector_type == '3D':
1694+
f_w = f_w / (1 - xsi)
1695+
if self.U.grid.zdim > 1:
1696+
if self._is_land2D(di, yi, xi) and self._is_land2D(di, yi, xi+1) and self._is_land2D(di, yi+1, xi) \
1697+
and self._is_land2D(di, yi+1, xi+1) and zeta > 0:
1698+
if self.U.interp_method == 'partialslip':
1699+
f_u = f_u * (.5 + .5 * zeta) / zeta
1700+
f_v = f_v * (.5 + .5 * zeta) / zeta
1701+
elif self.U.interp_method == 'freeslip':
1702+
f_u = f_u / zeta
1703+
f_v = f_v / zeta
1704+
if self._is_land2D(di+1, yi, xi) and self._is_land2D(di+1, yi, xi+1) and self._is_land2D(di+1, yi+1, xi) \
1705+
and self._is_land2D(di+1, yi+1, xi+1) and zeta < 1:
1706+
if self.U.interp_method == 'partialslip':
1707+
f_u = f_u * (1 - .5 * zeta) / (1 - zeta)
1708+
f_v = f_v * (1 - .5 * zeta) / (1 - zeta)
1709+
elif self.U.interp_method == 'freeslip':
1710+
f_u = f_u / (1 - zeta)
1711+
f_v = f_v / (1 - zeta)
1712+
1713+
u = f_u * self.U.eval(time, z, y, x, particle)
1714+
v = f_v * self.V.eval(time, z, y, x, particle)
1715+
if self.vector_type == '3D':
1716+
w = f_w * self.W.eval(time, z, y, x, particle)
1717+
return u, v, w
1718+
else:
1719+
return u, v
1720+
16381721
def eval(self, time, z, y, x, particle=None):
1639-
if self.U.interp_method != 'cgrid_velocity':
1722+
if self.U.interp_method not in ['cgrid_velocity', 'partialslip', 'freeslip']:
16401723
u = self.U.eval(time, z, y, x, particle=particle, applyConversion=False)
16411724
v = self.V.eval(time, z, y, x, particle=particle, applyConversion=False)
16421725
u = self.U.units.to_target(u, x, y, z)
@@ -1648,19 +1731,22 @@ def eval(self, time, z, y, x, particle=None):
16481731
else:
16491732
return (u, v)
16501733
else:
1734+
interp = {'cgrid_velocity': {'2D': self.spatial_c_grid_interpolation2D, '3D': self.spatial_c_grid_interpolation3D},
1735+
'partialslip': {'2D': self.spatial_slip_interpolation, '3D': self.spatial_slip_interpolation},
1736+
'freeslip': {'2D': self.spatial_slip_interpolation, '3D': self.spatial_slip_interpolation}}
16511737
grid = self.U.grid
16521738
(ti, periods) = self.U.time_index(time)
16531739
time -= periods*(grid.time_full[-1]-grid.time_full[0])
16541740
if ti < grid.tdim-1 and time > grid.time[ti]:
16551741
t0 = grid.time[ti]
16561742
t1 = grid.time[ti + 1]
16571743
if self.vector_type == '3D':
1658-
(u0, v0, w0) = self.spatial_c_grid_interpolation3D(ti, z, y, x, time, particle=particle)
1659-
(u1, v1, w1) = self.spatial_c_grid_interpolation3D(ti + 1, z, y, x, time, particle=particle)
1744+
(u0, v0, w0) = interp[self.U.interp_method]['3D'](ti, z, y, x, time, particle=particle)
1745+
(u1, v1, w1) = interp[self.U.interp_method]['3D'](ti + 1, z, y, x, time, particle=particle)
16601746
w = w0 + (w1 - w0) * ((time - t0) / (t1 - t0))
16611747
else:
1662-
(u0, v0) = self.spatial_c_grid_interpolation2D(ti, z, y, x, time, particle=particle)
1663-
(u1, v1) = self.spatial_c_grid_interpolation2D(ti + 1, z, y, x, time, particle=particle)
1748+
(u0, v0) = interp[self.U.interp_method]['2D'](ti, z, y, x, time, particle=particle)
1749+
(u1, v1) = interp[self.U.interp_method]['2D'](ti + 1, z, y, x, time, particle=particle)
16641750
u = u0 + (u1 - u0) * ((time - t0) / (t1 - t0))
16651751
v = v0 + (v1 - v0) * ((time - t0) / (t1 - t0))
16661752
if self.vector_type == '3D':
@@ -1672,9 +1758,9 @@ def eval(self, time, z, y, x, particle=None):
16721758
# of the defined time range or if we have hit an
16731759
# exact value in the time array.
16741760
if self.vector_type == '3D':
1675-
return self.spatial_c_grid_interpolation3D(ti, z, y, x, grid.time[ti], particle=particle)
1761+
return interp[self.U.interp_method]['3D'](ti, z, y, x, grid.time[ti], particle=particle)
16761762
else:
1677-
return self.spatial_c_grid_interpolation2D(ti, z, y, x, grid.time[ti], particle=particle)
1763+
return interp[self.U.interp_method]['2D'](ti, z, y, x, grid.time[ti], particle=particle)
16781764

16791765
def __getitem__(self, key):
16801766
if _isParticle(key):

parcels/fieldset.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,8 @@ def from_c_grid_dataset(cls, filenames, variables, dimensions, indices=None, mes
587587
if 'U' in dimensions and 'W' in dimensions and dimensions['U'] != dimensions['W']:
588588
raise ValueError("On a C-grid, the dimensions of velocities should be the corners (f-points) of the cells, so the same for U, V and W. "
589589
"See also https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/documentation_indexing.ipynb")
590+
if 'interp_method' in kwargs.keys():
591+
raise TypeError("On a C-grid, the interpolation method for velocities should not be overridden")
590592

591593
interp_method = {}
592594
for v in variables:

parcels/include/index_search.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ typedef float type_coord;
1818

1919
typedef enum
2020
{
21-
LINEAR=0, NEAREST=1, CGRID_VELOCITY=2, CGRID_TRACER=3, BGRID_VELOCITY=4, BGRID_W_VELOCITY=5, BGRID_TRACER=6, LINEAR_INVDIST_LAND_TRACER=7
21+
LINEAR=0, NEAREST=1, CGRID_VELOCITY=2, CGRID_TRACER=3, BGRID_VELOCITY=4, BGRID_W_VELOCITY=5, BGRID_TRACER=6, LINEAR_INVDIST_LAND_TRACER=7, PARTIALSLIP=8, FREESLIP=9
2222
} InterpCode;
2323

2424
typedef enum

0 commit comments

Comments
 (0)