Product notes¶
Differences between DISP productions that affect reading a frame, found while using real frames. Each note says what changed, how it was found and what disp-xr does about it.
DISP-S1 displacement precision: float32 before November 2025, float64 after¶
What changed. DISP-S1 granules produced in November 2025 and later store
the displacement layer as float64. Earlier productions store it as
float32. No other layer changes: the corrections, short_wavelength_displacement,
the quality layers and the masks have the same dtype, chunks and
compression in every production.
Not a reprocessing. The later granules continue the time series rather
than replace it. In frame F11116 (central California), the April 2025
production ends at 2024-10-03. The first November 2025 granule is a
ministack referenced on that date (20241003T140837Z_20241015T140837Z). A
time series that runs past October 2024 therefore needs both productions.
How it was found. The split-metric study (T29, 2026-10-04) downloaded
all 389 F11116 granules from CMR. open_disp refused them with
MixedProductionError:
| Production | Granules | displacement |
Secondary dates |
|---|---|---|---|
| April 2025 | 314 | float32 | 2016-07-05 to 2024-10-03 |
| November 2025 | 45 | float64 | from 2024-10-15 |
| August 2026 | 30 | float64 | to 2026-04-26 |
Every 2D layer of one granule from each production was compared with h5py:
displacement float32 float64 float64
same: connected_component_labels, corrections/ionospheric_delay,
corrections/perpendicular_baseline, corrections/solid_earth_tide,
estimated_phase_quality, persistent_scatterer_mask, phase_similarity,
recommended_mask, short_wavelength_displacement, shp_counts,
temporal_coherence, timeseries_inversion_residuals, water_mask
What disp-xr does. open_disp reads granules that differ only in the
precision of a float layer:
- it raises a
MixedPrecisionWarningthat lists each production; - it casts the layer to float32 (float32 resolves about 10 nm on a 10 cm displacement);
- it records the layer in
attrs["mixed_precision"].
Any other difference (an integer layer becoming float, a new fill value,
other compression or chunks) still raises MixedProductionError. So does
build_virtual_frame, because a virtual store references the stored
chunks and needs one dtype per array.
import warnings
import disp_xr as dxr
from disp_xr.product import MixedPrecisionWarning
with warnings.catch_warnings():
warnings.simplefilter("ignore", MixedPrecisionWarning) # once you know
ds = dxr.open_disp("F11116/")
ds.attrs["mixed_precision"] # ['displacement']
DISP-S1 time encoding changed in November 2025¶
What changed. The same productions also encode time and
reference_time differently. The earlier granules store 0 seconds since the
acquisition time itself (seconds since 2024-10-03 14:08:37.435763), which
decodes exactly. The later granules store float seconds since 2010
(seconds since 2010-01-01 00:00:00.000000), which decodes a few
nanoseconds off: 2024-10-03 14:08:37.435763008.
Why it matters. Ministacks are chained through exact dates: each
ministack's reference date must be an epoch of the previous one. In F11116
the November 2025 ministack references 2024-10-03, but that date read from
the April 2025 granule differs by 8 ns, so chain raised
MissingCrossoverError.
What disp-xr does. open_disp reads time and reference_time to the
whole second (floored), as granule names give them
(20241003T140837Z). Epochs of one frame are days apart, so nothing below a
second is used.
Open questions for OPERA¶
- Is the float64 displacement intended? Its granules are larger, and float32 already holds more precision than the measurement has.
- Could the time encoding stay one style across productions?