Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
57a9c3b
Moving the time interpolation down to within _Interpolator functions
erikvansebille Feb 27, 2025
02aee73
merge conflict fixed
erikvansebille Feb 28, 2025
a49e4c0
Pushing the time interpolation also to Interpolators
erikvansebille Feb 28, 2025
8010945
Removing interptime context by choosing time interpolation based on t…
erikvansebille Mar 3, 2025
722fecd
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 3, 2025
4502c12
implementing time-interpolation in _linear_3d
erikvansebille Mar 3, 2025
1a52622
Fixing 3D cgrid_interpolation
erikvansebille Mar 4, 2025
439f8a3
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 4, 2025
e25a2a2
Fixing mypi error
erikvansebille Mar 4, 2025
5c085b0
cleaning up cgrid interpolation
erikvansebille Mar 5, 2025
1398340
Fixing slip interpolation
erikvansebille Mar 5, 2025
dfebcf1
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 5, 2025
d2781e5
Fixing typing error
erikvansebille Mar 5, 2025
3a4a9a5
Fixing _spatial_slip_interpolation signature
erikvansebille Mar 5, 2025
37ee5e4
Ignoring sgrid tests for now
erikvansebille Mar 5, 2025
6bd0499
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 7, 2025
7ce1663
xfailing croco 3D advection for now
erikvansebille Mar 7, 2025
ff44d72
Doing time interpolation inside c-grid interpolation function
erikvansebille Mar 7, 2025
2b24b47
Also time-interpolating the _linear_invdist_land_tracer functions
erikvansebille Mar 7, 2025
aa6d2f0
Adding calculate_next_ti helper function
erikvansebille Mar 7, 2025
17d4be2
Fixing small bugs in interpolation
erikvansebille Mar 7, 2025
51f60ec
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 10, 2025
4cc9f2e
Rename field interpolation methods
erikvansebille Mar 10, 2025
6ca3d58
Addressing reviewer comments
erikvansebille Mar 12, 2025
374177d
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 12, 2025
4b062cc
Fixing typo
erikvansebille Mar 12, 2025
1fab4a2
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 12, 2025
7dede65
Update parcels/field.py
erikvansebille Mar 12, 2025
b807a5d
Attempt to fix mypy issue
erikvansebille Mar 12, 2025
1ae7eef
Merge branch 'swap_space_and_time_interpolation_order' of https://git…
erikvansebille Mar 12, 2025
8306c42
Updating review suggestions on should_calculate_next_ti
erikvansebille Mar 12, 2025
99b50d1
Fixing numpy.equal call
erikvansebille Mar 12, 2025
92b3ef7
Removing type-checking
erikvansebille Mar 12, 2025
2892ad2
Using np.greater instead of not np.equal
erikvansebille Mar 12, 2025
48db381
Merge branch 'v4-dev' into swap_space_and_time_interpolation_order
erikvansebille Mar 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 82 additions & 17 deletions parcels/_interpolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import numpy as np

from parcels._typing import GridIndexingType
from parcels.tools._helpers import should_calculate_next_ti


@dataclass
Expand All @@ -14,6 +15,8 @@
----------
data: np.ndarray
field data of shape (time, y, x)
tau: float
time interpolation coordinate in unit length
eta: float
y-direction interpolation coordinate in unit cube (between 0 and 1)
xsi: float
Expand All @@ -28,6 +31,7 @@
"""

data: np.ndarray
tau: float
eta: float
xsi: float
ti: int
Expand All @@ -45,6 +49,8 @@
field data of shape (time, z, y, x). This needs to be complete in the vertical
direction as some interpolation methods need to know whether they are at the
surface or bottom.
tau: float
time interpolation coordinate in unit length
zeta: float
vertical interpolation coordinate in unit cube
eta: float
Expand All @@ -65,6 +71,7 @@
"""

data: np.ndarray
tau: float
zeta: float
eta: float
xsi: float
Expand Down Expand Up @@ -110,7 +117,11 @@
def _nearest_2d(ctx: InterpolationContext2D) -> float:
xii = ctx.xi if ctx.xsi <= 0.5 else ctx.xi + 1
yii = ctx.yi if ctx.eta <= 0.5 else ctx.yi + 1
return ctx.data[ctx.ti, yii, xii]
ft0 = ctx.data[ctx.ti, yii, xii]
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return ft0
ft1 = ctx.data[ctx.ti + 1, yii, xii]
return (1 - ctx.tau) * ft0 + ctx.tau * ft1

Check warning on line 124 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L123-L124

Added lines #L123 - L124 were not covered by tests


def _interp_on_unit_square(*, eta: float, xsi: float, data: np.ndarray, yi: int, xi: int) -> float:
Expand All @@ -128,7 +139,11 @@
@register_2d_interpolator("partialslip")
@register_2d_interpolator("freeslip")
def _linear_2d(ctx: InterpolationContext2D) -> float:
return _interp_on_unit_square(eta=ctx.eta, xsi=ctx.xsi, data=ctx.data[ctx.ti, :, :], yi=ctx.yi, xi=ctx.xi)
ft0 = _interp_on_unit_square(eta=ctx.eta, xsi=ctx.xsi, data=ctx.data[ctx.ti, :, :], yi=ctx.yi, xi=ctx.xi)
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return ft0
ft1 = _interp_on_unit_square(eta=ctx.eta, xsi=ctx.xsi, data=ctx.data[ctx.ti + 1, :, :], yi=ctx.yi, xi=ctx.xi)
return (1 - ctx.tau) * ft0 + ctx.tau * ft1


@register_2d_interpolator("linear_invdist_land_tracer")
Expand All @@ -142,6 +157,13 @@
land = np.isclose(data[ti, yi : yi + 2, xi : xi + 2], 0.0)
nb_land = np.sum(land)

def _get_data_temporalinterp(*, ti, yi, xi):
dt0 = data[ti, yi, xi]
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return dt0
dt1 = data[ti + 1, yi, xi]
return (1 - ctx.tau) * dt0 + ctx.tau * dt1

Check warning on line 165 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L164-L165

Added lines #L164 - L165 were not covered by tests

if nb_land == 4:
return 0
elif nb_land > 0:
Expand All @@ -154,9 +176,9 @@
if land[j][i] == 1: # index search led us directly onto land
return 0
else:
return data[ti, yi + j, xi + i]
return _get_data_temporalinterp(ti=ti, yi=yi + j, xi=xi + i)

Check warning on line 179 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L179

Added line #L179 was not covered by tests
elif land[j][i] == 0:
val += data[ti, yi + j, xi + i] / distance
val += _get_data_temporalinterp(ti=ti, yi=yi + j, xi=xi + i) / distance
w_sum += 1 / distance
return val / w_sum
else:
Expand All @@ -166,33 +188,64 @@
@register_2d_interpolator("cgrid_tracer")
@register_2d_interpolator("bgrid_tracer")
def _tracer_2d(ctx: InterpolationContext2D) -> float:
return ctx.data[ctx.ti, ctx.yi + 1, ctx.xi + 1]
ft0 = ctx.data[ctx.ti, ctx.yi + 1, ctx.xi + 1]
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return ft0
ft1 = ctx.data[ctx.ti + 1, ctx.yi + 1, ctx.xi + 1]
return (1 - ctx.tau) * ft0 + ctx.tau * ft1

Check warning on line 195 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L194-L195

Added lines #L194 - L195 were not covered by tests


@register_3d_interpolator("nearest")
def _nearest_3d(ctx: InterpolationContext3D) -> float:
xii = ctx.xi if ctx.xsi <= 0.5 else ctx.xi + 1
yii = ctx.yi if ctx.eta <= 0.5 else ctx.yi + 1
zii = ctx.zi if ctx.zeta <= 0.5 else ctx.zi + 1
return ctx.data[ctx.ti, zii, yii, xii]
ft0 = ctx.data[ctx.ti, zii, yii, xii]
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return ft0
ft1 = ctx.data[ctx.ti + 1, zii, yii, xii]
return (1 - ctx.tau) * ft0 + ctx.tau * ft1


def _get_cgrid_depth_point(*, zeta: float, data: np.ndarray, zi: int, yi: int, xi: int) -> float:
f0 = data[zi, yi, xi]
f1 = data[zi + 1, yi, xi]
return (1 - zeta) * f0 + zeta * f1


@register_3d_interpolator("cgrid_velocity")
def _cgrid_velocity_3d(ctx: InterpolationContext3D) -> float:
def _cgrid_W_velocity_3d(ctx: InterpolationContext3D) -> float:
# evaluating W velocity in c_grid
if ctx.gridindexingtype == "nemo":
f0 = ctx.data[ctx.ti, ctx.zi, ctx.yi + 1, ctx.xi + 1]
f1 = ctx.data[ctx.ti, ctx.zi + 1, ctx.yi + 1, ctx.xi + 1]
ft0 = _get_cgrid_depth_point(
zeta=ctx.zeta, data=ctx.data[ctx.ti, :, :, :], zi=ctx.zi, yi=ctx.yi + 1, xi=ctx.xi + 1
)
elif ctx.gridindexingtype in ["mitgcm", "croco"]:
f0 = ctx.data[ctx.ti, ctx.zi, ctx.yi, ctx.xi]
f1 = ctx.data[ctx.ti, ctx.zi + 1, ctx.yi, ctx.xi]
return (1 - ctx.zeta) * f0 + ctx.zeta * f1
ft0 = _get_cgrid_depth_point(zeta=ctx.zeta, data=ctx.data[ctx.ti, :, :, :], zi=ctx.zi, yi=ctx.yi, xi=ctx.xi)
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return ft0

if ctx.gridindexingtype == "nemo":
ft1 = _get_cgrid_depth_point(
zeta=ctx.zeta, data=ctx.data[ctx.ti + 1, :, :, :], zi=ctx.zi, yi=ctx.yi + 1, xi=ctx.xi + 1
)
elif ctx.gridindexingtype in ["mitgcm", "croco"]:
ft1 = _get_cgrid_depth_point(zeta=ctx.zeta, data=ctx.data[ctx.ti + 1, :, :, :], zi=ctx.zi, yi=ctx.yi, xi=ctx.xi)
return (1 - ctx.tau) * ft0 + ctx.tau * ft1


@register_3d_interpolator("linear_invdist_land_tracer")
def _linear_invdist_land_tracer_3d(ctx: InterpolationContext3D) -> float:
land = np.isclose(ctx.data[ctx.ti, ctx.zi : ctx.zi + 2, ctx.yi : ctx.yi + 2, ctx.xi : ctx.xi + 2], 0.0)
nb_land = np.sum(land)

def _get_data_temporalinterp(*, ti, zi, yi, xi):
dt0 = ctx.data[ti, zi, yi, xi]
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return dt0
dt1 = data[ti + 1, zi, yi, xi]
return (1 - ctx.tau) * dt0 + ctx.tau * dt1

Check warning on line 247 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L246-L247

Added lines #L246 - L247 were not covered by tests

if nb_land == 8:
return 0
elif nb_land > 0:
Expand All @@ -206,9 +259,11 @@
if land[k][j][i] == 1: # index search led us directly onto land
return 0
else:
return ctx.data[ctx.ti, ctx.zi + k, ctx.yi + j, ctx.xi + i]
return _get_data_temporalinterp(ti=ctx.ti, zi=ctx.zi + k, yi=ctx.yi + j, xi=ctx.xi + i)

Check warning on line 262 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L262

Added line #L262 was not covered by tests
elif land[k][j][i] == 0:
val += ctx.data[ctx.ti, ctx.zi + k, ctx.yi + j, ctx.xi + i] / distance
val += (
_get_data_temporalinterp(ti=ctx.ti, zi=ctx.zi + k, yi=ctx.yi + j, xi=ctx.xi + i) / distance
)
w_sum += 1 / distance
return val / w_sum
else:
Expand Down Expand Up @@ -253,9 +308,15 @@
def _linear_3d(ctx: InterpolationContext3D) -> float:
zdim = ctx.data.shape[1]
data_3d = ctx.data[ctx.ti, :, :, :]
f0, f1 = _get_3d_f0_f1(eta=ctx.eta, xsi=ctx.xsi, data=data_3d, zi=ctx.zi, yi=ctx.yi, xi=ctx.xi)
fz0, fz1 = _get_3d_f0_f1(eta=ctx.eta, xsi=ctx.xsi, data=data_3d, zi=ctx.zi, yi=ctx.yi, xi=ctx.xi)
if should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
data_3d = ctx.data[ctx.ti + 1, :, :, :]
fz0_t1, fz1_t1 = _get_3d_f0_f1(eta=ctx.eta, xsi=ctx.xsi, data=data_3d, zi=ctx.zi, yi=ctx.yi, xi=ctx.xi)
fz0 = (1 - ctx.tau) * fz0 + ctx.tau * fz0_t1
if fz1_t1 is not None and fz1 is not None:
fz1 = (1 - ctx.tau) * fz1 + ctx.tau * fz1_t1

return _z_layer_interp(zeta=ctx.zeta, f0=f0, f1=f1, zi=ctx.zi, zdim=zdim, gridindexingtype=ctx.gridindexingtype)
return _z_layer_interp(zeta=ctx.zeta, f0=fz0, f1=fz1, zi=ctx.zi, zdim=zdim, gridindexingtype=ctx.gridindexingtype)


@register_3d_interpolator("bgrid_velocity")
Expand All @@ -277,4 +338,8 @@
@register_3d_interpolator("bgrid_tracer")
@register_3d_interpolator("cgrid_tracer")
def _tracer_3d(ctx: InterpolationContext3D) -> float:
return ctx.data[ctx.ti, ctx.zi, ctx.yi + 1, ctx.xi + 1]
ft0 = ctx.data[ctx.ti, ctx.zi, ctx.yi + 1, ctx.xi + 1]
if not should_calculate_next_ti(ctx.ti, ctx.tau, ctx.data.shape[0]):
return ft0
ft1 = ctx.data[ctx.ti + 1, ctx.zi, ctx.yi + 1, ctx.xi + 1]
return (1 - ctx.tau) * ft0 + ctx.tau * ft1

Check warning on line 345 in parcels/_interpolation.py

View check run for this annotation

Codecov / codecov/patch

parcels/_interpolation.py#L341-L345

Added lines #L341 - L345 were not covered by tests
8 changes: 3 additions & 5 deletions parcels/application_kernels/advection.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,14 @@ def AdvectionAnalytical(particle, fieldset, time): # pragma: no cover
direction = 1.0 if particle.dt > 0 else -1.0
withW = True if "W" in [f.name for f in fieldset.get_fields()] else False
withTime = True if len(fieldset.U.grid.time_full) > 1 else False
ti = fieldset.U._time_index(time)
tau, zeta, eta, xsi, ti, zi, yi, xi = fieldset.U._search_indices(
time, particle.depth, particle.lat, particle.lon, particle=particle
)
ds_t = particle.dt
if withTime:
tau = (time - fieldset.U.grid.time[ti]) / (fieldset.U.grid.time[ti + 1] - fieldset.U.grid.time[ti])
time_i = np.linspace(0, fieldset.U.grid.time[ti + 1] - fieldset.U.grid.time[ti], I_s)
ds_t = min(ds_t, time_i[np.where(time - fieldset.U.grid.time[ti] < time_i)[0][0]])

zeta, eta, xsi, zi, yi, xi = fieldset.U._search_indices(
time, particle.depth, particle.lat, particle.lon, ti, particle=particle
)
if withW:
if abs(xsi - 1) < tol:
if fieldset.U.data[0, zi + 1, yi + 1, xi + 1] > 0:
Expand Down
Loading
Loading