Skip to content

Make mesh files CF compliant - #762

Open
xylar wants to merge 10 commits into
MPAS-Dev:masterfrom
xylar:fix-cf-compliance
Open

xylar wants to merge 10 commits into
MPAS-Dev:masterfrom
xylar:fix-cf-compliance

Conversation

@xylar

@xylar xylar commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator

Meshes from MpasMeshConverter.x and MpasCellCuller.x failed the CF checker because they set Conventions = "MPAS", and no mesh creation tool wrote units on the mesh variables. This PR moves the metadata that Polaris currently patches in (E3SM-Project/polaris#784) into the tools that create the variables.

Changes

  • mpas_tools.mesh.attrs (new): a table of long_name, units and standard_name for the MPAS mesh variables, adapted from Polaris's attrs.yaml, with latitude/longitude and cell_area standard names. It also adds cf_conventions() and add_mesh_attrs(). The table is a Python dict because pyyaml isn't a runtime dependency.
  • MpasMeshConverter.x and MpasCellCuller.x (mesh_conversion_tools_netcdf_c):
    • They write Conventions = "CF-1.8 MPAS", keeping the entries (including any CF version) of the input's Conventions.
    • Every variable gets the attributes from the table. This fixes the wrong or unclear long names from Make mesh files CF compliant #760, e.g. cellsOnVertex was "vertices adj. to each vertex", the two triangle qualities shared one name, and the culler's dvEdge was "length of arc between centres".
    • ncutil::def_var() takes optional units and standard_name.
  • make_planar_hex_mesh(), jigsaw_to_netcdf() and triangle_to_netcdf() add the same metadata and Conventions.
  • SCRIP files: grid_imask units are "1" instead of "unitless".
  • New tests in tests/test_cf_attrs.py check the Python tools and both C++ tools against the table. The docs are updated.

The legacy netcdf-cxx tools in mesh_tools/mesh_conversion_tools/ are unchanged.

Two commits only apply pre-commit formatting to modules that predated the hooks (planar_hex, triangle_to_netcdf and the SCRIP modules), so reviewing commit by commit is easiest.

Testing

I built the package locally with rattler-build (Python 3.14 variant). All recipe tests passed (70 passed, 5 skipped). I ran cfchecks (cfchecker 4.1.0) on the reproduction from #757 and on the QU 1920 km test mesh through the converter and the culler:

File Before After
planar hex base_mesh.nc 0 errors, 38 warnings 0 errors, 0 warnings
planar culled_mesh.nc (cull + convert) 1 error 0 errors, 0 warnings
QU 1920 km converted — 0 errors, 0 warnings
QU 1920 km culled — 0 errors, 0 warnings

While doing this I found a separate law-of-cosines typo in the converter's triangle angle quality, reported in #761 and not fixed here.

Fixes #757


Posted by Claude Code on @xylar's behalf. The testing, analysis and wording above are AI-authored; please check them accordingly.

🤖 Generated with Claude Code

xylar and others added 10 commits September 24, 2026 06:53
These modules predate the ruff and flynt hooks.  Reformat them before
changing them so the functional changes are easy to review.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add mpas_tools.mesh.attrs with a table of long_name, units and
standard_name for the MPAS mesh variables, cf_conventions() to add
CF-1.8 (unless another CF version is present) and MPAS to a Conventions
attribute, and add_mesh_attrs() to apply both to a mesh dataset.

The table is adapted from the one in E3SM-Project/polaris#784, with
standard names for latitude, longitude and cell area.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
ncutil::def_var() takes optional units and standard_name attributes,
and cf_conventions() builds a Conventions attribute with a CF entry
from an input one, matching mpas_tools.mesh.attrs.cf_conventions().

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
MpasMeshConverter.x and MpasCellCuller.x wrote Conventions = "MPAS",
which CF checkers report as an error.  They now write "CF-1.8 MPAS",
keeping the entries (including any CF version) of the input's
Conventions.

Also fix the debug message for reading mesh_spec in the culler.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every variable that MpasMeshConverter.x and MpasCellCuller.x write now
has the long_name, units and standard_name from mpas_tools.mesh.attrs.
Several long names were wrong or unclear (e.g. cellsOnVertex was
"vertices adj. to each vertex", both triangle qualities were "quality of
mesh dual cells" and the culler's dvEdge was "length of arc between
centres"), and none of the variables had units.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
make_planar_hex_mesh(), jigsaw_to_netcdf() and triangle_to_netcdf()
wrote no units or long_name on the mesh variables and no Conventions.
They now add the metadata from mpas_tools.mesh.attrs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Reformat before changing them so the functional change is easy to
review.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
"unitless" is not a valid udunits string; CF uses "1" for dimensionless
quantities.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Check cf_conventions() and that planar hex meshes, and meshes from
MpasCellCuller.x and MpasMeshConverter.x, have the attributes in
mpas_tools.mesh.attrs and a CF Conventions entry, including keeping an
existing CF version.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@xylar

xylar commented Sep 24, 2026

Copy link
Copy Markdown
Collaborator Author

@trhille, could I have you give this a look, since it will potentially affect MALI and Compass (as well as Polaris and Omega, which we are trying hard to make CF-compliant)?

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mesh files are not CF compliant

1 participant