Drive section neighbor-finding from xgcm topology metadata#5
Closed
hdrake wants to merge 1 commit into
Closed
Conversation
Replace the hard-coded `topology=` string ("latlon"/"cartesian"/"MOM-tripolar")
with neighbor-finding inferred from the `xgcm.Grid` the caller already supplies,
and extend section-finding and transports to multi-tile grids (face_connections).
Single-tile grids: neighbors follow from each axis' `boundary` metadata
("periodic" -> wrap, else clip), read via the public `axis.boundary` property
(no more private `._boundary`). Behavior is unchanged; existing tests pass as-is.
Multi-tile grids (lat-lon-cap, cubed-sphere): `gridutils.build_neighbor_maps`
pads index-valued arrays with xgcm and reads the halos to get each corner's
neighbors with axis-rotation/reversal already applied, reusing xgcm's tested
padding. A reciprocity check raises instead of returning the silently-wrong
neighbors xgcm's padding produces (hash-seed-dependently) for the most complex
reversed topologies. Section state carries a `face` index; `grid_section`
returns the face component for multi-tile grids.
Transports/tracers across face seams: each section edge's normal velocity is
read in a single face's frame (source-first dual-anchor), so nothing is rotated
across the seam, and the per-edge sign is computed geometrically ("does the
velocity point left of travel?") so it stays consistent across rotated faces
without a single global orientation factor. Verified by split-grid equivalence
(a 2-face grid is a flat grid cut in half) for symmetric and non-symmetric
axis-preserving seams, and by a streamfunction-difference test (transport
P1->P2 = psi(P2)-psi(P1)) for a genuinely rotated 2-face grid.
The tripolar/bipolar fold (a face self-connection) is detected and rejected
with NotImplementedError; xgcm does not support it either (xgcm issue #194).
New tests in sectionate/tests/test_section_multitile.py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Owner
Author
|
Reopening against MOM6-community/sectionate instead. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Section-finding used to hard-code how to deal with a few grid topologies via a
topology=string ("latlon"/"cartesian"/"MOM-tripolar"), and the whole transport/tracer pipeline assumed a single logically-rectangular(Y, X)tile. This PR makes neighbor-finding read from thexgcm.Gridthe caller already supplies — its per-axisboundaryandface_connectionsmetadata — so periodicity, the bipolar north fold, and inter-tile connectivity "just work." It extends section-finding and transports to multi-tile grids (lat-lon-cap, cubed-sphere) and to all three native C-grid staggerings, and ships two real-world example notebooks that double as validation.Changes
Topology from xgcm metadata (no
topology=). Neighbors follow from each axis'boundary—"periodic"→ wrap, fill/extend wall → clip, and a single-tile bipolar north fold{"Y": {"fold": ...}}→ handled natively via xgcm's fold padding. Thetopology=argument and the hard-coded north-fold formula are gone;gridutils.build_neighbor_mapsbuilds the topology-aware neighbor maps the pathfinder consumes.Multi-tile geometry (
face_connections).build_neighbor_mapsbuilds index-valued arrays, pads them once with xgcm, and reads the halos to get each corner's neighbors with axis rotation/reversal already applied — reusing xgcm's tested padding rather than reimplementing topology. A reciprocity check raises rather than return silently-wrong neighbors. Section state carries afaceindex;grid_sectionreturns it for multi-tile grids.All three C-grid staggerings native. Vorticity points may sit at
"outer"(MOM6 symmetric),"right"(MOM6 non-symmetric), or"left"(MITgcm/ECCO, incl. lat-lon-cap) positions, distinguished by a per-position velocity index offset (gridutils.corner_position/corner_offset). No conversion to a symmetric grid is needed.Deterministic walk +
curveoption. The section walk is deterministic and direction-independent (admits neighbors strictly closer to the endpoint plus any seam twin, breaking ties by index), so periodic/fold-seam crossings no longer hinge on floating-point rounding.grid_sectiontakescurve=—"great circle"(default geodesic) or"latitude circle"(constant-latitude paths that march in longitude).Transports / tracers across seams. Each section edge's normal velocity is read in a single face's frame (source-first dual-anchor), so no velocity is rotated across a seam. The per-edge sign is computed geometrically — "does the stored velocity point to the left of the section's direction of travel?" — so it stays consistent across rotated faces without a single global orientation factor.
convergent_transport/extract_tracerselect the contributing face pointwise.Examples
examples/4_sections_on_global_tripolar_grid.ipynb— sections traced across the bipolar north fold on a global tripolar grid, including acurve="latitude circle"global section.examples/5_MOC_transports_ECCOv4r4.ipynb— end-to-end depth-space global meridional overturning streamfunction from ECCOv4r4 on its native 13-tile lat-lon-cap (LLC90) grid: multi-tile seam crossing + native"left"staggering + latitude-circle sections, on real model output. Its small ECCO data subset is fetched from Zenodo (10.5281/zenodo.21051424) with MD5 checks, so it runs with no NASA Earthdata login.Verification
rtol 1e-12.psi(P2) - psi(P1)— a known, non-zero, rotation-independent answer needing no model data.PYTHONHASHSEED(new files:test_section_multitile.py,test_section_fold.py,test_section_reversibility.py,test_left_grid.py,test_section_cornercases.py).Dependency note
The bipolar-fold path relies on fold-aware xgcm (bipolar fold xgcm#711 + face-connection padding fix #713), currently the unreleased
hdrake/xgcm@tripolar-north-fold. The fold testsskipwithout it; everything else runs onxgcm>=0.9.0.Known limitations (guarded, not silent)
face_connectionsraisesNotImplementedError— build the grid as a single tile with the fold as aboundary({"X": "periodic", "Y": {"fold": "corner"}}) instead, which is supported natively.🤖 Generated with Claude Code