Keep a short current-state note for the shared VIIRS / MODIS SPIReS workflow.
This file should describe:
- the active sensor-agnostic architecture
- current data model and workflow expectations
- known issues that are still open
- the next concrete engineering steps
Historical implementation details from the large April 2026 refactor now live in:
notes_rtp_archive_2026-04.md
- in sandboxed terminal sessions, prefer
mambaoverconda - active environment:
spipy14 - use a writable cache pattern for sandboxed
mambaor notebook runs:XDG_CACHE_HOME=/tmp/mamba-cache
- example command:
XDG_CACHE_HOME=/tmp/mamba-cache mamba run -n spipy14 python -m pytest SpiPy/tests/test_viirs_r0.py
spires/sensors/registry.py- sensor / platform normalization and adapter lookup
spires/sensors/api.py- generic dispatch for
open_surface_reflectance(...) prepare_scene_for_inversion(...)build_timeseries(...)build_r0(...)build_r0_from_sources(...)run_inversion(...)get_execution_profile(...)
- generic dispatch for
spires/sensors/full_workflow.py- shared inversion workflow core after prepared
RandR0are available
- shared inversion workflow core after prepared
spires/sensors/r0_core.py- shared
R0source-stack, optional Zarr-backed staging, and compositing machinery
- shared
spires/sensors/io.py- generic safe dataset load / validate / atomic write helpers
spires/sensors/viirs/- reader, QA, bands, geospatial, ancillary, thin workflow / shared-core
R0wrappers
- reader, QA, bands, geospatial, ancillary, thin workflow / shared-core
spires/sensors/modis/- reader, QA, bands, geospatial, ancillary, thin workflow / shared-core
R0wrappers
- reader, QA, bands, geospatial, ancillary, thin workflow / shared-core
Keep ingestion and QA sensor-specific.
Once a prepared scene has canonical reflectance, geometry, masks, and R0, the inversion path should stay shared whenever possible.
- Read raw sensor files and build a prepared scene on the analysis grid.
- Build or reuse a validated
R0background dataset. Use the unifiedspires.sensors.build_r0_from_sources(...)API for both MODIS and VIIRS; passzarr_pathand time-major chunks for memory-safe local builds. - Run the shared inversion workflow with sensor-specific wrappers only where band / LUT logic differs.
- Write outputs through the shared safe I/O layer.
reflectance(y, x, band)solar_zenith(y, x)sensor_zenith(y, x)- component masks such as:
mask_invalid_reflectancemask_bad_geometrymask_watermask_low_observation_support
valid_r0_maskvalid_inversion_mask
r0_reflectance(y, x, band)r0_count(y, x)- diagnostic layers such as
r0_source_index,r0_source_time, and rule-selection fields
raw_viewable_snow_fractionraw_shade_fractionraw_canopy_fractionraw_snow_fractiondust_concentrationgrain_sizevalid_inversion_mask
Note:
- legacy
fscaandfshadealiases are intentionally no longer written
Current persisted output safeguards:
R0NetCDFs write atomically through a temp file and replace the final path only after validation- inversion NetCDFs use the same safe-write pattern
- existing outputs are not reused just because the file exists
- reusable outputs must pass lightweight validation
- new files are marked with
build_status="complete"
This was added after a Terra R0 file was found to be corrupted after an interrupted notebook run.
Some Aqua scenes contain heavy band-6 fill, which propagates into large invalid striped regions after scene preparation and then into inversion outputs because the current MODIS inversion path requires all seven bands.
This is a scene-quality / product-availability issue, not currently a reader bug.
Grouped inversion can still produce coherent missing patches in cases where ungrouped inversion returns values.
Current working hypothesis:
- a representative pixel can fail inversion and that failed solution then gets broadcast to the whole group
The shared wrappers and safe I/O refactor are in place, but the unified notebook still needs a fresh full end-to-end validation pass across the local MODIS and VIIRS platform runs using the current architecture.
The earlier Terra fsca ~= 0.5 problem was traced to a corrupted persisted Terra R0 file rather than a confirmed Terra-specific inversion or LUT problem.
Regenerating the R0 file fixed the issue.
The older fsca / fshade alias duplication has been removed from written outputs.
- Run a clean end-to-end validation pass in
examples/11_unified_multisensor_playground.ipynbusing the shared-core workflow and safe output writing. - Decide how Aqua scenes with excessive MODIS band-6 fill should be handled: reject, warn, or support only through a future reduced-band path with a compatible LUT.
- Debug grouped inversion failure modes with representative-vs-member comparisons and fallback behavior for failed groups.
- Document the generic sensor API kwargs in one central place.
- Replace the temporary canopy-input path with a durable tile-level ancillary product.
- future sensor adapters for Sentinel-2, Landsat 8/9, and HLS
- earlier
HDF -> zarrstaging for large batch runs - lighter reader modes when downstream steps do not need full QA/support fields
- optional ice-fraction ancillary support
- revisit separate Terra / Aqua LUTs only if future evidence suggests one shared MODIS LUT is insufficient