Skip to content

Fix clip_domain broadcasting error for extents strictly inside the domain#558

Open
martinguthrie93 wants to merge 2 commits into
pySTEPS:masterfrom
martinguthrie93:fix-clip-domain-interior-window
Open

Fix clip_domain broadcasting error for extents strictly inside the domain#558
martinguthrie93 wants to merge 2 commits into
pySTEPS:masterfrom
martinguthrie93:fix-clip-domain-interior-window

Conversation

@martinguthrie93

Copy link
Copy Markdown

Summary

Fixes #557.

pysteps.utils.dimension.clip_domain raised

ValueError: could not broadcast input array from shape (a,b) into shape (c,d)

whenever the requested clipping extent lay strictly inside the source domain. Since clip_domain is the standard way to crop a precipitation field to a geographic bounding box, any workflow that clips to an interior region of interest hit this.

Root cause

The source and destination copy windows were computed independently, using strict pixel-center comparisons (x_coord < right_ / > left_) against two different reference boxes (the requested extent vs. the full source domain). When the extent was strictly interior, the strict comparison dropped a pixel on one side and the two windows ended up with different sizes, so the final assignment failed to broadcast.

The previous tests only used extents whose edge coincided with the source-domain boundary, a special case where the window sizes happened to match, so the bug went unnoticed.

Fix

Because clip_domain preserves the pixel size, clipping is an integer-pixel window operation. The window is now recomputed from a single pixel offset between the clipped grid and the source array (col_offset / row_offset, the latter accounting for the yorigin convention), so the source and destination windows always match in size.

Additional benefits of the offset-based formulation:

  • extents that extend beyond the source domain are now padded with metadata["zerovalue"] instead of raising;
  • the returned metadata (x1, x2, y1, y2) stays consistent with the clipped pixel grid and preserves the pixel size.

For the fully-contained case used elsewhere in the test suite (e.g. the 512x512 MCH clip in helpers.py), the returned array is byte-for-byte identical to the previous behaviour.

Tests

pysteps/tests/test_utils_dimension.py:

  • interior clip that previously raised, for both yorigin="upper" and yorigin="lower";
  • an out-of-domain extent that must be zero-padded;
  • a check that the returned metadata describes the clipped pixel grid.

All existing clip_domain cases still pass, and black reports no changes.

HoHo and others added 2 commits July 3, 2026 15:54
clip_domain determined the source and destination copy windows
independently, using strict pixel-center comparisons against two
different reference boxes (the requested extent vs. the full source
domain). Whenever the requested extent lay strictly inside the source
domain, the two windows could end up with different sizes, raising

    ValueError: could not broadcast input array from shape (a,b)
    into shape (c,d)

The previous tests only exercised extents whose edge coincided with the
source domain boundary, which happened to produce matching window sizes,
so the bug went unnoticed.

Because clip_domain preserves the pixel size, clipping is an
integer-pixel window operation. Recompute it from a single pixel offset
between the clipped grid and the source array, so the source and
destination windows always match in size. This also makes extents that
extend beyond the source domain pad with the zero value instead of
raising, and keeps the returned metadata consistent with the pixel grid.

Add regression tests for interior clips (both yorigin conventions),
out-of-domain padding, and the returned metadata.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the unused `x2` local (unused-variable) and drop the
`num, nt, ny, nx = R.shape` unpacking in favour of indexing `R.shape`
directly, which keeps the local-variable count at or below the previous
implementation. No behavioural change; all clip_domain tests still pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

clip_domain raises ValueError (broadcast mismatch) for extents strictly inside the domain

1 participant