Skip to content

Commit 2b2adcf

Browse files
Moving test for length-1 fields from v3 to v4
1 parent ee6344f commit 2b2adcf

4 files changed

Lines changed: 97 additions & 58 deletions

File tree

parcels/application_kernels/interpolation.py

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,22 @@ def XBiLinearPeriodic(
7272
data = field.data.data[:, zi, yi : yi + 2, xi : xi + 2]
7373
data = (1 - tau) * data[ti, :, :] + tau * data[ti + 1, :, :]
7474

75-
return (
76-
(1 - xsi) * (1 - eta) * data[0, 0]
77-
+ xsi * (1 - eta) * data[0, 1]
78-
+ xsi * eta * data[1, 1]
79-
+ (1 - xsi) * eta * data[1, 0]
80-
)
75+
xsi = 0 if not np.isfinite(xsi) else xsi
76+
eta = 0 if not np.isfinite(eta) else eta
77+
78+
if xsi > 0 and eta > 0:
79+
return (
80+
(1 - xsi) * (1 - eta) * data[0, 0]
81+
+ xsi * (1 - eta) * data[0, 1]
82+
+ xsi * eta * data[1, 1]
83+
+ (1 - xsi) * eta * data[1, 0]
84+
)
85+
elif xsi > 0 and eta == 0:
86+
return (1 - xsi) * data[0, 0] + xsi * data[0, 1]
87+
elif xsi == 0 and eta > 0:
88+
return (1 - eta) * data[0, 0] + eta * data[1, 0]
89+
else:
90+
return data[0, 0]
8191

8292

8393
def XTriLinear(
@@ -97,14 +107,27 @@ def XTriLinear(
97107

98108
data = field.data.data[:, zi : zi + 2, yi : yi + 2, xi : xi + 2]
99109
data = (1 - tau) * data[ti, :, :, :] + tau * data[ti + 1, :, :, :]
100-
data = (1 - zeta) * data[zi, :, :] + zeta * data[zi + 1, :, :]
101-
102-
return (
103-
(1 - xsi) * (1 - eta) * data[0, 0]
104-
+ xsi * (1 - eta) * data[0, 1]
105-
+ xsi * eta * data[1, 1]
106-
+ (1 - xsi) * eta * data[1, 0]
107-
)
110+
if zeta > 0:
111+
data = (1 - zeta) * data[0, :, :] + zeta * data[1, :, :]
112+
else:
113+
data = data[0, :, :]
114+
115+
xsi = 0 if not np.isfinite(xsi) else xsi
116+
eta = 0 if not np.isfinite(eta) else eta
117+
118+
if xsi > 0 and eta > 0:
119+
return (
120+
(1 - xsi) * (1 - eta) * data[0, 0]
121+
+ xsi * (1 - eta) * data[0, 1]
122+
+ xsi * eta * data[1, 1]
123+
+ (1 - xsi) * eta * data[1, 0]
124+
)
125+
elif xsi > 0 and eta == 0:
126+
return (1 - xsi) * data[0, 0] + xsi * data[0, 1]
127+
elif xsi == 0 and eta > 0:
128+
return (1 - eta) * data[0, 0] + eta * data[1, 0]
129+
else:
130+
return data[0, 0]
108131

109132

110133
def UXPiecewiseConstantFace(

parcels/xgrid.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,8 @@ def _search_1d_array(
463463
float
464464
Barycentric coordinate.
465465
"""
466+
if len(arr) < 2:
467+
return 0, 0.0
466468
i = np.argmin(arr <= x) - 1
467469
bcoord = (x - arr[i]) / (arr[i + 1] - arr[i])
468470
return i, bcoord

tests/test_advection.py

Lines changed: 0 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -124,50 +124,6 @@ def test_advection_2DCROCO():
124124
assert np.allclose(pset.lon_nextloop, [x + runtime for x in X], atol=1e-3)
125125

126126

127-
@pytest.mark.v4alpha
128-
@pytest.mark.xfail(reason="GH1946")
129-
@pytest.mark.parametrize("u", [-0.3, np.array(0.2)])
130-
@pytest.mark.parametrize("v", [0.2, np.array(1)])
131-
@pytest.mark.parametrize("w", [None, -0.2, np.array(0.7)])
132-
def test_length1dimensions(u, v, w):
133-
(lon, xdim) = (np.linspace(-10, 10, 21), 21) if isinstance(u, np.ndarray) else (0, 1)
134-
(lat, ydim) = (np.linspace(-15, 15, 31), 31) if isinstance(v, np.ndarray) else (-4, 1)
135-
(depth, zdim) = (np.linspace(-5, 5, 11), 11) if (isinstance(w, np.ndarray) and w is not None) else (3, 1)
136-
dimensions = {"lon": lon, "lat": lat, "depth": depth}
137-
138-
dims = []
139-
if zdim > 1:
140-
dims.append(zdim)
141-
if ydim > 1:
142-
dims.append(ydim)
143-
if xdim > 1:
144-
dims.append(xdim)
145-
if len(dims) > 0:
146-
U = u * np.ones(dims, dtype=np.float32)
147-
V = v * np.ones(dims, dtype=np.float32)
148-
if w is not None:
149-
W = w * np.ones(dims, dtype=np.float32)
150-
else:
151-
U, V, W = u, v, w
152-
153-
data = {"U": U, "V": V}
154-
if w is not None:
155-
data["W"] = W
156-
fieldset = FieldSet.from_data(data, dimensions, mesh="flat")
157-
158-
x0, y0, z0 = 2, 8, -4
159-
pset = ParticleSet(fieldset, pclass=Particle, lon=x0, lat=y0, depth=z0)
160-
pfunc = AdvectionRK4 if w is None else AdvectionRK4_3D
161-
kernel = pset.Kernel(pfunc)
162-
pset.execute(kernel, runtime=5, dt=1)
163-
164-
assert len(pset.lon) == len([p.lon for p in pset])
165-
assert ((np.array([p.lon - x0 for p in pset]) - 4 * u) < 1e-6).all()
166-
assert ((np.array([p.lat - y0 for p in pset]) - 4 * v) < 1e-6).all()
167-
if w:
168-
assert ((np.array([p.depth - y0 for p in pset]) - 4 * w) < 1e-6).all()
169-
170-
171127
@pytest.mark.v4alpha
172128
@pytest.mark.xfail(reason="GH1946")
173129
def test_analyticalAgrid():

tests/v4/test_advection.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import numpy as np
22
import pytest
3+
import xarray as xr
34

45
from parcels._datasets.structured.generic import simple_UV_dataset
56
from parcels.application_kernels.advection import AdvectionEE, AdvectionRK4, AdvectionRK4_3D, AdvectionRK45
@@ -129,6 +130,63 @@ def SubmergeParticle(particle, fieldset, time): # pragma: no cover
129130
assert len(pset) == 0
130131

131132

133+
@pytest.mark.parametrize("u", [-0.3, np.array(0.2)])
134+
@pytest.mark.parametrize("v", [0.2, np.array(1)])
135+
@pytest.mark.parametrize("w", [None, -0.2, np.array(0.7)])
136+
def test_length1dimensions(u, v, w):
137+
(lon, xdim) = (np.linspace(-10, 10, 21), 21) if isinstance(u, np.ndarray) else (np.array([0]), 1)
138+
(lat, ydim) = (np.linspace(-15, 15, 31), 31) if isinstance(v, np.ndarray) else (np.array([-4]), 1)
139+
(depth, zdim) = (
140+
(np.linspace(-5, 5, 11), 11) if (isinstance(w, np.ndarray) and w is not None) else (np.array([3]), 1)
141+
)
142+
143+
tdim = 2 # TODO make this also work for length-1 time dimensions
144+
dims = (tdim, zdim, ydim, xdim)
145+
U = u * np.ones(dims, dtype=np.float32)
146+
V = v * np.ones(dims, dtype=np.float32)
147+
if w is not None:
148+
W = w * np.ones(dims, dtype=np.float32)
149+
150+
ds = xr.Dataset(
151+
{
152+
"U": (["time", "depth", "YG", "XG"], U),
153+
"V": (["time", "depth", "YG", "XG"], V),
154+
},
155+
coords={
156+
"time": (["time"], [np.timedelta64(0, "s"), np.timedelta64(10, "s")], {"axis": "T"}),
157+
"depth": (["depth"], depth, {"axis": "Z"}),
158+
"YC": (["YC"], np.arange(ydim) + 0.5, {"axis": "Y"}),
159+
"YG": (["YG"], np.arange(ydim), {"axis": "Y", "c_grid_axis_shift": -0.5}),
160+
"XC": (["XC"], np.arange(xdim) + 0.5, {"axis": "X"}),
161+
"XG": (["XG"], np.arange(xdim), {"axis": "X", "c_grid_axis_shift": -0.5}),
162+
"lat": (["YG"], lat, {"axis": "Y", "c_grid_axis_shift": 0.5}),
163+
"lon": (["XG"], lon, {"axis": "X", "c_grid_axis_shift": -0.5}),
164+
},
165+
)
166+
if w:
167+
ds["W"] = (["time", "depth", "YG", "XG"], W)
168+
169+
grid = XGrid.from_dataset(ds)
170+
U = Field("U", ds["U"], grid, interp_method=XTriLinear)
171+
V = Field("V", ds["V"], grid, interp_method=XTriLinear)
172+
fields = [U, V, VectorField("UV", U, V)]
173+
if w:
174+
W = Field("W", ds["W"], grid, interp_method=XTriLinear)
175+
fields.append(VectorField("UVW", U, V, W))
176+
fieldset = FieldSet(fields)
177+
178+
x0, y0, z0 = 2, 8, -4
179+
pset = ParticleSet(fieldset, lon=x0, lat=y0, depth=z0)
180+
kernel = AdvectionRK4 if w is None else AdvectionRK4_3D
181+
pset.execute(kernel, runtime=np.timedelta64(5, "s"), dt=np.timedelta64(1, "s"))
182+
183+
assert len(pset.lon) == len([p.lon for p in pset])
184+
assert ((np.array([p.lon - x0 for p in pset]) - 4 * u) < 1e-6).all()
185+
assert ((np.array([p.lat - y0 for p in pset]) - 4 * v) < 1e-6).all()
186+
if w:
187+
assert ((np.array([p.depth - z0 for p in pset]) - 4 * w) < 1e-6).all()
188+
189+
132190
@pytest.mark.parametrize(
133191
"method, rtol",
134192
[

0 commit comments

Comments
 (0)