Skip to content

geotiff: auto-promote float16 reads to float32 (#1941)#1944

Merged
brendancol merged 1 commit into
mainfrom
rockout-accuracy-low-geotiff-2026-05-15-02
May 15, 2026
Merged

geotiff: auto-promote float16 reads to float32 (#1941)#1944
brendancol merged 1 commit into
mainfrom
rockout-accuracy-low-geotiff-2026-05-15-02

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Closes #1941.

Summary

  • tiff_dtype_to_numpy(16, SAMPLE_FORMAT_FLOAT) previously raised; an externally-produced GeoTIFF with BitsPerSample=16 + SampleFormat=3 could not be read.
  • Writer auto-promotes float16 to float32 already; the reader now matches that contract by returning float32 on the user-visible dtype while a new tiff_storage_dtype keeps the raw 2-byte view so the byte view in _decode_strip_or_tile stays correct.
  • GPU paths route the rare half-precision case to the CPU decoder via the existing stripped-layout fallback; the GDS gate also returns False for the same key.

Test plan

  • Dtype-map keys: tiff_dtype_to_numpy(16, 3) == float32, tiff_storage_dtype(16, 3) == float16, identity on non-promoted keys.
  • Eager open_geotiff and read_geotiff_dask round-trip a tifffile-written float16 file to float32.
  • Predictor=3 + float16 also round-trips.
  • Regression guards for float32, float64, uint16 still match the original dtype.
  • Existing test_float16_not_supported is updated to assert the new behaviour.
  • pytest xrspatial/geotiff/tests/ non-GPU/HTTP: 2382 passed, 7 skipped.

The writer auto-promoted float16 inputs to float32 before encoding,
but the read-side dtype map in _dtypes.tiff_dtype_to_numpy had no entry
for (16, SAMPLE_FORMAT_FLOAT), so any externally produced GeoTIFF with
half-precision samples failed at parse time with "Unsupported
BitsPerSample=16, SampleFormat=3". rasterio / GDAL handle these files;
xrspatial did not.

Fix:

- tiff_dtype_to_numpy(16, 3) returns np.float32 (matches the writer's
  promotion contract).
- A new tiff_storage_dtype(bps, sf) returns the raw on-disk dtype
  (np.float16 for this key, identical to tiff_dtype_to_numpy for
  every other key). _decode_strip_or_tile uses the storage dtype to
  view the 2-byte samples then casts to float32 once.
- GPU paths fall back to CPU decode for float16 (bps != itemsize * 8)
  because the GDS/tile-assembly kernels assume bps matches the
  user-visible dtype; the existing stripped-layout fallback handles
  the fallback dispatch.

Regression test in test_float16_read_1941.py: dtype-map keys, eager and
dask round-trip of an external float16 file, predictor=3 + float16, plus
regression guards for float32/float64/uint16. Existing
test_edge_cases.test_float16_not_supported is updated to assert the new
auto-promotion behaviour.
Copilot AI review requested due to automatic review settings May 15, 2026 14:43
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label May 15, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@brendancol brendancol merged commit 12d938c into main May 15, 2026
17 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

geotiff: float16 GeoTIFFs cannot be read despite writer auto-promotion

2 participants