Phase 2 — Processing Pipeline
Duration: ~14 working days Critical-path predecessor: Phase 1 (locked) Status: in progress
Deliverables (§5.4)
- Atmospheric correction — Py6S radiative transfer + Ross-Li BRDF + SCS+C topographic
- Cloud / shadow masking — Fmask 4.0 + s2cloudless + Himalayan tuning
- Endmember unmixing — LSMA + MESMA + CUDA kernel (
swir_unmix_kernel.cu) - Snow decision tree — multi-criterion fusion (NDSI / NIR / TIR / DEM / cloud / temporal)
- CV subsystem — pyramidal LK, Farnebäck, SIFT co-registration
- SAR pipeline — σ⁰ calibration, Refined Lee, Nagler & Rott wet-snow
- Thermal / energy balance — full snowmelt energy budget Q_m
- Biosphere masking — Liu et al. canopy-gap correction + RF classifier
- Validation — R² ≥ 0.85 vs MOD10A1 (acceptance gate)
Acceptance Gate
Daily basin-wide FSC R² ≥ 0.85 vs MOD10A1, demonstrated over a 30-day rolling window.
Run:
cd snow-ir-backend
pytest tests/processing -v --cov=snow_ir.processing
python -m snow_ir.validation.fsc_vs_mod10a1 \
--snow-ir data/work/snow/<asset>_FSC.tif \
--reference data/mod10a1/<date>.tif \
--asset-id <asset>
Run a Scene End-to-End
from datetime import datetime, timezone
from pathlib import Path
from snow_ir.processing.atmospheric.six_s_correction import AtmosphericState
from snow_ir.orchestration.scene_pipeline import SceneInputs, process_scene
inputs = SceneInputs(
asset_id="S2_T43SDV_20240115",
sensor="S2-L2A",
acquired_at=datetime(2024, 1, 15, tzinfo=timezone.utc),
band_paths={
"B02": Path("data/raw/B02.tif"),
"B03": Path("data/raw/B03.tif"),
"B04": Path("data/raw/B04.tif"),
"B08": Path("data/raw/B08.tif"),
"B11": Path("data/raw/B11.tif"),
"B12": Path("data/raw/B12.tif"),
},
dem_path=Path("data/dem/copernicus_glo30.tif"),
)
atm = AtmosphericState(
aot_550nm=0.12, water_vapour_g_cm2=0.8, ozone_du=300.0,
altitude_km=3.5, solar_zenith_deg=55.0, solar_azimuth_deg=160.0,
view_zenith_deg=5.0, view_azimuth_deg=100.0, month=1, day=15,
)
process_scene(inputs, atm)