chore: initialize insar management system v2
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shelve
|
||||
import shutil
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
def choose_path(scene: Dict[str, Any], primary_key: str, fallback_key: str) -> str:
|
||||
primary = scene.get(primary_key)
|
||||
fallback = scene.get(fallback_key)
|
||||
for candidate in (primary, fallback):
|
||||
if candidate and Path(candidate).exists():
|
||||
return str(Path(candidate))
|
||||
raise FileNotFoundError(
|
||||
f"Neither {primary_key} nor {fallback_key} exists for scene {scene.get('date') or scene.get('imaging_date')}"
|
||||
)
|
||||
|
||||
|
||||
def load_manifest(path: Path) -> Dict[str, Any]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def remove_existing_shelve(stem: Path) -> None:
|
||||
for suffix in ("", ".db", ".dat", ".dir", ".bak"):
|
||||
candidate = Path(str(stem) + suffix)
|
||||
if candidate.exists():
|
||||
if candidate.is_dir():
|
||||
shutil.rmtree(candidate)
|
||||
else:
|
||||
candidate.unlink()
|
||||
|
||||
|
||||
def shelve_stem_exists(stem: Path) -> bool:
|
||||
for suffix in ("", ".db", ".dat", ".dir", ".bak"):
|
||||
if Path(str(stem) + suffix).exists():
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@dataclass
|
||||
class SceneResult:
|
||||
date: str
|
||||
output_dir: str
|
||||
slc_path: str
|
||||
data_shelve: str
|
||||
status: str
|
||||
bytes_written: Optional[int]
|
||||
started_at_utc: str
|
||||
ended_at_utc: str
|
||||
|
||||
|
||||
def materialize_one_scene(
|
||||
scene: Dict[str, Any],
|
||||
force: bool,
|
||||
) -> SceneResult:
|
||||
import isce
|
||||
from isceobj.Sensor import createSensor
|
||||
|
||||
date = str(scene["date"])
|
||||
output_dir = Path(scene["target_dir_wsl"])
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
slc_path = Path(scene["expected_slc_wsl"])
|
||||
slc_xml_path = Path(scene["expected_slc_xml_wsl"])
|
||||
data_shelve = Path(scene["expected_data_shelve_wsl"])
|
||||
|
||||
tiff_path = choose_path(scene, "source_tiff_wsl", "source_tiff_windows")
|
||||
orbit_xml = choose_path(scene, "orbit_xml_wsl", "orbit_xml_windows")
|
||||
|
||||
if force:
|
||||
for path in (slc_path, slc_xml_path, Path(str(slc_path) + ".vrt")):
|
||||
if path.exists():
|
||||
path.unlink()
|
||||
remove_existing_shelve(data_shelve)
|
||||
|
||||
if slc_path.exists() and slc_xml_path.exists() and shelve_stem_exists(data_shelve):
|
||||
now = datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
|
||||
return SceneResult(
|
||||
date=date,
|
||||
output_dir=str(output_dir),
|
||||
slc_path=str(slc_path),
|
||||
data_shelve=str(data_shelve),
|
||||
status="skipped_existing",
|
||||
bytes_written=slc_path.stat().st_size,
|
||||
started_at_utc=now,
|
||||
ended_at_utc=now,
|
||||
)
|
||||
|
||||
started_at = datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
|
||||
|
||||
sensor = createSensor("LUTAN1")
|
||||
sensor.configure()
|
||||
sensor.tiff = tiff_path
|
||||
sensor.orbitFile = orbit_xml
|
||||
sensor.output = str(slc_path)
|
||||
sensor.extractImage()
|
||||
sensor.extractDoppler()
|
||||
sensor.frame.getImage().renderHdr()
|
||||
|
||||
remove_existing_shelve(data_shelve)
|
||||
with shelve.open(str(data_shelve)) as db:
|
||||
db["frame"] = sensor.frame
|
||||
|
||||
ended_at = datetime.utcnow().replace(microsecond=0).isoformat() + "Z"
|
||||
report = {
|
||||
"date": date,
|
||||
"source_tiff": tiff_path,
|
||||
"orbit_xml": orbit_xml,
|
||||
"output_slc": str(slc_path),
|
||||
"output_slc_xml": str(slc_xml_path),
|
||||
"data_shelve": str(data_shelve),
|
||||
"frame_lines": sensor.frame.getNumberOfLines(),
|
||||
"frame_samples": sensor.frame.getNumberOfSamples(),
|
||||
"started_at_utc": started_at,
|
||||
"ended_at_utc": ended_at,
|
||||
}
|
||||
(output_dir / "materialization_report.json").write_text(
|
||||
json.dumps(report, indent=2, ensure_ascii=False),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
return SceneResult(
|
||||
date=date,
|
||||
output_dir=str(output_dir),
|
||||
slc_path=str(slc_path),
|
||||
data_shelve=str(data_shelve),
|
||||
status="materialized",
|
||||
bytes_written=slc_path.stat().st_size if slc_path.exists() else None,
|
||||
started_at_utc=started_at,
|
||||
ended_at_utc=ended_at,
|
||||
)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Materialize LT-1 stack acquisitions into stripmapStack-ready SLC/date directories."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--stack-manifest",
|
||||
required=True,
|
||||
help="Path to stack_input_manifest.json generated by build_lt1_stack_prep.py",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dates",
|
||||
nargs="+",
|
||||
default=None,
|
||||
help="Optional subset of acquisition dates to materialize, for example 20250510 20250705",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Overwrite existing .slc/.xml/data outputs for the selected dates.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
manifest_path = Path(args.stack_manifest)
|
||||
if not manifest_path.exists():
|
||||
raise FileNotFoundError(f"Stack manifest not found: {manifest_path}")
|
||||
|
||||
manifest = load_manifest(manifest_path)
|
||||
scenes = list(manifest.get("scenes", []))
|
||||
if not scenes:
|
||||
raise ValueError(f"No scenes found in stack manifest: {manifest_path}")
|
||||
|
||||
selected_dates = set(args.dates or [])
|
||||
if selected_dates:
|
||||
scenes = [scene for scene in scenes if str(scene["date"]) in selected_dates]
|
||||
if not scenes:
|
||||
raise ValueError(f"No matching dates found in manifest for selection: {sorted(selected_dates)}")
|
||||
|
||||
results: List[SceneResult] = []
|
||||
for scene in scenes:
|
||||
print(f"Materializing {scene['date']} -> {scene['target_dir_wsl']}")
|
||||
result = materialize_one_scene(scene, force=args.force)
|
||||
results.append(result)
|
||||
print(f" status={result.status} slc={result.slc_path}")
|
||||
|
||||
report = {
|
||||
"generated_at_utc": datetime.utcnow().replace(microsecond=0).isoformat() + "Z",
|
||||
"stack_manifest": str(manifest_path),
|
||||
"results": [result.__dict__ for result in results],
|
||||
}
|
||||
|
||||
report_path = manifest_path.parent / "materialization_summary.json"
|
||||
report_path.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
print(f"Summary: {report_path}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user