feat(isce2): harden managed production flow

- add one-time base DEM preparation utility and prepared-first DEM resolution

- support geocode resume/full-geocode and guard large unprepared DEMs

- repair missing completion files during in-place ISCE2 publish rebuild

- add ISCE2 stabilization update log
This commit is contained in:
2026-04-27 07:52:20 +08:00
parent 1e44101eb2
commit 5290b071b3
10 changed files with 995 additions and 45 deletions
+33 -2
View File
@@ -32,6 +32,7 @@ ORBIT_MARGIN_MAX_SEC = 120.0
TARGET_GRID_SIZE_MIN_M = 5
TARGET_GRID_SIZE_MAX_M = 100
RERUN_MODE_UNFINISHED_ONLY = "unfinished_only"
RESUME_STAGE_CHOICES = {"", "unwrap", "geocode", "export"}
def _read_env(name: str, default: str = "") -> str:
@@ -70,6 +71,16 @@ def _normalize_optional_path(value: Any) -> str:
return os.path.normpath(os.path.abspath(text))
def _prefer_prepared_dem_variant(path: str) -> str:
normalized = _normalize_optional_path(path)
if not normalized or normalized.lower().endswith(".wgs84"):
return normalized
prepared = normalized + ".wgs84"
if os.path.isfile(prepared) and os.path.isfile(prepared + ".xml"):
return prepared
return normalized
def _load_json_file(path: str) -> Dict[str, Any]:
try:
with open(path, "r", encoding="utf-8") as fp:
@@ -146,11 +157,11 @@ class Isce2Engine(DinsarEngine):
@property
def _dem_path(self) -> str:
explicit = _read_env("ISCE2_DEM_PATH", "")
explicit = _prefer_prepared_dem_variant(_read_env("ISCE2_DEM_PATH", ""))
if explicit:
return explicit
base = _read_env("IDL_DINSAR_DEM_BASE_FILE", "")
return f"{base}.wgs84" if base else ""
return _prefer_prepared_dem_variant(base) if base else ""
@property
def _orbit_pool_isce2(self) -> str:
@@ -320,6 +331,18 @@ class Isce2Engine(DinsarEngine):
)
normalized["orbit_margin_sec"] = orbit_margin
if "full_geocode" in normalized:
normalized["full_geocode"] = bool(normalized["full_geocode"])
if "resume_from" in normalized and normalized["resume_from"] is not None:
resume_from = str(normalized["resume_from"]).strip().lower()
if resume_from not in RESUME_STAGE_CHOICES:
raise ValueError("resume_from must be one of: unwrap, geocode, export")
normalized["resume_from"] = resume_from
if bool(normalized.get("force")) and str(normalized.get("resume_from") or "").strip():
raise ValueError("force cannot be used together with resume_from")
return normalized
# ------------------------------------------------------------------
@@ -507,6 +530,8 @@ class Isce2Engine(DinsarEngine):
bbox_margin: Any,
wavelength: Any,
orbit_margin_sec: Any,
full_geocode: bool,
resume_from: str,
pair_meta: Dict[str, Any],
) -> Dict[str, Any]:
return {
@@ -541,6 +566,8 @@ class Isce2Engine(DinsarEngine):
"bbox_margin": bbox_margin,
"wavelength": wavelength,
"orbit_margin_sec": orbit_margin_sec,
"full_geocode": bool(full_geocode),
"resume_from": str(resume_from or "").strip(),
},
"pair_meta": dict(pair_meta or {}),
}
@@ -650,6 +677,8 @@ class Isce2Engine(DinsarEngine):
bbox_margin = extra.get("bbox_margin")
wavelength = LT1_FIXED_WAVELENGTH
orbit_margin_sec = extra.get("orbit_margin_sec")
full_geocode = bool(extra.get("full_geocode"))
resume_from = str(extra.get("resume_from") or "").strip().lower()
wsl_isce2_pool = ""
if self._orbit_pool_isce2:
@@ -792,6 +821,8 @@ class Isce2Engine(DinsarEngine):
bbox_margin=bbox_margin,
wavelength=wavelength,
orbit_margin_sec=orbit_margin_sec,
full_geocode=full_geocode,
resume_from=resume_from,
pair_meta=pair_meta,
)
broker_result = wsl_broker.run_manifest(