Skip to content

One crop frame for every topo type; drop crop_bounds from topo.data - #765

Draft
mandli wants to merge 11 commits into
clawpack:masterfrom
mandli:topo-crop-frame
Draft

mandli wants to merge 11 commits into
clawpack:masterfrom
mandli:topo-crop-frame

Conversation

@mandli

@mandli mandli commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

This PR ties together and tries to address a lot of the confusion around the new windows into files, especially the netCDF files. Much of the language should apply to the ASCII files as well as netCDF, so I may have missed some of those. The diagram is also editable if someone wants to make it more clear.


Stacked on #763, which is stacked on #762. Please review only the commits
after 86bc5002:

  • 140f52e0 adds the failing tests.
  • 2b8d3c9e is the fix.
  • d6e579f8 adds the design doc and diagram.

This PR will be rebased as #762 and #763 land.

This answers @rjleveque's question about crop_bounds versus crop_extent
in topo.data. It is PR A of the plan in
dev/design/topo_input_roadmap.md §2.8. Start with the new reference page
dev/design/topo_crop_windows.md. It names every crop "window" (file extent,
crop_extent, each entry's window in the file, the window actually loaded,
the array extent, and the domain), gives each one's coordinate frame, and has a
diagram for a netCDF crop across the antimeridian.

What was wrong

  • crop_bounds was not a duplicate of crop_extent. It was each
    topo.data entry's crop in that file's own coordinates. It differs from
    crop_extent when a crop is split at the antimeridian, and Fortran used it
    in place of crop_extent.
  • netCDF and ASCII cropped in different frames when x_shift/y_shift was
    set.
    ASCII applied the crop after the shift, as documented. netCDF applied
    it before the shift, in both Python and Fortran. With x_shift = 10 and
    crop_extent = [0, 20, …], ASCII loaded [0, 20] and netCDF loaded
    [10, 30], so a run on [0, 20] stopped with "topo arrays do not cover
    domain".
  • Python and Fortran could drop different edge columns. Python compared crop
    edges exactly, while Fortran allowed 1e-6·dx. For example, crop
    [-99.5, -99.0] on a 0.1° grid written by Topography.write gave Python 5
    points and Fortran 6. Over 1,905 crop edges on grid lines, the two disagreed
    on 1,017.

What changes

  • crop_extent is in domain coordinates (after x_shift/y_shift) for every
    topo type, in Python and in Fortran.
  • topo.data no longer has crop_bounds for topo, dtopo or met. Fortran gets
    each entry's window from crop_extent − lon_wrap_offset − shift and clips it
    to the file. A hand-built [4, path, TopoMetadata] entry whose crop exists
    only in its metadata now has it written as crop_extent.
  • One round-off allowance, CROP_TOL = 1e-6 of the grid spacing, is shared by
    Python (coordinate_tools.CROP_TOL) and Fortran (topo_module.f90). It
    guards round-off only and does not move crop edges.

Behavior changes (for release notes)

  • netCDF topography cropped with x_shift/y_shift now selects the
    documented region. The old window was the crop moved by the shift.
  • An old topo.data that contains a crop_bounds line stops with
    "Regenerate topo.data with 'make data'". Without that stop, an old file
    whose crop was only in crop_bounds would load the wrong window silently.
  • A crop edge within 1e-6·dx of a grid point now keeps that point in Python,
    matching Fortran.

Verification

  • New failing-first tests:
    • tests/test_topo_crop_frame.py: types 2/3/4 under a shift, for read and
      for the write-time coverage check.
    • test_shifted_crop_is_in_domain_coordinates in
      tests/regression/topo_crop: an end-to-end Fortran run. Every cell's
      topography matches an exact linear field to 1e-8, using the cos(latitude)
      area weighting of the spherical cell average.
    • tests/test_crop_tolerance.py: Python and Fortran use the same constant;
      on the 1,905-edge sweep Python picks the same points as Fortran's index
      formula; the -99.5 case keeps 6 points. With the constant set to 0,
      5 of these fail.
    • A regression test that an old topo.data with crop_bounds stops.
  • Existing suites:
    • Python tests/: 661 passed.
    • tests/regression, bowl-slosh-netcdf (including coarsened),
      dtopo, chile2010: 43 passed, 1 expected failure (marked xfail).
      chile2010 includes lon_360, which builds topo_entries() entries by
      hand with a −360 offset.

Not in this PR

mandli added 11 commits October 19, 2026 11:05
)

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
)

crop_indices no longer indexes past the array in the align search and raises EmptyAlignedCropWindow instead of returning an inverted window; topotools reports it with its own message.

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…ack#761)

apply_align_buffer_coarsen now stops, naming the file and axis, when the align shift passes the window end, matching Python's EmptyAlignedCropWindow. Previously the run continued silently with a point outside the crop. Adds a topo_crop regression for topo types 3 and 4 and records the status in the topo input roadmap.

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
… topo roadmap

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…ack#760)

A crop_extent the file does not cover is an error at make data for types 2/3/4, allowing half a cell at the edges; type-4 crops across the antimeridian still split. Adds a Fortran backstop regression for a crop that misses its file, and corrects roadmap §2.7.

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…wpack#760)

TopographyData.write checks crop_extent against the file's cell edges (half a cell past the outermost points) for types 2/3 (after x/y_shift) and 4 (allowing the +/-360 wrap), with one message naming the file, its extent and the usable overlap. Fortran type 4 now stops when a requested crop misses its file, as types 2/3 already do. ASCII crops past the file, including across the antimeridian, now error instead of being clipped.

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
The fatal branch of the topo coverage check (over 1% of the domain uncovered) ended with a bare stop, which exits 0, so scripts and CI could not tell it from success. The 'do not quite cover' warning branch is unchanged.

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…nder x/y_shift (§2.8)

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…rop round-off tolerance (§2.8)

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…ws.md)

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
…an for each

Signed-off-by: Kyle Mandli <kyle.mandli@gmail.com>
Assisted-by: claude claude-opus-5-5
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