Repository navigation
Topology-driven section-finding + outer-lattice multi-tile transports (from xgcm metadata) #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hdrake
wants to merge
67
commits into
MOM6-community:master
Choose a base branch
from
hdrake:topology-driven-neighbors
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 18 commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
be994ff
Drive section neighbor-finding from xgcm topology metadata
hdrake d97ecca
Unify seam handling via zero-length-face dropping; add bipolar fold s…
hdrake 41ce711
Re-execute all example notebooks against the bipolar-fold grid
hdrake 4949fe6
Add gridutils.symmetrize: support 'left'-staggered (MITgcm/ECCO) grids
hdrake 362ab56
Fix self-connection fold check to read grid._face_connections
hdrake e81bd4e
Trim reciprocity-check comments to the essentials
hdrake 64cc479
Support 'left' (MITgcm/ECCO) C-grids natively via per-position corner…
hdrake 47ab5af
Sync example-notebook prose with three-position grid support
hdrake 3d852e6
Add CLAUDE.md documenting three-position grid support (supersedes #46)
hdrake ec71fe4
CLAUDE.md: keep PR description in sync when pushing to an open PR
hdrake 7952e75
Make the section walk deterministic and add a curve option
hdrake f606683
Test that oblique multi-segment sections are reversible
hdrake b981c15
Rewrite example 5 as depth-space MOC from ECCOv4r4 (LLC90)
hdrake 88132c3
Correct cross-tile seam neighbors on staggered (left/right) grids
hdrake 2fc76dc
CLAUDE.md: use docs_env_sectionate (fold-aware xgcm) for local dev
hdrake 59571e1
Load example 5 ECCO data from Zenodo instead of earthaccess
hdrake 0a66164
Demo latitude-circle sections in the tripolar example
hdrake f666a7b
Ignore local data cache, build artifacts, and .DS_Store
hdrake e19551e
Address review: drop model-convention labels from source; rename chec…
hdrake 7a0dd36
Fix docs build pointer and sync CLAUDE.md with renamed API
hdrake 1debde8
Address review: pin pandoc for docs, harden Zenodo loader, doc f_c
hdrake a6f5286
Add native-grid section visualization to the ECCO MOC example
hdrake 4df149c
Fix is_mask_inside sign inversion on multi-tile grids
hdrake 870d9a8
Rebuild staggered multi-tile corner topology on the outer lattice
hdrake 9b79c02
Route all multi-tile topology through the outer corner graph; add exa…
hdrake b1baabc
tests: geometry-first 'left' cubed-sphere fixture with streamfunction…
hdrake b45d75a
ci: install combined xgcm (fold #711/#712 + vector-pad #749); re-exec…
hdrake 8e6e0f2
tests: cover right-staggering, open-wall zeroing, and reverse-gluing …
hdrake 67248ca
reverse=True: precise error for non-symmetric grids; document outer+r…
hdrake 2ed310e
Support outer (symmetric) grids with reverse=True gluings
hdrake 9af0c92
Add AI Usage Policy to CLAUDE.md (follow xgcm policy)
hdrake 223cb76
Migrate to xgcm dev-v1.0.0 (boundary/periodic -> padding API)
hdrake 5f2576f
tests: pin geometric per-edge sign stability at the geographic pole
hdrake af6e878
Allow zero-length (360->0) latitude-circle loop closures
hdrake 2cbeb27
Fix conservation leak at multi-tile corners stored on no face (#49)
hdrake fbeaf00
Terminology cleanup: replace metaphorical jargon with conventional ph…
hdrake b1264d9
Guard spherical_angle against degenerate zero-length arcs
hdrake 188685d
Resolve multi-tile corner identity topologically; snap only for the p…
hdrake d2854a9
Address PR review: accurate cut comment, rung-2 note, snap-failure guard
hdrake 0062cd0
Merge pull request #6 from hdrake/topological-corner-resolution
hdrake 9326473
Depend on released xgcm >= 0.10.1 instead of the dev-v1.0.0 git ref
hdrake 113b03a
Merge upstream master into topology-driven-neighbors
hdrake a15638e
Per-branch conda envs in CLAUDE.md; fix version section after merge
hdrake 0c2708d
Match layer/interface through the grid, not string substitution
hdrake 096e132
Pad only over the axes the array actually spans
hdrake 4d7306a
Take layer/interface from the grid's Z axis; default both to None
hdrake 140de68
Re-execute the example notebooks on this branch
hdrake 4a78d98
Re-execute the example notebooks on this branch
hdrake 9023252
Merge pull request #8 from hdrake/fix-horizontal-only-padding
hdrake 5b92ea2
Merge base branch (with #8) into fix-layer-interface-matching
hdrake 0eeb6e1
Take the vertical coordinates from the data and the grid, not the caller
hdrake 9993903
Re-execute the example notebooks on the merge result
hdrake 055010c
Merge pull request #7 from hdrake/fix-layer-interface-matching
hdrake dfbe0b2
Address PR #47 review: docs wording, ECCO record, topology check
hdrake 7b93104
Always take the shortest path between section waypoints
hdrake 568ac7b
Correct two overclaiming comments surfaced by the review questions
hdrake efe9101
Add an animated docs page explaining the section-tracing algorithm
hdrake fe35ddc
Merge pull request #12 from hdrake/algorithm-walkthrough-docs
hdrake d0ef93b
Decide the curve per segment, and make "latitude circle" mean it
hdrake c566d7d
Correct false claims in the docs added by the review follow-up
hdrake 124fa06
Update section.py
hdrake 2269bb0
Drop the face-existence and mutuality checks; trust xgcm
hdrake 007a534
Update section.py
hdrake eabe1f5
Merge pull request #10 from hdrake/pr47-lat-circle-shortest-path
hdrake 9fc40cd
Refactor comments in section tracing logic
hdrake 7313dd8
Merge remote-tracking branch 'origin/topology-driven-neighbors' into …
hdrake 68d2c2e
Merge pull request #9 from hdrake/pr47-review-docs
hdrake File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| # CLAUDE.md | ||
|
|
||
| This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. | ||
|
|
||
| ## Project Overview | ||
|
|
||
| Sectionate is a Python package for sampling grid-consistent hydrographic sections from structured ocean model outputs (e.g. MOM6). It traces paths along C-grid velocity faces between geographic waypoints and computes transports/tracer values along those sections. Only structured grids are supported. | ||
|
|
||
| ## Development Setup | ||
|
|
||
| ```bash | ||
| conda env create -f ci/environment.yml | ||
| conda activate test_env_sectionate | ||
| pip install -e . | ||
| ``` | ||
|
|
||
| **Local development environment:** use the `docs_env_sectionate` conda env | ||
| (`/opt/anaconda3/envs/docs_env_sectionate`) for developing this package — running the | ||
| test suite, executing the example notebooks, and any package work in this workspace. | ||
| Keep it updated as needed; in particular it must carry the unreleased **fold-aware | ||
| xgcm** (`hdrake/xgcm@tripolar-north-fold`, which includes the bipolar fold #711 and the | ||
| face-connection padding fix #713). The ECCO example (notebook 5) pulls its data subset | ||
| from Zenodo (concept DOI `10.5281/zenodo.21051424`) via stdlib `urllib` with MD5 checks — | ||
| no `earthaccess`/Earthdata login needed. Install xgcm with | ||
| `pip install "git+https://github.com/hdrake/xgcm.git@tripolar-north-fold"`. | ||
| Caveat: that dev build reports version `0.1.devNNN`, which is `< 0.9.0`, so re-running | ||
| `pip install -e .` (sectionate requires `xgcm>=0.9.0`) silently reinstalls a released xgcm | ||
| over it; reinstall the fold-aware xgcm afterwards with `--no-deps`. A correctly set up env | ||
| runs the full suite with **0 skips** (fold tests require the fold-aware xgcm; they `skip` | ||
| otherwise). | ||
|
|
||
| ## Commands | ||
|
|
||
| - **Run all tests:** `pytest` | ||
| - **Run a single test:** `pytest sectionate/tests/test_section.py::test_find_closest_grid_point` | ||
| - **Build docs:** `cd docs && make html` (requires `docs/environment.yml` environment) | ||
|
|
||
| ## Definition of Done (always, before committing) | ||
|
|
||
| Before committing any change to this repository, always do all of the following — use | ||
| parallel agents where it is faster: | ||
|
|
||
| 1. **Run the full test suite** (`pytest`) and confirm it passes. | ||
| 2. **Re-execute the example notebooks** in `examples/` and confirm they run cleanly. | ||
| 3. **Scan the repo for inconsistencies / outdated information** introduced by the change — | ||
| including docstrings, `README.md`, files under `docs/`, the example notebooks, and this | ||
| `CLAUDE.md` — and update them so docs and code stay in sync. | ||
|
|
||
| ## Keeping pull requests in sync | ||
|
|
||
| When pushing a new commit to a branch that already has an open PR, also update that PR's | ||
| top-comment description so it stays consistent with the most recent commit: | ||
|
|
||
| - Revise the summary / "Changes" prose to reflect what the latest commit actually did. | ||
| - Update any task/status checklist — check off completed items (`- [ ]` → `- [x]`) and add | ||
| new ones as needed. | ||
| - Edit it in place with `gh pr edit <number> --repo <owner>/<repo> --body-file <file>` (find | ||
| the PR for the current branch with `gh pr view --json number,url`). | ||
|
|
||
| ## Architecture | ||
|
|
||
| The package is organized around a pipeline: define sections → map to grid → compute transports/tracers. | ||
|
|
||
| ### Core Modules | ||
|
|
||
| - **`section.py`** — Section definition and grid path algorithms. `Section` holds named waypoint coordinates; `GriddedSection` extends it with grid index information. `grid_section()` is the main entry point that maps geographic waypoints to grid vorticity-point indices `(i_c, j_c)` by walking the grid between waypoints along the `curve` requested (`"great circle"`, the default geodesic, or `"latitude circle"`); each segment must span less than 180°. The walk is deterministic and direction-independent: it admits neighbors strictly closer to the endpoint plus any seam twin of the current cell (so periodic/fold-seam crossings don't hinge on floating-point rounding), and breaks ties by index. Grid topology is inferred entirely from `xgcm.Grid` metadata — each axis' `boundary` (periodic wrap, fill/extend wall, or a single-tile bipolar north fold `{"Y": {"fold": ...}}`) and `face_connections` for multi-tile grids — so there is no `topology` keyword. The pathfinder consumes topology-aware neighbor maps built by `gridutils.build_neighbor_maps`. | ||
|
|
||
| - **`transports.py`** — Transport computation along sections. `uvindices_from_qindices()` converts vorticity-point indices to U/V velocity-point indices using a per-position corner offset (`gridutils.corner_offset`) covering all three C-grid staggerings: 'outer' (symmetric), 'right' (non-symmetric), and 'left' (MITgcm/ECCO). `convergent_transport()` is the main function: it lazily computes signed normal transports with configurable orientation (positive inward to the polygon defined by the section). | ||
|
|
||
| - **`tracers.py`** — `extract_tracer()` interpolates tracer data to U/V points along a section path for cross-section plotting. | ||
|
|
||
| - **`gridutils.py`** — Grid introspection utilities: `corner_position()` returns the shared vorticity corner position (`"outer"`/symmetric, `"right"`/non-symmetric, or `"left"`/MITgcm-ECCO) and `corner_offset()` the corresponding velocity index shift used throughout transports/tracers; `check_symmetric()` is a thin wrapper (True iff `"outer"`). `coord_dict()` and `get_geo_corners()` extract coordinate/dimension names from `xgcm.Grid` metadata; `build_neighbor_maps()` builds the topology-aware neighbor maps the pathfinder consumes. | ||
|
|
||
| - **`utils.py`** — Section catalog I/O. Sections can be loaded by name from JSON catalog files in `sectionate/catalog/`. Also provides `save_gridded_section()`/`load_gridded_section()` for persisting gridded sections. | ||
|
|
||
| ### Key Concepts | ||
|
|
||
| - **Vorticity points (q-points):** Sections are defined as paths through vorticity-point indices `(i_c, j_c)`. Consecutive q-points define velocity faces (either U or V). | ||
| - **Corner staggering (three positions):** Vorticity sits at one of three xgcm positions: `"outer"` (MOM6 symmetric, M+1×N+1), `"right"` (MOM6 non-symmetric, M×N), or `"left"` (MITgcm/ECCO, incl. the lat-lon-cap, M×N). All three are native; they differ only by a per-position velocity index offset (`gridutils.corner_offset`: outer→0, right→+1, left→0). `"left"` indexes like `"outer"`; it differs only in array length and in that the *high* corner row/column is absent (so a section exactly on the north/east domain wall clips one row inside). | ||
| - **Sign conventions:** For a *closed* section, `convergent_transport()` determines orientation (clockwise/counterclockwise) using stereographic projection and signed polygon area, then applies sign corrections so positive transport means "inward" (toward the enclosed polygon). For an *open* section there is no enclosing polygon, so `positive_in` is undefined; it instead uses the **left-of-transect** convention — `positive_in=True` makes positive transport point to the left of the section as traversed from the first to the last waypoint — and emits a `UserWarning`. `is_section_counterclockwise()` is only consulted in the closed case. | ||
| - **xgcm.Grid dependency:** The package relies heavily on `xgcm.Grid` for grid metadata (axis boundaries, coordinate positions, dataset access via `grid._ds`). | ||
|
|
||
| ## Version | ||
|
|
||
| Version is in `sectionate/version.py` and read by hatchling at build time. | ||
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove "(e.g. MOM6)"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change "Only structured grids are supported" to supports any structured model whose grid can be defined by a
xgcm.Gridobject.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
In hdrake#9.
Written by Claude Code.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done — it now reads that sectionate supports any structured model whose grid can be described by an
xgcm.Gridobject.In hdrake#9.
Written by Claude Code.