Skip to content

Commit 2ce1af8

Browse files
committed
Remove add_periodic_halo() methods on Grid, Field, FieldSet
- Remove Grid.meriodonal_halo and Grid.zonal_halo - Update tests (removal and marking) accordingly
1 parent 380089b commit 2ce1af8

File tree

10 files changed

+28
-181
lines changed

10 files changed

+28
-181
lines changed

docs/examples/example_mitgcm.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
from datetime import timedelta
22
from pathlib import Path
33

4+
import pytest
5+
46
import parcels
57

68

@@ -49,6 +51,8 @@ def periodicBC(particle, fieldset, time): # pragma: no cover
4951
)
5052

5153

54+
@pytest.mark.v4alpha
55+
@pytest.mark.xfail(reason="Test uses add_periodic_halo(). Update to not use it.")
5256
def test_mitgcm_output(tmpdir):
5357
def get_path() -> Path:
5458
return tmpdir / "MIT_particles.zarr"

docs/examples/example_moving_eddies.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,10 @@ def test_moving_eddies_file(mesh, tmpdir):
250250
assert pset[1].lon < 2.0 and 48.8 < pset[1].lat < 48.85
251251

252252

253+
@pytest.mark.v4alpha
254+
@pytest.mark.xfail(
255+
reason="Calls fieldset.add_periodic_halo(). In v4, interpolation should work without adding halo."
256+
)
253257
def test_periodic_and_computeTimeChunk_eddies():
254258
data_folder = parcels.download_example_dataset("MovingEddies_data")
255259
filename = str(data_folder / "moving_eddies")

parcels/field.py

Lines changed: 8 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -629,12 +629,12 @@ def from_netcdf(
629629
if len(buffer_data.shape) == 4:
630630
errormessage = (
631631
f"Field {filebuffer.name} expecting a data shape of [tdim={grid.tdim}, zdim={grid.zdim}, "
632-
f"ydim={grid.ydim - 2 * grid.meridional_halo}, xdim={grid.xdim - 2 * grid.zonal_halo}] "
632+
f"ydim={grid.ydim}, xdim={grid.xdim }] "
633633
f"but got shape {buffer_data.shape}. Flag transpose=True could help to reorder the data."
634634
)
635635
assert buffer_data.shape[0] == grid.tdim, errormessage
636-
assert buffer_data.shape[2] == grid.ydim - 2 * grid.meridional_halo, errormessage
637-
assert buffer_data.shape[3] == grid.xdim - 2 * grid.zonal_halo, errormessage
636+
assert buffer_data.shape[2] == grid.ydim, errormessage
637+
assert buffer_data.shape[3] == grid.xdim, errormessage
638638

639639
if len(buffer_data.shape) == 2:
640640
data_list.append(buffer_data.reshape(sum(((len(tslice), 1), buffer_data.shape), ())))
@@ -760,28 +760,22 @@ def _reshape(self, data, transpose=False):
760760
"Flag transpose=True could help to reorder the data."
761761
)
762762
assert data.shape[0] == self.grid.tdim, errormessage
763-
assert data.shape[2] == self.grid.ydim - 2 * self.grid.meridional_halo, errormessage
764-
assert data.shape[3] == self.grid.xdim - 2 * self.grid.zonal_halo, errormessage
763+
assert data.shape[2] == self.grid.ydim, errormessage
764+
assert data.shape[3] == self.grid.xdim, errormessage
765765
if self.gridindexingtype == "pop":
766766
assert data.shape[1] == self.grid.zdim or data.shape[1] == self.grid.zdim - 1, errormessage
767767
else:
768768
assert data.shape[1] == self.grid.zdim, errormessage
769769
else:
770770
assert data.shape == (
771771
self.grid.tdim,
772-
self.grid.ydim - 2 * self.grid.meridional_halo,
773-
self.grid.xdim - 2 * self.grid.zonal_halo,
772+
self.grid.ydim,
773+
self.grid.xdim,
774774
), (
775775
f"Field {self.name} expecting a data shape of [tdim, ydim, xdim]. "
776776
"Flag transpose=True could help to reorder the data."
777777
)
778-
if self.grid.meridional_halo > 0 or self.grid.zonal_halo > 0:
779-
data = self.add_periodic_halo(
780-
zonal=self.grid.zonal_halo > 0,
781-
meridional=self.grid.meridional_halo > 0,
782-
halosize=max(self.grid.meridional_halo, self.grid.zonal_halo),
783-
data=data,
784-
)
778+
785779
return data
786780

787781
def set_scaling_factor(self, factor):
@@ -935,54 +929,6 @@ def eval(self, time, z, y, x, particle=None, applyConversion=True):
935929
else:
936930
return value
937931

938-
def add_periodic_halo(self, zonal, meridional, halosize=5, data=None):
939-
"""Add a 'halo' to all Fields in a FieldSet.
940-
941-
Add a 'halo' to all Fields in a FieldSet, through extending the Field (and lon/lat)
942-
by copying a small portion of the field on one side of the domain to the other.
943-
Before adding a periodic halo to the Field, it has to be added to the Grid on which the Field depends
944-
945-
See `this tutorial <../examples/tutorial_periodic_boundaries.ipynb>`__
946-
for a detailed explanation on how to set up periodic boundaries
947-
948-
Parameters
949-
----------
950-
zonal : bool
951-
Create a halo in zonal direction.
952-
meridional : bool
953-
Create a halo in meridional direction.
954-
halosize : int
955-
Size of the halo (in grid points). Default is 5 grid points
956-
data :
957-
if data is not None, the periodic halo will be achieved on data instead of self.data and data will be returned (Default value = None)
958-
"""
959-
dataNone = not isinstance(data, np.ndarray)
960-
if self.grid.defer_load and dataNone:
961-
return
962-
data = self.data if dataNone else data
963-
if zonal:
964-
if len(data.shape) == 3:
965-
data = np.concatenate((data[:, :, -halosize:], data, data[:, :, 0:halosize]), axis=len(data.shape) - 1)
966-
assert data.shape[2] == self.grid.xdim, "Third dim must be x."
967-
else:
968-
data = np.concatenate(
969-
(data[:, :, :, -halosize:], data, data[:, :, :, 0:halosize]), axis=len(data.shape) - 1
970-
)
971-
assert data.shape[3] == self.grid.xdim, "Fourth dim must be x."
972-
if meridional:
973-
if len(data.shape) == 3:
974-
data = np.concatenate((data[:, -halosize:, :], data, data[:, 0:halosize, :]), axis=len(data.shape) - 2)
975-
assert data.shape[1] == self.grid.ydim, "Second dim must be y."
976-
else:
977-
data = np.concatenate(
978-
(data[:, :, -halosize:, :], data, data[:, :, 0:halosize, :]), axis=len(data.shape) - 2
979-
)
980-
assert data.shape[2] == self.grid.ydim, "Third dim must be y."
981-
if dataNone:
982-
self.data = data
983-
else:
984-
return data
985-
986932
def write(self, filename, varname=None):
987933
"""Write a :class:`Field` to a netcdf file.
988934

parcels/fieldset.py

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,26 +1361,6 @@ def add_constant(self, name, value):
13611361
"""
13621362
setattr(self, name, value)
13631363

1364-
def add_periodic_halo(self, zonal=False, meridional=False, halosize=5):
1365-
"""Add a 'halo' to all :class:`parcels.field.Field` objects in a FieldSet,
1366-
through extending the Field (and lon/lat) by copying a small portion
1367-
of the field on one side of the domain to the other.
1368-
1369-
Parameters
1370-
----------
1371-
zonal : bool
1372-
Create a halo in zonal direction (Default value = False)
1373-
meridional : bool
1374-
Create a halo in meridional direction (Default value = False)
1375-
halosize : int
1376-
size of the halo (in grid points). Default is 5 grid points
1377-
"""
1378-
for grid in self.gridset.grids:
1379-
grid.add_periodic_halo(zonal, meridional, halosize)
1380-
for value in self.__dict__.values():
1381-
if isinstance(value, Field):
1382-
value.add_periodic_halo(zonal, meridional, halosize)
1383-
13841364
def write(self, filename):
13851365
"""Write FieldSet to NetCDF file using NEMO convention.
13861366
@@ -1448,9 +1428,7 @@ def computeTimeChunk(self, time=0.0, dt=1):
14481428
zd = g.zdim - 1
14491429
else:
14501430
zd = g.zdim
1451-
data = np.empty(
1452-
(g.tdim, zd, g.ydim - 2 * g.meridional_halo, g.xdim - 2 * g.zonal_halo), dtype=np.float32
1453-
)
1431+
data = np.empty((g.tdim, zd, g.ydim, g.xdim), dtype=np.float32)
14541432
f._loaded_time_indices = range(2)
14551433
for tind in f._loaded_time_indices:
14561434
for fb in f.filebuffers:
@@ -1469,9 +1447,7 @@ def computeTimeChunk(self, time=0.0, dt=1):
14691447
zd = g.zdim - 1
14701448
else:
14711449
zd = g.zdim
1472-
data = np.empty(
1473-
(g.tdim, zd, g.ydim - 2 * g.meridional_halo, g.xdim - 2 * g.zonal_halo), dtype=np.float32
1474-
)
1450+
data = np.empty((g.tdim, zd, g.ydim, g.xdim), dtype=np.float32)
14751451
if signdt >= 0:
14761452
f._loaded_time_indices = [1]
14771453
if f.filebuffers[0] is not None:

parcels/grid.py

Lines changed: 0 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ def __init__(
6868
assert_valid_mesh(mesh)
6969
self._mesh = mesh
7070
self._zonal_periodic = False
71-
self._zonal_halo = 0
72-
self._meridional_halo = 0
7371
self._lat_flipped = False
7472
self._defer_load = False
7573
self._lonlat_minmax = np.array(
@@ -108,10 +106,6 @@ def negate_depth(self):
108106
def mesh(self):
109107
return self._mesh
110108

111-
@property
112-
def meridional_halo(self):
113-
return self._meridional_halo
114-
115109
@property
116110
def lonlat_minmax(self):
117111
return self._lonlat_minmax
@@ -124,10 +118,6 @@ def time_origin(self):
124118
def zonal_periodic(self):
125119
return self._zonal_periodic
126120

127-
@property
128-
def zonal_halo(self):
129-
return self._zonal_halo
130-
131121
@property
132122
def defer_load(self):
133123
return self._defer_load
@@ -279,50 +269,6 @@ def xdim(self):
279269
def ydim(self):
280270
return self.lat.size
281271

282-
def add_periodic_halo(self, zonal: bool, meridional: bool, halosize: int = 5):
283-
"""Add a 'halo' to the Grid, through extending the Grid (and lon/lat)
284-
similarly to the halo created for the Fields
285-
286-
Parameters
287-
----------
288-
zonal : bool
289-
Create a halo in zonal direction
290-
meridional : bool
291-
Create a halo in meridional direction
292-
halosize : int
293-
size of the halo (in grid points). Default is 5 grid points
294-
"""
295-
if zonal:
296-
lonshift = self.lon[-1] - 2 * self.lon[0] + self.lon[1]
297-
if not np.allclose(self.lon[1] - self.lon[0], self.lon[-1] - self.lon[-2]):
298-
warnings.warn(
299-
"The zonal halo is located at the east and west of current grid, "
300-
"with a dx = lon[1]-lon[0] between the last nodes of the original grid and the first ones of the halo. "
301-
"In your grid, lon[1]-lon[0] != lon[-1]-lon[-2]. Is the halo computed as you expect?",
302-
FieldSetWarning,
303-
stacklevel=2,
304-
)
305-
self._lon = np.concatenate((self.lon[-halosize:] - lonshift, self.lon, self.lon[0:halosize] + lonshift))
306-
self._zonal_periodic = True
307-
self._zonal_halo = halosize
308-
if meridional:
309-
if not np.allclose(self.lat[1] - self.lat[0], self.lat[-1] - self.lat[-2]):
310-
warnings.warn(
311-
"The meridional halo is located at the north and south of current grid, "
312-
"with a dy = lat[1]-lat[0] between the last nodes of the original grid and the first ones of the halo. "
313-
"In your grid, lat[1]-lat[0] != lat[-1]-lat[-2]. Is the halo computed as you expect?",
314-
FieldSetWarning,
315-
stacklevel=2,
316-
)
317-
latshift = self.lat[-1] - 2 * self.lat[0] + self.lat[1]
318-
self._lat = np.concatenate((self.lat[-halosize:] - latshift, self.lat, self.lat[0:halosize] + latshift))
319-
self._meridional_halo = halosize
320-
self._lonlat_minmax = np.array(
321-
[np.nanmin(self.lon), np.nanmax(self.lon), np.nanmin(self.lat), np.nanmax(self.lat)], dtype=np.float32
322-
)
323-
if isinstance(self, RectilinearSGrid):
324-
self._add_Sdepth_periodic_halo(zonal, meridional, halosize)
325-
326272

327273
class RectilinearZGrid(RectilinearGrid):
328274
"""Rectilinear Z Grid.
@@ -469,23 +415,6 @@ def xdim(self):
469415
def ydim(self):
470416
return self.lon.shape[0]
471417

472-
def add_periodic_halo(self, zonal, meridional, halosize=5):
473-
"""Add a 'halo' to the Grid, through extending the Grid (and lon/lat)
474-
similarly to the halo created for the Fields
475-
476-
Parameters
477-
----------
478-
zonal : bool
479-
Create a halo in zonal direction
480-
meridional : bool
481-
Create a halo in meridional direction
482-
halosize : int
483-
size of the halo (in grid points). Default is 5 grid points
484-
"""
485-
raise NotImplementedError(
486-
"CurvilinearGrid does not support add_periodic_halo. See https://github.com/OceanParcels/Parcels/pull/1811"
487-
)
488-
489418

490419
class CurvilinearZGrid(CurvilinearGrid):
491420
"""Curvilinear Z Grid.

tests/test_advection.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ def periodicBC(particle, fieldset, time): # pragma: no cover
275275
particle.lat = math.fmod(particle.lat, 1)
276276

277277

278+
@pytest.mark.v4alpha
279+
@pytest.mark.xfail(reason="Calls fieldset.add_periodic_halo(). In v4, interpolation should work without adding halo.")
278280
def test_advection_periodic_zonal():
279281
xdim, ydim, halosize = 100, 100, 3
280282
fieldset = create_periodic_fieldset(xdim, ydim, uvel=1.0, vvel=0.0)
@@ -286,6 +288,8 @@ def test_advection_periodic_zonal():
286288
assert abs(pset.lon[0] - 0.15) < 0.1
287289

288290

291+
@pytest.mark.v4alpha
292+
@pytest.mark.xfail(reason="Calls fieldset.add_periodic_halo(). In v4, interpolation should work without adding halo.")
289293
def test_advection_periodic_meridional():
290294
xdim, ydim = 100, 100
291295
fieldset = create_periodic_fieldset(xdim, ydim, uvel=0.0, vvel=1.0)
@@ -297,6 +301,8 @@ def test_advection_periodic_meridional():
297301
assert abs(pset.lat[0] - 0.15) < 0.1
298302

299303

304+
@pytest.mark.v4alpha
305+
@pytest.mark.xfail(reason="Calls fieldset.add_periodic_halo(). In v4, interpolation should work without adding halo.")
300306
def test_advection_periodic_zonal_meridional():
301307
xdim, ydim = 100, 100
302308
fieldset = create_periodic_fieldset(xdim, ydim, uvel=1.0, vvel=1.0)

tests/test_fieldset.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -429,17 +429,6 @@ def test_fieldset_write_curvilinear(tmpdir):
429429
assert np.allclose(getattr(fieldset2.dx, var), getattr(fieldset.dx, var))
430430

431431

432-
def test_curv_fieldset_add_periodic_halo():
433-
fname = str(TEST_DATA / "mask_nemo_cross_180lon.nc")
434-
filenames = {"dx": fname, "dy": fname, "mesh_mask": fname}
435-
variables = {"dx": "e1u", "dy": "e1v"}
436-
dimensions = {"dx": {"lon": "glamu", "lat": "gphiu"}, "dy": {"lon": "glamu", "lat": "gphiu"}}
437-
fieldset = FieldSet.from_nemo(filenames, variables, dimensions)
438-
439-
with pytest.raises(NotImplementedError):
440-
fieldset.add_periodic_halo(zonal=3, meridional=2)
441-
442-
443432
def addConst(particle, fieldset, time): # pragma: no cover
444433
particle.lon = particle.lon + fieldset.movewest + fieldset.moveeast
445434

tests/test_fieldset_sampling.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ def test_fieldset_sample_eval(fieldset):
112112
assert np.allclose(u_s, lat, rtol=1e-5)
113113

114114

115+
@pytest.mark.v4remove
116+
@pytest.mark.xfail(reason="Test is directly testing adding the halo. This test should either be adapted or removed.")
115117
def test_fieldset_polar_with_halo(fieldset_geometric_polar):
116118
fieldset_geometric_polar.add_periodic_halo(zonal=5)
117119
pset = ParticleSet(fieldset_geometric_polar, pclass=pclass(), lon=0, lat=0)

tests/test_grids.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ def test_avoid_repeated_grids():
149149
assert fieldset.V.grid is not fieldset.U.grid
150150

151151

152+
@pytest.mark.v4alpha
153+
@pytest.mark.xfail(reason="Calls fieldset.add_periodic_halo(). Should adapt this test case.")
152154
def test_multigrids_pointer():
153155
lon_g0 = np.linspace(0, 1e4, 21, dtype=np.float32)
154156
lat_g0 = np.linspace(0, 1000, 2, dtype=np.float32)

tests/tools/test_warnings.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,6 @@
1717
from tests.utils import TEST_DATA
1818

1919

20-
def test_fieldset_warning_halo():
21-
# halo with inconsistent boundaries
22-
lat = [0, 1, 5, 10]
23-
lon = [0, 1, 5, 10]
24-
u = [[1, 1, 1, 1] for _ in range(4)]
25-
v = [[1, 1, 1, 1] for _ in range(4)]
26-
fieldset = FieldSet.from_data(data={"U": u, "V": v}, dimensions={"lon": lon, "lat": lat}, transpose=True)
27-
with pytest.warns(FieldSetWarning, match="The zonal halo is located at the east and west of current grid.*"):
28-
fieldset.add_periodic_halo(meridional=True, zonal=True)
29-
30-
3120
def test_fieldset_warning_latflipped():
3221
# flipping lats warning
3322
lat = [0, 1, 5, -5]

0 commit comments

Comments
 (0)