Software user manual#
Project: Sentinel-2 MSI Synthetic Raw Data Generator (s2_msi_raw_generator) · DRD: ECSS-E-ST-40C Rev.1 (SUM). The E2ES
runs a S2B L1B backward through the exact inverse of the operational L0→L1B
radiometric chain (invert offset, relative-response/PRNU, dark, un-bin, SWIR re-stage, defective,
crosstalk, on-board-eq; MTF-deconvolution is OFF, so PSF and noise are not re-applied) to
reconstruct L1A → L0plus (CCSDS-122 ISP) → Synthetic L0. Success is the Synthetic L0 matching the reference
ESA reference ESA L0 img (10/20 m bands ≤~4 DN). It also provides cal-DB derivation tooling.
1. Installation#
Python ≥ 3.11. The runtime needs only numpy and zarr — no EOPF CPM, no external processor.
pip install -e ".[read]" # numpy + zarr (reader + L0 writer)
# or for development (adds pytest):
pip install -e ".[dev]"
2. Quick start#
pytest # full suite (S2 L1B/eopf cases skip without env)
The packagedS2 PSF matrices live under s2_msi_raw_generator/data/psf/; no external data is needed for the unit
tests. S2 L1B runs need EOPF L1A/L1B .zarr and the operational GIPP folder (see §4).
3. The pipeline#
All operations run through the single driver scripts/run_pipeline.py: a phase-structured,
idempotent pipeline over one data-store root (inputs/ caldb/ l0/ l1a_prime/ l1b/ quicklook/ figures/ report/; $OUTPUT_DIR). Copy .env.example to .env and set the five required path
variables before running the driver. Nominal L0s land under l0/;
every calibration product (the S02MSIDCA/S02MSISCA campaign L0s + the cal-DB ADFs) under
caldb/. Every product file name follows the EOPF PSFD §3 convention
(s2_msi_raw_generator.naming, REQ-FUNC-091).
Phase set |
Phases |
Needs |
|---|---|---|
Nominal mode (default; REQ-FUNC-093) |
|
numpy+zarr; |
Calibration mode ( |
|
numpy+zarr only |
On demand |
|
numpy+zarr only |
Data-store sync |
|
numpy+stdlib; DB = the ipf/data-store registry |
# copy and edit paths once
cp .env.example .env
# pull the shared data-store into the local working copy ($OUTPUT_DIR)
S2_PHASES=fetch-store python scripts/run_pipeline.py
# S2 L1B chain, all phases (fetch → package → decode → validate → report)
python scripts/run_pipeline.py
# re-run individual phases (idempotent; JSON per phase under <store>/report/)
S2_PHASES=preflight,package,ground-decode S2_LINES=4096 python scripts/run_pipeline.py
# calibration campaign: dark + sun-diffuser acquisitions as downlink Synthetic L0 products
# (S02MSIDCA / S02MSISCA, compressed ISPs) + the Option-Y cal-DB — everything → <store>/caldb/
python scripts/run_pipeline.py calibration
# standalone Option-Y cal-DB (same numbers as the campaign derivation — deterministic seeds)
S2_PHASES=build-caldb python scripts/run_pipeline.py
# operational per-detector PRNU (+ dark from a dark-calibration granule) → .npz for BandADF.from_product
S2_PHASES=derive-adf S2_L1A_INPUT=<L1A.zarr> [S2_DARK=<dark.zarr>] python scripts/run_pipeline.py
Run the gated tests on S2 data:
S2_GIPP_DIR=<GIPP_dir> S2_L1A_INPUT=<L1A.zarr> pytest tests/ -q
4. CLI + configuration reference#
run_pipeline.py [nominal|calibration] — the CLI takes only the mode (default
nominal). Copy .env.example to .env and set paths; optional tuning uses S2_* variables:
Variable |
Required |
Meaning (consuming phases) |
|---|---|---|
|
yes |
S2 L1B zarr (reverse-l1b, figures) |
|
yes |
ESA L0 zarr (validate-reverse, import-l0) |
|
yes |
|
|
yes |
|
|
yes |
pipeline store root ( |
|
no |
mode’s default set — comma phase list |
|
|
first-N-lines window |
|
all 13 |
band list |
|
|
RNG seed (cal-acquire, build-caldb) |
|
|
campaign / cal-DB detector width |
|
|
calibration lines per frame |
|
all cores |
parallel workers |
|
— |
L1A path override (preflight, derive-adf) |
|
— |
dark-calibration granule (derive-adf) |
|
|
publish-store coordinates |
Phases are idempotent and re-runnable individually; each writes its JSON under
<store>/report/ and the final report phase assembles e2e_report.md. See
docs/vv/s2_l1b_e2e.md for the S2 L1B chain acceptance criteria.
5. Outputs#
Synthetic L0 RAW product — EOPF L0 Zarr (zarr v2):
measurements/d{DD}/b{BB}/band{N}(uint16, 156 arrays),quality/d{DD}/b{BB}/mask(uint8), optionalconditions/anc_data/s{APID}/ISP telemetry, and root STAC +sensor_configuration+processing_history.adf_provenancemetadata. See the ICD (icd.md).Open-container L0 + cal-DB + L1B — the processor handoff products (PSFD
_OCsuffix; ADF setnuc/dark/radiometric/spectral[/noise].zarr+ calibration acquisitionsflatfield.zarr,dark.zarr:/frame; PSFD-named L1B reflectance).V&V evidence — per-phase JSONs +
e2e_report.mdunder<store>/report/. The primary acceptance evidence is thevalidatephase: Synthetic L0 vs the reference ESA L0img(10/20 m bands ≤~4 DN).radiometric-vvis a secondary self-consistency sanity check of the inverse radiometric operators.Images —
quicklook/PNGs (the Synthetic-L0 quicklook).