Skip to content

Packed int16 NDVI (NetCDF)

netcdfNetCDFEPSG:4326tinybundled

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:

pip install "geocase[all]"

View GeoCase on PyPI.

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_scale and confirm the two disagree.
  • Decoded values fall inside [-1, 1].
  • scale_factor is 1e-4 (gated by expected_scale_factor).
  • The fill cell is masked, not scaled.

Required capabilities

  • load
  • coordinate-inspection
  • nodata-check

Files

Browse this case on GitHub

Source and license

  • Source: geocase-curated
  • License: MIT

Tags

cf-conventions ndvi netcdf packing scale-factor