From b75fd524c6c17177cf516f58b028a900a286e4ca Mon Sep 17 00:00:00 2001 From: Erik van Sebille Date: Mon, 13 Jul 2026 13:56:05 +0200 Subject: [PATCH] Add support for copernicusmarine without depth And convert NaNs to zeroes (for interpolators) --- src/parcels/convert.py | 18 ++++++++++++++++++ tests/test_convert.py | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/parcels/convert.py b/src/parcels/convert.py index c8cea9ce3..e9a5d61a1 100644 --- a/src/parcels/convert.py +++ b/src/parcels/convert.py @@ -241,6 +241,21 @@ def _maybe_swap_depth_direction(ds: xr.Dataset) -> xr.Dataset: return ds +def _maybe_expand_depth_dimension(ds: xr.Dataset) -> xr.Dataset: + if "depth" not in ds.dims: + ds = ds.expand_dims(dim={"depth": [0]}, axis=1) + logger.info("No depth dimension found in dataset. Added a singleton depth dimension.") + return ds + + +def _maybe_fill_na_to_zeros(ds: xr.Dataset) -> xr.Dataset: + for var in ds.data_vars: + if ds[var].isnull().any(): + ds[var] = ds[var].fillna(0) + logger.info(f"Filled NaN values in variable '{var}' with zeros.") + return ds + + # TODO is this function still needed, now that we require users to provide field names explicitly? def _discover_U_and_V(ds: xr.Dataset, cf_standard_names_fallbacks) -> xr.Dataset: # Assumes that the dataset has U and V data @@ -541,6 +556,9 @@ def copernicusmarine_to_sgrid( ds.attrs.clear() # Clear global attributes from the merging ds = _maybe_rename_coords(ds, _COPERNICUS_MARINE_AXIS_VARNAMES) + ds = _maybe_expand_depth_dimension(ds) + ds = _maybe_fill_na_to_zeros(ds) + if "W" in ds.data_vars: # Negate W to convert from up positive to down positive (as that's the direction of positive z) ds["W"].data *= -1 diff --git a/tests/test_convert.py b/tests/test_convert.py index 6a05bc960..e8abe61a0 100644 --- a/tests/test_convert.py +++ b/tests/test_convert.py @@ -174,6 +174,23 @@ def test_convert_copernicusmarine_no_logs(ds, caplog): assert caplog.text == "" +def test_convert_copernicusmarine_withnans(caplog): + ds = datasets_circulation_models["ds_copernicusmarine"] + ds["uo"].data[0, 0, 0, 0] = float("nan") + ds_fset = convert.copernicusmarine_to_sgrid(fields={"uo": ds["uo"]}) + fieldset = FieldSet.from_sgrid_conventions(ds_fset) + assert fieldset.uo.data[0, 0, 0, 0] == 0.0 + assert "Filled NaN values in variable 'uo' with zeros." in caplog.text + + +def test_convert_copernicusmarine_nodepth(caplog): + ds = datasets_circulation_models["ds_copernicusmarine"] + ds = ds.isel(depth=0).drop_vars("depth") + ds_fset = convert.copernicusmarine_to_sgrid(fields={"uo": ds["uo"]}) + FieldSet.from_sgrid_conventions(ds_fset) + assert "No depth dimension found in dataset. Added a singleton depth dimension." in caplog.text + + def test_convert_fesom_to_ugrid(): grid_file = open_remote_dataset("Benchmarks_FESOM2-baroclinic-gyre/grid") data_files = open_remote_dataset("Benchmarks_FESOM2-baroclinic-gyre/data")