Skip to content

Commit 1bbc400

Browse files
Merge branch 'master' into tutorials
2 parents e05b93b + df73eaf commit 1bbc400

15 files changed

Lines changed: 1017 additions & 631 deletions

parcels/examples/example_dask_chunk_OCMs.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,23 @@ def fieldset_from_ofam(chunk_mode):
121121
return FieldSet.from_netcdf(filenames, variables, dimensions, allow_time_extrapolation=True, field_chunksize=chs, chunkdims_name_map=name_map)
122122

123123

124+
def fieldset_from_mitgcm(chunk_mode):
125+
data_path = path.join(path.dirname(__file__), "MITgcm_example_data/")
126+
filenames = {"U": data_path + "mitgcm_UV_surface_zonally_reentrant.nc",
127+
"V": data_path + "mitgcm_UV_surface_zonally_reentrant.nc"}
128+
variables = {"U": "UVEL", "V": "VVEL"}
129+
dimensions = {"U": {"lon": "XG", "lat": "YG", "time": "time"},
130+
"V": {"lon": "XG", "lat": "YG", "time": "time"}}
131+
132+
chs = False
133+
name_map = {'lon': 'XG', 'lat': 'YG', 'time': 'time'}
134+
if chunk_mode == 'auto':
135+
chs = 'auto'
136+
elif chunk_mode == 'specific':
137+
chs = (1, 50, 100)
138+
return FieldSet.from_mitgcm(filenames, variables, dimensions, mesh='flat', field_chunksize=chs, chunkdims_name_map=name_map)
139+
140+
124141
def compute_nemo_particle_advection(field_set, mode, lonp, latp):
125142

126143
def periodicBC(particle, fieldSet, time):
@@ -300,6 +317,27 @@ def test_ofam_3D(mode, chunk_mode):
300317
assert(abs(pset[0].lat - 11) < 1)
301318

302319

320+
@pytest.mark.parametrize('mode', ['jit'])
321+
@pytest.mark.parametrize('chunk_mode', [False, 'auto', 'specific'])
322+
def test_mitgcm(mode, chunk_mode):
323+
if chunk_mode == 'auto':
324+
dask.config.set({'array.chunk-size': '1024KiB'})
325+
else:
326+
dask.config.set({'array.chunk-size': '128MiB'})
327+
field_set = fieldset_from_mitgcm(chunk_mode)
328+
lons, lats = 5e5, 5e5
329+
330+
pset = ParticleSet.from_list(fieldset=field_set, pclass=ptype[mode], lon=lons, lat=lats)
331+
pset.execute(AdvectionRK4, runtime=delta(days=1), dt=delta(minutes=5))
332+
# MITgcm sample file dimensions: time=10, XG=400, YG=200
333+
assert (len(field_set.U.grid.load_chunk) == len(field_set.V.grid.load_chunk))
334+
if chunk_mode in [False, 'auto']:
335+
assert (len(field_set.U.grid.load_chunk) == 1)
336+
elif chunk_mode == 'specific':
337+
assert (len(field_set.U.grid.load_chunk) == (1 * int(math.ceil(400.0/50.0)) * int(math.ceil(200.0/100.0))))
338+
assert np.allclose(pset[0].lon, 5.27e5, atol=1e3)
339+
340+
303341
@pytest.mark.parametrize('mode', ['jit'])
304342
def test_diff_entry_dimensions_chunks(mode):
305343
data_path = path.join(path.dirname(__file__), 'NemoNorthSeaORCA025-N006_data/')

parcels/examples/example_nemo_curvilinear.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def run_nemo_curvilinear(mode, outfile, advtype='RK4'):
2929
'data': data_path + 'V_purely_zonal-ORCA025_grid_V.nc4'}}
3030
variables = {'U': 'U', 'V': 'V'}
3131
dimensions = {'lon': 'glamf', 'lat': 'gphif'}
32-
field_chunksize = {'y': 2, 'x': 2}
32+
field_chunksize = {'y': 256, 'x': 512}
3333
field_set = FieldSet.from_nemo(filenames, variables, dimensions, field_chunksize=field_chunksize)
3434
assert field_set.U.field_chunksize == field_chunksize
3535

parcels/field.py

Lines changed: 92 additions & 596 deletions
Large diffs are not rendered by default.

parcels/fieldfilebuffer.py

Lines changed: 565 additions & 0 deletions
Large diffs are not rendered by default.

parcels/fieldset.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ def check_velocityfields(U, V, W):
234234
if U.grid.xdim == 1 or U.grid.ydim == 1 or V.grid.xdim == 1 or V.grid.ydim == 1:
235235
raise NotImplementedError('C-grid velocities require longitude and latitude dimensions at least length 2')
236236

237-
if U.gridindexingtype not in ['nemo', 'mitgcm']:
238-
raise ValueError("Field.gridindexing has to be one of 'nemo' or 'mitgcm'")
237+
if U.gridindexingtype not in ['nemo', 'mitgcm', 'mom5']:
238+
raise ValueError("Field.gridindexing has to be one of 'nemo', 'mitgcm' or 'mom5")
239239

240240
if U.gridindexingtype == 'mitgcm' and U.grid.gtype in [GridCode.CurvilinearZGrid, GridCode.CurvilinearZGrid]:
241241
raise NotImplementedError('Curvilinear Grids are not implemented for mitgcm-style grid indexing.'
@@ -680,6 +680,72 @@ def from_pop(cls, filenames, variables, dimensions, indices=None, mesh='spherica
680680
raise SyntaxError("'depth_units' has to be 'm' or 'cm'")
681681
return fieldset
682682

683+
@classmethod
684+
def from_mom5(cls, filenames, variables, dimensions, indices=None, mesh='spherical',
685+
allow_time_extrapolation=None, time_periodic=False,
686+
tracer_interp_method='bgrid_tracer', field_chunksize='auto', **kwargs):
687+
"""Initialises FieldSet object from NetCDF files of MOM5 fields.
688+
689+
:param filenames: Dictionary mapping variables to file(s). The
690+
filepath may contain wildcards to indicate multiple files,
691+
or be a list of file.
692+
filenames can be a list [files], a dictionary {var:[files]},
693+
a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
694+
or a dictionary of dictionaries {var:{dim:[files]}}
695+
time values are in filenames[data]
696+
:param variables: Dictionary mapping variables to variable names in the netCDF file(s).
697+
Note that the built-in Advection kernels assume that U and V are in m/s
698+
:param dimensions: Dictionary mapping data dimensions (lon,
699+
lat, depth, time, data) to dimensions in the netCF file(s).
700+
Note that dimensions can also be a dictionary of dictionaries if
701+
dimension names are different for each variable.
702+
U[k,j+1,i],V[k,j+1,i] ____________________U[k,j+1,i+1],V[k,j+1,i+1]
703+
| |
704+
| W[k-1:k+1,j+1,i+1],T[k,j+1,i+1] |
705+
| |
706+
U[k,j,i],V[k,j,i] ________________________U[k,j,i+1],V[k,j,i+1]
707+
In 2D: U and V nodes are on the cell vertices and interpolated bilinearly as a A-grid.
708+
T node is at the cell centre and interpolated constant per cell as a C-grid.
709+
In 3D: U and V nodes are at the midlle of the cell vertical edges,
710+
They are interpolated bilinearly (independently of z) in the cell.
711+
W nodes are at the centre of the horizontal interfaces, but below the U and V.
712+
They are interpolated linearly (as a function of z) in the cell.
713+
Note that W is normally directed upward in MOM5, but Parcels requires W
714+
in the positive z-direction (downward) so W is multiplied by -1.
715+
T node is at the cell centre, and constant per cell.
716+
:param indices: Optional dictionary of indices for each dimension
717+
to read from file(s), to allow for reading of subset of data.
718+
Default is to read the full extent of each dimension.
719+
Note that negative indices are not allowed.
720+
:param fieldtype: Optional dictionary mapping fields to fieldtypes to be used for UnitConverter.
721+
(either 'U', 'V', 'Kh_zonal', 'Kh_meridional' or None)
722+
:param mesh: String indicating the type of mesh coordinates and
723+
units used during velocity interpolation, see also https://nbviewer.jupyter.org/github/OceanParcels/parcels/blob/master/parcels/examples/tutorial_unitconverters.ipynb:
724+
725+
1. spherical (default): Lat and lon in degree, with a
726+
correction for zonal velocity U near the poles.
727+
2. flat: No conversion, lat/lon are assumed to be in m.
728+
:param allow_time_extrapolation: boolean whether to allow for extrapolation
729+
(i.e. beyond the last available time snapshot)
730+
Default is False if dimensions includes time, else True
731+
:param time_periodic: To loop periodically over the time component of the Field. It is set to either False or the length of the period (either float in seconds or datetime.timedelta object). (Default: False)
732+
This flag overrides the allow_time_interpolation and sets it to False
733+
:param tracer_interp_method: Method for interpolation of tracer fields. It is recommended to use 'bgrid_tracer' (default)
734+
Note that in the case of from_mom5() and from_bgrid(), the velocity fields are default to 'bgrid_velocity'
735+
:param field_chunksize: size of the chunks in dask loading
736+
737+
738+
"""
739+
740+
if 'creation_log' not in kwargs.keys():
741+
kwargs['creation_log'] = 'from_mom5'
742+
fieldset = cls.from_b_grid_dataset(filenames, variables, dimensions, mesh=mesh, indices=indices, time_periodic=time_periodic,
743+
allow_time_extrapolation=allow_time_extrapolation, tracer_interp_method=tracer_interp_method,
744+
field_chunksize=field_chunksize, gridindexingtype='mom5', **kwargs)
745+
if hasattr(fieldset, 'W'):
746+
fieldset.W.set_scaling_factor(-1)
747+
return fieldset
748+
683749
@classmethod
684750
def from_b_grid_dataset(cls, filenames, variables, dimensions, indices=None, mesh='spherical',
685751
allow_time_extrapolation=None, time_periodic=False,

parcels/gridset.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def add_grid(self, field):
1717
grid = field.grid
1818
existing_grid = False
1919
for g in self.grids:
20-
if field.field_chunksize != grid.master_chunksize:
20+
if field.field_chunksize != grid.master_chunksize and grid.master_chunksize not in [None, False]:
2121
logger.warning_once("Field chunksize and Grid master chunksize are not equal - erroneous behaviour expected.")
2222
break
2323
if g == grid:

parcels/include/index_search.h

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ typedef enum
2323

2424
typedef enum
2525
{
26-
NEMO = 0, MITGCM = 1
26+
NEMO = 0, MITGCM = 1, MOM5 = 2
2727
} GridIndexingType;
2828

2929
typedef struct
@@ -56,9 +56,14 @@ typedef enum
5656
RECTILINEAR_Z_GRID=0, RECTILINEAR_S_GRID=1, CURVILINEAR_Z_GRID=2, CURVILINEAR_S_GRID=3
5757
} GridCode;
5858

59-
static inline StatusCode search_indices_vertical_z(type_coord z, int zdim, float *zvals, int *zi, double *zeta)
59+
static inline StatusCode search_indices_vertical_z(type_coord z, int zdim, float *zvals, int *zi, double *zeta, int gridindexingtype)
6060
{
6161
if (zvals[zdim-1] > zvals[0]){
62+
if ((z < zvals[0]) && (gridindexingtype == MOM5) && (z > 2 * zvals[0] - zvals[1])){
63+
*zi = -1;
64+
*zeta = z / zvals[0];
65+
return SUCCESS;
66+
}
6267
if (z < zvals[0]) {return ERROR_THROUGH_SURFACE;}
6368
if (z > zvals[zdim-1]) {return ERROR_OUT_OF_BOUNDS;}
6469
while (*zi < zdim-1 && z > zvals[*zi+1]) ++(*zi);
@@ -162,7 +167,8 @@ static inline void reconnect_bnd_indices(int *xi, int *yi, int xdim, int ydim, i
162167

163168
static inline StatusCode search_indices_rectilinear(type_coord x, type_coord y, type_coord z, CStructuredGrid *grid, GridCode gcode,
164169
int *xi, int *yi, int *zi, double *xsi, double *eta, double *zeta,
165-
int ti, double time, double t0, double t1, int interp_method)
170+
int ti, double time, double t0, double t1, int interp_method,
171+
int gridindexingtype)
166172
{
167173
int xdim = grid->xdim;
168174
int ydim = grid->ydim;
@@ -239,7 +245,7 @@ static inline StatusCode search_indices_rectilinear(type_coord x, type_coord y,
239245
if (zdim > 1){
240246
switch(gcode){
241247
case RECTILINEAR_Z_GRID:
242-
status = search_indices_vertical_z(z, zdim, zvals, zi, zeta);
248+
status = search_indices_vertical_z(z, zdim, zvals, zi, zeta, gridindexingtype);
243249
break;
244250
case RECTILINEAR_S_GRID:
245251
status = search_indices_vertical_s(z, xdim, ydim, zdim, zvals,
@@ -264,7 +270,8 @@ static inline StatusCode search_indices_rectilinear(type_coord x, type_coord y,
264270

265271
static inline StatusCode search_indices_curvilinear(type_coord x, type_coord y, type_coord z, CStructuredGrid *grid, GridCode gcode,
266272
int *xi, int *yi, int *zi, double *xsi, double *eta, double *zeta,
267-
int ti, double time, double t0, double t1, int interp_method)
273+
int ti, double time, double t0, double t1, int interp_method,
274+
int gridindexingtype)
268275
{
269276
int xi_old = *xi;
270277
int yi_old = *yi;
@@ -375,7 +382,7 @@ static inline StatusCode search_indices_curvilinear(type_coord x, type_coord y,
375382
if (zdim > 1){
376383
switch(gcode){
377384
case CURVILINEAR_Z_GRID:
378-
status = search_indices_vertical_z(z, zdim, zvals, zi, zeta);
385+
status = search_indices_vertical_z(z, zdim, zvals, zi, zeta, gridindexingtype);
379386
break;
380387
case CURVILINEAR_S_GRID:
381388
status = search_indices_vertical_s(z, xdim, ydim, zdim, zvals,
@@ -402,18 +409,19 @@ static inline StatusCode search_indices_curvilinear(type_coord x, type_coord y,
402409
* */
403410
static inline StatusCode search_indices(type_coord x, type_coord y, type_coord z, CStructuredGrid *grid,
404411
int *xi, int *yi, int *zi, double *xsi, double *eta, double *zeta,
405-
GridCode gcode, int ti, double time, double t0, double t1, int interp_method)
412+
GridCode gcode, int ti, double time, double t0, double t1, int interp_method,
413+
int gridindexingtype)
406414
{
407415
switch(gcode){
408416
case RECTILINEAR_Z_GRID:
409417
case RECTILINEAR_S_GRID:
410418
return search_indices_rectilinear(x, y, z, grid, gcode, xi, yi, zi, xsi, eta, zeta,
411-
ti, time, t0, t1, interp_method);
419+
ti, time, t0, t1, interp_method, gridindexingtype);
412420
break;
413421
case CURVILINEAR_Z_GRID:
414422
case CURVILINEAR_S_GRID:
415423
return search_indices_curvilinear(x, y, z, grid, gcode, xi, yi, zi, xsi, eta, zeta,
416-
ti, time, t0, t1, interp_method);
424+
ti, time, t0, t1, interp_method, gridindexingtype);
417425
break;
418426
default:
419427
printf("Only RECTILINEAR_Z_GRID, RECTILINEAR_S_GRID, CURVILINEAR_Z_GRID and CURVILINEAR_S_GRID grids are currently implemented\n");

0 commit comments

Comments
 (0)