From ca03cd3bab8cc35d93f60fac4e206e15f4c292bf Mon Sep 17 00:00:00 2001 From: Zachary Hoppinen Date: Sat, 9 May 2026 13:43:29 -0600 Subject: [PATCH] use AOI bounds for FCF clip_box, drop ref-based variant The ref-based clip_box bounds in generate_forest_fraction_dataarray were failing on some non-CONUS AOIs (white_mtns 2024_2025) with: rasterio.errors.WindowError: Bounds and transform are inconsistent Investigation: generate_reference_grid already reprojects ref to EPSG:4326 and clips to aoi.bounds, so ref.rio.bounds() was effectively the same as aoi.bounds anyway. The "tighter crop" optimization gave zero practical benefit but introduced a bug surface where pixel-edge snapping or projection round-trip quirks could produce a degenerate window on the FCF raster. Drop the if-ref branch, always use aoi.bounds + 0.05 deg halo. Co-Authored-By: Claude Opus 4.7 (1M context) --- spicy_snow/processing/generate_dataarrays.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/spicy_snow/processing/generate_dataarrays.py b/spicy_snow/processing/generate_dataarrays.py index 748dea4..1bac6bb 100644 --- a/spicy_snow/processing/generate_dataarrays.py +++ b/spicy_snow/processing/generate_dataarrays.py @@ -18,7 +18,7 @@ # faster reprojection utils import rasterio import rioxarray -from rasterio.warp import reproject, Resampling, transform_bounds +from rasterio.warp import reproject, Resampling from rasterio.enums import Resampling as Rsmp from rasterio.transform import rowcol @@ -343,16 +343,13 @@ def generate_forest_fraction_dataarray(aoi, ref = None) -> xr.Dataset: # clip to the target area BEFORE any computation, otherwise the # full raster gets loaded into memory and the process is killed. fcf = rioxarray.open_rasterio(fcf_path).squeeze(drop=True) - # Build the clip box in EPSG:4326 (FCF native CRS). Prefer the - # reprojection target's bounds when available for the tightest crop; - # fall back to the AOI bounds. - if ref is not None: - xmin, ymin, xmax, ymax = transform_bounds( - ref.rio.crs, "EPSG:4326", *ref.rio.bounds() - ) - else: - xmin, ymin, xmax, ymax = aoi.bounds + # Clip in EPSG:4326 (FCF native CRS) using AOI bounds. The ref grid + # is also in EPSG:4326 and clipped to aoi.bounds in + # generate_reference_grid, so using ref.rio.bounds() here was + # equivalent but vulnerable to pixel-edge / projection round-trip + # quirks that produced degenerate windows on some AOIs. # Small halo so reproject_match has neighboring pixels available. + xmin, ymin, xmax, ymax = aoi.bounds buf = 0.05 # ~5 km in degrees fcf = fcf.rio.clip_box( minx=xmin - buf, miny=ymin - buf, maxx=xmax + buf, maxy=ymax + buf