Skip to content

Commit a9be1f5

Browse files
Adding test for periodic boundaries advection
1 parent 3f6a82e commit a9be1f5

2 files changed

Lines changed: 63 additions & 18 deletions

File tree

tests/test_advection.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -186,19 +186,6 @@ def periodicBC(particle, fieldset, time): # pragma: no cover
186186
particle.lat = math.fmod(particle.lat, 1)
187187

188188

189-
@pytest.mark.v4alpha
190-
@pytest.mark.xfail(reason="Calls fieldset.add_periodic_halo(). In v4, interpolation should work without adding halo.")
191-
def test_advection_periodic_zonal():
192-
xdim, ydim, halosize = 100, 100, 3
193-
fieldset = create_periodic_fieldset(xdim, ydim, uvel=1.0, vvel=0.0)
194-
fieldset.add_periodic_halo(zonal=True, halosize=halosize)
195-
assert len(fieldset.U.lon) == xdim + 2 * halosize
196-
197-
pset = ParticleSet(fieldset, pclass=Particle, lon=[0.5], lat=[0.5])
198-
pset.execute(AdvectionRK4 + pset.Kernel(periodicBC), runtime=timedelta(hours=20), dt=timedelta(seconds=30))
199-
assert abs(pset.lon[0] - 0.15) < 0.1
200-
201-
202189
@pytest.mark.v4alpha
203190
@pytest.mark.xfail(reason="Calls fieldset.add_periodic_halo(). In v4, interpolation should work without adding halo.")
204191
def test_advection_periodic_meridional():

tests/v4/test_advection.py

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,39 @@ def BiLinear( # TODO move to interpolation file
3737
)
3838

3939

40+
def BiLinearPeriodic( # TODO move to interpolation file
41+
field: Field,
42+
ti: int,
43+
position: dict[_XGRID_AXES, tuple[int, float | np.ndarray]],
44+
tau: np.float32 | np.float64,
45+
t: np.float32 | np.float64,
46+
z: np.float32 | np.float64,
47+
y: np.float32 | np.float64,
48+
x: np.float32 | np.float64,
49+
):
50+
"""Bilinear interpolation on a regular grid with periodic boundary conditions in horizontal directions."""
51+
xi, xsi = position["X"]
52+
yi, eta = position["Y"]
53+
zi, zeta = position["Z"]
54+
55+
if xi < 0:
56+
xi = 0
57+
xsi = (x - field.grid.lon[xi]) / (field.grid.lon[xi + 1] - field.grid.lon[xi])
58+
if yi < 0:
59+
yi = 0
60+
eta = (y - field.grid.lat[yi]) / (field.grid.lat[yi + 1] - field.grid.lat[yi])
61+
62+
data = field.data.data[:, zi, yi : yi + 2, xi : xi + 2]
63+
data = (1 - tau) * data[ti, :, :] + tau * data[ti + 1, :, :]
64+
65+
return (
66+
(1 - xsi) * (1 - eta) * data[0, 0]
67+
+ xsi * (1 - eta) * data[0, 1]
68+
+ xsi * eta * data[1, 1]
69+
+ (1 - xsi) * eta * data[1, 0]
70+
)
71+
72+
4073
def TriLinear( # TODO move to interpolation file
4174
field: Field,
4275
ti: int,
@@ -84,15 +117,40 @@ def test_advection_zonal(mesh_type, npart=10):
84117
U = Field("U", ds["U"], grid, mesh_type=mesh_type, interp_method=BiLinear)
85118
V = Field("V", ds["V"], grid, mesh_type=mesh_type, interp_method=BiLinear)
86119
UV = VectorField("UV", U, V)
87-
fieldset2D = FieldSet([U, V, UV])
120+
fieldset = FieldSet([U, V, UV])
88121

89-
pset2D = ParticleSet(fieldset2D, lon=np.zeros(npart) + 20.0, lat=np.linspace(0, 80, npart))
90-
pset2D.execute(AdvectionRK4, runtime=np.timedelta64(2, "h"), dt=np.timedelta64(15, "m"))
122+
pset = ParticleSet(fieldset, lon=np.zeros(npart) + 20.0, lat=np.linspace(0, 80, npart))
123+
pset.execute(AdvectionRK4, runtime=np.timedelta64(2, "h"), dt=np.timedelta64(15, "m"))
91124

92125
if mesh_type == "spherical":
93-
assert (np.diff(pset2D.lon) > 1.0e-4).all()
126+
assert (np.diff(pset.lon) > 1.0e-4).all()
94127
else:
95-
assert (np.diff(pset2D.lon) < 1.0e-4).all()
128+
assert (np.diff(pset.lon) < 1.0e-4).all()
129+
130+
131+
def periodicBC(particle, fieldset, time):
132+
particle.total_dlon += particle_dlon # noqa
133+
particle.lon = np.fmod(particle.lon, fieldset.U.grid.lon[-1])
134+
particle.lat = np.fmod(particle.lat, fieldset.U.grid.lat[-1])
135+
136+
137+
def test_advection_zonal_periodic():
138+
ds = simple_UV_dataset(dims=(2, 2, 2, 2), mesh_type="flat")
139+
ds["U"].data[:] = 0.1
140+
ds["lon"].data = np.array([0, 2])
141+
ds["lat"].data = np.array([0, 2])
142+
143+
grid = XGrid.from_dataset(ds)
144+
U = Field("U", ds["U"], grid, interp_method=BiLinearPeriodic)
145+
V = Field("V", ds["V"], grid, interp_method=BiLinearPeriodic)
146+
UV = VectorField("UV", U, V)
147+
fieldset = FieldSet([U, V, UV])
148+
149+
PeriodicParticle = Particle.add_variable(Variable("total_dlon", initial=0))
150+
pset = ParticleSet(fieldset, pclass=PeriodicParticle, lon=[0.5], lat=[0.5])
151+
pset.execute([AdvectionEE, periodicBC], runtime=np.timedelta64(40, "s"), dt=np.timedelta64(1, "s"))
152+
assert np.isclose(pset.total_dlon[0], 4, atol=1e-5)
153+
assert np.isclose(pset.lon_nextloop[0], 0.5, atol=1e-5)
96154

97155

98156
def test_horizontal_advection_in_3D_flow(npart=10):

0 commit comments

Comments
 (0)