@@ -140,6 +140,18 @@ def check_complete(self):
140140 else :
141141 self .add_vector_field (VectorField ('UVW' , self .U , self .V , self .W ))
142142
143+ @classmethod
144+ def parse_wildcards (cls , paths , filenames , var ):
145+ if not isinstance (paths , list ):
146+ paths = sorted (glob (str (paths )))
147+ if len (paths ) == 0 :
148+ notfound_paths = filenames [var ] if type (filenames ) is dict and var in filenames else filenames
149+ raise IOError ("FieldSet files not found: %s" % str (notfound_paths ))
150+ for fp in paths :
151+ if not path .exists (fp ):
152+ raise IOError ("FieldSet file not found: %s" % str (fp ))
153+ return paths
154+
143155 @classmethod
144156 def from_netcdf (cls , filenames , variables , dimensions , indices = None ,
145157 mesh = 'spherical' , allow_time_extrapolation = None , time_periodic = False , full_load = False , ** kwargs ):
@@ -148,6 +160,10 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None,
148160 :param filenames: Dictionary mapping variables to file(s). The
149161 filepath may contain wildcards to indicate multiple files,
150162 or be a list of file.
163+ filenames can be a list [files], a dictionary {var:[files]},
164+ a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
165+ or a dictionary of dictionaries {var:{dim:[files]}}.
166+ time values are in filenames[data]
151167 :param variables: Dictionary mapping variables to variable
152168 names in the netCDF file(s).
153169 :param dimensions: Dictionary mapping data dimensions (lon,
@@ -178,15 +194,12 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None,
178194 fields = {}
179195 for var , name in variables .items ():
180196 # Resolve all matching paths for the current variable
181- paths = filenames [var ] if type (filenames ) is dict else filenames
182- if not isinstance (paths , list ):
183- paths = sorted (glob (str (paths )))
184- if len (paths ) == 0 :
185- notfound_paths = filenames [var ] if type (filenames ) is dict else filenames
186- raise IOError ("FieldSet files not found: %s" % str (notfound_paths ))
187- for fp in paths :
188- if not path .exists (fp ):
189- raise IOError ("FieldSet file not found: %s" % str (fp ))
197+ paths = filenames [var ] if type (filenames ) is dict and var in filenames else filenames
198+ if type (paths ) is not dict :
199+ paths = cls .parse_wildcards (paths , filenames , var )
200+ else :
201+ for dim , p in paths .items ():
202+ paths [dim ] = cls .parse_wildcards (p , filenames , var )
190203
191204 # Use dimensions[var] and indices[var] if either of them is a dict of dicts
192205 dims = dimensions [var ] if var in dimensions else dimensions
@@ -198,11 +211,19 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None,
198211 for procvar , _ in fields .items ():
199212 procdims = dimensions [procvar ] if procvar in dimensions else dimensions
200213 procinds = indices [procvar ] if (indices and procvar in indices ) else indices
201- if (type (filenames ) is not dict or filenames [procvar ] == filenames [var ]) \
202- and procdims == dims and procinds == inds :
203- grid = fields [procvar ].grid
204- kwargs ['dataFiles' ] = fields [procvar ].dataFiles
205- break
214+ if procdims == dims and procinds == inds :
215+ sameGrid = False
216+ if (type (filenames ) is not dict or filenames [procvar ] == filenames [var ]):
217+ sameGrid = True
218+ elif type (filenames [procvar ]) == dict :
219+ sameGrid = True
220+ for dim in ['lon' , 'lat' , 'depth' ]:
221+ if dim in dimensions :
222+ sameGrid *= filenames [procvar ][dim ] == filenames [var ][dim ]
223+ if sameGrid :
224+ grid = fields [procvar ].grid
225+ kwargs ['dataFiles' ] = fields [procvar ].dataFiles
226+ break
206227 fields [var ] = Field .from_netcdf (paths , var , dims , inds , grid = grid , mesh = mesh ,
207228 allow_time_extrapolation = allow_time_extrapolation ,
208229 time_periodic = time_periodic , full_load = full_load , ** kwargs )
@@ -215,19 +236,29 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
215236 allow_time_extrapolation = None , time_periodic = False ,
216237 tracer_interp_method = 'linear' , ** kwargs ):
217238 """Initialises FieldSet object from NetCDF files of Curvilinear NEMO fields.
218- Note that this assumes there is a variable mesh_mask that is used for the dimensions
219239
220240 :param filenames: Dictionary mapping variables to file(s). The
221241 filepath may contain wildcards to indicate multiple files,
222- or be a list of file. At least a 'mesh_mask' needs to be present
242+ or be a list of file.
243+ filenames can be a list [files], a dictionary {var:[files]},
244+ a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
245+ or a dictionary of dictionaries {var:{dim:[files]}}
246+ time values are in filenames[data]
223247 :param variables: Dictionary mapping variables to variable
224- names in the netCDF file(s). Must include a variable 'mesh_mask' that
225- holds the dimensions
248+ names in the netCDF file(s).
226249 :param dimensions: Dictionary mapping data dimensions (lon,
227250 lat, depth, time, data) to dimensions in the netCF file(s).
228251 Note that dimensions can also be a dictionary of dictionaries if
229- dimension names are different for each variable
230- (e.g. dimensions['U'], dimensions['V'], etc).
252+ dimension names are different for each variable.
253+ Watch out: NEMO is discretised on a C-grid:
254+ U and V velocities are not located on the same nodes (see https://www.nemo-ocean.eu/doc/node19.html ).
255+ __V1__
256+ | |
257+ U0 U1
258+ |__V0__|
259+ To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes,
260+ which are located on the corners of the cells.
261+ (for indexing details: https://www.nemo-ocean.eu/doc/img360.png )
231262 :param indices: Optional dictionary of indices for each dimension
232263 to read from file(s), to allow for reading of subset of data.
233264 Default is to read the full extent of each dimension.
@@ -247,7 +278,8 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
247278
248279 """
249280
250- dimension_filename = filenames .pop ('mesh_mask' ) if type (filenames ) is dict else filenames
281+ if 'U' in dimensions and 'V' in dimensions and dimensions ['U' ] != dimensions ['V' ]:
282+ raise RuntimeError ("On a c-grid discretisation like NEMO, U and V should have the same dimensions" )
251283
252284 interp_method = {}
253285 for v in variables :
@@ -257,8 +289,7 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
257289 interp_method [v ] = tracer_interp_method
258290
259291 return cls .from_netcdf (filenames , variables , dimensions , mesh = mesh , indices = indices , time_periodic = time_periodic ,
260- allow_time_extrapolation = allow_time_extrapolation , interp_method = interp_method ,
261- dimension_filename = dimension_filename , ** kwargs )
292+ allow_time_extrapolation = allow_time_extrapolation , interp_method = interp_method , ** kwargs )
262293
263294 @classmethod
264295 def from_parcels (cls , basename , uvar = 'vozocrtx' , vvar = 'vomecrty' , indices = None , extra_fields = None ,
0 commit comments