Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a995f3c
feat(web): React+TS UI for search, config, and job monitoring
scottstanie May 24, 2026
d5533b4
docs(web): screenshots + route-ordering and label-nesting fixes
scottstanie May 24, 2026
c25c296
feat(web): track picker, granule export, full-page config, AOI on top
scottstanie May 24, 2026
ff08d7c
docs(web): repeatable screenshot script + advanced-config shots
scottstanie May 24, 2026
8d04197
feat(web): live step-bar + screenshots from a real OPERA job
scottstanie May 24, 2026
e82f0f1
fix(web): plumb search params into Config tab, stop WS reconnect storm
scottstanie May 25, 2026
4d7aa70
fix(web): reap stale jobs, harden websocket loop, depollute hot paths
scottstanie May 25, 2026
2bcc82d
feat(ifg): add multilooked interferogram workflow with optional unwra…
scottstanie Jun 2, 2026
2c52858
feat(web): workflow-type toggle in ConfigPanel (displacement vs inter…
scottstanie Jun 2, 2026
1ad3be4
feat(web): burst-ID picker, fix Optional[X] dropdowns, fix section he…
scottstanie Jun 2, 2026
a6ae22d
fix(web): fix $ref+siblings rendered as free-form object (Add newKey …
scottstanie Jun 2, 2026
16a510a
fix: websocket subscriber unhashable + OPERA burst ID from filename
scottstanie Jun 2, 2026
503beaa
fix(web): IFG jobs show interferograms dir, not missing dolphin dir
scottstanie Jun 2, 2026
0615124
fix: OPERA date parsing + form defaults + hide unrenderable tuple fields
scottstanie Jun 2, 2026
3d85de3
fix(web): scope getDefaultFormState to visible fields only
scottstanie Jun 2, 2026
8a3eaa8
feat(ifg): add stitch step with bbox crop and optional burst-alignmen…
scottstanie Jun 2, 2026
c06e19b
fix: correct QA metrics pair label and auto-unique work_dir
scottstanie Jun 2, 2026
0d1ab8f
fix(ifg): stitch complex IFG to avoid interpolating across ±π discont…
scottstanie Jun 2, 2026
c431076
fix(ifg): re-download static layers when count is incomplete
scottstanie Jun 2, 2026
58c8682
feat: port burst alignment from dolphin, wire into stitch step
scottstanie Jun 2, 2026
4b73a21
fix: exclude stitched/ and burst_aligned/ from _collect_existing_ifg_…
scottstanie Jun 2, 2026
61256a8
fix(_burst_alignment): strip dates from dir-prefix in _build_output_p…
scottstanie Jun 2, 2026
e97d4cc
refactor(_burst_alignment): use opera_utils._date_format_to_regex for…
scottstanie Jun 2, 2026
9e35aa2
fix: run burst alignment per date-pair, not across all pairs at once
scottstanie Jun 2, 2026
ee9b53f
feat(notebook): interactive JupyterHub notebook for IFG workflow
scottstanie Jun 2, 2026
e429a2f
fix: address code review findings in crossmul and IFG workflow
scottstanie Jun 3, 2026
3041ad5
test: add unit + integration tests for _crossmul and _burst_alignment
scottstanie Jun 3, 2026
d5454e1
fix: forward overwrite flag to _derive_wrapped_phase in _stitch_ifgs
scottstanie Jun 3, 2026
1acd301
no pngs
scottstanie Jun 3, 2026
af398fa
no pngs
scottstanie Jun 3, 2026
c42bcf9
feat(ifg): default run_burst_align to True
scottstanie Jun 3, 2026
e67ecbf
scripts: add burst alignment before/after comparison script
scottstanie Jun 3, 2026
7739877
scripts: add seam-zoom + difference panel to burst alignment comparison
scottstanie Jun 3, 2026
e4cc978
chore: mark package-lock.json as linguist-generated
scottstanie Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# SCM syntax highlighting
pixi.lock linguist-language=YAML linguist-generated=true
src/sweets/web/frontend/package-lock.json linguist-generated=true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,4 @@ cython_debug/
*.egg-info
.DS_Store
*.pdf
docs/ifg_workflow_executed.*
148 changes: 148 additions & 0 deletions docs/ifg-workflow-test-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Running the IFG Workflow: Test Guide

Quick reference for testing the `IfgWorkflow` on OPERA CSLC data.

## 1. Create a config YAML

The minimum config for an OPERA CSLC run:

```yaml
work_dir: /path/to/output/dir
bbox:
- -118.2295 # xmin (west)
- 34.7939 # ymin (south)
- -116.5642 # xmax (east)
- 35.8195 # ymax (north)

search:
kind: opera-cslc
out_dir: data
bbox: [-118.2295, 34.7939, -116.5642, 35.8195]
start: "2025-04-01T00:00:00"
end: "2025-06-01T00:00:00"
relativeOrbit: 64
# Optional: pin burst IDs instead of deriving from bbox each run
burst_ids:
- t064_135521_iw1
- t064_135521_iw2
# ... (use opera_utils.get_burst_ids_for_frame(frame_id) to list them)

network:
max_bandwidth: 2 # nearest-2 network (each date connects to 2 neighbors)

crossmul:
lines_per_block: 512

stitch:
run_stitch: true
crop_to_bbox: true
run_burst_align: true # remove inter-burst seam artifacts
burst_align_degree: 0 # 0 = constant offset per burst; 1 = planar ramp

unwrap:
run_unwrap: false

overwrite: false
```

To get the burst IDs for a known OPERA DISP frame:

```python
from opera_utils import get_burst_ids_for_frame
print(get_burst_ids_for_frame(16941))
```

## 2. Run the workflow

```bash
python -m sweets ifg-run sweets_ifg_config.yaml
```

### Re-running from a specific step

```
Step 1 — DEM/watermask download + CSLC download
Step 2 — Geometry stitching (LOS east/north/incidence angles)
Step 3 — Crossmul (per-burst complex IFGs + coherence)
Step 4 — Stitch (burst alignment + merge_by_date + wrapped phase)
Step 5 — Unwrap (snaphu, if enabled)
```

To skip download and re-run from crossmul onward:

```bash
python -m sweets ifg-run sweets_ifg_config.yaml --starting-step 3
```

To re-run only the stitch step (crossmul outputs already exist):

```bash
python -m sweets ifg-run sweets_ifg_config.yaml --starting-step 4
```

When re-running the stitch step, delete the existing stitched outputs first
so `overwrite: false` does not silently reuse them:

```bash
find <work_dir>/interferograms/stitched -maxdepth 1 -name "*.tif" -delete
```

## 3. Output layout

```
<work_dir>/
dem.tif
watermask.tif
geometry/
los_east.tif los_north.tif incidence_angle.tif ...
data/
<CSLCs>
static_layers/
interferograms/
t064_135521_iw1/
20250403_20250415/
20250403_20250415_ifg.tif # complex64 crossmul output
20250403_20250415_coherence.tif
...
stitched/
20250403_20250415_ifg.tif # burst-aligned complex
20250403_20250415_coherence.tif
20250403_20250415_wrapped_phase.tif # np.angle(ifg), derived after stitch
burst_aligned/
t064_135521_iw1__20250403_20250415_ifg.aligned.tif
...
```

Key design decisions:
- Crossmul saves **complex64** `_ifg.tif` (not wrapped phase) so that
`merge_by_date` interpolates real+imag independently, avoiding ±π
discontinuities at burst seams.
- Wrapped phase is derived with `np.angle()` **after** stitching.
- Burst alignment runs **per date pair** (27 bursts each), not across all
pairs at once — passing all pairs together caused same-geography bursts
from different epochs to be compared as "overlapping", producing garbage
corrections.

## 4. Plot and QA

```python
from sweets.plotting import plot_ifg_pairs, save_ifg_qa_metrics
from pathlib import Path

stitch_dir = Path("<work_dir>/interferograms/stitched")

# Thumbnail grid of wrapped phase + coherence
plot_ifg_pairs(stitch_dir, max_pairs=13, output_path="ifgs.png")

# Per-pair coherence metrics + JSON sidecar
save_ifg_qa_metrics(stitch_dir, output_path="qa.png")
```

## 5. Test dataset (frame 16941)

- **Frame**: OPERA DISP frame 16941, T064 ascending, S California / Mojave
- **AOI**: `POLYGON((-118.2295 34.7939,-116.5642 34.7939,-116.5642 35.8195,-118.2295 35.8195,-118.2295 34.7939))`
- **Dates**: 2025-04-01 to 2025-06-01 (13 acquisitions, 6-day repeat)
- **Bursts**: 27 (9 frames × 3 IW subswaths)
- **Data on**: `/Volumes/WD_BLACK_SN7100_4TB/Documents/Learning/sweets-testing/sweets-f16941/`
- **Config**: `sweets_ifg_config.yaml` in the same directory
Loading
Loading