Gdt40 save#813
Conversation
There was a problem hiding this comment.
Templating
This PR includes changes that may be worth sharing via templating. For each file listed below, please either:
- Action the suggestion via a pull request editing/adding the relevant file in the SciTools/.github
templates/directory. 1 - Raise an issue against the SciTools/.github repo for the above action if you really don't have 10mins spare right now. Include an assignee, to avoid it being forgotten.
- Dismiss the suggestion if the changes are not suitable for templating.
You will need to dismiss this review before this PR can be merged. Recommend the reviewer does this as their final action before merging, as this text will continually update as commits come in.
Templated files
The following changed files are templated:
-
pyproject.toml, templated bySciTools/.github/templates/pyproject.toml
Footnotes
-
Include this text in the PR body to avoid any notifications about applying the template changes back to the source repo!
@scitools-templating: please no update notification on: iris-grib↩
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #813 +/- ##
==========================================
- Coverage 90.05% 89.70% -0.36%
==========================================
Files 10 10
Lines 2564 2680 +116
Branches 420 440 +20
==========================================
+ Hits 2309 2404 +95
- Misses 156 169 +13
- Partials 99 107 +8 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…d dim needs a dimcoord.
Update 2026-07-21
Not implemented:
Still to-do:
|
There was a problem hiding this comment.
Pull request overview
Adds experimental support for saving GRIB2 reduced Gaussian grids (GDT 3.40) by recording the original grid template on load and using it to select an appropriate ecCodes sample/template during save.
Changes:
- Record GRIB2 grid template number on load via a new
TEMPLATE_RECORDcontrol and attach agaussian_gridDimCoord for reduced Gaussian grids. - Add save-rule logic for GDT 3.40 (including detection + template 40 writer) and update the save pipeline to select a reduced-gg sample.
- Update/extend unit + integration tests and expected CML outputs to include the new
gaussian_gridcoordinate and round-trip behavior.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
src/iris_grib/_save_rules.py |
Adds GDT 3.40 detection and encoding logic; threads chosen x/y coords through save rules. |
src/iris_grib/_grib2_convert.py |
Adds TEMPLATE_RECORD and records GRIB2_GRID_TEMPLATE; adds gaussian_grid DimCoord on reduced-gg load. |
src/iris_grib/__init__.py |
Updates save path to fall back to aux lat/lon for reduced-gg and select an ecCodes reduced-gg sample when enabled. |
src/iris_grib/_grib1_legacy/grib1_load_rules.py |
Adds special-case reference handling for surface pressure and introduces gaussian_grid DimCoord for that case. |
src/iris_grib/tests/unit/grib2_convert/test_grid_definition_template_40.py |
Updates expected metadata for GDT40 reduced load to include the gaussian_grid DimCoord. |
src/iris_grib/tests/integration/round_trip/test_grid_definition_section.py |
Converts tests to pytest style and adds an experimental GDT40 load→save→load test. |
src/iris_grib/tests/results/**/reduced*.cml |
Updates expected serialized cube outputs to include gaussian_grid. |
pyproject.toml |
Adjusts mypy configuration (disallow_untyped_decorators = false). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| eccodes.codes_set(grib, "longitudeOfFirstGridPoint", int(1.0e6 * lon0)) | ||
| eccodes.codes_set(grib, "longitudeOfLastGridPoint", int(1.0e6 * lon1)) | ||
|
|
||
| eccodes.codes_set(grib, "N", n_lat_vals / 2) |
| # N.B. we could here be dealing with data on a "rotated gaussion" grid, | ||
| # (GDT 3.41 or 3.43), but we don't yet support those. |
| grib_message = eccodes.codes_grib_new_from_samples(template_name) | ||
| result = _save_rules.run(slice2D, grib_message, cube, x_coord, y_coord) | ||
| if result is not None: | ||
| grib_message = result |
| When present, the 'GRIB_GRID_TEMPLATE' attribute is used to control how certain | ||
| types of data are saved -- notably, for gaussian grids. |
| def test_gdt40_loadsave(tmp_path, record): | ||
| loadpath = tests.get_data_path(("GRIB", "reduced", "reduced_gg.grib2")) | ||
| cube = load_cube(loadpath) | ||
| print(cube) |
| print("\nORIGINAL:") | ||
| print(cube) | ||
| print(coord_dims_names(cube)) | ||
| print("\n\nRELOADED:") | ||
| print(cube_reloaded) |
| print(coord_dims_names(cube)) | ||
| print("\n\nRELOADED:") | ||
| print(cube_reloaded) | ||
| print(coord_dims_names(cube_reloaded)) |
| print(cube_reloaded) | ||
| print(coord_dims_names(cube_reloaded)) | ||
| assert coord_dims_names(cube_reloaded) == coord_dims_names(cube) | ||
| assert np.all(cube_reloaded.data == cube.data) |
| ReferenceTarget("ref_surface_pressure", ensure_surface_air_pressure_name) | ||
| ) | ||
| dim_coords_and_dims.append( | ||
| (DimCoord(np.arange(grib._x_points.shape[0]), long_name="gaussian_grid"), 0) |
Addresses #785
So far, so highly sketchy + experimental
NOTE: I don't really like 94a3d38 because we only want to support calling without coords for the sake of the existing unit tests.But I tried adapting some of the existing mock-ist tests + it's really quite awkward