4242 "wo" : "W" ,
4343}
4444
45+ _MITGCM_AXIS_VARNAMES = {
46+ "XC" : "X" ,
47+ "XG" : "X" ,
48+ "lon" : "X" ,
49+ "YC" : "Y" ,
50+ "YG" : "Y" ,
51+ "lat" : "Y" ,
52+ "Zu" : "Z" ,
53+ "Zl" : "Z" ,
54+ "Zp1" : "Z" ,
55+ "time" : "T" ,
56+ }
57+
58+ _MITGCM_VARNAMES_MAPPING = {
59+ "XG" : "lon" ,
60+ "YG" : "lat" ,
61+ "Zl" : "depth" ,
62+ }
63+
4564_COPERNICUS_MARINE_AXIS_VARNAMES = {
4665 "X" : "lon" ,
4766 "Y" : "lat" ,
@@ -114,7 +133,8 @@ def _maybe_remove_depth_from_lonlat(ds):
114133
115134def _set_axis_attrs (ds , dim_axis ):
116135 for dim , axis in dim_axis .items ():
117- ds [dim ].attrs ["axis" ] = axis
136+ if dim in ds :
137+ ds [dim ].attrs ["axis" ] = axis
118138 return ds
119139
120140
@@ -128,6 +148,16 @@ def _ds_rename_using_standard_names(ds: xr.Dataset | ux.UxDataset, name_dict: di
128148 return ds
129149
130150
151+ def _maybe_swap_depth_direction (ds : xr .Dataset ) -> xr .Dataset :
152+ if ds ["depth" ].size > 1 :
153+ if ds ["depth" ][0 ] > ds ["depth" ][- 1 ]:
154+ logger .info (
155+ "Depth dimension appears to be decreasing upward (i.e., from positive to negative values). Swapping depth dimension to be increasing upward for Parcels simulation."
156+ )
157+ ds = ds .reindex (depth = ds ["depth" ][::- 1 ])
158+ return ds
159+
160+
131161# TODO is this function still needed, now that we require users to provide field names explicitly?
132162def _discover_U_and_V (ds : xr .Dataset , cf_standard_names_fallbacks ) -> xr .Dataset :
133163 # Assumes that the dataset has U and V data
@@ -266,6 +296,66 @@ def nemo_to_sgrid(*, fields: dict[str, xr.Dataset | xr.DataArray], coords: xr.Da
266296 return ds
267297
268298
299+ def mitgcm_to_sgrid (* , fields : dict [str , xr .Dataset | xr .DataArray ], coords : xr .Dataset ) -> xr .Dataset :
300+ """Create an sgrid-compliant xarray.Dataset from a dataset of MITgcm netcdf files.
301+
302+ Parameters
303+ ----------
304+ fields : dict[str, xr.Dataset | xr.DataArray]
305+ Dictionary of xarray.DataArray objects as obtained from a set of MITgcm netcdf files.
306+ coords : xarray.Dataset, optional
307+ xarray.Dataset containing coordinate variables.
308+
309+ Returns
310+ -------
311+ xarray.Dataset
312+ Dataset object following SGRID conventions to be (optionally) modified and passed to a FieldSet constructor.
313+
314+ Notes
315+ -----
316+ See the MITgcm tutorial for more information on how to use MITgcm model outputs in Parcels
317+
318+ """
319+ fields = fields .copy ()
320+
321+ for name , field_da in fields .items ():
322+ if isinstance (field_da , xr .Dataset ):
323+ field_da = field_da [name ]
324+ # TODO: logging message, warn if multiple fields are in this dataset
325+ else :
326+ field_da = field_da .rename (name )
327+ fields [name ] = field_da
328+
329+ ds = xr .merge (list (fields .values ()) + [coords ])
330+ ds .attrs .clear () # Clear global attributes from the merging
331+
332+ ds = _maybe_rename_variables (ds , _MITGCM_VARNAMES_MAPPING )
333+ # ds = _set_axis_attrs(ds, _MITGCM_AXIS_VARNAMES)
334+ ds = _maybe_swap_depth_direction (ds )
335+
336+ if "grid" in ds .cf .cf_roles :
337+ raise ValueError (
338+ "Dataset already has a 'grid' variable (according to cf_roles). Didn't expect there to be grid metadata on copernicusmarine datasets - please open an issue with more information about your dataset."
339+ )
340+
341+ ds ["grid" ] = xr .DataArray (
342+ 0 ,
343+ attrs = sgrid .Grid2DMetadata (
344+ cf_role = "grid_topology" ,
345+ topology_dimension = 2 ,
346+ node_dimensions = ("lon" , "lat" ),
347+ node_coordinates = ("lon" , "lat" ),
348+ face_dimensions = (
349+ sgrid .DimDimPadding ("XC" , "lon" , sgrid .Padding .HIGH ),
350+ sgrid .DimDimPadding ("YC" , "lat" , sgrid .Padding .HIGH ),
351+ ),
352+ vertical_dimensions = (sgrid .DimDimPadding ("depth" , "depth" , sgrid .Padding .HIGH ),),
353+ ).to_attrs (),
354+ )
355+
356+ return ds
357+
358+
269359def copernicusmarine_to_sgrid (
270360 * , fields : dict [str , xr .Dataset | xr .DataArray ], coords : xr .Dataset | None = None
271361) -> xr .Dataset :
0 commit comments