Skip to content

merge() ignores per-raster nodata sentinels, leaks invalid pixels into mosaic #1448

@brendancol

Description

@brendancol

Summary

xrspatial.reproject.merge() only detects the nodata sentinel of the first raster in the input list. That single sentinel is then used for every other raster during reprojection and merging. When inputs use different sentinels, the non-first rasters' invalid pixels are not recognized as nodata and silently flow into the mosaic as real data.

Where

xrspatial/reproject/__init__.py:1385:

nd = nodata if nodata is not None else _detect_nodata(rasters[0], nodata)

nd is then passed unchanged into _reproject_chunk_numpy for every raster in both _merge_inmemory and _merge_block_adapter.

Concrete example

  • Raster A has NaN nodata, valid data = 10.
  • Raster B has -9999 nodata, valid data = 20, with -9999 sentinels in part of its footprint.

Calling merge([a, b], strategy='mean') returns -9999 values in B's nodata regions because _reproject_chunk_numpy was told the sentinel is NaN, so it never converted -9999 to NaN before resampling. Worse, with strategy='mean' and a 0-sentinel input, sentinel zeros are folded into averages, producing wrong numerical results with no warning.

The user-supplied nodata argument is the desired output sentinel and is unrelated to the per-raster input sentinels, so checking nodata is not None does not save us either.

Fix

Detect each raster's own nodata sentinel independently of the user-supplied output nodata. Reproject each raster with its own input sentinel, canonicalize to NaN before the strategy merge, then convert NaN back to the user-requested output nodata at the end. The strategy merge already handles NaN canonical via its use_nan branch.

This affects both the in-memory and dask paths.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions