Skip to content

Commit 622cf93

Browse files
Creating convert.copernicusmarine_to_sgrid
1 parent e07b143 commit 622cf93

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

src/parcels/convert.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
"wo": "W",
4343
}
4444

45+
_COPERNICUS_MARINE_AXIS_VARNAMES = {
46+
"X": "lon",
47+
"Y": "lat",
48+
"Z": "depth",
49+
"T": "time",
50+
}
51+
4552

4653
def _maybe_bring_UV_depths_to_depth(ds):
4754
if "U" in ds.variables and "depthu" in ds.U.coords and "depth" in ds.coords:
@@ -257,3 +264,67 @@ def nemo_to_sgrid(*, fields: dict[str, xr.Dataset | xr.DataArray], coords: xr.Da
257264
# Update to use lon and lat for internal naming
258265
ds = sgrid.rename(ds, {"gphif": "lat", "glamf": "lon"}) # TODO: Logging message about rename
259266
return ds
267+
268+
269+
def copernicusmarine_to_sgrid(
270+
*, fields: dict[str, xr.Dataset | xr.DataArray], coords: xr.Dataset | None = None
271+
) -> xr.Dataset:
272+
"""Create an sgrid-compliant xarray.Dataset from a dataset of Copernicus Marine netcdf files.
273+
274+
Parameters
275+
----------
276+
fields : dict[str, xr.Dataset | xr.DataArray]
277+
Dictionary of xarray.DataArray objects as obtained from a set of Copernicus Marine netcdf files.
278+
coords : xarray.Dataset, optional
279+
xarray.Dataset containing coordinate variables. By default these are time, depth, latitude, longitude
280+
281+
Returns
282+
-------
283+
xarray.Dataset
284+
Dataset object following SGRID conventions to be (optionally) modified and passed to a FieldSet constructor.
285+
286+
Notes
287+
-----
288+
See https://help.marine.copernicus.eu/en/collections/9080063-copernicus-marine-toolbox for more information on the copernicusmarine toolbox.
289+
The toolbox to ingest data from most of the products on the Copernicus Marine Service (https://data.marine.copernicus.eu/products) into an xarray.Dataset.
290+
You can use indexing and slicing to select a subset of the data before passing it to this function.
291+
292+
"""
293+
fields = fields.copy()
294+
295+
for name, field_da in fields.items():
296+
if isinstance(field_da, xr.Dataset):
297+
field_da = field_da[name]
298+
# TODO: logging message, warn if multiple fields are in this dataset
299+
else:
300+
field_da = field_da.rename(name)
301+
fields[name] = field_da
302+
303+
ds = xr.merge(list(fields.values()) + ([coords] if coords is not None else []))
304+
ds.attrs.clear() # Clear global attributes from the merging
305+
306+
ds = _maybe_rename_coords(ds, _COPERNICUS_MARINE_AXIS_VARNAMES)
307+
if "W" in ds.data_vars:
308+
# Negate W to convert from up positive to down positive (as that's the direction of positive z)
309+
ds["W"].data *= -1
310+
311+
if "grid" in ds.cf.cf_roles:
312+
raise ValueError(
313+
"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."
314+
)
315+
ds["grid"] = xr.DataArray(
316+
0,
317+
attrs=sgrid.Grid2DMetadata( # use dummy *_center dimensions - this is A grid data (all defined on nodes)
318+
cf_role="grid_topology",
319+
topology_dimension=2,
320+
node_dimensions=("lon", "lat"),
321+
node_coordinates=("lon", "lat"),
322+
face_dimensions=(
323+
sgrid.DimDimPadding("x_center", "lon", sgrid.Padding.LOW),
324+
sgrid.DimDimPadding("y_center", "lat", sgrid.Padding.LOW),
325+
),
326+
vertical_dimensions=(sgrid.DimDimPadding("z_center", "depth", sgrid.Padding.LOW),),
327+
).to_attrs(),
328+
)
329+
330+
return ds

0 commit comments

Comments
 (0)