1919from parcels ._core .xgrid import _DEFAULT_XGCM_KWARGS , XGrid
2020from parcels ._logger import logger
2121from parcels ._typing import Mesh
22- from parcels .interpolators import XConstantField
22+ from parcels .interpolators import UXPiecewiseConstantFace , UXPiecewiseLinearNode , XConstantField , XLinear
2323
2424if TYPE_CHECKING :
2525 from parcels ._core .basegrid import BaseGrid
@@ -240,22 +240,22 @@ def from_copernicusmarine(ds: xr.Dataset):
240240
241241 fields = {}
242242 if "U" in ds .data_vars and "V" in ds .data_vars :
243- fields ["U" ] = Field ("U" , ds ["U" ], grid )
244- fields ["V" ] = Field ("V" , ds ["V" ], grid )
243+ fields ["U" ] = Field ("U" , ds ["U" ], grid , XLinear )
244+ fields ["V" ] = Field ("V" , ds ["V" ], grid , XLinear )
245245 fields ["U" ].units = GeographicPolar ()
246246 fields ["V" ].units = Geographic ()
247247
248248 if "W" in ds .data_vars :
249249 ds ["W" ] -= ds [
250250 "W"
251251 ] # Negate W to convert from up positive to down positive (as that's the direction of positive z)
252- fields ["W" ] = Field ("W" , ds ["W" ], grid )
252+ fields ["W" ] = Field ("W" , ds ["W" ], grid , XLinear )
253253 fields ["UVW" ] = VectorField ("UVW" , fields ["U" ], fields ["V" ], fields ["W" ])
254254 else :
255255 fields ["UV" ] = VectorField ("UV" , fields ["U" ], fields ["V" ])
256256
257257 for varname in set (ds .data_vars ) - set (fields .keys ()):
258- fields [varname ] = Field (varname , ds [varname ], grid )
258+ fields [varname ] = Field (varname , ds [varname ], grid , XLinear )
259259
260260 return FieldSet (list (fields .values ()))
261261
@@ -283,19 +283,19 @@ def from_fesom2(ds: ux.UxDataset):
283283
284284 fields = {}
285285 if "U" in ds .data_vars and "V" in ds .data_vars :
286- fields ["U" ] = Field ("U" , ds ["U" ], grid )
287- fields ["V" ] = Field ("V" , ds ["V" ], grid )
286+ fields ["U" ] = Field ("U" , ds ["U" ], grid , _select_uxinterpolator ( ds [ "U" ]) )
287+ fields ["V" ] = Field ("V" , ds ["V" ], grid , _select_uxinterpolator ( ds [ "U" ]) )
288288 fields ["U" ].units = GeographicPolar ()
289289 fields ["V" ].units = Geographic ()
290290
291291 if "W" in ds .data_vars :
292- fields ["W" ] = Field ("W" , ds ["W" ], grid )
292+ fields ["W" ] = Field ("W" , ds ["W" ], grid , _select_uxinterpolator ( ds [ "U" ]) )
293293 fields ["UVW" ] = VectorField ("UVW" , fields ["U" ], fields ["V" ], fields ["W" ])
294294 else :
295295 fields ["UV" ] = VectorField ("UV" , fields ["U" ], fields ["V" ])
296296
297297 for varname in set (ds .data_vars ) - set (fields .keys ()):
298- fields [varname ] = Field (varname , ds [varname ], grid )
298+ fields [varname ] = Field (varname , ds [varname ], grid , _select_uxinterpolator ( ds [ varname ]) )
299299
300300 return FieldSet (list (fields .values ()))
301301
@@ -425,7 +425,6 @@ def _discover_fesom2_U_and_V(ds: ux.UxDataset) -> ux.UxDataset:
425425 "Dataset has only one of the two variables 'U' and 'V'. Please rename the appropriate variable in your dataset to have both 'U' and 'V' for Parcels simulation."
426426 )
427427
428- uv_found = False
429428 for common_U , common_V in common_fesom_UV :
430429 if common_U in ds :
431430 if common_V not in ds :
@@ -436,7 +435,6 @@ def _discover_fesom2_U_and_V(ds: ux.UxDataset) -> ux.UxDataset:
436435 )
437436 else :
438437 ds = _ds_rename_using_standard_names (ds , {common_U : "U" , common_V : "V" })
439- uv_found = True
440438 break
441439
442440 else :
@@ -447,11 +445,7 @@ def _discover_fesom2_U_and_V(ds: ux.UxDataset) -> ux.UxDataset:
447445 "Please rename the appropriate variables in your dataset to have both 'U' and 'V' for Parcels simulation."
448446 )
449447 continue
450- if not uv_found :
451- raise ValueError (
452- f"Dataset has neither 'U' nor 'V' in potential options { common_fesom_UV !r} , "
453- f"Please provide a dataset that has both 'U' and 'V' for Parcels simulation."
454- )
448+
455449 return ds
456450
457451
@@ -463,3 +457,36 @@ def _ds_rename_using_standard_names(ds: xr.Dataset | ux.UxDataset, name_dict: di
463457 f"cf_xarray found variable { name !r} with CF standard name { standard_name !r} in dataset, renamed it to { rename_to !r} for Parcels simulation."
464458 )
465459 return ds
460+
461+
462+ def _select_uxinterpolator (da : ux .UxDataArray ):
463+ """Selects the appropriate uxarray interpolator for a given uxarray UxDataArray"""
464+ supported_uxinterp_mapping = {
465+ # (nz1,n_face): face-center laterally, layer centers vertically — piecewise constant
466+ "nz1,n_face" : UXPiecewiseConstantFace ,
467+ # (nz,n_node): node/corner laterally, layer interfaces vertically — barycentric lateral & linear vertical
468+ "nz,n_node" : UXPiecewiseLinearNode ,
469+ }
470+ # Extract only spatial dimensions, neglecting time
471+ da_spatial_dims = tuple (d for d in da .dims if d not in ("time" ,))
472+ if len (da_spatial_dims ) != 2 :
473+ raise ValueError (
474+ "Fields on unstructured grids must have two spatial dimensions, one vertical (nz or nz1) and one lateral (n_face, n_edge, or n_node)"
475+ )
476+
477+ # Construct key (string) for mapping to interpolator
478+ # Find vertical and lateral tokens
479+ vdim = None
480+ ldim = None
481+ for d in da_spatial_dims :
482+ if d in ("nz" , "nz1" ):
483+ vdim = d
484+ if d in ("n_face" , "n_node" ):
485+ ldim = d
486+ # Map to supported interpolators
487+ if vdim and ldim :
488+ key = f"{ vdim } ,{ ldim } "
489+ if key in supported_uxinterp_mapping .keys ():
490+ return supported_uxinterp_mapping [key ]
491+
492+ return None
0 commit comments