@@ -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,
@@ -180,15 +196,12 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None,
180196 fields = {}
181197 for var , name in variables .items ():
182198 # Resolve all matching paths for the current variable
183- paths = filenames [var ] if type (filenames ) is dict else filenames
184- if not isinstance (paths , list ):
185- paths = sorted (glob (str (paths )))
186- if len (paths ) == 0 :
187- notfound_paths = filenames [var ] if type (filenames ) is dict else filenames
188- raise IOError ("FieldSet files not found: %s" % str (notfound_paths ))
189- for fp in paths :
190- if not path .exists (fp ):
191- raise IOError ("FieldSet file not found: %s" % str (fp ))
199+ paths = filenames [var ] if type (filenames ) is dict and var in filenames else filenames
200+ if type (paths ) is not dict :
201+ paths = cls .parse_wildcards (paths , filenames , var )
202+ else :
203+ for dim , p in paths .items ():
204+ paths [dim ] = cls .parse_wildcards (p , filenames , var )
192205
193206 # Use dimensions[var] and indices[var] if either of them is a dict of dicts
194207 dims = dimensions [var ] if var in dimensions else dimensions
@@ -200,11 +213,19 @@ def from_netcdf(cls, filenames, variables, dimensions, indices=None,
200213 for procvar , _ in fields .items ():
201214 procdims = dimensions [procvar ] if procvar in dimensions else dimensions
202215 procinds = indices [procvar ] if (indices and procvar in indices ) else indices
203- if (type (filenames ) is not dict or filenames [procvar ] == filenames [var ]) \
204- and procdims == dims and procinds == inds :
205- grid = fields [procvar ].grid
206- kwargs ['dataFiles' ] = fields [procvar ].dataFiles
207- break
216+ if procdims == dims and procinds == inds :
217+ sameGrid = False
218+ if (type (filenames ) is not dict or filenames [procvar ] == filenames [var ]):
219+ sameGrid = True
220+ elif type (filenames [procvar ]) == dict :
221+ sameGrid = True
222+ for dim in ['lon' , 'lat' , 'depth' ]:
223+ if dim in dimensions :
224+ sameGrid *= filenames [procvar ][dim ] == filenames [var ][dim ]
225+ if sameGrid :
226+ grid = fields [procvar ].grid
227+ kwargs ['dataFiles' ] = fields [procvar ].dataFiles
228+ break
208229 fields [var ] = Field .from_netcdf (paths , var , dims , inds , grid = grid , mesh = mesh ,
209230 allow_time_extrapolation = allow_time_extrapolation ,
210231 time_periodic = time_periodic , full_load = full_load , ** kwargs )
@@ -217,19 +238,29 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
217238 allow_time_extrapolation = None , time_periodic = False ,
218239 tracer_interp_method = 'linear' , ** kwargs ):
219240 """Initialises FieldSet object from NetCDF files of Curvilinear NEMO fields.
220- Note that this assumes there is a variable mesh_mask that is used for the dimensions
221241
222242 :param filenames: Dictionary mapping variables to file(s). The
223243 filepath may contain wildcards to indicate multiple files,
224- or be a list of file. At least a 'mesh_mask' needs to be present
244+ or be a list of file.
245+ filenames can be a list [files], a dictionary {var:[files]},
246+ a dictionary {dim:[files]} (if lon, lat, depth and/or data not stored in same files as data),
247+ or a dictionary of dictionaries {var:{dim:[files]}}
248+ time values are in filenames[data]
225249 :param variables: Dictionary mapping variables to variable
226- names in the netCDF file(s). Must include a variable 'mesh_mask' that
227- holds the dimensions
250+ names in the netCDF file(s).
228251 :param dimensions: Dictionary mapping data dimensions (lon,
229252 lat, depth, time, data) to dimensions in the netCF file(s).
230253 Note that dimensions can also be a dictionary of dictionaries if
231- dimension names are different for each variable
232- (e.g. dimensions['U'], dimensions['V'], etc).
254+ dimension names are different for each variable.
255+ Watch out: NEMO is discretised on a C-grid:
256+ U and V velocities are not located on the same nodes (see https://www.nemo-ocean.eu/doc/node19.html ).
257+ __V1__
258+ | |
259+ U0 U1
260+ |__V0__|
261+ To interpolate U, V velocities on the C-grid, Parcels needs to read the f-nodes,
262+ which are located on the corners of the cells.
263+ (for indexing details: https://www.nemo-ocean.eu/doc/img360.png )
233264 :param indices: Optional dictionary of indices for each dimension
234265 to read from file(s), to allow for reading of subset of data.
235266 Default is to read the full extent of each dimension.
@@ -249,7 +280,8 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
249280
250281 """
251282
252- dimension_filename = filenames .pop ('mesh_mask' ) if type (filenames ) is dict else filenames
283+ if 'U' in dimensions and 'V' in dimensions and dimensions ['U' ] != dimensions ['V' ]:
284+ raise RuntimeError ("On a c-grid discretisation like NEMO, U and V should have the same dimensions" )
253285
254286 interp_method = {}
255287 for v in variables :
@@ -259,8 +291,7 @@ def from_nemo(cls, filenames, variables, dimensions, indices=None, mesh='spheric
259291 interp_method [v ] = tracer_interp_method
260292
261293 return cls .from_netcdf (filenames , variables , dimensions , mesh = mesh , indices = indices , time_periodic = time_periodic ,
262- allow_time_extrapolation = allow_time_extrapolation , interp_method = interp_method ,
263- dimension_filename = dimension_filename , ** kwargs )
294+ allow_time_extrapolation = allow_time_extrapolation , interp_method = interp_method , ** kwargs )
264295
265296 @classmethod
266297 def from_parcels (cls , basename , uvar = 'vozocrtx' , vvar = 'vomecrty' , indices = None , extra_fields = None ,
0 commit comments