Skip to content

MAINT: Some cleanup of convert.py - #2964

Merged
VeckoTheGecko merged 17 commits into
Parcels-code:mainfrom
VeckoTheGecko:push-spyoxpwzwvqp
Oct 23, 2026
Merged

VeckoTheGecko merged 17 commits into
Parcels-code:mainfrom
VeckoTheGecko:push-spyoxpwzwvqp

Conversation

@VeckoTheGecko

Copy link
Copy Markdown
Contributor

Description

Refactoring of the convert.py module.

(will discuss more in-person)

Pre-merge TODO:

  • Remove legacy testing file

Checklist

  • Closes #xxxx
  • Tests added
  • This PR targets the correct branch (main for normal development, v3-support for v3 support)

AI Disclosure

  • This PR contains AI-generated content.
    • I have tested any AI-generated content in my PR.
    • I take responsibility for any AI-generated content in my PR.
    • Describe how you used it (e.g., by pasting your prompt):

nemo_to_sgrid and copernicusmarine_to_sgrid negate W with `.data *= -1`,
which modifies the caller's array in place.
Safety net for refactoring parcels.convert. tests/_legacy_convert.py is a
verbatim copy of convert.py; test_convert_legacy.py runs 42 input cases
through both and requires identical output datasets, errors, log messages
and warnings. Inputs reuse existing tutorial, remote and synthetic datasets
plus variations of them targeting otherwise unexercised branches, raising
branch coverage of convert.py from 69% to 89% (the rest is dead or
unreachable code).

Both files are meant to be deleted once the refactor lands.
- Remove _discover_U_and_V and _ds_rename_using_standard_names, which had
  no callers since field names became an explicit argument
- Remove duplicate entries from _NEMO_DIMENSION_COORD_NAMES (only used for
  membership checks and idempotent loops, so no behaviour change)
- Document the actual fields/coords parameters of nemo_to_sgrid
- Fix grammar in the module docstring

No behaviour change: tests/test_convert_legacy.py passes unchanged.
Pull the code duplicated across the SGRID converters into helpers:

- _normalize_fields: turn each entry of `fields` into a DataArray named
  after its key (previously copy-pasted in all 5 converters)
- _attach_sgrid_grid: add the 'grid' variable with 2D SGRID metadata
  (previously copy-pasted in all 5 converters)
- _flip_w_to_positive_down: negate W (previously in NEMO and Copernicus)

No behaviour change: tests/test_convert_legacy.py passes unchanged. In
particular, _flip_w_to_positive_down still modifies W in place, and
_attach_sgrid_grid does not run _assert_no_grid_metadata (Delft3D never
called it). Both are left for a follow-up that intentionally changes
behaviour.
- Add a _ModelConventions dataclass holding a model's expected coords,
  variable renames and axis attributes, and use it for NEMO, MITgcm, CROCO
  and Delft3D instead of 3-4 loose module constants each. NEMO's list of
  kept dimensions and Copernicus Marine's rename-by-CF-axis mapping stay
  separate constants, as no other model uses them.
- Move the FESOM2/ICON vertical dimension constants up with the others.
- Split _maybe_bring_other_depths_to_depth, which did two unrelated
  things, into _rename_nemo_depth_dims and
  _nemo_maybe_expand_depth_dimension. The latter is not yet merged with
  _maybe_expand_depth_dimension, as they insert the depth dimension at a
  different position and log different messages.

No behaviour change: tests/test_convert_legacy.py passes unchanged.
nemo_to_sgrid and copernicusmarine_to_sgrid negated W with `.data *= -1`,
which changed the user's input array in place. Negate into a new array
instead.
_assert_no_grid_metadata looked for a "grid" key in ds.cf.cf_roles, but
that mapping is keyed by cf_role value, so existing grid metadata
(cf_role "grid_topology") was never detected. Check for
"grid_topology" instead, and run the check from _attach_sgrid_grid so
that every converter does it (delft3d_to_sgrid previously didn't).
nemo_to_sgrid and delft3d_to_sgrid kept the global attributes that
xr.merge copied over from the first field, whereas the other SGRID
converters cleared them. Clear them in all converters, and attach the grid
through parcels._sgrid._attach_sgrid_metadata so that the output also
has Conventions="SGRID", as Parcels' own SGRID datasets do.
NEMO and Copernicus Marine each had their own helper to add a singleton
depth dimension to surface data. They logged different messages, and NEMO
inserted depth before time while Copernicus inserted it after. Use a single
helper for both, which puts depth after time (the order Parcels transposes
fields to anyway). Unlike expand_dims(axis=1), this also works for data
variables with fewer than two dimensions.
Each value in `fields` may be a Dataset, from which the variable named
after the field is selected. This was undocumented, and a Dataset without
such a variable raised a bare KeyError. Document it in the docstrings of
the SGRID converters and raise a ValueError explaining the fix instead.

Also use model-specific variable names in the docstring examples, and
don't mark `coords` as optional for mitgcm_to_sgrid and croco_to_sgrid,
where it is required.
Move the check for existing grid metadata from parcels.convert into
parcels._sgrid._attach_sgrid_metadata, so it applies wherever SGRID
metadata is attached. The convert functions now call
_attach_sgrid_metadata directly (as the rest of the codebase does), which
makes their _attach_sgrid_grid wrapper unnecessary.

@erikvansebille erikvansebille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this already looks quite nice! See below some first comments/suggestions

Comment thread src/parcels/convert.py
Comment thread src/parcels/convert.py
Comment thread src/parcels/convert.py
# Conflicts:
#	src/parcels/convert.py
#	tests/test_convert.py
Re-adds the MOM6 converter and tests from upstream (Parcels-code#2935), which were
left out when resolving the merge conflicts. Uses the shared helpers
(_ModelConventions, _normalize_fields, _attach_sgrid_metadata) and
clears global attributes like the other SGRID converters.
… copy

Parcels-code#2958 changed the CROCO SGRID padding in croco_to_sgrid from HIGH to
NONE. Mirror that in the frozen legacy copy so test_convert_legacy.py
compares against the current behaviour on main.
@VeckoTheGecko

Copy link
Copy Markdown
Contributor Author

I've gone and fixed the merge conflicts here. The behaviour in the old convert and new convert file are equal, so I've cleaned up the temporary files (58b9cc7 ).

Is this good to merge now @erikvansebille ?

@VeckoTheGecko
VeckoTheGecko marked this pull request as ready for review October 22, 2026 12:50

@erikvansebille erikvansebille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me now!

@VeckoTheGecko
VeckoTheGecko enabled auto-merge (squash) October 23, 2026 12:02
@VeckoTheGecko
VeckoTheGecko merged commit a17ac11 into Parcels-code:main Oct 23, 2026
19 of 20 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Parcels development Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants