Tutorial: build a consistent-mode database¶
This walkthrough produces the consistent-GSLC (consistent-mode) database for
NISAR frames over North America, from scratch. Anyone with the two inputs below
can follow it end to end. It mirrors the make flow used by burst_db for
DISP-S1.
For the why behind each step, read Background: how consistent mode works.
What you'll produce¶
opera-nisar-disp-frame-to-bounds-<date>.json(.zip) # frame bounding boxes
opera-nisar-disp-frames.gpkg # NA frames + frame_idx (side output)
gslc_catalog.csv # parsed GSLC file list
opera-nisar-disp-consistent-gslc-<date>.json(.zip) # the consistent-mode database
opera-nisar-disp-reference-dates-<date>.json(.zip) # reference-epoch resets
opera-nisar-disp-consistent-gslc-with-processing-mode-<date>.json(.zip)
Prerequisites¶
nisar_dbinstalled and thenisar-dbCLI on yourPATH(see Install).-
Two inputs:
Input What it is How to get it NISAR_TrackFrame_L_YYYYMMDD.gpkgGlobal NISAR track/frame GeoPackage nisar-db download-frame-db(public CMR granuleG3817504902-ASF)gslc_files.txtOne NISAR GSLC S3 path / granule ID per line List your GSLC bucket, or nisar-db search --output-csv
Fetching the TrackFrame database
nisar-db download-frame-db needs only Earthdata Login credentials in
~/.netrc, and reuses the file if it is already there. Step 1 fetches it
on its own when --nisar-gpkg is omitted, so you can skip this if the
GeoPackage is the only input you are missing.
Getting a GSLC file list
Any newline-delimited list of GSLC names works — S3 URIs, local paths, or bare granule IDs. For example, from a bucket scan:
Work in a clean output directory:
Step 1 — Filter frames to North America¶
Build the frame-to-bound mapping. Its side output,
opera-nisar-disp-frames.gpkg, is the filtered set of NA frames carrying the
frame_idx key that every later step uses.
nisar-db create-frame-to-bound \
--nisar-gpkg NISAR_TrackFrame_L_YYYYMMDD.gpkg \
--output opera-nisar-disp-frame-to-bounds.json
Drop --nisar-gpkg to download the TrackFrame database first (into --gpkg-dir,
the current directory by default):
Produces:
opera-nisar-disp-frame-to-bounds.json(+.json.zip)opera-nisar-disp-frames.gpkg← needed by Step 3
Step 2 — Parse the GSLC file list into a catalog¶
Turn the raw file list into a structured CSV with the mode, coverage,
track, frame, and sensing_time columns the selection needs. Restrict to
North America with --na-only.
nisar-db create-gslc-csv \
--input gslc_files.txt \
--output gslc_catalog.csv \
--na-only \
--nisar-gpkg NISAR_TrackFrame_L_YYYYMMDD.gpkg
The command prints a mode_family and coverage summary so you can sanity-check
the distribution before selecting. Produces gslc_catalog.csv (and a
*_frame_summary.csv).
Step 3 — Select the consistent mode per frame¶
Combine the catalog (Step 2) with the filtered frames GPKG (Step 1). This applies the selection logic: dominant mode → majority coverage → one acquisition per date.
nisar-db create-consistent \
--catalog gslc_catalog.csv \
--nisar-gpkg opera-nisar-disp-frames.gpkg \
--output opera-nisar-disp-consistent-gslc.json
Produces opera-nisar-disp-consistent-gslc.json (+ .json.zip), keyed by
frame_idx with common_mode, common_coverage, and sensing_time_list for
each frame. This is the consistent-mode database.
Optional: apply a blackout filter¶
To remove seasonally unusable acquisitions (e.g. snow winters), pass a
blackout-dates JSON. First build it — the
snow_analysis.geojson input comes from
Derive blackout dates from snow cover:
nisar-db create-blackout-dates \
--input-file snow_analysis.geojson \
--output-file nisar-blackout-dates.json
Then re-run Step 3 with --blackout-file:
nisar-db create-consistent \
--catalog gslc_catalog.csv \
--nisar-gpkg opera-nisar-disp-frames.gpkg \
--blackout-file nisar-blackout-dates.json \
--output opera-nisar-disp-consistent-gslc-no-snow.json
As in burst_db, keep both the blackout-applied and the unfiltered database:
the filtered one is operational, the unfiltered one is the full record.
Step 4 — Reference (reset) dates¶
Add per-frame reference resets so the processor caps interferogram baselines (see Reference dates). Passing the blackout file anchors each frame on a snow-free month:
nisar-db create-reference-dates \
--consistent-json opera-nisar-disp-consistent-gslc.json \
--blackout-file nisar-blackout-dates.json \
--output opera-nisar-disp-reference-dates.json
Without --blackout-file, the epochs instead follow each frame's own
acquisition history — a new one every --interval years, but only once
--min-acquisitions acquisitions have accumulated.
Step 5 — Processing-mode labels¶
Mark which acquisitions form complete batches the processor can run now (see Processing modes):
nisar-db label-processing-mode \
--consistent-json opera-nisar-disp-consistent-gslc.json \
--previous-json opera-nisar-disp-consistent-gslc-2026-04-25.json \
--output opera-nisar-disp-consistent-gslc-with-processing-mode.json
sensing_time_list becomes a {sensing_time: label} map of historical_NN,
forward_NN, and no_run. --previous-json is optional; it adds
metadata.frames_with_changed_mode, the frames whose winning
(common_mode, common_coverage) flipped since the last release and whose
existing stack therefore cannot be reused.
Do it all with make¶
The repository Makefile chains every step above (given a catalog CSV, a
NISAR_TrackFrame_L_*.gpkg, and a snow-analysis GeoJSON in the current
directory), mirroring burst_db's release build:
# from a directory containing the .gpkg, gslc_catalog*.csv and snow analysis
make -f /path/to/nisar_db/Makefile
That produces the full release asset set: frame-to-bounds, the simplified frame
geometries, blackout dates, both consistent-GSLC variants, the processing-mode
labelled version, and the reference dates. make help lists the parameters
(NISAR_GPKG, GSLC_CATALOG, SNOW_GEOJSON, PREVIOUS_CONSISTENT) and the
clean / cleanall targets.
Do it all from an S3 bucket¶
make starts from a GSLC file list you already have. To go all the way from a
bucket instead, scripts/prepare_viewer_inputs.py chains Steps 1-3 and sources
the granules by scanning S3:
python scripts/prepare_viewer_inputs.py \
--nisar-gpkg NISAR_TrackFrame_L_YYYYMMDD.gpkg \
--outdir notebooks --profile saml-pub
--nisar-gpkg is optional here too; omit it and the TrackFrame database is
downloaded into --outdir.
It writes opera-nisar-disp-frames.gpkg, gslc_catalog.duckdb,
gslc_catalog.csv, and opera-nisar-disp-consistent-gslc-<YYYYMMDD>.json —
the inputs the frame viewer consumes. Unlike the file-list
route, the DuckDB catalog carries a production_datetime column (the S3 object's
LastModified, since granule names hold no production time).
The S3 scan takes minutes; --skip-frames / --skip-catalog reuse existing
artifacts while iterating on the selection step.
Verify the output¶
import json, zipfile
with zipfile.ZipFile("opera-nisar-disp-consistent-gslc.json.zip") as z:
data = json.loads(z.read(z.namelist()[0]))
frames = data["data"]
print(f"{len(frames)} frames")
example = next(iter(frames.values()))
print(example["common_mode"], example["common_coverage"],
len(example["sensing_time_list"]), "acquisitions")
You should see one entry per North America frame, each with a single
(common_mode, common_coverage) and a sorted sensing_time_list of one epoch
per calendar date — exactly the stack DISP-NISAR will process.
Recap¶
flowchart TD
G["NISAR_TrackFrame_L_*.gpkg"] -->|Step 1| FTB["create-frame-to-bound<br/>→ opera-nisar-disp-frames.gpkg"]
L["gslc_files.txt"] -->|Step 2| CAT["create-gslc-csv<br/>→ gslc_catalog.csv"]
FTB -->|Step 3| CON["create-consistent"]
CAT -->|Step 3| CON
BL["create-blackout-dates"] --> CON
CON --> OUT["opera-nisar-disp-consistent-gslc-*.json"]
OUT -->|Step 4| REF["create-reference-dates<br/>→ reference-dates JSON"]
BL -.-> REF
OUT -->|Step 5| PM["label-processing-mode<br/>→ …-with-processing-mode-*.json"]