Skip to content

Commit f734195

Browse files
Adding peninsula dataset to generated and advection tests
1 parent a0c02b4 commit f734195

File tree

2 files changed

+101
-11
lines changed

2 files changed

+101
-11
lines changed

parcels/_datasets/structured/generated.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,89 @@ def decaying_moving_eddy_dataset(xdim=2, ydim=2):
147147
)
148148

149149

150+
def peninsula_dataset(xdim=100, ydim=50, mesh="flat", grid_type="A"):
151+
"""Construct a fieldset encapsulating the flow field around an idealised peninsula.
152+
153+
Parameters
154+
----------
155+
xdim :
156+
Horizontal dimension of the generated fieldset
157+
ydim :
158+
Vertical dimension of the generated fieldset
159+
mesh : str
160+
String indicating the type of mesh coordinates and
161+
units used during velocity interpolation:
162+
163+
1. spherical: Lat and lon in degree, with a
164+
correction for zonal velocity U near the poles.
165+
2. flat (default): No conversion, lat/lon are assumed to be in m.
166+
grid_type :
167+
Option whether grid is either Arakawa A (default) or C
168+
169+
The original test description can be found in Fig. 2.2.3 in:
170+
North, E. W., Gallego, A., Petitgas, P. (Eds). 2009. Manual of
171+
recommended practices for modelling physical - biological
172+
interactions during fish early life.
173+
ICES Cooperative Research Report No. 295. 111 pp.
174+
http://archimer.ifremer.fr/doc/00157/26792/24888.pdf
175+
"""
176+
domainsizeX, domainsizeY = (1.0e5, 5.0e4)
177+
La = np.linspace(1e3, domainsizeX, xdim, dtype=np.float32)
178+
Wa = np.linspace(1e3, domainsizeY, ydim, dtype=np.float32)
179+
180+
u0 = 1
181+
x0 = domainsizeX / 2
182+
R = 0.32 * domainsizeX / 2
183+
184+
# Create the fields
185+
P = np.zeros((ydim, xdim), dtype=np.float32)
186+
U = np.zeros_like(P)
187+
V = np.zeros_like(P)
188+
x, y = np.meshgrid(La, Wa, sparse=True, indexing="xy")
189+
P[:, :] = u0 * R**2 * y / ((x - x0) ** 2 + y**2) - u0 * y
190+
191+
# Set land points to zero
192+
landpoints = P >= 0.0
193+
P[landpoints] = 0.0
194+
195+
if grid_type == "A":
196+
U[:, :] = u0 - u0 * R**2 * ((x - x0) ** 2 - y**2) / (((x - x0) ** 2 + y**2) ** 2)
197+
V[:, :] = -2 * u0 * R**2 * ((x - x0) * y) / (((x - x0) ** 2 + y**2) ** 2)
198+
U[landpoints] = 0.0
199+
V[landpoints] = 0.0
200+
Udims = ["YC", "XG"]
201+
Vdims = ["YG", "XC"]
202+
elif grid_type == "C":
203+
U = np.zeros(P.shape)
204+
V = np.zeros(P.shape)
205+
V[:, 1:] = (P[:, 1:] - P[:, :-1]) / (La[1] - La[0])
206+
U[1:, :] = -(P[1:, :] - P[:-1, :]) / (Wa[1] - Wa[0])
207+
Udims = ["YG", "XG"]
208+
Vdims = ["YG", "XG"]
209+
else:
210+
raise RuntimeError(f"Grid_type {grid_type} is not a valid option")
211+
212+
# Convert from m to lat/lon for spherical meshes
213+
lon = La / 1852.0 / 60.0 if mesh == "spherical" else La
214+
lat = Wa / 1852.0 / 60.0 if mesh == "spherical" else Wa
215+
216+
return xr.Dataset(
217+
{
218+
"U": (Udims, U),
219+
"V": (Vdims, V),
220+
"P": (["YG", "XG"], P),
221+
},
222+
coords={
223+
"YC": (["YC"], np.arange(ydim) + 0.5, {"axis": "Y"}),
224+
"YG": (["YG"], np.arange(ydim), {"axis": "Y", "c_grid_axis_shift": -0.5}),
225+
"XC": (["XC"], np.arange(xdim) + 0.5, {"axis": "X"}),
226+
"XG": (["XG"], np.arange(xdim), {"axis": "X", "c_grid_axis_shift": -0.5}),
227+
"lat": (["YG"], lat, {"axis": "Y", "c_grid_axis_shift": 0.5}),
228+
"lon": (["XG"], lon, {"axis": "X", "c_grid_axis_shift": -0.5}),
229+
},
230+
)
231+
232+
150233
def stommel_gyre_dataset(xdim=200, ydim=200, grid_type="A"):
151234
"""Simulate a periodic current along a western boundary, with significantly
152235
larger velocities along the western edge than the rest of the region

tests/v4/test_advection.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from parcels._datasets.structured.generated import (
77
decaying_moving_eddy_dataset,
88
moving_eddy_dataset,
9+
peninsula_dataset,
910
radial_rotation_dataset,
1011
simple_UV_dataset,
1112
stommel_gyre_dataset,
@@ -324,18 +325,28 @@ def truth_moving(x_0, y_0, t):
324325
assert np.allclose(pset.lat_nextloop, exp_lat, rtol=rtol)
325326

326327

327-
# TODO decrease atol for Stommel gyre test once the C-grid is implemented
328+
# TODO decrease atol for these tests once the C-grid is implemented
328329
@pytest.mark.parametrize(
329330
"method, atol",
330331
[
331-
("RK4", 1e-1),
332-
("RK45", 1e-1),
332+
("RK4", 1),
333+
("RK45", 1),
333334
],
334335
)
335336
@pytest.mark.parametrize("grid_type", ["A", "C"])
336-
def test_stommel_gyre(method, grid_type, atol):
337-
"""Test advection in the Stommel gyre."""
338-
ds = stommel_gyre_dataset(grid_type=grid_type)
337+
@pytest.mark.parametrize("flowfield", ["stommel_gyre", "peninsula"])
338+
def test_gyre_flowfields(method, grid_type, atol, flowfield):
339+
npart = 2
340+
if flowfield == "peninsula":
341+
ds = peninsula_dataset(grid_type=grid_type)
342+
start_lat = np.linspace(3e3, 47e3, npart)
343+
start_lon = 3e3 * np.ones_like(start_lat)
344+
runtime = np.timedelta64(1, "D")
345+
else:
346+
ds = stommel_gyre_dataset(grid_type=grid_type)
347+
start_lon = np.linspace(10e3, 100e3, npart)
348+
start_lat = np.ones_like(start_lon) * 5000e3
349+
runtime = np.timedelta64(2, "D")
339350
grid = XGrid.from_dataset(ds)
340351
U = Field("U", ds["U"], grid, interp_method=XBiLinear)
341352
V = Field("V", ds["V"], grid, interp_method=XBiLinear)
@@ -344,10 +355,6 @@ def test_stommel_gyre(method, grid_type, atol):
344355
fieldset = FieldSet([U, V, P, UV])
345356

346357
dt = np.timedelta64(1, "m") # TODO check these settings (and possibly increase)
347-
runtime = np.timedelta64(2, "D")
348-
npart = 2
349-
start_lon = np.linspace(10e3, 100e3, npart)
350-
start_lat = np.ones_like(start_lon) * 5000e3
351358

352359
if method == "RK45":
353360
# Use RK45Particles to set next_dt
@@ -371,4 +378,4 @@ def UpdateP(particle, fieldset, time): # pragma: no cover
371378

372379
pset = ParticleSet(fieldset, pclass=SampleParticle, lon=start_lon, lat=start_lat, time=np.timedelta64(0, "s"))
373380
pset.execute([kernel[method], UpdateP], dt=dt, runtime=runtime)
374-
assert np.allclose(pset.p_start, pset.p, atol=atol)
381+
np.testing.assert_allclose(pset.p_start, pset.p, atol=atol)

0 commit comments

Comments
 (0)