Packed int16 NDVI (NetCDF)¶
NDVI stored as int16 with scale_factor 1e-4, the standard CF packing convention. A reader that ignores scale_factor gets plausible-looking integers in the thousands instead of NDVI in [-1, 1] -- wrong by four orders of magnitude, with nothing raised and nothing to notice.
| Property | Value |
|---|---|
| Case ID | ndvi_packed_netcdf |
| Category | netcdf |
| Format | NetCDF |
| CRS | EPSG:4326 |
| Location | Western Europe (synthetic) |
| Test tier | unit |
| Size class | tiny |
| Storage class | bundled |
| Redistributable | yes |
| Loader | xarray |
| Status | validated |
Use this case¶
import pytest
@pytest.mark.geocase_case("ndvi_packed_netcdf")
def test_ndvi_packed_netcdf(geocase_case) -> None:
data = geocase_case.load()
assert data is not None
Use GeoCase in your tests¶
Install the complete set of vector, raster, and NetCDF dependencies:
What this case checks¶
Verify that packed values are unpacked through scale_factor/add_offset before use, and that the fill value is masked rather than scaled into a plausible-looking number.
Risk types covered¶
Expected behavior¶
| Assertion | Expected |
|---|---|
expect_loadable |
yes |
expect_nodata |
yes |
expected_scale_factor |
0.0001 |
Notes¶
Purpose¶
NDVI stored under the standard CF packing convention: int16 on disk, with
scale_factor = 1e-4 and add_offset = 0.0. The physical values span
[-1, 1]; the stored values span [-10000, 10000].
Why this is a trap and not just a format detail¶
The failure is silent and plausible. A reader that ignores scale_factor
does not crash and does not warn — it returns integers in the thousands, which
look like perfectly reasonable numbers until someone compares them to an NDVI
scale. The reads that matter here are a pair:
raw = xarray.open_dataset(path, mask_and_scale=False) # int16, max 10000
ok = xarray.open_dataset(path) # float, max 1.0
The fill value compounds it. _FillValue = -32768 scaled rather than masked
becomes -3.2768, still a finite float and still outside NDVI's range — so it
survives into an average and quietly drags it down.
Cross-container pair¶
This case deliberately mirrors the raster case ndvi_scaled_int16_small,
which carries the same failure mode in a GeoTIFF. The two are linked in both
directions via params.analogous_case_id.
They are worth having as a pair because the packing metadata lives in a completely different place in each container — a GDAL band scale in one, a CF variable attribute in the other — and libraries routinely handle one and not the other. A reader that passes one of these and fails the other has exactly the gap the pair exists to find.
Typical checks¶
- Open with and without
mask_and_scaleand confirm the two disagree. - Decoded values fall inside
[-1, 1]. scale_factoris1e-4(gated byexpected_scale_factor).- The fill cell is masked, not scaled.
Required capabilities¶
loadcoordinate-inspectionnodata-check
Files¶
- Primary:
ndvi_packed.nc - Notes:
notes.md
Source and license¶
- Source: geocase-curated
- License: MIT
Tags¶
cf-conventions ndvi netcdf packing scale-factor
Related cases¶
- Lat/Lon Small NetCDF --
latlon_small - NDVI Scaled Int16 Small --
ndvi_scaled_int16_small - CF Time Units and Non-Conventional Dimension Order --
cf_time_ordering_netcdf - Bottom-Up DEM (Positive Y Resolution) --
bottom_up_dem_small - COG Multispectral Small --
cog_multispectral_small