Skip to content

docs[next]: add a shallow water model example notebook - #2749

Draft
havogt wants to merge 2 commits into
mainfrom
havogt/swm-example-notebook
Draft

docs[next]: add a shallow water model example notebook#2749
havogt wants to merge 2 commits into
mainfrom
havogt/swm-example-notebook

Conversation

@havogt

@havogt havogt commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Adds the NCAR SWM shallow water benchmark as a single gt4py.next notebook. First of a small stack; this one is a pure examples/ addition with no src/ changes.

Contents

file size
examples/swm.ipynb 15 KB the example
examples/swm_numpy.py 4.8 KB NumPy reference implementation
examples/swm_reference.npz 4.8 KB u, v, p after 4000 steps, 16x16

The model is doubly periodic on an Arakawa C-grid, leapfrog with a Robert-Asselin filter, integrated by one fused field operator producing all six updated fields.

Periodicity is outside GT4Py here

The halo is refreshed in NumPy after each step. Expressing the wrap inside the field operator needs f(I + M) with M a program argument, which the frontend rejects at FOAST construction — that is deliberately deferred to a later PR in this stack so this one carries no frontend risk.

Validation

Two levels, because the full benchmark is too slow for CI:

  • every run — 100 steps, GT4Py vs the NumPy reference. ~5 s.
  • opt-in (RUN_FULL_BENCHMARK = True) — the full 4000 steps against swm_reference.npz. ~20 s.

I ran the opt-in check before opening this; it passes. Measured differences, against peak |u|,|v| ~ 3.8 and |p| ~ 5e4:

100 steps 4000 steps tolerance
u 2.1e-13 9.6e-13 atol=1e-11
v 2.0e-13 7.2e-13 atol=1e-11
p 5.1e-11 3.1e-10 atol=1e-8

The two implementations sum the same terms in a different order, so they agree to rounding rather than bit-for-bit. Tolerances are absolute because u and v cross zero, and are set with ~30x headroom for portability across the CI matrix.

The NumPy reference is itself checked against the NCAR data: it reproduces ref/16x16/{u,v,p}.step4000.final.bin to 1.1e-12 / 8.2e-13 / 2.6e-10.

Notes

  • swm_reference.npz is derived from NCAR/SWM ref/16x16, which is Apache-2.0; provenance is recorded in the notebook.
  • The scheme is Sadourny (1975), cited in the notebook with its DOI. The constants (dt=90, dx=1e5, alpha=0.001, …) are Swarztrauber's 1984 NCAR benchmark configuration rather than results from the paper — the notebook says so, since the distinction is easy to get wrong.
  • Follows the examples/ conventions: license header as a markdown cell, embedded backend by default with compiled ones commented out, outputs and execution counts stripped.
  • pytest --nbmake examples passes (5 notebooks, 21 s).

Next in the stack

  1. collapse the eight *_staggered operator pairs using staggered dimensions
  2. move periodicity into the field operator (needs the frontend changes)

havogt added 2 commits August 5, 2026 12:52
Port the NCAR/SWM shallow water benchmark to a single gt4py.next notebook,
alongside a NumPy reference and the 16x16 reference state after the full
4000-step run. Periodicity is applied outside GT4Py for now, which keeps the
example free of any src/ changes.
The scheme is verified against Sadourny (1975) Eq. 4 -- cu, cv, h, z are his
U, V, H and eta term for term. The constants are not from the paper, and the
'Swarztrauber 1984' attribution came from a code comment in NCAR/SWM rather
than from any reference, so point at the benchmark repo instead.
@havogt

havogt commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Corrected the provenance note. The earlier text credited the configuration to "Paul Swarztrauber's 1984 NCAR benchmark setup" — that came from a code-header comment in swm_c/c/shallow_swap.c ("Code by Paul N. Swarztrauber, NCAR, October 1984"), which is an authorship attribution, not a citable reference. There is no 1984 paper, and whether the constants originate with him was never established.

Now that I have the paper, two things are settled:

  • The scheme mapping is verified, not inferred. Sadourny p. 682 defines U = P̄ˣu, V = P̄ʸv, H = P + ½(ū²ˣ + v̄²ʸ), η = (δₓv − δᵧu)/P̄ˣʸ — exactly cu, cv, h, z, term for term, on the Fig. 1 C-grid. The notebook now states this with his notation.
  • The configuration is not from the paper. Sadourny damps the leapfrog by averaging odd and even time levels every N steps (ν = 1/N, his §3), not with a per-step Robert-Asselin filter. So alpha = 0.001 in particular is a different mechanism, not his value.

The notebook now attributes the scheme to Sadourny and the configuration to NCAR/SWM, without inventing a person in between.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant