fix(s1-rtc): store nodata as NaN, not 0, so titiler masks it transparent#202
Merged
Merged
Conversation
S1 RTC previews render the out-of-swath region as opaque black while the S2 reference renders it transparent. The cause is the *data*, not the metadata: #201 already gave vv/vh the same dtype/`fill_value`=NaN/ `_FillValue`/`grid_mapping` encoding as S2, but those are inert because no NaN is ever written — s1tiling stores `0.0` out of swath, and titiler treats `0` as valid data and paints it black. Mask nodata to NaN at the writer: - vv/vh: `np.where(border_mask == 0, NaN, ...)` — border_mask is the authoritative valid-data mask (0 = no-data). `_downsample_2d` already uses `np.nanmean` for floats, so NaN propagates to every overview level. - float conditions (gamma_area/lia): masked read off the GeoTIFF's declared nodata (border_mask is N/A for static conditions); a no-op when no nodata is declared. Only newly re-ingested cubes get NaN; existing cubes are remediated separately. Tests: NaN ⟺ border_mask==0 at native + overview levels, masking round-trips via `use_zarr_fill_value_as_mask`, conditions declared-nodata → NaN. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
S1 RTC previews render the out-of-swath region as opaque black while the S2 reference renders it transparent. The cause is the data, not the metadata: #201 already gave
vv/vhthe same dtype /fill_value=NaN/_FillValue/grid_mappingencoding as S2, but those are inert because no NaN is ever written — s1tiling stores0.0out of swath, and titiler treats0as valid data and paints it black._FillValue)This is the data half; #201 was the metadata half.
What
Mask nodata → NaN at the writer (
src/eopf_geozarr/conversion/s1_ingest.py):vv/vh—np.where(border_mask == 0, NaN, …)before overview generation.border_maskis the authoritative valid-data mask (0= no-data)._downsample_2dalready usesnp.nanmeanfor floats, so NaN propagates to every overview level.gamma_area/lia) — masked read off the GeoTIFF's declared nodata (border_maskis N/A for static conditions); a no-op when no nodata is declared.No change to the create-store paths — only the two read sites are touched (12 src lines).
Tests (TDD, RED→GREEN)
tests/test_s1_rtc_ingest.py— all 4 fail on082913a, pass after the fix:test_nodata_masked_to_nan(new) — NaN ⟺border_mask == 0at native and the r20m overview; valid pixels stay finite.test_fill_value_masking_roundtrip(rewritten) — masked region now comes fromborder_mask, not a pre-seeded NaN; round-trips viause_zarr_fill_value_as_mask.test_conditions_nodata_masked_to_nan(new) — declared-nodata → NaN.test_preserves_data_integrity(updated) — valid region preserved exactly, nodata region NaN.Plan trio (
test_s1_rtc_ingest+test_array_attrs+test_integration_sentinel1) = 85 passed; wholetests/green (exit 0, optional-dep skips only).Stacks on #201; targets #180.
🤖 Generated with Claude Code