chore: sync repository with current workspace state
This commit is contained in:
@@ -177,9 +177,26 @@ PYINT_DEM_MODE=local_fabdem
|
||||
PYINT_FABDEM_ROOT=
|
||||
# When PYINT_DEM_MODE=prepared_file, point this to the same prepared WGS84 DEM.
|
||||
PYINT_PREPARED_DEM_PATH=
|
||||
# 0 means do not derive looks from a target output grid.
|
||||
PYINT_DEFAULT_TARGET_GRID_SIZE_M=0
|
||||
# Source DEM resolution recorded in PyINT/Gamma run metadata.
|
||||
PYINT_DEM_RESOLUTION_M=30.0
|
||||
PYINT_OPENTOPO_DEM_TYPE=SRTMGL1
|
||||
PYINT_OPENTOPO_API_KEY=
|
||||
PYINT_DEM_STRICT=true
|
||||
# Gamma unwrap support and quality support reporting are intentionally separate.
|
||||
PYINT_UNWRAP_COH_THRESHOLD=0.05
|
||||
PYINT_PRODUCT_COH_THRESHOLD=0.20
|
||||
PYINT_GAMMA_NODATA_VALUE=-9999.0
|
||||
PYINT_GEO_INTERP=1
|
||||
PYINT_ATMCOR_ENABLED=false
|
||||
PYINT_ATMCOR_USE_FOR_DISP=false
|
||||
PYINT_REFLATTEN_ENABLED=true
|
||||
PYINT_REFLATTEN_MODEL=plane
|
||||
PYINT_REFLATTEN_COH_THRESHOLD=0.70
|
||||
PYINT_REFLATTEN_FALLBACK_COH_THRESHOLD=0.20
|
||||
PYINT_REFLATTEN_RANGE_STEP=32
|
||||
PYINT_REFLATTEN_AZIMUTH_STEP=32
|
||||
PYINT_ORBIT_POLICY=require_txt
|
||||
PYINT_ORBIT_POOL_TXT=D:\orbit_pools\envi
|
||||
PYINT_RECORD_INPUT_ASSETS=true
|
||||
|
||||
@@ -265,9 +265,26 @@ class Settings(BaseSettings):
|
||||
PYINT_DEM_MODE: str = "local_fabdem"
|
||||
PYINT_FABDEM_ROOT: str = ""
|
||||
PYINT_PREPARED_DEM_PATH: str = ""
|
||||
PYINT_DEM_RESOLUTION_M: float = 30.0
|
||||
PYINT_OPENTOPO_DEM_TYPE: str = "SRTMGL1"
|
||||
PYINT_OPENTOPO_API_KEY: str = ""
|
||||
PYINT_DEM_STRICT: bool = True
|
||||
PYINT_UNWRAP_COH_THRESHOLD: float = 0.05
|
||||
PYINT_PRODUCT_COH_THRESHOLD: float = 0.20
|
||||
PYINT_REFERENCE_MODE: str = "none"
|
||||
PYINT_REFERENCE_COH_THRESHOLD: float = 0.30
|
||||
PYINT_DERAMP_MODE: str = "none"
|
||||
PYINT_DERAMP_COH_THRESHOLD: float = 0.30
|
||||
PYINT_GAMMA_NODATA_VALUE: float = -9999.0
|
||||
PYINT_GEO_INTERP: str = "1"
|
||||
PYINT_ATMCOR_ENABLED: bool = False
|
||||
PYINT_ATMCOR_USE_FOR_DISP: bool = False
|
||||
PYINT_REFLATTEN_ENABLED: bool = True
|
||||
PYINT_REFLATTEN_MODEL: str = "plane"
|
||||
PYINT_REFLATTEN_COH_THRESHOLD: float = 0.70
|
||||
PYINT_REFLATTEN_FALLBACK_COH_THRESHOLD: float = 0.20
|
||||
PYINT_REFLATTEN_RANGE_STEP: int = 32
|
||||
PYINT_REFLATTEN_AZIMUTH_STEP: int = 32
|
||||
PYINT_ORBIT_POLICY: str = "require_txt"
|
||||
PYINT_ORBIT_POOL_TXT: str = ""
|
||||
PYINT_RECORD_INPUT_ASSETS: bool = True
|
||||
@@ -491,6 +508,70 @@ class Settings(BaseSettings):
|
||||
if pyint_dem_mode not in {"local_fabdem", "opentopo", "prepared_file"}:
|
||||
pyint_dem_mode = "local_fabdem"
|
||||
object.__setattr__(self, "PYINT_DEM_MODE", pyint_dem_mode)
|
||||
object.__setattr__(self, "PYINT_DEM_RESOLUTION_M", max(0.1, float(self.PYINT_DEM_RESOLUTION_M or 30.0)))
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_UNWRAP_COH_THRESHOLD",
|
||||
min(1.0, max(0.0, float(self.PYINT_UNWRAP_COH_THRESHOLD or 0.05))),
|
||||
)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_PRODUCT_COH_THRESHOLD",
|
||||
min(1.0, max(0.0, float(self.PYINT_PRODUCT_COH_THRESHOLD or 0.20))),
|
||||
)
|
||||
pyint_reference_mode = str(self.PYINT_REFERENCE_MODE or "none").strip().lower() or "none"
|
||||
if pyint_reference_mode not in {"none", "coh_median"}:
|
||||
pyint_reference_mode = "none"
|
||||
object.__setattr__(self, "PYINT_REFERENCE_MODE", pyint_reference_mode)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_REFERENCE_COH_THRESHOLD",
|
||||
min(1.0, max(0.0, float(self.PYINT_REFERENCE_COH_THRESHOLD or 0.30))),
|
||||
)
|
||||
pyint_deramp_mode = str(self.PYINT_DERAMP_MODE or "none").strip().lower() or "none"
|
||||
if pyint_deramp_mode not in {"none", "plane"}:
|
||||
pyint_deramp_mode = "none"
|
||||
object.__setattr__(self, "PYINT_DERAMP_MODE", pyint_deramp_mode)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_DERAMP_COH_THRESHOLD",
|
||||
min(1.0, max(0.0, float(self.PYINT_DERAMP_COH_THRESHOLD or 0.30))),
|
||||
)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_GAMMA_NODATA_VALUE",
|
||||
float(self.PYINT_GAMMA_NODATA_VALUE if self.PYINT_GAMMA_NODATA_VALUE is not None else -9999.0),
|
||||
)
|
||||
pyint_geo_interp = str(self.PYINT_GEO_INTERP or "0").strip()
|
||||
if pyint_geo_interp not in {"0", "1"}:
|
||||
pyint_geo_interp = "1"
|
||||
object.__setattr__(self, "PYINT_GEO_INTERP", pyint_geo_interp)
|
||||
pyint_reflatten_model = str(self.PYINT_REFLATTEN_MODEL or "plane").strip().lower() or "plane"
|
||||
if pyint_reflatten_model in {"linear"}:
|
||||
pyint_reflatten_model = "plane"
|
||||
if pyint_reflatten_model not in {"plane", "quadratic"}:
|
||||
pyint_reflatten_model = "plane"
|
||||
object.__setattr__(self, "PYINT_REFLATTEN_MODEL", pyint_reflatten_model)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_REFLATTEN_COH_THRESHOLD",
|
||||
min(1.0, max(0.0, float(self.PYINT_REFLATTEN_COH_THRESHOLD or 0.70))),
|
||||
)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_REFLATTEN_FALLBACK_COH_THRESHOLD",
|
||||
min(1.0, max(0.0, float(self.PYINT_REFLATTEN_FALLBACK_COH_THRESHOLD or 0.20))),
|
||||
)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_REFLATTEN_RANGE_STEP",
|
||||
max(1, int(self.PYINT_REFLATTEN_RANGE_STEP or 32)),
|
||||
)
|
||||
object.__setattr__(
|
||||
self,
|
||||
"PYINT_REFLATTEN_AZIMUTH_STEP",
|
||||
max(1, int(self.PYINT_REFLATTEN_AZIMUTH_STEP or 32)),
|
||||
)
|
||||
if not self.PYINT_OPENTOPO_DEM_TYPE:
|
||||
object.__setattr__(self, "PYINT_OPENTOPO_DEM_TYPE", "SRTMGL1")
|
||||
pyint_orbit_policy = str(self.PYINT_ORBIT_POLICY or "require_txt").strip().lower() or "require_txt"
|
||||
|
||||
@@ -8,7 +8,9 @@ from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from ..config import get_env_text, read_bool_env, settings
|
||||
from ..services.dinsar_completion_files import repair_managed_completion_files
|
||||
from ..services.dinsar_naming import write_run_metadata
|
||||
from ..services.isce2_result_validator import validate_isce2_result_files
|
||||
from ..services.pyint_input_assets_service import (
|
||||
get_pyint_dem_summary,
|
||||
get_pyint_orbit_context,
|
||||
@@ -17,11 +19,33 @@ from ..services.pyint_input_assets_service import (
|
||||
)
|
||||
from ..services.pyint_service import (
|
||||
DEFAULT_AZIMUTH_LOOKS,
|
||||
DEFAULT_DEM_RESOLUTION_M,
|
||||
DEFAULT_DERAMP_COH_THRESHOLD,
|
||||
DEFAULT_DERAMP_MODE,
|
||||
DEFAULT_ATMCOR_ENABLED,
|
||||
DEFAULT_ATMCOR_USE_FOR_DISP,
|
||||
DEFAULT_GEO_INTERP,
|
||||
DEFAULT_PARALLEL_WORKERS,
|
||||
DEFAULT_PRODUCT_COH_THRESHOLD,
|
||||
DEFAULT_RANGE_LOOKS,
|
||||
DEFAULT_REFLATTEN_AZIMUTH_STEP,
|
||||
DEFAULT_REFLATTEN_COH_THRESHOLD,
|
||||
DEFAULT_REFLATTEN_ENABLED,
|
||||
DEFAULT_REFLATTEN_FALLBACK_COH_THRESHOLD,
|
||||
DEFAULT_REFLATTEN_MODEL,
|
||||
DEFAULT_REFLATTEN_RANGE_STEP,
|
||||
DEFAULT_REFERENCE_COH_THRESHOLD,
|
||||
DEFAULT_REFERENCE_MODE,
|
||||
DEFAULT_TARGET_GRID_SIZE_M,
|
||||
DEFAULT_UNWRAP_COH_THRESHOLD,
|
||||
MAX_LOOKS,
|
||||
MAX_PARALLEL_WORKERS,
|
||||
REFLATTEN_MODEL_CHOICES,
|
||||
TARGET_GRID_SIZE_MAX_M,
|
||||
TARGET_GRID_SIZE_MIN_M,
|
||||
build_project_name,
|
||||
calculate_dem_oversampling,
|
||||
calculate_looks_from_task_dir,
|
||||
check_pyint_environment,
|
||||
infer_scene_date_from_archives,
|
||||
infer_task_identity,
|
||||
@@ -31,10 +55,11 @@ from ..services.pyint_service import (
|
||||
to_wsl_path,
|
||||
validate_pyint_root_dir,
|
||||
)
|
||||
from ..services.wsl_service import run_wsl_command
|
||||
from ..services.wsl_service import run_wsl_command_stream
|
||||
from .base import DinsarEngine, EngineAvailability, EngineProfile, RunRequest, RunResult
|
||||
|
||||
RERUN_MODE_UNFINISHED_ONLY = "unfinished_only"
|
||||
DEFAULT_COHERENCE_MASK_THRESHOLD = DEFAULT_PRODUCT_COH_THRESHOLD
|
||||
|
||||
|
||||
def _read_env(name: str, default: str = "") -> str:
|
||||
@@ -121,6 +146,85 @@ class PyintEngine(DinsarEngine):
|
||||
def _dem_mode(self) -> str:
|
||||
return str(getattr(settings, "PYINT_DEM_MODE", "local_fabdem") or "local_fabdem").strip().lower()
|
||||
|
||||
@property
|
||||
def _dem_resolution_m(self) -> float:
|
||||
return max(0.1, float(getattr(settings, "PYINT_DEM_RESOLUTION_M", DEFAULT_DEM_RESOLUTION_M) or DEFAULT_DEM_RESOLUTION_M))
|
||||
|
||||
@property
|
||||
def _default_unwrap_coh_threshold(self) -> float:
|
||||
return float(getattr(settings, "PYINT_UNWRAP_COH_THRESHOLD", DEFAULT_UNWRAP_COH_THRESHOLD) or DEFAULT_UNWRAP_COH_THRESHOLD)
|
||||
|
||||
@property
|
||||
def _default_product_coh_threshold(self) -> float:
|
||||
return float(getattr(settings, "PYINT_PRODUCT_COH_THRESHOLD", DEFAULT_PRODUCT_COH_THRESHOLD) or DEFAULT_PRODUCT_COH_THRESHOLD)
|
||||
|
||||
@property
|
||||
def _default_reference_mode(self) -> str:
|
||||
return str(getattr(settings, "PYINT_REFERENCE_MODE", DEFAULT_REFERENCE_MODE) or DEFAULT_REFERENCE_MODE).strip().lower()
|
||||
|
||||
@property
|
||||
def _default_reference_coh_threshold(self) -> float:
|
||||
return float(getattr(settings, "PYINT_REFERENCE_COH_THRESHOLD", DEFAULT_REFERENCE_COH_THRESHOLD) or DEFAULT_REFERENCE_COH_THRESHOLD)
|
||||
|
||||
@property
|
||||
def _default_deramp_mode(self) -> str:
|
||||
return str(getattr(settings, "PYINT_DERAMP_MODE", DEFAULT_DERAMP_MODE) or DEFAULT_DERAMP_MODE).strip().lower()
|
||||
|
||||
@property
|
||||
def _default_deramp_coh_threshold(self) -> float:
|
||||
return float(getattr(settings, "PYINT_DERAMP_COH_THRESHOLD", DEFAULT_DERAMP_COH_THRESHOLD) or DEFAULT_DERAMP_COH_THRESHOLD)
|
||||
|
||||
@property
|
||||
def _gamma_nodata_value(self) -> float:
|
||||
return float(getattr(settings, "PYINT_GAMMA_NODATA_VALUE", -9999.0) if getattr(settings, "PYINT_GAMMA_NODATA_VALUE", None) is not None else -9999.0)
|
||||
|
||||
@property
|
||||
def _geo_interp(self) -> str:
|
||||
value = str(getattr(settings, "PYINT_GEO_INTERP", DEFAULT_GEO_INTERP) or DEFAULT_GEO_INTERP).strip()
|
||||
return value if value in {"0", "1"} else DEFAULT_GEO_INTERP
|
||||
|
||||
@property
|
||||
def _atmcor_enabled(self) -> bool:
|
||||
return bool(getattr(settings, "PYINT_ATMCOR_ENABLED", DEFAULT_ATMCOR_ENABLED))
|
||||
|
||||
@property
|
||||
def _atmcor_use_for_disp(self) -> bool:
|
||||
return bool(getattr(settings, "PYINT_ATMCOR_USE_FOR_DISP", DEFAULT_ATMCOR_USE_FOR_DISP))
|
||||
|
||||
@property
|
||||
def _reflatten_enabled(self) -> bool:
|
||||
return bool(getattr(settings, "PYINT_REFLATTEN_ENABLED", DEFAULT_REFLATTEN_ENABLED))
|
||||
|
||||
@property
|
||||
def _reflatten_model(self) -> str:
|
||||
value = str(getattr(settings, "PYINT_REFLATTEN_MODEL", DEFAULT_REFLATTEN_MODEL) or DEFAULT_REFLATTEN_MODEL).strip().lower()
|
||||
if value == "linear":
|
||||
value = "plane"
|
||||
return value if value in REFLATTEN_MODEL_CHOICES else DEFAULT_REFLATTEN_MODEL
|
||||
|
||||
@property
|
||||
def _reflatten_coh_threshold(self) -> float:
|
||||
return float(getattr(settings, "PYINT_REFLATTEN_COH_THRESHOLD", DEFAULT_REFLATTEN_COH_THRESHOLD) or DEFAULT_REFLATTEN_COH_THRESHOLD)
|
||||
|
||||
@property
|
||||
def _reflatten_fallback_coh_threshold(self) -> float:
|
||||
return float(
|
||||
getattr(
|
||||
settings,
|
||||
"PYINT_REFLATTEN_FALLBACK_COH_THRESHOLD",
|
||||
DEFAULT_REFLATTEN_FALLBACK_COH_THRESHOLD,
|
||||
)
|
||||
or DEFAULT_REFLATTEN_FALLBACK_COH_THRESHOLD
|
||||
)
|
||||
|
||||
@property
|
||||
def _reflatten_range_step(self) -> int:
|
||||
return max(1, int(getattr(settings, "PYINT_REFLATTEN_RANGE_STEP", DEFAULT_REFLATTEN_RANGE_STEP) or DEFAULT_REFLATTEN_RANGE_STEP))
|
||||
|
||||
@property
|
||||
def _reflatten_azimuth_step(self) -> int:
|
||||
return max(1, int(getattr(settings, "PYINT_REFLATTEN_AZIMUTH_STEP", DEFAULT_REFLATTEN_AZIMUTH_STEP) or DEFAULT_REFLATTEN_AZIMUTH_STEP))
|
||||
|
||||
@property
|
||||
def _fabdem_root(self) -> str:
|
||||
return _read_env("PYINT_FABDEM_ROOT", "")
|
||||
@@ -197,25 +301,39 @@ class PyintEngine(DinsarEngine):
|
||||
"label": "强制重跑",
|
||||
"type": "boolean",
|
||||
"default": False,
|
||||
"section": "Execution",
|
||||
"description": "删除当前 run_key 对应的工作区后重跑。",
|
||||
},
|
||||
"target_grid_size_m": {
|
||||
"label": "目标网格尺寸(米)",
|
||||
"type": "number",
|
||||
"default": DEFAULT_TARGET_GRID_SIZE_M,
|
||||
"step": 1,
|
||||
"min": TARGET_GRID_SIZE_MIN_M,
|
||||
"max": TARGET_GRID_SIZE_MAX_M,
|
||||
"section": "Advanced",
|
||||
"description": "可选。仅在未手动填写 looks 时用于估算多视数;不会重采样 DEM 或改写 Gamma 产品。",
|
||||
"recommendation": "保持 0 使用显式或默认的 Gamma/PyINT looks。",
|
||||
},
|
||||
"range_looks": {
|
||||
"label": "距离向多视",
|
||||
"label": "距离向多视(手动覆盖)",
|
||||
"type": "number",
|
||||
"default": DEFAULT_RANGE_LOOKS,
|
||||
"step": 1,
|
||||
"min": 1,
|
||||
"max": MAX_LOOKS,
|
||||
"description": "PyINT 模板中的 range_looks。",
|
||||
"section": "Execution",
|
||||
"description": "PyINT/Gamma 模板中的 range_looks。",
|
||||
},
|
||||
"azimuth_looks": {
|
||||
"label": "方位向多视",
|
||||
"label": "方位向多视(手动覆盖)",
|
||||
"type": "number",
|
||||
"default": DEFAULT_AZIMUTH_LOOKS,
|
||||
"step": 1,
|
||||
"min": 1,
|
||||
"max": MAX_LOOKS,
|
||||
"description": "PyINT 模板中的 azimuth_looks。",
|
||||
"section": "Execution",
|
||||
"description": "PyINT/Gamma 模板中的 azimuth_looks。",
|
||||
},
|
||||
"parallel_workers": {
|
||||
"label": "并行数",
|
||||
@@ -224,18 +342,121 @@ class PyintEngine(DinsarEngine):
|
||||
"step": 1,
|
||||
"min": 1,
|
||||
"max": MAX_PARALLEL_WORKERS,
|
||||
"section": "Execution",
|
||||
"description": "同步控制 raw2slc/coreg/diff/unwrap/geocode 的并行数。",
|
||||
},
|
||||
"coherence_mask_threshold": {
|
||||
"label": "Coherence quality",
|
||||
"type": "number",
|
||||
"default": self._default_product_coh_threshold,
|
||||
"step": 0.05,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"section": "Delivery",
|
||||
"description": "Only used for quality support statistics. It is not applied as a Python product mask.",
|
||||
"recommendation": "Use 0.20 by default for LT-1 single-pair reporting; raise it for stricter review maps.",
|
||||
},
|
||||
"unwrap_coh_threshold": {
|
||||
"label": "Unwrap coherence",
|
||||
"type": "number",
|
||||
"default": self._default_unwrap_coh_threshold,
|
||||
"step": 0.05,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"section": "Advanced",
|
||||
"description": "Minimum coherence used by Gamma rascc_mask/mcf during unwrapping.",
|
||||
"recommendation": "Use 0.05 for ENVI-like permissive LT-1 unwrapping; raise it only when low-coherence bridges cause unwrap artifacts.",
|
||||
},
|
||||
"geo_interp": {
|
||||
"label": "Geocode interpolation",
|
||||
"type": "select",
|
||||
"default": self._geo_interp,
|
||||
"enum": ["0", "1"],
|
||||
"section": "Advanced",
|
||||
"description": "Gamma geocode_back interpolation mode: 0 nearest, 1 bicubic spline.",
|
||||
},
|
||||
"atmcor": {
|
||||
"label": "Gamma atmcor",
|
||||
"type": "boolean",
|
||||
"default": self._atmcor_enabled,
|
||||
"section": "Advanced",
|
||||
"description": "Run PyINT/Gamma atm_correction stage using atm_mod_2d/atm_sim_2d/sub_phase.",
|
||||
},
|
||||
"atmcor_use_for_disp": {
|
||||
"label": "Use atmcor for disp",
|
||||
"type": "boolean",
|
||||
"default": self._atmcor_use_for_disp,
|
||||
"section": "Advanced",
|
||||
"description": "Use the Gamma atmospheric-corrected unwrapped phase as dispmap input when available.",
|
||||
},
|
||||
"reflatten": {
|
||||
"label": "Gamma residual reflatten",
|
||||
"type": "boolean",
|
||||
"default": self._reflatten_enabled,
|
||||
"section": "Gamma Refinement",
|
||||
"description": "After unwrapping, fit and remove residual long-wavelength phase ramps with Gamma rascc_mask/quad_fit/quad_sub.",
|
||||
"recommendation": "Keep enabled for LT-1 D-InSAR unless validating the raw PyINT/Gamma baseline.",
|
||||
},
|
||||
"reflatten_model": {
|
||||
"label": "Reflatten model",
|
||||
"type": "select",
|
||||
"default": self._reflatten_model,
|
||||
"enum": ["plane", "quadratic"],
|
||||
"section": "Gamma Refinement",
|
||||
"description": "Gamma quad_fit model used for residual phase trend removal.",
|
||||
"recommendation": "plane is safer for single-pair production; use quadratic only when a clear curved residual ramp remains.",
|
||||
},
|
||||
"reflatten_coh_threshold": {
|
||||
"label": "Reflatten coherence",
|
||||
"type": "number",
|
||||
"default": self._reflatten_coh_threshold,
|
||||
"step": 0.05,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"section": "Gamma Refinement",
|
||||
"description": "Coherence threshold used to build the fit mask.",
|
||||
"recommendation": "Keep the primary fit conservative at 0.70; the backend can retry with a looser fallback.",
|
||||
},
|
||||
"reflatten_fallback_coh_threshold": {
|
||||
"label": "Reflatten fallback coherence",
|
||||
"type": "number",
|
||||
"default": self._reflatten_fallback_coh_threshold,
|
||||
"step": 0.05,
|
||||
"min": 0.0,
|
||||
"max": 1.0,
|
||||
"section": "Gamma Refinement",
|
||||
"description": "Fallback coherence threshold if the primary reflatten fit does not have enough usable samples.",
|
||||
},
|
||||
"reflatten_range_step": {
|
||||
"label": "Reflatten range step",
|
||||
"type": "number",
|
||||
"default": self._reflatten_range_step,
|
||||
"step": 1,
|
||||
"min": 1,
|
||||
"section": "Gamma Refinement",
|
||||
"description": "Sampling step in range pixels for Gamma quad_fit control points.",
|
||||
},
|
||||
"reflatten_azimuth_step": {
|
||||
"label": "Reflatten azimuth step",
|
||||
"type": "number",
|
||||
"default": self._reflatten_azimuth_step,
|
||||
"step": 1,
|
||||
"min": 1,
|
||||
"section": "Gamma Refinement",
|
||||
"description": "Sampling step in azimuth lines for Gamma quad_fit control points.",
|
||||
},
|
||||
"unwrap": {
|
||||
"label": "执行解缠",
|
||||
"type": "boolean",
|
||||
"default": True,
|
||||
"section": "Execution",
|
||||
"description": "关闭后仅做到差分干涉图,不做解缠。",
|
||||
},
|
||||
"geocode": {
|
||||
"label": "执行地理编码",
|
||||
"type": "boolean",
|
||||
"default": True,
|
||||
"section": "Execution",
|
||||
"description": "关闭后不导出地理编码结果。",
|
||||
},
|
||||
},
|
||||
@@ -257,10 +478,36 @@ class PyintEngine(DinsarEngine):
|
||||
return False
|
||||
return bool(value)
|
||||
|
||||
for key in ("force", "unwrap", "geocode"):
|
||||
for key in ("force", "unwrap", "geocode", "atmcor", "atmcor_use_for_disp", "reflatten"):
|
||||
if key in normalized:
|
||||
normalized[key] = _coerce_bool(normalized[key])
|
||||
|
||||
if "geo_interp" in normalized and normalized["geo_interp"] is not None:
|
||||
value = str(normalized["geo_interp"] or "").strip()
|
||||
if not value:
|
||||
normalized.pop("geo_interp", None)
|
||||
elif value not in {"0", "1"}:
|
||||
raise ValueError("geo_interp must be 0 or 1.")
|
||||
else:
|
||||
normalized["geo_interp"] = value
|
||||
|
||||
if "target_grid_size_m" in normalized and str(normalized["target_grid_size_m"] or "").strip() == "":
|
||||
normalized.pop("target_grid_size_m", None)
|
||||
|
||||
if "target_grid_size_m" in normalized and normalized["target_grid_size_m"] is not None:
|
||||
try:
|
||||
grid_size = float(normalized["target_grid_size_m"])
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ValueError("目标网格尺寸必须为数字。") from exc
|
||||
if int(grid_size) != grid_size:
|
||||
raise ValueError("目标网格尺寸必须使用整数米。")
|
||||
grid_size = int(grid_size)
|
||||
if grid_size < TARGET_GRID_SIZE_MIN_M or grid_size > TARGET_GRID_SIZE_MAX_M:
|
||||
raise ValueError(
|
||||
f"目标网格尺寸必须在 {TARGET_GRID_SIZE_MIN_M} 到 {TARGET_GRID_SIZE_MAX_M} 米之间。"
|
||||
)
|
||||
normalized["target_grid_size_m"] = grid_size
|
||||
|
||||
for key, maximum, label in (
|
||||
("range_looks", MAX_LOOKS, "距离向多视"),
|
||||
("azimuth_looks", MAX_LOOKS, "方位向多视"),
|
||||
@@ -268,6 +515,9 @@ class PyintEngine(DinsarEngine):
|
||||
):
|
||||
if key not in normalized or normalized[key] is None:
|
||||
continue
|
||||
if str(normalized[key]).strip() == "":
|
||||
normalized.pop(key, None)
|
||||
continue
|
||||
try:
|
||||
parsed = int(normalized[key])
|
||||
except (TypeError, ValueError) as exc:
|
||||
@@ -276,6 +526,59 @@ class PyintEngine(DinsarEngine):
|
||||
raise ValueError(f"{label}必须在 1 到 {maximum} 之间。")
|
||||
normalized[key] = parsed
|
||||
|
||||
for mode_key, choices in (
|
||||
("reference_mode", {"none", "coh_median"}),
|
||||
("deramp_mode", {"none", "plane"}),
|
||||
("reflatten_model", {"plane", "linear", "quadratic"}),
|
||||
):
|
||||
if mode_key not in normalized or normalized[mode_key] is None:
|
||||
continue
|
||||
value = str(normalized[mode_key] or "").strip().lower()
|
||||
if not value:
|
||||
normalized.pop(mode_key, None)
|
||||
continue
|
||||
if mode_key == "reflatten_model" and value == "linear":
|
||||
value = "plane"
|
||||
if value not in choices:
|
||||
supported = ", ".join(sorted(choices))
|
||||
raise ValueError(f"{mode_key} must be one of: {supported}.")
|
||||
normalized[mode_key] = value
|
||||
|
||||
for threshold_key in (
|
||||
"coherence_mask_threshold",
|
||||
"unwrap_coh_threshold",
|
||||
"reference_coh_threshold",
|
||||
"deramp_coh_threshold",
|
||||
"reflatten_coh_threshold",
|
||||
"reflatten_fallback_coh_threshold",
|
||||
):
|
||||
if threshold_key not in normalized or normalized[threshold_key] is None:
|
||||
continue
|
||||
if str(normalized[threshold_key]).strip() == "":
|
||||
normalized.pop(threshold_key, None)
|
||||
continue
|
||||
try:
|
||||
parsed_threshold = float(normalized[threshold_key])
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ValueError(f"{threshold_key} must be a number.") from exc
|
||||
if parsed_threshold < 0.0 or parsed_threshold > 1.0:
|
||||
raise ValueError(f"{threshold_key} must be between 0.0 and 1.0.")
|
||||
normalized[threshold_key] = parsed_threshold
|
||||
|
||||
for step_key in ("reflatten_range_step", "reflatten_azimuth_step"):
|
||||
if step_key not in normalized or normalized[step_key] is None:
|
||||
continue
|
||||
if str(normalized[step_key]).strip() == "":
|
||||
normalized.pop(step_key, None)
|
||||
continue
|
||||
try:
|
||||
parsed_step = int(normalized[step_key])
|
||||
except (TypeError, ValueError) as exc:
|
||||
raise ValueError(f"{step_key} must be an integer.") from exc
|
||||
if parsed_step < 1:
|
||||
raise ValueError(f"{step_key} must be greater than or equal to 1.")
|
||||
normalized[step_key] = parsed_step
|
||||
|
||||
return normalized
|
||||
|
||||
def _has_completed_task_result(self, task_dir: str, profile_code: str) -> bool:
|
||||
@@ -413,7 +716,10 @@ class PyintEngine(DinsarEngine):
|
||||
total_tasks = len(task_dirs)
|
||||
run_started_at = datetime.utcnow()
|
||||
run_started_at_text = run_started_at.isoformat(timespec="seconds") + "Z"
|
||||
run_key = f"run_{run_started_at.strftime('%Y%m%dT%H%M%SZ')}_{self.engine_code}_{request.profile}"
|
||||
managed_run_key = str(extra.get("__managed_run_key") or "").strip()
|
||||
run_key = managed_run_key or f"run_{run_started_at.strftime('%Y%m%dT%H%M%SZ')}_{self.engine_code}_{request.profile}"
|
||||
managed_run_dir_override = str(extra.get("__managed_run_dir") or "").strip()
|
||||
managed_native_output_dir_override = str(extra.get("__managed_native_output_dir") or "").strip()
|
||||
progress_callback = request.progress_callback
|
||||
|
||||
def emit_progress(event_type: str, **payload: Any) -> None:
|
||||
@@ -426,9 +732,44 @@ class PyintEngine(DinsarEngine):
|
||||
|
||||
timeout = max(60, int(request.timeout_seconds or self.default_timeout_seconds))
|
||||
force = bool(extra.get("force"))
|
||||
range_looks = int(extra.get("range_looks", DEFAULT_RANGE_LOOKS))
|
||||
azimuth_looks = int(extra.get("azimuth_looks", DEFAULT_AZIMUTH_LOOKS))
|
||||
target_grid_size_m = int(extra.get("target_grid_size_m") or 0)
|
||||
manual_range_looks = extra.get("range_looks")
|
||||
manual_azimuth_looks = extra.get("azimuth_looks")
|
||||
parallel_workers = int(extra.get("parallel_workers", DEFAULT_PARALLEL_WORKERS))
|
||||
dem_resolution_m = self._dem_resolution_m
|
||||
dem_oversampling = calculate_dem_oversampling(
|
||||
dem_resolution_m=dem_resolution_m,
|
||||
target_grid_size_m=target_grid_size_m,
|
||||
)
|
||||
dem_lat_ovr = float(dem_oversampling["oversampling"])
|
||||
dem_lon_ovr = float(dem_oversampling["oversampling"])
|
||||
unwrap_coh_threshold = float(extra.get("unwrap_coh_threshold", self._default_unwrap_coh_threshold))
|
||||
coherence_mask_threshold = float(extra.get("coherence_mask_threshold", self._default_product_coh_threshold))
|
||||
reference_mode = "none"
|
||||
reference_coh_threshold = float(self._default_reference_coh_threshold)
|
||||
deramp_mode = "none"
|
||||
deramp_coh_threshold = float(self._default_deramp_coh_threshold)
|
||||
gamma_nodata_value = self._gamma_nodata_value
|
||||
geo_interp = str(extra.get("geo_interp", self._geo_interp) or self._geo_interp).strip()
|
||||
if geo_interp not in {"0", "1"}:
|
||||
geo_interp = DEFAULT_GEO_INTERP
|
||||
atmcor = bool(extra.get("atmcor", self._atmcor_enabled))
|
||||
atmcor_use_for_disp = bool(extra.get("atmcor_use_for_disp", self._atmcor_use_for_disp)) if atmcor else False
|
||||
reflatten = bool(extra.get("reflatten", self._reflatten_enabled))
|
||||
reflatten_model = str(extra.get("reflatten_model", self._reflatten_model) or self._reflatten_model).strip().lower()
|
||||
if reflatten_model == "linear":
|
||||
reflatten_model = "plane"
|
||||
if reflatten_model not in {"plane", "quadratic"}:
|
||||
reflatten_model = DEFAULT_REFLATTEN_MODEL
|
||||
reflatten_coh_threshold = float(extra.get("reflatten_coh_threshold", self._reflatten_coh_threshold))
|
||||
reflatten_fallback_coh_threshold = float(
|
||||
extra.get(
|
||||
"reflatten_fallback_coh_threshold",
|
||||
self._reflatten_fallback_coh_threshold,
|
||||
)
|
||||
)
|
||||
reflatten_range_step = int(extra.get("reflatten_range_step", self._reflatten_range_step))
|
||||
reflatten_azimuth_step = int(extra.get("reflatten_azimuth_step", self._reflatten_azimuth_step))
|
||||
unwrap = bool(extra.get("unwrap", True))
|
||||
geocode = bool(extra.get("geocode", True))
|
||||
|
||||
@@ -443,6 +784,57 @@ class PyintEngine(DinsarEngine):
|
||||
wsl_prepared_dem_path = to_wsl_path(prepared_dem_path) if prepared_dem_path else ""
|
||||
shared_orbit_context = get_pyint_orbit_context()
|
||||
|
||||
def resolve_pair_looks(task_dir: str) -> Dict[str, Any]:
|
||||
manual_range = int(manual_range_looks) if manual_range_looks is not None else None
|
||||
manual_azimuth = int(manual_azimuth_looks) if manual_azimuth_looks is not None else None
|
||||
calculation: Dict[str, Any] = {}
|
||||
error_text = ""
|
||||
|
||||
if target_grid_size_m > 0 and (manual_range is None or manual_azimuth is None):
|
||||
try:
|
||||
calculation = calculate_looks_from_task_dir(
|
||||
task_dir,
|
||||
target_grid_size_m,
|
||||
)
|
||||
except Exception as exc:
|
||||
error_text = str(exc)
|
||||
calculation = {
|
||||
"mode": "fallback_default",
|
||||
"target_resolution_m": target_grid_size_m,
|
||||
"error": error_text,
|
||||
}
|
||||
elif manual_range is None or manual_azimuth is None:
|
||||
calculation = {
|
||||
"mode": "gamma_default_looks",
|
||||
"target_resolution_m": None,
|
||||
}
|
||||
|
||||
range_looks = manual_range
|
||||
if range_looks is None:
|
||||
range_looks = int(calculation.get("range_looks") or DEFAULT_RANGE_LOOKS)
|
||||
|
||||
azimuth_looks = manual_azimuth
|
||||
if azimuth_looks is None:
|
||||
azimuth_looks = int(calculation.get("azimuth_looks") or DEFAULT_AZIMUTH_LOOKS)
|
||||
|
||||
if manual_range is not None or manual_azimuth is not None:
|
||||
calculation = {
|
||||
**calculation,
|
||||
"mode": "manual_override" if calculation else "manual",
|
||||
"manual_range_looks": manual_range,
|
||||
"manual_azimuth_looks": manual_azimuth,
|
||||
}
|
||||
|
||||
calculation["resolved_range_looks"] = int(range_looks)
|
||||
calculation["resolved_azimuth_looks"] = int(azimuth_looks)
|
||||
calculation["target_grid_size_m"] = int(target_grid_size_m)
|
||||
return {
|
||||
"range_looks": int(range_looks),
|
||||
"azimuth_looks": int(azimuth_looks),
|
||||
"calculation": calculation,
|
||||
"error": error_text,
|
||||
}
|
||||
|
||||
task_results: List[Dict[str, Any]] = []
|
||||
output_dirs: List[str] = []
|
||||
pairs_processed = 0
|
||||
@@ -458,11 +850,19 @@ class PyintEngine(DinsarEngine):
|
||||
slave_date = task_identity["slave_date"]
|
||||
|
||||
work_run_root = os.path.normpath(os.path.join(self._work_root, pair_key, run_key))
|
||||
output_dir = os.path.normpath(os.path.join(self._output_root, pair_key, "runs", run_key, "native"))
|
||||
run_dir = os.path.normpath(managed_run_dir_override) if managed_run_dir_override else os.path.normpath(
|
||||
os.path.join(self._output_root, pair_key, "runs", run_key)
|
||||
)
|
||||
output_dir = (
|
||||
os.path.normpath(managed_native_output_dir_override)
|
||||
if managed_native_output_dir_override
|
||||
else os.path.join(run_dir, "native")
|
||||
)
|
||||
template_root = os.path.normpath(os.path.join(self._template_root, pair_key, run_key))
|
||||
project_name = build_project_name(pair_key, run_key)
|
||||
project_dir = os.path.join(work_run_root, project_name)
|
||||
input_assets_dir = os.path.join(work_run_root, "input_assets")
|
||||
# Keep input assets outside the run root because the WSL pipeline may delete run_root on --force.
|
||||
input_assets_dir = os.path.join(self._work_root, pair_key, "input_assets", run_key)
|
||||
|
||||
wsl_task_dir = to_wsl_path(task_dir)
|
||||
wsl_project_dir = to_wsl_path(project_dir)
|
||||
@@ -663,6 +1063,45 @@ class PyintEngine(DinsarEngine):
|
||||
else ""
|
||||
)
|
||||
|
||||
look_resolution = resolve_pair_looks(task_dir)
|
||||
range_looks = int(look_resolution["range_looks"])
|
||||
azimuth_looks = int(look_resolution["azimuth_looks"])
|
||||
look_calculation = dict(look_resolution.get("calculation") or {})
|
||||
look_message = (
|
||||
f"PyINT looks resolved for {task_alias}: "
|
||||
f"range={range_looks}, azimuth={azimuth_looks}, "
|
||||
f"target_grid={target_grid_size_m or 'not_set'}m, mode={look_calculation.get('mode', 'unknown')}"
|
||||
)
|
||||
if look_resolution.get("error"):
|
||||
look_message += f", fallback_reason={look_resolution['error']}"
|
||||
emit_progress(
|
||||
"log",
|
||||
pair_index=pair_index,
|
||||
pair_total=total_tasks,
|
||||
task_name=task_name,
|
||||
task_alias=task_alias,
|
||||
pair_key=pair_key,
|
||||
level="WARNING" if look_resolution.get("error") else "INFO",
|
||||
source="looks",
|
||||
message=look_message,
|
||||
)
|
||||
emit_progress(
|
||||
"log",
|
||||
pair_index=pair_index,
|
||||
pair_total=total_tasks,
|
||||
task_name=task_name,
|
||||
task_alias=task_alias,
|
||||
pair_key=pair_key,
|
||||
level="INFO",
|
||||
source="dem",
|
||||
message=(
|
||||
f"PyINT DEM oversampling for {task_alias}: "
|
||||
f"dem_resolution={dem_resolution_m:g}m, target_grid={target_grid_size_m or 'not_set'}m, "
|
||||
f"dem_lat_ovr={dem_lat_ovr:g}, dem_lon_ovr={dem_lon_ovr:g}, "
|
||||
f"actual_grid={float(dem_oversampling.get('actual_grid_size_m') or 0.0):g}m"
|
||||
),
|
||||
)
|
||||
|
||||
cmd_parts = [
|
||||
f"{quote_shell(self._python)} {quote_shell(self._pipeline_script)} {quote_shell(wsl_task_dir)}",
|
||||
f"--project-dir {quote_shell(wsl_project_dir)}",
|
||||
@@ -679,10 +1118,24 @@ class PyintEngine(DinsarEngine):
|
||||
f"--orbit-policy {quote_shell(self._orbit_policy)}",
|
||||
f"--range-looks {range_looks}",
|
||||
f"--azimuth-looks {azimuth_looks}",
|
||||
f"--dem-resolution-m {dem_resolution_m}",
|
||||
f"--dem-lat-ovr {dem_lat_ovr}",
|
||||
f"--dem-lon-ovr {dem_lon_ovr}",
|
||||
f"--parallel-workers {parallel_workers}",
|
||||
f"--master-date {quote_shell(master_date)}" if master_date else "",
|
||||
f"--slave-date {quote_shell(slave_date)}" if slave_date else "",
|
||||
f"--time-baseline-days {time_baseline_days}",
|
||||
f"--target-grid-size-m {target_grid_size_m}",
|
||||
f"--unwrap-coh-threshold {unwrap_coh_threshold}",
|
||||
f"--coherence-mask-threshold {coherence_mask_threshold}",
|
||||
f"--geo-interp {quote_shell(geo_interp)}",
|
||||
f"--gamma-nodata-value {gamma_nodata_value}",
|
||||
"--reflatten" if reflatten else "--no-reflatten",
|
||||
f"--reflatten-model {quote_shell(reflatten_model)}",
|
||||
f"--reflatten-coh-threshold {reflatten_coh_threshold}",
|
||||
f"--reflatten-fallback-coh-threshold {reflatten_fallback_coh_threshold}",
|
||||
f"--reflatten-range-step {reflatten_range_step}",
|
||||
f"--reflatten-azimuth-step {reflatten_azimuth_step}",
|
||||
f"--input-assets-dir {quote_shell(wsl_input_assets_dir)}" if wsl_input_assets_dir else "",
|
||||
f"--input-assets-json {quote_shell(wsl_input_assets_json)}" if wsl_input_assets_json else "",
|
||||
f"--lt1-precise-orbit-enabled {'true' if self._lt1_precise_orbit_enabled else 'false'}",
|
||||
@@ -695,6 +1148,8 @@ class PyintEngine(DinsarEngine):
|
||||
f"--lt1-precise-orbit-backup {'true' if self._lt1_precise_orbit_backup else 'false'}",
|
||||
f"--lt1-precise-orbit-orb-filt-degree {self._lt1_precise_orbit_orb_filt_degree}",
|
||||
"--unwrap" if unwrap else "--no-unwrap",
|
||||
"--atmcor" if atmcor else "--no-atmcor",
|
||||
"--atmcor-use-for-disp" if atmcor_use_for_disp else "--no-atmcor-use-for-disp",
|
||||
"--geocode" if geocode else "--no-geocode",
|
||||
]
|
||||
if self._dem_mode == "local_fabdem" and wsl_fabdem_root:
|
||||
@@ -712,19 +1167,61 @@ class PyintEngine(DinsarEngine):
|
||||
cmd_parts.append("--force")
|
||||
|
||||
cmd = " ".join(part for part in cmd_parts if part)
|
||||
rc, stdout, stderr = run_wsl_command(
|
||||
def _emit_stream_log(level: str, source: str, text: str) -> None:
|
||||
line = str(text or "").strip()
|
||||
if not line:
|
||||
return
|
||||
max_len = 2000
|
||||
if len(line) > max_len:
|
||||
line = line[:max_len] + "...<truncated>"
|
||||
emit_progress(
|
||||
"log",
|
||||
pair_index=pair_index,
|
||||
pair_total=total_tasks,
|
||||
task_name=task_name,
|
||||
task_alias=task_alias,
|
||||
pair_key=pair_key,
|
||||
level=level,
|
||||
source=source,
|
||||
message=line,
|
||||
)
|
||||
|
||||
rc, stdout, stderr = run_wsl_command_stream(
|
||||
cmd,
|
||||
distro=self._distro,
|
||||
timeout=timeout,
|
||||
stdout_callback=lambda line: _emit_stream_log("INFO", "stdout", line),
|
||||
stderr_callback=lambda line: _emit_stream_log("WARNING", "stderr", line),
|
||||
)
|
||||
|
||||
success = rc == 0
|
||||
error_text = stderr.strip() if stderr else ""
|
||||
validation_result: Dict[str, Any] = {}
|
||||
completion_files_result: Dict[str, Any] = {}
|
||||
primary_file = ""
|
||||
source_files: List[str] = []
|
||||
if success:
|
||||
pairs_processed += 1
|
||||
try:
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
write_run_metadata(
|
||||
output_dir,
|
||||
{
|
||||
os.makedirs(run_dir, exist_ok=True)
|
||||
standard_disp_path = os.path.join(run_dir, "assets", "disp", "disp.tif")
|
||||
standard_coh_path = os.path.join(run_dir, "assets", "coh", "coh.tif")
|
||||
if geocode:
|
||||
validation_sources = [standard_disp_path]
|
||||
if os.path.isfile(standard_coh_path):
|
||||
validation_sources.append(standard_coh_path)
|
||||
validation_result = validate_isce2_result_files(
|
||||
standard_disp_path,
|
||||
validation_sources,
|
||||
)
|
||||
if not bool(validation_result.get("accepted")):
|
||||
issues = validation_result.get("issues") or []
|
||||
issue_text = "; ".join(str(item) for item in issues[:3]) or "unknown validation error"
|
||||
raise RuntimeError(f"PyINT standard GeoTIFF validation failed: {issue_text}")
|
||||
primary_file = str(validation_result.get("primary_file") or standard_disp_path)
|
||||
source_files = list(validation_result.get("source_files") or validation_sources)
|
||||
|
||||
run_metadata = {
|
||||
"run_key": run_key,
|
||||
"pair_key": pair_key,
|
||||
"task_name": task_name,
|
||||
@@ -734,15 +1231,50 @@ class PyintEngine(DinsarEngine):
|
||||
"source_root": os.path.normpath(request.root_dir),
|
||||
"task_dir": os.path.normpath(task_dir),
|
||||
"work_dir": work_run_root,
|
||||
"output_dir": output_dir,
|
||||
"output_dir": run_dir,
|
||||
"native_output_dir": output_dir,
|
||||
"project_dir": project_dir,
|
||||
"runtime_id": settings.PYINT_RUNTIME_ID,
|
||||
"started_at": run_started_at_text,
|
||||
"finished_at": datetime.utcnow().isoformat(timespec="seconds") + "Z",
|
||||
"primary_file": primary_file,
|
||||
"source_files": source_files,
|
||||
"acceptance": validation_result,
|
||||
"params": {
|
||||
"force": force,
|
||||
"target_grid_size_m": target_grid_size_m,
|
||||
"dem_resolution_m": dem_resolution_m,
|
||||
"dem_oversampling": dem_oversampling,
|
||||
"dem_lat_ovr": dem_lat_ovr,
|
||||
"dem_lon_ovr": dem_lon_ovr,
|
||||
"range_looks": range_looks,
|
||||
"azimuth_looks": azimuth_looks,
|
||||
"manual_range_looks": manual_range_looks,
|
||||
"manual_azimuth_looks": manual_azimuth_looks,
|
||||
"look_calculation": look_calculation,
|
||||
"parallel_workers": parallel_workers,
|
||||
"unwrap_coh_threshold": unwrap_coh_threshold,
|
||||
"coherence_quality_threshold": coherence_mask_threshold,
|
||||
"reference_mode": reference_mode,
|
||||
"reference_coh_threshold": reference_coh_threshold,
|
||||
"deramp_mode": deramp_mode,
|
||||
"deramp_coh_threshold": deramp_coh_threshold,
|
||||
"gamma_nodata_value": gamma_nodata_value,
|
||||
"geo_interp": geo_interp,
|
||||
"atmcor": atmcor,
|
||||
"atmcor_use_for_disp": atmcor_use_for_disp,
|
||||
"reflatten": reflatten,
|
||||
"reflatten_model": reflatten_model,
|
||||
"reflatten_coh_threshold": reflatten_coh_threshold,
|
||||
"reflatten_fallback_coh_threshold": reflatten_fallback_coh_threshold,
|
||||
"reflatten_range_step": reflatten_range_step,
|
||||
"reflatten_azimuth_step": reflatten_azimuth_step,
|
||||
"gamma_native_export": {
|
||||
"python_data_processing_applied": False,
|
||||
"coherence_mask_applied": False,
|
||||
"reference_applied": False,
|
||||
"deramp_applied": False,
|
||||
},
|
||||
"unwrap": unwrap,
|
||||
"geocode": geocode,
|
||||
},
|
||||
@@ -765,10 +1297,24 @@ class PyintEngine(DinsarEngine):
|
||||
"policy_version": pair_meta.get("policy_version"),
|
||||
"selection_strategy": pair_meta.get("selection_strategy"),
|
||||
"input_assets": input_assets_summary,
|
||||
},
|
||||
}
|
||||
write_run_metadata(run_dir, run_metadata)
|
||||
write_run_metadata(output_dir, run_metadata)
|
||||
if geocode and primary_file:
|
||||
completion_files_result = repair_managed_completion_files(
|
||||
run_dir,
|
||||
primary_file=primary_file,
|
||||
source_files=source_files,
|
||||
run_meta=run_metadata,
|
||||
)
|
||||
output_dirs.append(output_dir)
|
||||
else:
|
||||
output_dirs.append(run_dir)
|
||||
pairs_processed += 1
|
||||
except Exception as exc:
|
||||
success = False
|
||||
error_text = str(exc)
|
||||
stderr = (stderr.rstrip() + "\n" + error_text) if stderr else error_text
|
||||
|
||||
if not success:
|
||||
pairs_failed += 1
|
||||
|
||||
emit_progress(
|
||||
@@ -780,7 +1326,7 @@ class PyintEngine(DinsarEngine):
|
||||
pair_key=pair_key,
|
||||
success=success,
|
||||
returncode=rc,
|
||||
error=stderr.strip() if stderr else "",
|
||||
error=error_text,
|
||||
)
|
||||
task_results.append(
|
||||
{
|
||||
@@ -791,13 +1337,45 @@ class PyintEngine(DinsarEngine):
|
||||
"task_dir": task_dir,
|
||||
"work_dir": work_run_root,
|
||||
"project_dir": project_dir,
|
||||
"output_dir": output_dir,
|
||||
"run_dir": run_dir,
|
||||
"output_dir": run_dir,
|
||||
"native_output_dir": output_dir,
|
||||
"primary_file": primary_file,
|
||||
"source_files": source_files,
|
||||
"acceptance": validation_result,
|
||||
"completion_files": completion_files_result,
|
||||
"target_grid_size_m": target_grid_size_m,
|
||||
"dem_resolution_m": dem_resolution_m,
|
||||
"dem_oversampling": dem_oversampling,
|
||||
"dem_lat_ovr": dem_lat_ovr,
|
||||
"dem_lon_ovr": dem_lon_ovr,
|
||||
"range_looks": range_looks,
|
||||
"azimuth_looks": azimuth_looks,
|
||||
"manual_range_looks": manual_range_looks,
|
||||
"manual_azimuth_looks": manual_azimuth_looks,
|
||||
"look_calculation": look_calculation,
|
||||
"unwrap_coh_threshold": unwrap_coh_threshold,
|
||||
"coherence_quality_threshold": coherence_mask_threshold,
|
||||
"reference_mode": reference_mode,
|
||||
"reference_coh_threshold": reference_coh_threshold,
|
||||
"deramp_mode": deramp_mode,
|
||||
"deramp_coh_threshold": deramp_coh_threshold,
|
||||
"gamma_nodata_value": gamma_nodata_value,
|
||||
"geo_interp": geo_interp,
|
||||
"atmcor": atmcor,
|
||||
"atmcor_use_for_disp": atmcor_use_for_disp,
|
||||
"gamma_native_export": {
|
||||
"python_data_processing_applied": False,
|
||||
"coherence_mask_applied": False,
|
||||
"reference_applied": False,
|
||||
"deramp_applied": False,
|
||||
},
|
||||
"command": cmd,
|
||||
"success": success,
|
||||
"returncode": rc,
|
||||
"stdout_tail": stdout[-3000:] if stdout else "",
|
||||
"stderr_tail": stderr[-3000:] if stderr else "",
|
||||
"error": stderr.strip() if stderr else "",
|
||||
"error": error_text,
|
||||
"wsl_task_dir": wsl_task_dir,
|
||||
"wsl_project_dir": wsl_project_dir,
|
||||
"wsl_output_dir": wsl_output_dir,
|
||||
@@ -849,9 +1427,32 @@ class PyintEngine(DinsarEngine):
|
||||
"started_at": run_started_at_text,
|
||||
"force": force,
|
||||
"timeout_seconds": timeout,
|
||||
"range_looks": range_looks,
|
||||
"azimuth_looks": azimuth_looks,
|
||||
"target_grid_size_m": target_grid_size_m,
|
||||
"dem_resolution_m": dem_resolution_m,
|
||||
"dem_oversampling": dem_oversampling,
|
||||
"dem_lat_ovr": dem_lat_ovr,
|
||||
"dem_lon_ovr": dem_lon_ovr,
|
||||
"range_looks": last_task_result.get("range_looks"),
|
||||
"azimuth_looks": last_task_result.get("azimuth_looks"),
|
||||
"manual_range_looks": manual_range_looks,
|
||||
"manual_azimuth_looks": manual_azimuth_looks,
|
||||
"parallel_workers": parallel_workers,
|
||||
"unwrap_coh_threshold": unwrap_coh_threshold,
|
||||
"coherence_quality_threshold": coherence_mask_threshold,
|
||||
"reference_mode": reference_mode,
|
||||
"reference_coh_threshold": reference_coh_threshold,
|
||||
"deramp_mode": deramp_mode,
|
||||
"deramp_coh_threshold": deramp_coh_threshold,
|
||||
"gamma_nodata_value": gamma_nodata_value,
|
||||
"geo_interp": geo_interp,
|
||||
"atmcor": atmcor,
|
||||
"atmcor_use_for_disp": atmcor_use_for_disp,
|
||||
"gamma_native_export": {
|
||||
"python_data_processing_applied": False,
|
||||
"coherence_mask_applied": False,
|
||||
"reference_applied": False,
|
||||
"deramp_applied": False,
|
||||
},
|
||||
"unwrap": unwrap,
|
||||
"geocode": geocode,
|
||||
"command": last_task_result.get("command", ""),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -268,6 +268,7 @@ async def submit_run(
|
||||
else:
|
||||
job_type = JOB_TYPE_PYINT_RUN
|
||||
max_attempts = PYINT_PRODUCTION_JOB_MAX_ATTEMPTS
|
||||
create_managed_run = True
|
||||
if validation_summary is not None:
|
||||
validated_task_count = validation_summary.get("task_count", 0)
|
||||
payload["extra"].update(
|
||||
|
||||
@@ -27,6 +27,7 @@ from .workflow_service import workflow_service
|
||||
|
||||
TASK_TYPE_DINSAR_PRODUCTION = "IDL_RUN_DINSAR"
|
||||
TASK_TYPE_ISCE2_DINSAR_PRODUCTION = "ISCE2_RUN"
|
||||
TASK_TYPE_PYINT_DINSAR_PRODUCTION = "PYINT_RUN"
|
||||
RUN_STATUS_PENDING = "PENDING"
|
||||
RUN_STATUS_RUNNING = "RUNNING"
|
||||
RUN_STATUS_COMPLETED = "COMPLETED"
|
||||
@@ -75,6 +76,8 @@ def _task_type_for_engine(engine_code: str) -> str:
|
||||
return TASK_TYPE_DINSAR_PRODUCTION
|
||||
if normalized == "isce2":
|
||||
return TASK_TYPE_ISCE2_DINSAR_PRODUCTION
|
||||
if normalized in {"pyint", "gamma"}:
|
||||
return TASK_TYPE_PYINT_DINSAR_PRODUCTION
|
||||
raise ValueError(f"Unsupported engine for D-InSAR production run: {engine_code}")
|
||||
|
||||
|
||||
@@ -84,6 +87,8 @@ def _workflow_name_for_engine(engine_code: str) -> str:
|
||||
return "dinsar_sarscape_production"
|
||||
if normalized == "isce2":
|
||||
return "dinsar_isce2_production"
|
||||
if normalized in {"pyint", "gamma"}:
|
||||
return "dinsar_pyint_gamma_production"
|
||||
raise ValueError(f"Unsupported engine for D-InSAR production run: {engine_code}")
|
||||
|
||||
|
||||
@@ -93,6 +98,8 @@ def _workflow_step_name_for_engine(engine_code: str) -> str:
|
||||
return RUNS_STEP_NAME
|
||||
if normalized == "isce2":
|
||||
return "Execute ISCE2 D-InSAR items"
|
||||
if normalized in {"pyint", "gamma"}:
|
||||
return "Execute PyINT/Gamma D-InSAR items"
|
||||
raise ValueError(f"Unsupported engine for D-InSAR production run: {engine_code}")
|
||||
|
||||
|
||||
@@ -329,6 +336,82 @@ def _execution_dir(item: DinsarProductionRunItemORM, run_key: str) -> str:
|
||||
return os.path.join(item.results_root_dir, "runs", run_key)
|
||||
|
||||
|
||||
def _first_text(*values: Any) -> str:
|
||||
for value in values:
|
||||
text = str(value or "").strip()
|
||||
if text:
|
||||
return text
|
||||
return ""
|
||||
|
||||
|
||||
def _read_json_if_exists(path: str) -> Dict[str, Any]:
|
||||
text = str(path or "").strip()
|
||||
if not text or not os.path.isfile(text):
|
||||
return {}
|
||||
try:
|
||||
with open(text, "r", encoding="utf-8") as fp:
|
||||
payload = json.load(fp)
|
||||
return payload if isinstance(payload, dict) else {}
|
||||
except Exception:
|
||||
return {}
|
||||
|
||||
|
||||
def _maybe_join(base: str, *parts: str) -> str:
|
||||
text = str(base or "").strip()
|
||||
if not text:
|
||||
return ""
|
||||
return os.path.normpath(os.path.join(text, *parts))
|
||||
|
||||
|
||||
def _build_output_paths(
|
||||
*,
|
||||
engine_code: str,
|
||||
item: DinsarProductionRunItemORM,
|
||||
run_key: str,
|
||||
output_dir: str,
|
||||
manifest_path: Optional[str] = None,
|
||||
) -> Dict[str, Any]:
|
||||
run_dir = os.path.normpath(str(output_dir or _execution_dir(item, run_key)))
|
||||
native_dir = _maybe_join(run_dir, "native")
|
||||
paths: Dict[str, Any] = {
|
||||
"run_dir": run_dir,
|
||||
"native_dir": native_dir,
|
||||
"assets_dir": _maybe_join(run_dir, "assets"),
|
||||
"quality_dir": _maybe_join(run_dir, "quality"),
|
||||
"manifest_path": str(manifest_path or "").strip(),
|
||||
}
|
||||
|
||||
if str(engine_code or "").strip().lower() in {"pyint", "gamma"}:
|
||||
pair_key = _first_text(item.pair_key, os.path.basename(os.path.dirname(os.path.dirname(run_dir))))
|
||||
project_name = f"{pair_key}_{run_key}" if pair_key and run_key else ""
|
||||
work_root = _maybe_join(settings.PYINT_WORK_ROOT, pair_key, run_key)
|
||||
project_dir = _maybe_join(work_root, project_name) if project_name else ""
|
||||
|
||||
summary_payload = _read_json_if_exists(_maybe_join(native_dir, "pyint_run_summary.json"))
|
||||
summary_project_dir = _first_text(summary_payload.get("project_dir"))
|
||||
project_dir = summary_project_dir or project_dir
|
||||
|
||||
master_date = _first_text(summary_payload.get("master_date"))
|
||||
slave_date = _first_text(summary_payload.get("slave_date"))
|
||||
pair_name = f"{master_date}-{slave_date}" if master_date and slave_date else ""
|
||||
ifgrams_dir = _maybe_join(project_dir, "ifgrams", pair_name) if pair_name else _maybe_join(project_dir, "ifgrams")
|
||||
|
||||
paths.update(
|
||||
{
|
||||
"work_dir": work_root,
|
||||
"project_dir": project_dir,
|
||||
"ifgrams_dir": ifgrams_dir,
|
||||
"reflatten_dir": _maybe_join(run_dir, "gamma_reflatten"),
|
||||
"native_reflatten_dir": _maybe_join(native_dir, "reflatten"),
|
||||
"pyint_summary_path": _maybe_join(native_dir, "pyint_run_summary.json"),
|
||||
"stdout_log": _maybe_join(work_root, "pyint.stdout.log"),
|
||||
"stderr_log": _maybe_join(work_root, "pyint.stderr.log"),
|
||||
}
|
||||
)
|
||||
|
||||
return paths
|
||||
|
||||
|
||||
def _sanitize_pointer_fragment(value: str, default: str) -> str:
|
||||
text = _SAFE_POINTER_RE.sub("_", str(value or "").strip()).strip("._")
|
||||
return text or default
|
||||
@@ -616,6 +699,7 @@ class DinsarProductionService:
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
runs = result.scalars().all()
|
||||
run_ids = [run.run_id for run in runs if run.run_id]
|
||||
pending_reconcile = [
|
||||
run
|
||||
for run in runs
|
||||
@@ -636,6 +720,15 @@ class DinsarProductionService:
|
||||
) or changed
|
||||
if changed:
|
||||
await db.commit()
|
||||
items_by_run_id: Dict[str, List[DinsarProductionRunItemORM]] = {}
|
||||
if run_ids:
|
||||
items_result = await db.execute(
|
||||
select(DinsarProductionRunItemORM)
|
||||
.where(DinsarProductionRunItemORM.run_id.in_(run_ids))
|
||||
.order_by(DinsarProductionRunItemORM.order_index.asc(), DinsarProductionRunItemORM.id.asc())
|
||||
)
|
||||
for item in items_result.scalars().all():
|
||||
items_by_run_id.setdefault(item.run_id, []).append(item)
|
||||
return {
|
||||
"runs": [
|
||||
{
|
||||
@@ -656,6 +749,29 @@ class DinsarProductionService:
|
||||
"completed_items": run.completed_items,
|
||||
"failed_items": run.failed_items,
|
||||
"skipped_items": run.skipped_items,
|
||||
"items": [
|
||||
{
|
||||
"task_name": item.task_name,
|
||||
"task_alias": item.task_alias,
|
||||
"pair_key": item.pair_key,
|
||||
"status": item.status,
|
||||
"current_step": item.current_step,
|
||||
"latest_run_key": item.latest_run_key,
|
||||
"latest_output_dir": item.latest_output_dir,
|
||||
"latest_manifest_path": item.latest_manifest_path,
|
||||
"last_error": item.last_error,
|
||||
"paths": _build_output_paths(
|
||||
engine_code=run.engine_code,
|
||||
item=item,
|
||||
run_key=str(item.latest_run_key or ""),
|
||||
output_dir=str(item.latest_output_dir or _execution_dir(item, str(item.latest_run_key or ""))),
|
||||
manifest_path=item.latest_manifest_path,
|
||||
)
|
||||
if item.latest_run_key
|
||||
else {},
|
||||
}
|
||||
for item in items_by_run_id.get(run.run_id, [])[:5]
|
||||
],
|
||||
}
|
||||
for run in runs
|
||||
],
|
||||
|
||||
@@ -2058,6 +2058,25 @@ async def _handle_queued_engine_run(
|
||||
pair_index = max(0, int(event.get("pair_index") or 0))
|
||||
task_label = str(event.get("task_alias") or event.get("task_name") or "").strip()
|
||||
|
||||
if event_type == "log":
|
||||
level = str(event.get("level") or "INFO").strip().upper()
|
||||
if level not in {"DEBUG", "INFO", "WARNING", "ERROR"}:
|
||||
level = "INFO"
|
||||
source = str(event.get("source") or "").strip()
|
||||
message = str(event.get("message") or "").strip()
|
||||
if not message:
|
||||
continue
|
||||
label = task_label or str(progress_state.get("pair_label") or "").strip() or "pair"
|
||||
prefix = f"{engine_title} {pair_index}/{pair_total} {label}"
|
||||
if source:
|
||||
prefix = f"{prefix} {source}"
|
||||
await task_service.add_log(
|
||||
job.task_id,
|
||||
level,
|
||||
f"{prefix}: {message}",
|
||||
)
|
||||
continue
|
||||
|
||||
if event_type == "pair_started":
|
||||
progress = min(
|
||||
90,
|
||||
@@ -2496,7 +2515,22 @@ async def _run_wsl_dinsar_production_controller(
|
||||
if event is None:
|
||||
return
|
||||
event_type = str(event.get("event") or "").strip().lower()
|
||||
if event_type == "pair_started":
|
||||
if event_type == "log":
|
||||
level = str(event.get("level") or "INFO").strip().upper()
|
||||
if level not in {"DEBUG", "INFO", "WARNING", "ERROR"}:
|
||||
level = "INFO"
|
||||
source = str(event.get("source") or "").strip()
|
||||
message = str(event.get("message") or "").strip()
|
||||
if message:
|
||||
prefix = f"[{item_index}/{total_items}] {engine_title} {item_label}"
|
||||
if source:
|
||||
prefix = f"{prefix} {source}"
|
||||
await task_service.add_log(
|
||||
job.task_id,
|
||||
level,
|
||||
f"{prefix}: {message}",
|
||||
)
|
||||
elif event_type == "pair_started":
|
||||
progress_state["message"] = (
|
||||
f"[{engine_code}/{run.profile_code}] Running "
|
||||
f"{item_index}/{total_items}: {item_label}"
|
||||
@@ -2892,6 +2926,52 @@ async def _handle_isce2_run(job: SystemJobORM) -> None:
|
||||
|
||||
|
||||
async def _handle_pyint_run(job: SystemJobORM) -> None:
|
||||
production_run_id = str((job.payload or {}).get("production_run_id") or "").strip()
|
||||
if production_run_id:
|
||||
try:
|
||||
await _run_wsl_dinsar_production_controller(
|
||||
job,
|
||||
engine_code="pyint",
|
||||
engine_title="PyINT/Gamma",
|
||||
fallback_timeout_seconds=settings.PYINT_DEFAULT_TIMEOUT_SECONDS,
|
||||
)
|
||||
except Exception as exc:
|
||||
latest_message = f"PyINT/Gamma D-InSAR production controller failed: {exc}"
|
||||
try:
|
||||
async with AsyncSessionLocal() as db:
|
||||
run = await dinsar_production_service.get_run(production_run_id, db)
|
||||
if run is not None and str(run.status or "").strip().upper() not in {"COMPLETED", "FAILED", "CANCELLED"}:
|
||||
summary_payload = dict(run.summary_json or {})
|
||||
summary_payload["controller_error"] = str(exc)
|
||||
await dinsar_production_service.finalize_run(
|
||||
run,
|
||||
db=db,
|
||||
status="FAILED",
|
||||
summary_payload=summary_payload,
|
||||
latest_message=latest_message,
|
||||
)
|
||||
dinsar_production_service.append_run_log(
|
||||
run.run_id,
|
||||
f"[controller-failed] {exc}",
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
current_task = await task_service.get_task(job.task_id)
|
||||
if current_task and current_task.status not in {"COMPLETED", "FAILED", "CANCELLED"}:
|
||||
await task_service.add_log(job.task_id, "ERROR", latest_message)
|
||||
await task_service.update_task(
|
||||
job.task_id,
|
||||
status="FAILED",
|
||||
progress=100,
|
||||
message=latest_message,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
raise
|
||||
return
|
||||
|
||||
await _handle_queued_engine_run(
|
||||
job,
|
||||
engine_title="PyINT",
|
||||
|
||||
@@ -316,6 +316,7 @@ def get_pyint_dem_summary() -> Dict[str, Any]:
|
||||
"hdr_exists": bool(prepared_dem_info.get("hdr_exists")),
|
||||
"vrt_exists": bool(prepared_dem_info.get("vrt_exists")),
|
||||
},
|
||||
"configured_resolution_m": float(getattr(settings, "PYINT_DEM_RESOLUTION_M", 30.0) or 30.0),
|
||||
"opentopo_dem_type": opentopo_dem_type,
|
||||
"opentopo_api_key_configured": bool(opentopo_api_key),
|
||||
"status": status,
|
||||
|
||||
@@ -4,6 +4,8 @@ from __future__ import annotations
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import math
|
||||
import defusedxml.ElementTree as ET
|
||||
from dataclasses import dataclass, field
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -11,12 +13,83 @@ from typing import Any, Dict, Iterable, List, Optional
|
||||
|
||||
from ..config import get_env_text, read_bool_env, settings
|
||||
from .dinsar_naming import PAIR_META_FILENAME, build_fallback_pair_key, find_json_sidecar
|
||||
from .wsl_service import run_wsl_command
|
||||
from .wsl_service import run_wsl_exec
|
||||
|
||||
|
||||
LT1_INPUT_GLOBS = ("LT1*.tar.gz", "LT1*.tiff")
|
||||
DEFAULT_RANGE_LOOKS = 2
|
||||
DEFAULT_AZIMUTH_LOOKS = 2
|
||||
DEFAULT_DEM_RESOLUTION_M = 30.0
|
||||
DEFAULT_UNWRAP_COH_THRESHOLD = 0.05
|
||||
DEFAULT_PRODUCT_COH_THRESHOLD = 0.20
|
||||
DEFAULT_REFERENCE_MODE = "none"
|
||||
DEFAULT_REFERENCE_COH_THRESHOLD = 0.30
|
||||
DEFAULT_DERAMP_MODE = "none"
|
||||
DEFAULT_DERAMP_COH_THRESHOLD = 0.30
|
||||
DEFAULT_GEO_INTERP = "1"
|
||||
DEFAULT_ATMCOR_ENABLED = False
|
||||
DEFAULT_ATMCOR_USE_FOR_DISP = False
|
||||
DEFAULT_REFLATTEN_ENABLED = True
|
||||
DEFAULT_REFLATTEN_MODEL = "plane"
|
||||
DEFAULT_REFLATTEN_COH_THRESHOLD = 0.70
|
||||
DEFAULT_REFLATTEN_FALLBACK_COH_THRESHOLD = 0.20
|
||||
DEFAULT_REFLATTEN_RANGE_STEP = 32
|
||||
DEFAULT_REFLATTEN_AZIMUTH_STEP = 32
|
||||
DEM_OVERSAMPLING_MIN = 0.25
|
||||
DEM_OVERSAMPLING_MAX = 16.0
|
||||
REFERENCE_MODE_CHOICES = {"none", "coh_median"}
|
||||
DERAMP_MODE_CHOICES = {"none", "plane"}
|
||||
REFLATTEN_MODEL_CHOICES = {"plane", "linear", "quadratic"}
|
||||
|
||||
|
||||
def _read_default_target_grid_size_m() -> int:
|
||||
for name in ("PYINT_DEFAULT_TARGET_GRID_SIZE_M",):
|
||||
text = str(get_env_text(name, "") or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
try:
|
||||
value = float(text)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
if value > 0:
|
||||
return int(value)
|
||||
return 0
|
||||
|
||||
|
||||
def _read_float_env(names: Iterable[str], default: float) -> float:
|
||||
for name in names:
|
||||
text = str(get_env_text(name, "") or "").strip()
|
||||
if not text:
|
||||
continue
|
||||
try:
|
||||
value = float(text)
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
if math.isfinite(value):
|
||||
return value
|
||||
return float(default)
|
||||
|
||||
|
||||
DEFAULT_TARGET_GRID_SIZE_M = _read_default_target_grid_size_m()
|
||||
TARGET_GRID_SIZE_MIN_M = 0
|
||||
TARGET_GRID_SIZE_MAX_M = 100
|
||||
DEFAULT_DEM_RESOLUTION_M = _read_float_env(("PYINT_DEM_RESOLUTION_M",), DEFAULT_DEM_RESOLUTION_M)
|
||||
DEFAULT_UNWRAP_COH_THRESHOLD = _read_float_env(
|
||||
("PYINT_UNWRAP_COH_THRESHOLD",),
|
||||
DEFAULT_UNWRAP_COH_THRESHOLD,
|
||||
)
|
||||
DEFAULT_PRODUCT_COH_THRESHOLD = _read_float_env(
|
||||
("PYINT_PRODUCT_COH_THRESHOLD", "PYINT_COHERENCE_MASK_THRESHOLD"),
|
||||
DEFAULT_PRODUCT_COH_THRESHOLD,
|
||||
)
|
||||
DEFAULT_REFERENCE_COH_THRESHOLD = _read_float_env(
|
||||
("PYINT_REFERENCE_COH_THRESHOLD",),
|
||||
DEFAULT_REFERENCE_COH_THRESHOLD,
|
||||
)
|
||||
DEFAULT_DERAMP_COH_THRESHOLD = _read_float_env(
|
||||
("PYINT_DERAMP_COH_THRESHOLD",),
|
||||
DEFAULT_DERAMP_COH_THRESHOLD,
|
||||
)
|
||||
DEFAULT_PARALLEL_WORKERS = 1
|
||||
MAX_LOOKS = 32
|
||||
MAX_PARALLEL_WORKERS = 16
|
||||
@@ -76,6 +149,180 @@ def normalize_date_text(value: Any) -> str:
|
||||
return ""
|
||||
|
||||
|
||||
def _local_xml_tag_name(tag: Any) -> str:
|
||||
text = str(tag or "")
|
||||
return text.split("}")[-1] if "}" in text else text
|
||||
|
||||
|
||||
def _read_xml_first_parameter(xml_file: str, names: Iterable[str]) -> Optional[str]:
|
||||
path = os.path.normpath(str(xml_file or "").strip())
|
||||
if not path or not os.path.isfile(path):
|
||||
return None
|
||||
wanted = {str(name or "").strip().lower() for name in names if str(name or "").strip()}
|
||||
if not wanted:
|
||||
return None
|
||||
try:
|
||||
tree = ET.parse(path)
|
||||
root = tree.getroot()
|
||||
except Exception:
|
||||
return None
|
||||
for elem in root.iter():
|
||||
local_name = _local_xml_tag_name(elem.tag).lower()
|
||||
if local_name in wanted and elem.text and str(elem.text).strip():
|
||||
return str(elem.text).strip()
|
||||
return None
|
||||
|
||||
|
||||
def _read_scene_geometry_metadata(metadata_path: str) -> Dict[str, Any]:
|
||||
source = os.path.normpath(str(metadata_path or "").strip())
|
||||
range_spacing = _read_xml_first_parameter(
|
||||
source,
|
||||
("PixelSpacingRg", "columnSpacing", "slantRange", "range_pixel_spacing"),
|
||||
)
|
||||
azimuth_spacing = _read_xml_first_parameter(
|
||||
source,
|
||||
("PixelSpacingAz", "rowSpacing", "projectedSpacingAzimuth", "azimuth_pixel_spacing"),
|
||||
)
|
||||
incidence_angle = _read_xml_first_parameter(
|
||||
source,
|
||||
("IncidenceAngle", "incidence_angle"),
|
||||
)
|
||||
if not all((range_spacing, azimuth_spacing, incidence_angle)):
|
||||
raise ValueError(f"Cannot read range/azimuth spacing and incidence angle from: {source}")
|
||||
return {
|
||||
"source": source,
|
||||
"range_pixel_spacing_m": float(range_spacing),
|
||||
"azimuth_pixel_spacing_m": float(azimuth_spacing),
|
||||
"incidence_angle_deg": float(incidence_angle),
|
||||
}
|
||||
|
||||
|
||||
def _scene_geometry_metadata_candidates(directory: str, patterns: Iterable[str]) -> List[str]:
|
||||
root = os.path.normpath(str(directory or "").strip())
|
||||
if not root or not os.path.isdir(root):
|
||||
return []
|
||||
candidates: List[str] = []
|
||||
for pattern in patterns:
|
||||
candidates.extend(str(path) for path in Path(root).glob(pattern) if path.is_file())
|
||||
return [
|
||||
os.path.normpath(path)
|
||||
for path in sorted(
|
||||
set(candidates),
|
||||
key=lambda item: (0 if item.lower().endswith(".sml") else 1, item.lower()),
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def resolve_scene_geometry_metadata_files(scene_dir: str) -> List[str]:
|
||||
return _scene_geometry_metadata_candidates(
|
||||
scene_dir,
|
||||
(
|
||||
"*.sml",
|
||||
"*.SML",
|
||||
"*.meta.xml",
|
||||
"*.META.XML",
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def resolve_scene_geometry_metadata_file(scene_dir: str) -> str:
|
||||
candidates = resolve_scene_geometry_metadata_files(scene_dir)
|
||||
return candidates[0] if candidates else ""
|
||||
|
||||
|
||||
def calculate_looks_from_scene_metadata(
|
||||
*,
|
||||
master_metadata: str,
|
||||
slave_metadata: str,
|
||||
target_resolution_m: float,
|
||||
) -> Dict[str, Any]:
|
||||
target_resolution = float(target_resolution_m)
|
||||
if target_resolution <= 0:
|
||||
raise ValueError("target_resolution_m must be greater than 0")
|
||||
|
||||
master = _read_scene_geometry_metadata(master_metadata)
|
||||
slave = _read_scene_geometry_metadata(slave_metadata)
|
||||
|
||||
avg_azimuth = (
|
||||
float(master["azimuth_pixel_spacing_m"]) + float(slave["azimuth_pixel_spacing_m"])
|
||||
) / 2.0
|
||||
master_ground_range = float(master["range_pixel_spacing_m"]) / math.sin(
|
||||
math.radians(float(master["incidence_angle_deg"]))
|
||||
)
|
||||
slave_ground_range = float(slave["range_pixel_spacing_m"]) / math.sin(
|
||||
math.radians(float(slave["incidence_angle_deg"]))
|
||||
)
|
||||
avg_ground_range = (master_ground_range + slave_ground_range) / 2.0
|
||||
|
||||
range_ratio = target_resolution / avg_ground_range
|
||||
azimuth_ratio = target_resolution / avg_azimuth
|
||||
range_looks = max(1, int(math.floor(range_ratio + 0.5)))
|
||||
azimuth_looks = max(1, int(math.floor(azimuth_ratio + 0.5)))
|
||||
|
||||
return {
|
||||
"mode": "target_grid_size",
|
||||
"target_resolution_m": target_resolution,
|
||||
"range_looks": range_looks,
|
||||
"azimuth_looks": azimuth_looks,
|
||||
"avg_ground_range_spacing_m": avg_ground_range,
|
||||
"avg_azimuth_spacing_m": avg_azimuth,
|
||||
"range_look_ratio": range_ratio,
|
||||
"azimuth_look_ratio": azimuth_ratio,
|
||||
"resolved_ground_range_spacing_m": avg_ground_range * range_looks,
|
||||
"resolved_azimuth_spacing_m": avg_azimuth * azimuth_looks,
|
||||
"master": master,
|
||||
"slave": slave,
|
||||
}
|
||||
|
||||
|
||||
def calculate_looks_from_task_dir(task_dir: str, target_resolution_m: float) -> Dict[str, Any]:
|
||||
task_root = os.path.normpath(str(task_dir or "").strip())
|
||||
master_candidates = resolve_scene_geometry_metadata_files(os.path.join(task_root, "master"))
|
||||
slave_candidates = resolve_scene_geometry_metadata_files(os.path.join(task_root, "slave"))
|
||||
if not master_candidates or not slave_candidates:
|
||||
raise ValueError(f"Cannot find SML/meta XML metadata under task: {task_root}")
|
||||
errors: List[str] = []
|
||||
for master_metadata in master_candidates:
|
||||
for slave_metadata in slave_candidates:
|
||||
try:
|
||||
return calculate_looks_from_scene_metadata(
|
||||
master_metadata=master_metadata,
|
||||
slave_metadata=slave_metadata,
|
||||
target_resolution_m=target_resolution_m,
|
||||
)
|
||||
except Exception as exc:
|
||||
errors.append(f"{os.path.basename(master_metadata)} + {os.path.basename(slave_metadata)}: {exc}")
|
||||
detail = "; ".join(errors[:3]) if errors else "unknown metadata parsing error"
|
||||
raise ValueError(f"Cannot calculate looks from task metadata under {task_root}: {detail}")
|
||||
|
||||
|
||||
def calculate_dem_oversampling(
|
||||
*,
|
||||
dem_resolution_m: float,
|
||||
target_grid_size_m: float,
|
||||
) -> Dict[str, Any]:
|
||||
dem_resolution = float(dem_resolution_m or 0.0)
|
||||
target_grid = float(target_grid_size_m or 0.0)
|
||||
if not math.isfinite(dem_resolution) or dem_resolution <= 0:
|
||||
dem_resolution = DEFAULT_DEM_RESOLUTION_M
|
||||
|
||||
raw_factor = dem_resolution / target_grid if math.isfinite(target_grid) and target_grid > 0 else None
|
||||
oversampling = 1.0
|
||||
actual_grid = dem_resolution / oversampling if oversampling > 0 else dem_resolution
|
||||
mismatch_ratio = abs(actual_grid - target_grid) / target_grid if target_grid > 0 else None
|
||||
return {
|
||||
"mode": "gamma_dem_oversampling",
|
||||
"dem_resolution_m": dem_resolution,
|
||||
"target_grid_size_m": target_grid,
|
||||
"raw_oversampling": raw_factor,
|
||||
"oversampling": oversampling,
|
||||
"actual_grid_size_m": actual_grid,
|
||||
"mismatch_ratio": mismatch_ratio,
|
||||
"min_oversampling": DEM_OVERSAMPLING_MIN,
|
||||
"max_oversampling": DEM_OVERSAMPLING_MAX,
|
||||
}
|
||||
|
||||
|
||||
def slugify_text(value: Any, *, default: str = "item", max_len: int = 96) -> str:
|
||||
text = _SAFE_TEXT_RE.sub("_", str(value or "").strip()).strip("._")
|
||||
if not text:
|
||||
@@ -278,7 +525,14 @@ def _gamma_prefix(gamma_env_script_wsl: str) -> str:
|
||||
script = str(gamma_env_script_wsl or "").strip()
|
||||
if not script:
|
||||
return ""
|
||||
return f". {quote_shell(script)} >/dev/null 2>&1 && "
|
||||
return f". {quote_shell(script)} >/dev/null 2>&1 || exit 1; "
|
||||
|
||||
|
||||
def _pyint_path_prefix(pyint_home_wsl: str) -> str:
|
||||
home = str(pyint_home_wsl or "").strip().rstrip("/")
|
||||
if not home:
|
||||
return ""
|
||||
return f"export PATH={quote_shell(home + '/pyint')}:\"$PATH\" && "
|
||||
|
||||
|
||||
def check_pyint_environment(
|
||||
@@ -320,7 +574,10 @@ def check_pyint_environment(
|
||||
def add(name: str, ok: bool, detail: str = "", skipped: bool = False) -> None:
|
||||
checks.append(PyintCheck(name=name, ok=ok, detail=detail, skipped=skipped))
|
||||
|
||||
rc, out, err = run_wsl_command("echo pyint_alive", distro=distro_value, timeout=15)
|
||||
def run_check(command: str, timeout: int = 30):
|
||||
return run_wsl_exec(["bash", "-lc", command], distro=distro_value, timeout=timeout)
|
||||
|
||||
rc, out, err = run_check("echo pyint_alive", timeout=15)
|
||||
wsl_ok = rc == 0 and "pyint_alive" in out
|
||||
add("WSL distro", wsl_ok, out or err or distro_value)
|
||||
|
||||
@@ -331,17 +588,15 @@ def check_pyint_environment(
|
||||
message=f"WSL distro is unavailable: {distro_value}",
|
||||
)
|
||||
|
||||
rc, out, err = run_wsl_command(
|
||||
rc, out, err = run_check(
|
||||
f"{quote_shell(python_value)} --version",
|
||||
distro=distro_value,
|
||||
timeout=15,
|
||||
)
|
||||
add("WSL Python", rc == 0, out or err or python_value)
|
||||
|
||||
if pyint_home_wsl:
|
||||
rc, out, err = run_wsl_command(
|
||||
rc, out, err = run_check(
|
||||
f"test -d {quote_shell(pyint_home_wsl)} && echo ok",
|
||||
distro=distro_value,
|
||||
timeout=10,
|
||||
)
|
||||
add("PYINT_HOME", rc == 0 and "ok" in out, pyint_home_wsl or err)
|
||||
@@ -349,9 +604,8 @@ def check_pyint_environment(
|
||||
add("PYINT_HOME", False, "PYINT_HOME is empty")
|
||||
|
||||
if pyint_app_wsl:
|
||||
rc, out, err = run_wsl_command(
|
||||
rc, out, err = run_check(
|
||||
f"test -f {quote_shell(pyint_app_wsl)} && echo ok",
|
||||
distro=distro_value,
|
||||
timeout=10,
|
||||
)
|
||||
add("pyintApp.py", rc == 0 and "ok" in out, pyint_app_wsl or err)
|
||||
@@ -367,17 +621,15 @@ def check_pyint_environment(
|
||||
if not path_text:
|
||||
add(name, False, f"{name} is empty")
|
||||
continue
|
||||
rc, out, err = run_wsl_command(
|
||||
rc, out, err = run_check(
|
||||
f"test -d {quote_shell(path_text)} && test -w {quote_shell(path_text)} && echo ok",
|
||||
distro=distro_value,
|
||||
timeout=10,
|
||||
)
|
||||
add(name, rc == 0 and "ok" in out, path_text or err)
|
||||
|
||||
if gamma_env_wsl:
|
||||
rc, out, err = run_wsl_command(
|
||||
rc, out, err = run_check(
|
||||
f"test -f {quote_shell(gamma_env_wsl)} && echo ok",
|
||||
distro=distro_value,
|
||||
timeout=10,
|
||||
)
|
||||
add("GAMMA env script", rc == 0 and "ok" in out, gamma_env_wsl or err)
|
||||
@@ -385,16 +637,16 @@ def check_pyint_environment(
|
||||
add("GAMMA env script", True, "Not configured; using current PATH", skipped=True)
|
||||
|
||||
gamma_prefix = _gamma_prefix(gamma_env_wsl)
|
||||
pyint_prefix = _pyint_path_prefix(pyint_home_wsl)
|
||||
for name, command_name in (
|
||||
("GAMMA LT1 import", "LT1_import_SLC_from_zipfiles1"),
|
||||
("GAMMA geocode_back", "geocode_back"),
|
||||
):
|
||||
rc, out, err = run_wsl_command(
|
||||
gamma_prefix + f"command -v {quote_shell(command_name)}",
|
||||
distro=distro_value,
|
||||
rc, out, err = run_check(
|
||||
gamma_prefix + pyint_prefix + f"command -v {quote_shell(command_name)} >/dev/null 2>&1 && echo ok",
|
||||
timeout=10,
|
||||
)
|
||||
add(name, rc == 0 and bool(out.strip()), out or err or command_name)
|
||||
add(name, rc == 0 and "ok" in out, out or err or command_name)
|
||||
|
||||
helper_path = (
|
||||
Path(__file__).resolve().parent.parent
|
||||
@@ -412,7 +664,7 @@ def check_pyint_environment(
|
||||
+ gamma_prefix
|
||||
+ f"{quote_shell(python_value)} {quote_shell(pyint_app_wsl)} -h >/dev/null"
|
||||
)
|
||||
rc, out, err = run_wsl_command(smoke_cmd, distro=distro_value, timeout=60)
|
||||
rc, out, err = run_check(smoke_cmd, timeout=60)
|
||||
add("PyINT smoke test", rc == 0, out or err or "pyintApp.py -h")
|
||||
else:
|
||||
add("PyINT smoke test", True, "Skipped", skipped=True)
|
||||
|
||||
@@ -11,8 +11,10 @@ from __future__ import annotations
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Dict, List, Optional, Sequence, Tuple
|
||||
from typing import Any, Callable, Dict, List, Optional, Sequence, Tuple
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -101,6 +103,79 @@ def _run_windows_command(
|
||||
)
|
||||
|
||||
|
||||
def _run_windows_command_stream(
|
||||
args: List[str],
|
||||
timeout: int = 30,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
stdout_callback: Optional[Callable[[str], None]] = None,
|
||||
stderr_callback: Optional[Callable[[str], None]] = None,
|
||||
) -> Tuple[int, str, str]:
|
||||
proc_env = os.environ.copy()
|
||||
if env:
|
||||
proc_env.update(env)
|
||||
|
||||
stdout_parts: List[str] = []
|
||||
stderr_parts: List[str] = []
|
||||
try:
|
||||
proc = subprocess.Popen(
|
||||
args,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=False,
|
||||
env=proc_env,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
return -2, "", "wsl.exe not found"
|
||||
except Exception as exc:
|
||||
return -3, "", str(exc)
|
||||
|
||||
def _drain(stream: Any, parts: List[str], callback: Optional[Callable[[str], None]]) -> None:
|
||||
for raw_line in iter(stream.readline, b""):
|
||||
text = _decode_subprocess_output(raw_line)
|
||||
if not text:
|
||||
continue
|
||||
parts.append(text)
|
||||
if callback:
|
||||
try:
|
||||
callback(text)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
threads = [
|
||||
threading.Thread(target=_drain, args=(proc.stdout, stdout_parts, stdout_callback), daemon=True),
|
||||
threading.Thread(target=_drain, args=(proc.stderr, stderr_parts, stderr_callback), daemon=True),
|
||||
]
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
timed_out = False
|
||||
deadline = time.monotonic() + max(1, int(timeout or 30))
|
||||
while proc.poll() is None:
|
||||
if time.monotonic() >= deadline:
|
||||
timed_out = True
|
||||
try:
|
||||
proc.kill()
|
||||
except Exception:
|
||||
pass
|
||||
break
|
||||
time.sleep(0.2)
|
||||
|
||||
try:
|
||||
returncode = proc.wait(timeout=10)
|
||||
except subprocess.TimeoutExpired:
|
||||
returncode = -1
|
||||
for thread in threads:
|
||||
thread.join(timeout=5)
|
||||
|
||||
stdout = "\n".join(stdout_parts)
|
||||
stderr = "\n".join(stderr_parts)
|
||||
if timed_out:
|
||||
timeout_text = f"command timed out ({timeout}s)"
|
||||
stderr = f"{stderr}\n{timeout_text}".strip()
|
||||
return -1, stdout, stderr
|
||||
return returncode, stdout, stderr
|
||||
|
||||
|
||||
def run_wsl_command(
|
||||
cmd: str,
|
||||
distro: Optional[str] = None,
|
||||
@@ -127,6 +202,33 @@ def run_wsl_command(
|
||||
return -3, "", str(exc)
|
||||
|
||||
|
||||
def run_wsl_command_stream(
|
||||
cmd: str,
|
||||
distro: Optional[str] = None,
|
||||
timeout: int = 30,
|
||||
env: Optional[Dict[str, str]] = None,
|
||||
stdout_callback: Optional[Callable[[str], None]] = None,
|
||||
stderr_callback: Optional[Callable[[str], None]] = None,
|
||||
) -> Tuple[int, str, str]:
|
||||
"""Run a WSL bash command and stream decoded stdout/stderr lines to callbacks."""
|
||||
wsl_exe = _find_wsl_executable()
|
||||
if not wsl_exe:
|
||||
return -2, "", "wsl.exe not found"
|
||||
|
||||
wsl_args = [wsl_exe]
|
||||
if distro:
|
||||
wsl_args += ["-d", distro]
|
||||
wsl_args += ["bash", "-lc", cmd]
|
||||
|
||||
return _run_windows_command_stream(
|
||||
wsl_args,
|
||||
timeout=timeout,
|
||||
env=env,
|
||||
stdout_callback=stdout_callback,
|
||||
stderr_callback=stderr_callback,
|
||||
)
|
||||
|
||||
|
||||
def run_wsl_exec(
|
||||
argv: Sequence[str],
|
||||
distro: Optional[str] = None,
|
||||
|
||||
@@ -60,7 +60,7 @@ for _gamma_dir in \
|
||||
_gamma_profile_prepend_path "${_gamma_dir}"
|
||||
done
|
||||
|
||||
_gamma_profile_repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
_gamma_profile_repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||||
_gamma_profile_pyint_dir="${_gamma_profile_repo_root}/third_party/PyINT/pyint"
|
||||
_gamma_profile_prepend_path "${_gamma_profile_pyint_dir}"
|
||||
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
# ISCE2 SBAS Time-Series Experiments
|
||||
|
||||
This folder is the isolated sandbox for validating the SBAS/time-series route before wiring it into production code.
|
||||
|
||||
## Purpose
|
||||
|
||||
- verify LT-1 stack compatibility with ISCE2 stack tooling
|
||||
- validate MintPy input and output expectations
|
||||
- record runnable command templates
|
||||
- collect conclusions that should later be promoted into `docs/` or backend services
|
||||
- maintain the current SBAS product contract before backend embedding
|
||||
|
||||
## Structure
|
||||
|
||||
- `notes/`
|
||||
- experiment notes, pitfalls, conclusions
|
||||
- `configs/`
|
||||
- sample templates, parameter files, manifest drafts
|
||||
- `scripts/`
|
||||
- throwaway or semi-stable experiment scripts
|
||||
- `scratch/`
|
||||
- local temporary workspace placeholder only
|
||||
|
||||
## Rules
|
||||
|
||||
- do not commit raw SAR scenes
|
||||
- do not commit large DEM or orbit datasets
|
||||
- do not commit large intermediate outputs
|
||||
- keep production code changes out of this folder unless the goal is to prototype file layout or commands
|
||||
- when an experiment becomes stable, move the result back into the formal backend or `docs/`
|
||||
|
||||
## Suggested first experiments
|
||||
|
||||
1. Check whether LT-1/LUTAN1 scenes can be ingested by official ISCE2 stack tooling.
|
||||
2. Determine whether MintPy can consume the generated stack layout without extra conversion.
|
||||
3. Record the minimal command chain needed for one small AOI smoke test.
|
||||
4. Draft the first `psinsar` manifest and product directory convention.
|
||||
|
||||
## Current scripts
|
||||
|
||||
- `backend/app/isce2_pipeline/lt1_input_resolver.py`
|
||||
- shared LT-1 input helper reused by D-InSAR and stack experiments
|
||||
- centralizes DEM resolution, orbit-pool resolution, and LT-1 precise-orbit XML generation
|
||||
- `scripts/scan_lt1_stack_candidates.py`
|
||||
- scan LT-1 single-scene folders and build a stack candidate manifest
|
||||
- `scripts/build_lt1_stack_prep.py`
|
||||
- consume a selected stack manifest
|
||||
- resolve orbit pool and DEM
|
||||
- generate a dry-run `scratch/...` workspace for `stripmapStack --nofocus`
|
||||
- write the current adapter contract and a preflight run script
|
||||
- `scripts/materialize_lt1_stack_scenes.py`
|
||||
- consume `scratch/.../stack_input_manifest.json`
|
||||
- materialize one or more LT-1 acquisitions into `SLC/YYYYMMDD/`
|
||||
- write `YYYYMMDD.slc`, `YYYYMMDD.slc.xml`, and `data`
|
||||
- `scripts/install_isce2_stack_runtime_ubuntu2404.sh`
|
||||
- install known WSL `isce2` runtime dependencies
|
||||
- default pip mirror is Tsinghua
|
||||
- `scripts/install_mintpy_runtime_ubuntu2404.sh`
|
||||
- create or update a dedicated WSL `mintpy` conda environment
|
||||
- default conda channels use Tsinghua mirror URLs
|
||||
- `scripts/install_mintpy_into_cloned_isce2_env_ubuntu2404.sh`
|
||||
- clone the working WSL `isce2` env into a dedicated unified-env target such as `isce2_mintpy`
|
||||
- install MintPy into that clone with Tsinghua mirror channels
|
||||
- `scripts/run_mintpy_unified_env_ubuntu2404.sh`
|
||||
- run MintPy commands directly inside the cloned unified env
|
||||
- `scripts/run_mintpy_sbas_unified_env_smoketest_ubuntu2404.sh`
|
||||
- run the current LT-1 SBAS smoke test in the cloned unified env
|
||||
- reuses the same strict-mask and patched-launcher helpers as the bridge route
|
||||
- `scripts/run_mintpy_with_isce_ubuntu2404.sh`
|
||||
- run MintPy commands in the dedicated `mintpy` env
|
||||
- bridge only the top-level WSL `isce` package into the `mintpy` env
|
||||
- avoids pulling conflicting `h5py` / numeric packages from the `isce2` env
|
||||
- `scripts/create_mintpy_all_ifgram_mask.py`
|
||||
- build a strict `maskAllValid.h5` from `inputs/ifgramStack.h5`
|
||||
- keep only pixels valid in all interferograms before SBAS inversion
|
||||
- `scripts/run_smallbaselineApp_patched.py`
|
||||
- repo-local launcher for MintPy `smallbaselineApp`
|
||||
- applies a local workaround for the MintPy `1.6.2` single-pixel partial-network inversion bug
|
||||
- `scripts/run_mintpy_sbas_smoketest_ubuntu2404.sh`
|
||||
- run the current LT-1 SBAS smoke test in three steps:
|
||||
- `load_data`
|
||||
- strict-mask generation
|
||||
- `modify_network -> velocity`
|
||||
- `scripts/export_mintpy_publish_products_ubuntu2404.sh`
|
||||
- geocode MintPy outputs into latitude/longitude grids
|
||||
- convert selected outputs into GeoTIFF
|
||||
- build a publish-style bundle with `manifest.json`, `assets/`, `preview/`, and `metadata/`
|
||||
- defaults to the bridge runner but now also supports `MINTPY_RUNNER=...` override
|
||||
- `scripts/export_mintpy_publish_products_unified_env_ubuntu2404.sh`
|
||||
- run the same publish export logic through the cloned unified env runner
|
||||
- `scripts/export_conda_env_snapshot_ubuntu2404.sh`
|
||||
- export one WSL conda environment into reproducible snapshot files
|
||||
- writes `no_builds.yml`, `explicit.txt`, `conda_list.txt`, and `runtime_versions.txt`
|
||||
- `scripts/export_phase4_env_snapshots_ubuntu2404.sh`
|
||||
- export both `isce2` and `isce2_mintpy_v1` snapshots for the current phase-4 record
|
||||
- `scripts/build_mintpy_publish_bundle.py`
|
||||
- generate `preview/velocity_preview.png`
|
||||
- summarize quality masks
|
||||
- write the publish-style `manifest.json`
|
||||
- `scripts/prepare_lt1_stack_dem.py`
|
||||
- clip a stack-local DEM window from the source DEM
|
||||
- store it under `scratch/.../inputs/dem/`
|
||||
- avoid global-DEM bbox problems during `createWaterMask`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh`
|
||||
- execute one generated `run_XX_*` file under `Ubuntu-24.04`
|
||||
- standardize `PATH`, `PYTHONPATH`, and log output
|
||||
- `scripts/create_synthetic_watermask.py`
|
||||
- create a local all-land `geom_reference/waterMask.rdr`
|
||||
- used only when `run_01_reference` cannot download `SWBD` from Earthdata
|
||||
|
||||
## Reproducible Flow
|
||||
|
||||
1. Generate or refresh the sample stack workspace with `build_lt1_stack_prep.py`.
|
||||
2. Materialize the LT-1 acquisitions with `materialize_lt1_stack_scenes.py`.
|
||||
3. Clip a stack-local DEM window with `prepare_lt1_stack_dem.py`.
|
||||
4. In `Ubuntu-24.04`, run `scripts/install_isce2_stack_runtime_ubuntu2404.sh`.
|
||||
5. Regenerate the stack workspace so it picks the local DEM.
|
||||
6. Run the generated wrapper through the validated chain:
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_01_reference`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_02_focus_split`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_03_geo2rdr_coarseResamp`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_04_refineSecondaryTiming`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_05_invertMisreg`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_06_fineResamp`
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh <scratch_root_wsl> run_07_grid_baseline`
|
||||
- if Earthdata credentials are missing, the wrapper now auto-generates a synthetic all-land `waterMask.rdr` from `shadowMask.rdr` and treats `run_01_reference` as recovered
|
||||
7. In `Ubuntu-24.04`, run `scripts/install_mintpy_runtime_ubuntu2404.sh` before the first MintPy validation.
|
||||
8. In `Ubuntu-24.04`, run `scripts/run_mintpy_with_isce_ubuntu2404.sh prep_isce.py ...` for the first MintPy metadata preparation on stripmapStack outputs.
|
||||
9. In `Ubuntu-24.04`, run:
|
||||
- `scripts/run_mintpy_sbas_smoketest_ubuntu2404.sh <cfg_wsl> <mintpy_work_dir_wsl>`
|
||||
10. Review:
|
||||
- `notes/PHASE2_MINTPY_SBAS_SMOKETEST.md`
|
||||
11. In `Ubuntu-24.04`, run:
|
||||
- `scripts/export_mintpy_publish_products_ubuntu2404.sh <mintpy_work_dir_wsl> <publish_dir_wsl>`
|
||||
12. Review:
|
||||
- `notes/PHASE3_PUBLISH_EXPORT_SMOKETEST.md`
|
||||
13. Record findings under `notes/` before promoting anything into backend code.
|
||||
|
||||
## Product Contract
|
||||
|
||||
Formal product guidance now lives in:
|
||||
|
||||
- `docs/ISCE2_SBAS_PRODUCT_SPEC.md`
|
||||
|
||||
Current practical rule:
|
||||
|
||||
- runtime success is proven by radar-coordinate `timeseries.h5` and `velocity.h5`
|
||||
- publish success is proven by a geocoded bundle under `publish/.../`
|
||||
- system embedding should treat `manifest.json` as the publish entrypoint
|
||||
- true time-series capability should be judged against `assets/geo_timeseries.h5`, not only `assets/velocity.tif`
|
||||
|
||||
## Unified-Environment Track
|
||||
|
||||
The bridge route remains the validated baseline.
|
||||
|
||||
A separate unified-environment experiment is now staged in:
|
||||
|
||||
- `notes/PHASE4_UNIFIED_ENV_EXPERIMENT.md`
|
||||
- `notes/PHASE4_UNIFIED_ENV_DECISION.md`
|
||||
|
||||
Current practical rule:
|
||||
|
||||
- the unified env has now completed the same SBAS smoke test chain and publish export in experiment scope
|
||||
- the unified env is now the preferred SBAS experiment runtime
|
||||
- do not replace or mutate the current `isce2` env used by D-InSAR production
|
||||
- do not replace the bridge route as the default fallback until the comparison note is fully written
|
||||
- current successful unified env:
|
||||
- `/home/administrator/miniconda3/envs/isce2_mintpy_v1`
|
||||
- current successful unified SBAS work dir:
|
||||
- `scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_unified_v1`
|
||||
- current successful unified publish dir:
|
||||
- `scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_unified_v1`
|
||||
|
||||
## Current Offline Assumption
|
||||
|
||||
- the LT-1 sample experiment already has local SAR scenes, local orbit XML, and a local DEM
|
||||
- the remaining optional online dependency is the `SWBD` water mask normally fetched by `createWaterMask.py`
|
||||
- for this experiment track, do not download `SWBD`
|
||||
- continue with the local synthetic all-land `waterMask.rdr` fallback until the stack route is otherwise stable
|
||||
- current validated MintPy boundary is radar-coordinate `timeseries.h5` plus `velocity.h5`
|
||||
- current validated publish boundary is a geocoded experiment bundle under `publish/.../`
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
-227
@@ -1,227 +0,0 @@
|
||||
# packages in environment at /home/administrator/miniconda3/envs/isce2:
|
||||
#
|
||||
# Name Version Build Channel
|
||||
_openmp_mutex 4.5 20_gnu conda-forge
|
||||
aom 3.9.1 hac33072_0 conda-forge
|
||||
attr 2.5.2 h39aace5_0 conda-forge
|
||||
aws-c-auth 0.9.3 hef928c7_0 conda-forge
|
||||
aws-c-cal 0.9.13 h2c9d079_1 conda-forge
|
||||
aws-c-common 0.12.6 hb03c661_0 conda-forge
|
||||
aws-c-compression 0.3.1 h8b1a151_9 conda-forge
|
||||
aws-c-event-stream 0.5.7 h28f887f_1 conda-forge
|
||||
aws-c-http 0.10.7 ha8fc4e3_5 conda-forge
|
||||
aws-c-io 0.23.3 hdaf4b65_5 conda-forge
|
||||
aws-c-mqtt 0.13.3 hc63082f_11 conda-forge
|
||||
aws-c-s3 0.11.3 h06ab39a_1 conda-forge
|
||||
aws-c-sdkutils 0.2.4 h8b1a151_4 conda-forge
|
||||
aws-checksums 0.2.7 h8b1a151_5 conda-forge
|
||||
aws-crt-cpp 0.35.2 h8824e59_6 conda-forge
|
||||
aws-sdk-cpp 1.11.606 hf38915e_9 conda-forge
|
||||
azure-core-cpp 1.16.1 h3a458e0_0 conda-forge
|
||||
azure-identity-cpp 1.13.2 h3a5f585_1 conda-forge
|
||||
azure-storage-blobs-cpp 12.15.0 h2a74896_1 conda-forge
|
||||
azure-storage-common-cpp 12.11.0 h3d7a050_1 conda-forge
|
||||
azure-storage-files-datalake-cpp 12.13.0 hf38f1be_1 conda-forge
|
||||
backports.zstd 1.3.0 py311h6b1f9c4_0 conda-forge
|
||||
blosc 1.21.6 he440d0b_1 conda-forge
|
||||
brotli-python 1.2.0 py311h66f275b_1 conda-forge
|
||||
brunsli 0.1 hd1e3526_2 conda-forge
|
||||
bzip2 1.0.8 hda65f42_9 conda-forge
|
||||
c-ares 1.34.6 hb03c661_0 conda-forge
|
||||
c-blosc2 2.23.1 hc31b594_0 conda-forge
|
||||
ca-certificates 2026.2.25 hbd8a1cb_0 conda-forge
|
||||
cached-property 1.5.2 hd8ed1ab_1 conda-forge
|
||||
cached_property 1.5.2 pyha770c72_1 conda-forge
|
||||
cairo 1.18.4 he90730b_1 conda-forge
|
||||
capnproto 1.2.0 hfc315d8_0 conda-forge
|
||||
certifi 2026.2.25 pyhd8ed1ab_0 conda-forge
|
||||
cfitsio 4.6.3 ha0b56bc_0 conda-forge
|
||||
charls 2.4.3 hecca717_0 conda-forge
|
||||
charset-normalizer 3.4.5 pyhd8ed1ab_0 conda-forge
|
||||
contourpy 1.3.3 pypi_0 pypi
|
||||
cycler 0.12.1 pypi_0 pypi
|
||||
cyrus-sasl 2.1.28 hac629b4_1 conda-forge
|
||||
dav1d 1.2.1 hd590300_0 conda-forge
|
||||
fftw 3.3.10 nompi_h3b011a4_112 conda-forge
|
||||
fmt 12.0.0 h2b0788b_0 conda-forge
|
||||
font-ttf-dejavu-sans-mono 2.37 hab24e00_0 conda-forge
|
||||
font-ttf-inconsolata 3.000 h77eed37_0 conda-forge
|
||||
font-ttf-source-code-pro 2.038 h77eed37_0 conda-forge
|
||||
font-ttf-ubuntu 0.83 h77eed37_3 conda-forge
|
||||
fontconfig 2.17.1 h27c8c51_0 conda-forge
|
||||
fonts-conda-ecosystem 1 0 conda-forge
|
||||
fonts-conda-forge 1 hc364b38_1 conda-forge
|
||||
fonttools 4.62.1 pypi_0 pypi
|
||||
freetype 2.14.2 ha770c72_0 conda-forge
|
||||
freexl 2.0.0 h9dce30a_2 conda-forge
|
||||
gdal 3.10.3 py311h34ccccb_27 conda-forge
|
||||
geos 3.14.1 h480dda7_0 conda-forge
|
||||
geotiff 1.7.4 h1000f5c_4 conda-forge
|
||||
giflib 5.2.2 hd590300_0 conda-forge
|
||||
h2 4.3.0 pyhcf101f3_0 conda-forge
|
||||
h5py 3.15.1 nompi_py311h0b2f468_101 conda-forge
|
||||
hdf4 4.2.15 h2a13503_7 conda-forge
|
||||
hdf5 1.14.6 nompi_h19486de_106 conda-forge
|
||||
hpack 4.1.0 pyhd8ed1ab_0 conda-forge
|
||||
hyperframe 6.1.0 pyhd8ed1ab_0 conda-forge
|
||||
icu 78.2 h33c6efd_0 conda-forge
|
||||
idna 3.11 pyhd8ed1ab_0 conda-forge
|
||||
imagecodecs 2026.3.6 py311h9837d23_1 conda-forge
|
||||
imageio 2.37.0 pyhfb79c49_0 conda-forge
|
||||
isce2 2.6.4 py311h916084f_2 conda-forge
|
||||
json-c 0.18 h6688a6e_0 conda-forge
|
||||
jxrlib 1.1 hd590300_3 conda-forge
|
||||
kealib 1.6.2 hb2f3951_2 conda-forge
|
||||
keyutils 1.6.3 hb9d3cd8_0 conda-forge
|
||||
kiwisolver 1.5.0 pypi_0 pypi
|
||||
krb5 1.22.2 ha1258a1_0 conda-forge
|
||||
lazy-loader 0.5 pyhd8ed1ab_0 conda-forge
|
||||
lcms2 2.18 h0c24ade_0 conda-forge
|
||||
ld_impl_linux-64 2.45.1 default_hbd61a6d_101 conda-forge
|
||||
lerc 4.1.0 hdb68285_0 conda-forge
|
||||
libabseil 20250512.1 cxx17_hba17884_0 conda-forge
|
||||
libacl 2.3.2 h0f662aa_0 conda-forge
|
||||
libaec 1.1.5 h088129d_0 conda-forge
|
||||
libarchive 3.8.5 gpl_hc2c16d8_100 conda-forge
|
||||
libavif16 1.4.0 hcfa2d63_0 conda-forge
|
||||
libblas 3.11.0 5_h4a7cf45_openblas conda-forge
|
||||
libbrotlicommon 1.2.0 hb03c661_1 conda-forge
|
||||
libbrotlidec 1.2.0 hb03c661_1 conda-forge
|
||||
libbrotlienc 1.2.0 hb03c661_1 conda-forge
|
||||
libcblas 3.11.0 5_h0358290_openblas conda-forge
|
||||
libcrc32c 1.1.2 h9c3ff4c_0 conda-forge
|
||||
libcurl 8.18.0 hcf29cc6_1 conda-forge
|
||||
libdeflate 1.25 h17f619e_0 conda-forge
|
||||
libedit 3.1.20250104 pl5321h7949ede_0 conda-forge
|
||||
libev 4.33 hd590300_2 conda-forge
|
||||
libexpat 2.7.4 hecca717_0 conda-forge
|
||||
libffi 3.5.2 h3435931_0 conda-forge
|
||||
libfreetype 2.14.2 ha770c72_0 conda-forge
|
||||
libfreetype6 2.14.2 h73754d4_0 conda-forge
|
||||
libgcc 15.2.0 he0feb66_18 conda-forge
|
||||
libgcc-ng 15.2.0 h69a702a_18 conda-forge
|
||||
libgdal 3.10.3 h3b705f5_27 conda-forge
|
||||
libgdal-core 3.10.3 h1f481a6_27 conda-forge
|
||||
libgdal-fits 3.10.3 hec9d828_27 conda-forge
|
||||
libgdal-grib 3.10.3 hb20eef8_27 conda-forge
|
||||
libgdal-hdf4 3.10.3 ha810028_27 conda-forge
|
||||
libgdal-hdf5 3.10.3 h966a9c2_27 conda-forge
|
||||
libgdal-jp2openjpeg 3.10.3 hdd07572_27 conda-forge
|
||||
libgdal-kea 3.10.3 h2bf108d_27 conda-forge
|
||||
libgdal-netcdf 3.10.3 ha526aae_27 conda-forge
|
||||
libgdal-pdf 3.10.3 h20efda7_27 conda-forge
|
||||
libgdal-pg 3.10.3 h55c2262_27 conda-forge
|
||||
libgdal-postgisraster 3.10.3 h55c2262_27 conda-forge
|
||||
libgdal-tiledb 3.10.3 h6c35068_27 conda-forge
|
||||
libgdal-xls 3.10.3 hdee084c_27 conda-forge
|
||||
libgfortran 15.2.0 h69a702a_18 conda-forge
|
||||
libgfortran5 15.2.0 h68bc16d_18 conda-forge
|
||||
libgl 1.7.0 ha4b6fd6_2 conda-forge
|
||||
libglib 2.86.4 h6548e54_1 conda-forge
|
||||
libglvnd 1.7.0 ha4b6fd6_2 conda-forge
|
||||
libglx 1.7.0 ha4b6fd6_2 conda-forge
|
||||
libgomp 15.2.0 he0feb66_18 conda-forge
|
||||
libgoogle-cloud 2.39.0 hdb79228_0 conda-forge
|
||||
libgoogle-cloud-storage 2.39.0 hdbdcf42_0 conda-forge
|
||||
libgrpc 1.73.1 h3288cfb_1 conda-forge
|
||||
libhwy 1.3.0 h4c17acf_1 conda-forge
|
||||
libiconv 1.18 h3b78370_2 conda-forge
|
||||
libjpeg-turbo 3.1.2 hb03c661_0 conda-forge
|
||||
libjxl 0.11.2 ha09017c_0 conda-forge
|
||||
libkml 1.3.0 haa4a5bd_1022 conda-forge
|
||||
liblapack 3.11.0 5_h47877c9_openblas conda-forge
|
||||
liblzma 5.8.2 hb03c661_0 conda-forge
|
||||
libnetcdf 4.9.3 nompi_hbf2fc22_104 conda-forge
|
||||
libnghttp2 1.67.0 had1ee68_0 conda-forge
|
||||
libnsl 2.0.1 hb9d3cd8_1 conda-forge
|
||||
libntlm 1.8 hb9d3cd8_0 conda-forge
|
||||
libopenblas 0.3.30 pthreads_h94d23a6_4 conda-forge
|
||||
libpng 1.6.55 h421ea60_0 conda-forge
|
||||
libpq 18.3 h9abb657_0 conda-forge
|
||||
libprotobuf 6.31.1 h49aed37_4 conda-forge
|
||||
libre2-11 2025.11.05 h7b12aa8_0 conda-forge
|
||||
librttopo 1.1.0 h46dd2a8_20 conda-forge
|
||||
libspatialite 5.1.0 gpl_h2abfd87_119 conda-forge
|
||||
libsqlite 3.52.0 hf4e2dac_0 conda-forge
|
||||
libssh2 1.11.1 hcf80075_0 conda-forge
|
||||
libstdcxx 15.2.0 h934c35e_18 conda-forge
|
||||
libstdcxx-ng 15.2.0 hdf11a46_18 conda-forge
|
||||
libtiff 4.7.1 h9d88235_1 conda-forge
|
||||
liburing 2.14 hb700be7_0 conda-forge
|
||||
libuuid 2.41.3 h5347b49_0 conda-forge
|
||||
libwebp-base 1.6.0 hd42ef1d_0 conda-forge
|
||||
libxcb 1.17.0 h8a09558_0 conda-forge
|
||||
libxcrypt 4.4.36 hd590300_1 conda-forge
|
||||
libxml2 2.15.2 he237659_0 conda-forge
|
||||
libxml2-16 2.15.2 hca6bf5a_0 conda-forge
|
||||
libxml2-devel 2.15.2 he237659_0 conda-forge
|
||||
libxslt 1.1.43 h711ed8c_1 conda-forge
|
||||
libzip 1.11.2 h6991a6a_0 conda-forge
|
||||
libzlib 1.3.1 hb9d3cd8_2 conda-forge
|
||||
libzopfli 1.0.3 h9c3ff4c_0 conda-forge
|
||||
lz4-c 1.10.0 h5888daf_1 conda-forge
|
||||
lzo 2.10 h280c20c_1002 conda-forge
|
||||
matplotlib 3.10.8 pypi_0 pypi
|
||||
minizip 4.0.10 h05a5f5f_0 conda-forge
|
||||
ncurses 6.5 h2d0b736_3 conda-forge
|
||||
networkx 3.6.1 pyhcf101f3_0 conda-forge
|
||||
nspr 4.38 h29cc59b_0 conda-forge
|
||||
nss 3.118 h445c969_0 conda-forge
|
||||
numpy 1.26.4 py311h64a7726_0 conda-forge
|
||||
openjpeg 2.5.4 h55fea9a_0 conda-forge
|
||||
openjph 0.26.3 h8d634f6_0 conda-forge
|
||||
openldap 2.6.10 hbde042b_1 conda-forge
|
||||
openmotif 2.3.8 hf55c2fc_5 conda-forge
|
||||
openssl 3.6.1 h35e630c_1 conda-forge
|
||||
packaging 26.0 pyhcf101f3_0 conda-forge
|
||||
pcre2 10.47 haa7fec5_0 conda-forge
|
||||
pillow 12.1.1 py311hf88fc01_0 conda-forge
|
||||
pip 26.0.1 pyh8b19718_0 conda-forge
|
||||
pixman 0.46.4 h54a6638_1 conda-forge
|
||||
poppler 25.07.0 h13eef12_1 conda-forge
|
||||
poppler-data 0.4.12 hd8ed1ab_0 conda-forge
|
||||
postgresql 18.3 h9d31465_0 conda-forge
|
||||
proj 9.7.1 he0df7b0_3 conda-forge
|
||||
pthread-stubs 0.4 hb9d3cd8_1002 conda-forge
|
||||
pyparsing 3.3.2 pypi_0 pypi
|
||||
pysocks 1.7.1 pyha55dd90_7 conda-forge
|
||||
python 3.11.15 hd63d673_0_cpython conda-forge
|
||||
python-dateutil 2.9.0.post0 pypi_0 pypi
|
||||
python_abi 3.11 8_cp311 conda-forge
|
||||
rav1e 0.8.1 h1fbca29_0 conda-forge
|
||||
re2 2025.11.05 h5301d42_0 conda-forge
|
||||
readline 8.3 h853b02a_0 conda-forge
|
||||
requests 2.32.5 pyhcf101f3_1 conda-forge
|
||||
s2n 1.6.2 he8a4886_1 conda-forge
|
||||
scikit-image 0.26.0 np2py311h2a99c40_0 conda-forge
|
||||
scipy 1.17.1 py311hbe70eeb_0 conda-forge
|
||||
setuptools 82.0.1 pyh332efcf_0 conda-forge
|
||||
six 1.17.0 pypi_0 pypi
|
||||
snappy 1.2.2 h03e3b7b_1 conda-forge
|
||||
spdlog 1.16.0 hffee6e0_1 conda-forge
|
||||
sqlite 3.52.0 h04a0ce9_0 conda-forge
|
||||
svt-av1 4.0.1 hecca717_0 conda-forge
|
||||
tifffile 2026.3.3 pyhd8ed1ab_0 conda-forge
|
||||
tiledb 2.29.2 h8821262_1 conda-forge
|
||||
tk 8.6.13 noxft_h366c992_103 conda-forge
|
||||
tzcode 2026a h280c20c_0 conda-forge
|
||||
tzdata 2025c hc9c84f9_1 conda-forge
|
||||
uriparser 0.9.8 hac33072_0 conda-forge
|
||||
urllib3 2.6.3 pyhd8ed1ab_0 conda-forge
|
||||
wheel 0.46.3 pyhd8ed1ab_0 conda-forge
|
||||
xerces-c 3.3.0 hd9031aa_1 conda-forge
|
||||
xorg-libice 1.1.2 hb9d3cd8_0 conda-forge
|
||||
xorg-libsm 1.2.6 he73a12e_0 conda-forge
|
||||
xorg-libx11 1.8.13 he1eb515_0 conda-forge
|
||||
xorg-libxau 1.0.12 hb03c661_1 conda-forge
|
||||
xorg-libxdmcp 1.1.5 hb03c661_1 conda-forge
|
||||
xorg-libxext 1.3.7 hb03c661_0 conda-forge
|
||||
xorg-libxft 2.3.9 h355ab9f_0 conda-forge
|
||||
xorg-libxmu 1.3.1 hb03c661_0 conda-forge
|
||||
xorg-libxp 1.0.4 hb03c661_0 conda-forge
|
||||
xorg-libxrender 0.9.12 hb9d3cd8_0 conda-forge
|
||||
xorg-libxt 1.3.1 hb9d3cd8_0 conda-forge
|
||||
zfp 1.0.1 h909a3a2_5 conda-forge
|
||||
zlib 1.3.1 hb9d3cd8_2 conda-forge
|
||||
zlib-ng 2.3.3 hceb46e0_1 conda-forge
|
||||
zstd 1.5.7 hb78ec9c_6 conda-forge
|
||||
@@ -1,221 +0,0 @@
|
||||
# This file may be used to create an environment using:
|
||||
# $ conda create --name <env> --file <this file>
|
||||
# platform: linux-64
|
||||
# created-by: conda 26.1.1
|
||||
@EXPLICIT
|
||||
https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/python_abi-3.11-8_cp311.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/attr-2.5.2-h39aace5_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-common-0.12.6-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/json-c-0.18-h6688a6e_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/rav1e-0.8.1-h1fbca29_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/tzcode-2026a-h280c20c_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-cal-0.9.13-h2c9d079_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-compression-0.3.1-h8b1a151_9.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-sdkutils-0.2.4-h8b1a151_4.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-checksums-0.2.7-h8b1a151_5.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/capnproto-1.2.0-hfc315d8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/charls-2.4.3-hecca717_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/fmt-12.0.0-h2b0788b_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/geos-3.14.1-h480dda7_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libabseil-20250512.1-cxx17_hba17884_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libacl-2.3.2-h0f662aa_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libev-4.33-hd590300_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/liburing-2.14-hb700be7_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/s2n-1.6.2-he8a4886_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/svt-av1-4.0.1-hecca717_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/zfp-1.0.1-h909a3a2_5.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-io-0.23.3-hdaf4b65_5.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/brunsli-0.1-hd1e3526_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/c-blosc2-2.23.1-hc31b594_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/fftw-3.3.10-nompi_h3b011a4_112.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_101.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libfreetype6-2.14.2-h73754d4_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libjxl-0.11.2-ha09017c_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libprotobuf-6.31.1-h49aed37_4.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libre2-11-2025.11.05-h7b12aa8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/librttopo-1.1.0-h46dd2a8_20.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/linux-64/minizip-4.0.10-h05a5f5f_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/spdlog-1.16.0-hffee6e0_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xerces-c-3.3.0-hd9031aa_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-event-stream-0.5.7-h28f887f_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-http-0.10.7-ha8fc4e3_5.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/freexl-2.0.0-h9dce30a_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libavif16-1.4.0-hcfa2d63_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libcurl-8.18.0-hcf29cc6_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libfreetype-2.14.2-ha770c72_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1022.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/nss-3.118-h445c969_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/re2-2025.11.05-h5301d42_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxext-1.3.7-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxt-1.3.1-hb9d3cd8_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-auth-0.9.3-hef928c7_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-mqtt-0.13.3-hc63082f_11.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/azure-core-cpp-1.16.1-h3a458e0_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/brotli-python-1.2.0-py311h66f275b_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/cfitsio-4.6.3-ha0b56bc_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/freetype-2.14.2-ha770c72_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_106.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.8.5-gpl_hc2c16d8_100.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgrpc-1.73.1-h3288cfb_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libxml2-devel-2.15.2-he237659_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/pillow-12.1.1-py311hf88fc01_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/proj-9.7.1-he0df7b0_3.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxmu-1.3.1-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxp-1.0.4-hb03c661_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-c-s3-0.11.3-h06ab39a_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/azure-identity-cpp-1.13.2-h3a5f585_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/azure-storage-common-cpp-12.11.0-h3d7a050_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2
|
||||
https://conda.anaconda.org/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/geotiff-1.7.4-h1000f5c_4.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/kealib-1.6.2-hb2f3951_2.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/lazy-loader-0.5-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-2.39.0-hdb79228_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.3-nompi_hbf2fc22_104.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libspatialite-5.1.0-gpl_h2abfd87_119.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/numpy-1.26.4-py311h64a7726_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/xorg-libxft-2.3.9-h355ab9f_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-crt-cpp-0.35.2-h8824e59_6.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/azure-storage-blobs-cpp-12.15.0-h2a74896_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/h5py-3.15.1-nompi_py311h0b2f468_101.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/imagecodecs-2026.3.6-py311h9837d23_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-core-3.10.3-h1f481a6_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgoogle-cloud-storage-2.39.0-hdbdcf42_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/openmotif-2.3.8-hf55c2fc_5.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/poppler-25.07.0-h13eef12_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/postgresql-18.3-h9d31465_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_0.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/aws-sdk-cpp-1.11.606-hf38915e_9.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.13.0-hf38f1be_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/gdal-3.10.3-py311h34ccccb_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-fits-3.10.3-hec9d828_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-grib-3.10.3-hb20eef8_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-hdf4-3.10.3-ha810028_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-hdf5-3.10.3-h966a9c2_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-jp2openjpeg-3.10.3-hdd07572_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-pdf-3.10.3-h20efda7_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-pg-3.10.3-h55c2262_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-postgisraster-3.10.3-h55c2262_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-xls-3.10.3-hdee084c_27.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda
|
||||
https://conda.anaconda.org/conda-forge/noarch/tifffile-2026.3.3-pyhd8ed1ab_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-kea-3.10.3-h2bf108d_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-netcdf-3.10.3-ha526aae_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/scikit-image-0.26.0-np2py311h2a99c40_0.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/tiledb-2.29.2-h8821262_1.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-tiledb-3.10.3-h6c35068_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/libgdal-3.10.3-h3b705f5_27.conda
|
||||
https://conda.anaconda.org/conda-forge/linux-64/isce2-2.6.4-py311h916084f_2.conda
|
||||
@@ -1,231 +0,0 @@
|
||||
name: isce2
|
||||
channels:
|
||||
- conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- _openmp_mutex=4.5
|
||||
- aom=3.9.1
|
||||
- attr=2.5.2
|
||||
- aws-c-auth=0.9.3
|
||||
- aws-c-cal=0.9.13
|
||||
- aws-c-common=0.12.6
|
||||
- aws-c-compression=0.3.1
|
||||
- aws-c-event-stream=0.5.7
|
||||
- aws-c-http=0.10.7
|
||||
- aws-c-io=0.23.3
|
||||
- aws-c-mqtt=0.13.3
|
||||
- aws-c-s3=0.11.3
|
||||
- aws-c-sdkutils=0.2.4
|
||||
- aws-checksums=0.2.7
|
||||
- aws-crt-cpp=0.35.2
|
||||
- aws-sdk-cpp=1.11.606
|
||||
- azure-core-cpp=1.16.1
|
||||
- azure-identity-cpp=1.13.2
|
||||
- azure-storage-blobs-cpp=12.15.0
|
||||
- azure-storage-common-cpp=12.11.0
|
||||
- azure-storage-files-datalake-cpp=12.13.0
|
||||
- backports.zstd=1.3.0
|
||||
- blosc=1.21.6
|
||||
- brotli-python=1.2.0
|
||||
- brunsli=0.1
|
||||
- bzip2=1.0.8
|
||||
- c-ares=1.34.6
|
||||
- c-blosc2=2.23.1
|
||||
- ca-certificates=2026.2.25
|
||||
- cached-property=1.5.2
|
||||
- cached_property=1.5.2
|
||||
- cairo=1.18.4
|
||||
- capnproto=1.2.0
|
||||
- certifi=2026.2.25
|
||||
- cfitsio=4.6.3
|
||||
- charls=2.4.3
|
||||
- charset-normalizer=3.4.5
|
||||
- cyrus-sasl=2.1.28
|
||||
- dav1d=1.2.1
|
||||
- fftw=3.3.10
|
||||
- fmt=12.0.0
|
||||
- font-ttf-dejavu-sans-mono=2.37
|
||||
- font-ttf-inconsolata=3.000
|
||||
- font-ttf-source-code-pro=2.038
|
||||
- font-ttf-ubuntu=0.83
|
||||
- fontconfig=2.17.1
|
||||
- fonts-conda-ecosystem=1
|
||||
- fonts-conda-forge=1
|
||||
- freetype=2.14.2
|
||||
- freexl=2.0.0
|
||||
- gdal=3.10.3
|
||||
- geos=3.14.1
|
||||
- geotiff=1.7.4
|
||||
- giflib=5.2.2
|
||||
- h2=4.3.0
|
||||
- h5py=3.15.1
|
||||
- hdf4=4.2.15
|
||||
- hdf5=1.14.6
|
||||
- hpack=4.1.0
|
||||
- hyperframe=6.1.0
|
||||
- icu=78.2
|
||||
- idna=3.11
|
||||
- imagecodecs=2026.3.6
|
||||
- imageio=2.37.0
|
||||
- isce2=2.6.4
|
||||
- json-c=0.18
|
||||
- jxrlib=1.1
|
||||
- kealib=1.6.2
|
||||
- keyutils=1.6.3
|
||||
- krb5=1.22.2
|
||||
- lazy-loader=0.5
|
||||
- lcms2=2.18
|
||||
- ld_impl_linux-64=2.45.1
|
||||
- lerc=4.1.0
|
||||
- libabseil=20250512.1
|
||||
- libacl=2.3.2
|
||||
- libaec=1.1.5
|
||||
- libarchive=3.8.5
|
||||
- libavif16=1.4.0
|
||||
- libblas=3.11.0
|
||||
- libbrotlicommon=1.2.0
|
||||
- libbrotlidec=1.2.0
|
||||
- libbrotlienc=1.2.0
|
||||
- libcblas=3.11.0
|
||||
- libcrc32c=1.1.2
|
||||
- libcurl=8.18.0
|
||||
- libdeflate=1.25
|
||||
- libedit=3.1.20250104
|
||||
- libev=4.33
|
||||
- libexpat=2.7.4
|
||||
- libffi=3.5.2
|
||||
- libfreetype=2.14.2
|
||||
- libfreetype6=2.14.2
|
||||
- libgcc=15.2.0
|
||||
- libgcc-ng=15.2.0
|
||||
- libgdal=3.10.3
|
||||
- libgdal-core=3.10.3
|
||||
- libgdal-fits=3.10.3
|
||||
- libgdal-grib=3.10.3
|
||||
- libgdal-hdf4=3.10.3
|
||||
- libgdal-hdf5=3.10.3
|
||||
- libgdal-jp2openjpeg=3.10.3
|
||||
- libgdal-kea=3.10.3
|
||||
- libgdal-netcdf=3.10.3
|
||||
- libgdal-pdf=3.10.3
|
||||
- libgdal-pg=3.10.3
|
||||
- libgdal-postgisraster=3.10.3
|
||||
- libgdal-tiledb=3.10.3
|
||||
- libgdal-xls=3.10.3
|
||||
- libgfortran=15.2.0
|
||||
- libgfortran5=15.2.0
|
||||
- libgl=1.7.0
|
||||
- libglib=2.86.4
|
||||
- libglvnd=1.7.0
|
||||
- libglx=1.7.0
|
||||
- libgomp=15.2.0
|
||||
- libgoogle-cloud=2.39.0
|
||||
- libgoogle-cloud-storage=2.39.0
|
||||
- libgrpc=1.73.1
|
||||
- libhwy=1.3.0
|
||||
- libiconv=1.18
|
||||
- libjpeg-turbo=3.1.2
|
||||
- libjxl=0.11.2
|
||||
- libkml=1.3.0
|
||||
- liblapack=3.11.0
|
||||
- liblzma=5.8.2
|
||||
- libnetcdf=4.9.3
|
||||
- libnghttp2=1.67.0
|
||||
- libnsl=2.0.1
|
||||
- libntlm=1.8
|
||||
- libopenblas=0.3.30
|
||||
- libpng=1.6.55
|
||||
- libpq=18.3
|
||||
- libprotobuf=6.31.1
|
||||
- libre2-11=2025.11.05
|
||||
- librttopo=1.1.0
|
||||
- libspatialite=5.1.0
|
||||
- libsqlite=3.52.0
|
||||
- libssh2=1.11.1
|
||||
- libstdcxx=15.2.0
|
||||
- libstdcxx-ng=15.2.0
|
||||
- libtiff=4.7.1
|
||||
- liburing=2.14
|
||||
- libuuid=2.41.3
|
||||
- libwebp-base=1.6.0
|
||||
- libxcb=1.17.0
|
||||
- libxcrypt=4.4.36
|
||||
- libxml2=2.15.2
|
||||
- libxml2-16=2.15.2
|
||||
- libxml2-devel=2.15.2
|
||||
- libxslt=1.1.43
|
||||
- libzip=1.11.2
|
||||
- libzlib=1.3.1
|
||||
- libzopfli=1.0.3
|
||||
- lz4-c=1.10.0
|
||||
- lzo=2.10
|
||||
- minizip=4.0.10
|
||||
- ncurses=6.5
|
||||
- networkx=3.6.1
|
||||
- nspr=4.38
|
||||
- nss=3.118
|
||||
- numpy=1.26.4
|
||||
- openjpeg=2.5.4
|
||||
- openjph=0.26.3
|
||||
- openldap=2.6.10
|
||||
- openmotif=2.3.8
|
||||
- openssl=3.6.1
|
||||
- packaging=26.0
|
||||
- pcre2=10.47
|
||||
- pillow=12.1.1
|
||||
- pip=26.0.1
|
||||
- pixman=0.46.4
|
||||
- poppler=25.07.0
|
||||
- poppler-data=0.4.12
|
||||
- postgresql=18.3
|
||||
- proj=9.7.1
|
||||
- pthread-stubs=0.4
|
||||
- pysocks=1.7.1
|
||||
- python=3.11.15
|
||||
- python_abi=3.11
|
||||
- rav1e=0.8.1
|
||||
- re2=2025.11.05
|
||||
- readline=8.3
|
||||
- requests=2.32.5
|
||||
- s2n=1.6.2
|
||||
- scikit-image=0.26.0
|
||||
- scipy=1.17.1
|
||||
- setuptools=82.0.1
|
||||
- snappy=1.2.2
|
||||
- spdlog=1.16.0
|
||||
- sqlite=3.52.0
|
||||
- svt-av1=4.0.1
|
||||
- tifffile=2026.3.3
|
||||
- tiledb=2.29.2
|
||||
- tk=8.6.13
|
||||
- tzcode=2026a
|
||||
- tzdata=2025c
|
||||
- uriparser=0.9.8
|
||||
- urllib3=2.6.3
|
||||
- wheel=0.46.3
|
||||
- xerces-c=3.3.0
|
||||
- xorg-libice=1.1.2
|
||||
- xorg-libsm=1.2.6
|
||||
- xorg-libx11=1.8.13
|
||||
- xorg-libxau=1.0.12
|
||||
- xorg-libxdmcp=1.1.5
|
||||
- xorg-libxext=1.3.7
|
||||
- xorg-libxft=2.3.9
|
||||
- xorg-libxmu=1.3.1
|
||||
- xorg-libxp=1.0.4
|
||||
- xorg-libxrender=0.9.12
|
||||
- xorg-libxt=1.3.1
|
||||
- zfp=1.0.1
|
||||
- zlib=1.3.1
|
||||
- zlib-ng=2.3.3
|
||||
- zstd=1.5.7
|
||||
- pip:
|
||||
- contourpy==1.3.3
|
||||
- cycler==0.12.1
|
||||
- fonttools==4.62.1
|
||||
- kiwisolver==1.5.0
|
||||
- matplotlib==3.10.8
|
||||
- pyparsing==3.3.2
|
||||
- python-dateutil==2.9.0.post0
|
||||
- six==1.17.0
|
||||
prefix: /home/administrator/miniconda3/envs/isce2
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
python_executable=/home/administrator/miniconda3/envs/isce2/bin/python
|
||||
python_version=3.11.15
|
||||
isce_present=True
|
||||
mintpy_present=False
|
||||
h5py_present=True
|
||||
isce_file=/home/administrator/miniconda3/envs/isce2/lib/python3.11/site-packages/isce/__init__.py
|
||||
isce_version=2.6.3
|
||||
2026-04-06 15:31:15,137 - h5py._conv - DEBUG - Creating converter from 7 to 5
|
||||
2026-04-06 15:31:15,138 - h5py._conv - DEBUG - Creating converter from 5 to 7
|
||||
2026-04-06 15:31:15,138 - h5py._conv - DEBUG - Creating converter from 7 to 5
|
||||
2026-04-06 15:31:15,139 - h5py._conv - DEBUG - Creating converter from 5 to 7
|
||||
h5py_version=3.15.1
|
||||
-350
@@ -1,350 +0,0 @@
|
||||
# packages in environment at /home/administrator/miniconda3/envs/isce2_mintpy_v1:
|
||||
#
|
||||
# Name Version Build Channel
|
||||
_openmp_mutex 4.5 20_gnu https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
_x86_64-microarch-level 3 3_skylake https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aom 3.9.1 hac33072_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
argcomplete 3.6.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
attr 2.5.2 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
attrs 26.1.0 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-auth 0.9.3 hef928c7_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-cal 0.9.13 h2c9d079_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-common 0.12.6 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-compression 0.3.1 h8b1a151_9 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-event-stream 0.5.7 h28f887f_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-http 0.10.7 ha8fc4e3_5 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-io 0.23.3 hdaf4b65_5 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-mqtt 0.13.3 hc63082f_11 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-s3 0.11.3 h06ab39a_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-c-sdkutils 0.2.4 h8b1a151_4 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-checksums 0.2.7 h8b1a151_5 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-crt-cpp 0.35.2 h8824e59_6 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
aws-sdk-cpp 1.11.606 hf38915e_9 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
azure-core-cpp 1.16.1 h3a458e0_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
azure-identity-cpp 1.13.2 h3a5f585_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
azure-storage-blobs-cpp 12.15.0 h2a74896_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
azure-storage-common-cpp 12.11.0 h3d7a050_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
azure-storage-files-datalake-cpp 12.13.0 hf38f1be_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
backports.zstd 1.3.0 py311h6b1f9c4_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
blosc 1.21.6 he440d0b_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
bokeh 3.9.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
brotli 1.2.0 hed03a55_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
brotli-bin 1.2.0 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
brotli-python 1.2.0 py311h66f275b_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
brunsli 0.1 hd1e3526_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
bzip2 1.0.8 hda65f42_9 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
c-ares 1.34.6 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
c-blosc2 2.23.1 hc31b594_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
ca-certificates 2026.2.25 hbd8a1cb_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cached-property 1.5.2 hd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cached_property 1.5.2 pyha770c72_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cairo 1.18.4 he90730b_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
capnproto 1.2.0 hfc315d8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cartopy 0.25.0 py311hed34c8f_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cdsapi 0.7.7 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
certifi 2026.2.25 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cffi 2.0.0 py311h03d9500_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cfgv 3.5.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cfitsio 4.6.3 ha0b56bc_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
charls 2.4.3 hecca717_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
charset-normalizer 3.4.5 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
click 8.3.1 pyh8f84b5b_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cloudpickle 3.1.2 pyhcf101f3_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
configobj 5.0.9 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
contourpy 1.3.3 py311h724c32c_4 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cvxopt 1.3.3 py311h3d1f434_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cycler 0.12.1 pyhcf101f3_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cyrus-sasl 2.1.28 hac629b4_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
cytoolz 1.1.0 py311h49ec1c0_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
dask 2026.3.0 pyhc364b38_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
dask-core 2026.3.0 pyhc364b38_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
dask-jobqueue 0.9.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
dav1d 1.2.1 hd590300_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
distlib 0.4.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
distributed 2026.3.0 pyhc364b38_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
donfig 0.8.1.post1 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
dsdp 5.8 hd9d9efa_1203 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
eccodes 2.46.0 h83bc92c_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
ecmwf-datastores-client 0.5.1 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fftw 3.3.10 nompi_h3b011a4_112 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
filelock 3.25.2 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fmt 12.0.0 h2b0788b_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
font-ttf-dejavu-sans-mono 2.37 hab24e00_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
font-ttf-inconsolata 3.000 h77eed37_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
font-ttf-source-code-pro 2.038 h77eed37_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
font-ttf-ubuntu 0.83 h77eed37_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fontconfig 2.17.1 h27c8c51_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fonts-conda-ecosystem 1 0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fonts-conda-forge 1 hc364b38_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fonttools 4.62.1 pypi_0 pypi
|
||||
freeglut 3.2.2 ha6d2627_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
freetype 2.14.2 ha770c72_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
freexl 2.0.0 h9dce30a_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
fsspec 2026.3.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
gdal 3.10.3 py311h34ccccb_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
geos 3.14.1 h480dda7_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
geotiff 1.7.4 h1000f5c_4 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
gflags 2.2.2 h5888daf_1005 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
giflib 5.2.2 hd590300_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
glog 0.7.1 hbabe93e_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
glpk 5.0 h445213a_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
gmp 6.3.0 hac33072_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
gsl 2.7 he838d99_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
h2 4.3.0 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
h5py 3.15.1 nompi_py311h0b2f468_101 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
hdf4 4.2.15 h2a13503_7 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
hdf5 1.14.6 nompi_h19486de_106 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
hpack 4.1.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
hyperframe 6.1.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
icu 78.2 h33c6efd_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
identify 2.6.18 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
idna 3.11 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
imagecodecs 2026.3.6 py311h9837d23_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
imageio 2.37.0 pyhfb79c49_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
importlib-metadata 8.8.0 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
isce2 2.6.4 py311h916084f_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
jasper 4.2.9 h1588d4d_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
jinja2 3.1.6 pyhcf101f3_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
joblib 1.5.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
json-c 0.18 h6688a6e_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
jxrlib 1.1 hd590300_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
kealib 1.6.2 hb2f3951_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
keyutils 1.6.3 hb9d3cd8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
kiwisolver 1.5.0 py311h724c32c_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
krb5 1.22.2 ha1258a1_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lazy-loader 0.5 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lcms2 2.18 h0c24ade_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
ld_impl_linux-64 2.45.1 default_hbd61a6d_102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lerc 4.1.0 hdb68285_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libabseil 20250512.1 cxx17_hba17884_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libacl 2.3.2 h0f662aa_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libaec 1.1.5 h088129d_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libamd 3.3.3 haaf9dc3_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libarchive 3.8.5 gpl_hc2c16d8_100 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libarrow 22.0.0 h2937f24_4_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libarrow-acero 22.0.0 hb826db4_4_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libarrow-compute 22.0.0 h58682fd_4_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libarrow-dataset 22.0.0 hb826db4_4_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libarrow-substrait 22.0.0 h9d9f3f8_4_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libattr 2.5.2 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libavif16 1.4.0 hcfa2d63_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libblas 3.11.0 5_h4a7cf45_openblas https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libbrotlicommon 1.2.0 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libbrotlidec 1.2.0 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libbrotlienc 1.2.0 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libbtf 2.3.2 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcamd 3.3.3 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcblas 3.11.0 5_h0358290_openblas https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libccolamd 3.3.4 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcholmod 5.3.1 h59ddab4_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcolamd 3.3.4 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcrc32c 1.1.2 h9c3ff4c_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcurl 8.18.0 hcf29cc6_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libcxsparse 4.4.1 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libdeflate 1.25 h17f619e_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libedit 3.1.20250104 pl5321h7949ede_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libev 4.33 hd590300_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libevent 2.1.12 hf998b51_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libexpat 2.7.4 hecca717_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libffi 3.5.2 h3435931_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libfreetype 2.14.2 ha770c72_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libfreetype6 2.14.2 h73754d4_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgcc 15.2.0 he0feb66_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgcc-ng 15.2.0 h69a702a_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal 3.10.3 h3b705f5_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-core 3.10.3 h1f481a6_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-fits 3.10.3 hec9d828_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-grib 3.10.3 hb20eef8_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-hdf4 3.10.3 ha810028_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-hdf5 3.10.3 h966a9c2_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-jp2openjpeg 3.10.3 hdd07572_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-kea 3.10.3 h2bf108d_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-netcdf 3.10.3 ha526aae_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-pdf 3.10.3 h20efda7_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-pg 3.10.3 h55c2262_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-postgisraster 3.10.3 h55c2262_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-tiledb 3.10.3 h6c35068_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgdal-xls 3.10.3 hdee084c_27 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgfortran 15.2.0 h69a702a_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgfortran5 15.2.0 h68bc16d_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgl 1.7.0 ha4b6fd6_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libglib 2.86.4 h6548e54_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libglu 9.0.3 h5888daf_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libglvnd 1.7.0 ha4b6fd6_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libglx 1.7.0 ha4b6fd6_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgomp 15.2.0 he0feb66_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgoogle-cloud 2.39.0 hdb79228_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgoogle-cloud-storage 2.39.0 hdbdcf42_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libgrpc 1.73.1 h3288cfb_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libhwy 1.3.0 h4c17acf_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libiconv 1.18 h3b78370_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libjpeg-turbo 3.1.2 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libjxl 0.11.2 ha09017c_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libklu 2.3.5 hf24d653_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libkml 1.3.0 haa4a5bd_1022 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
liblapack 3.11.0 5_h47877c9_openblas https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libldl 3.3.2 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
liblzma 5.8.2 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libnetcdf 4.9.3 nompi_hbf2fc22_104 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libnghttp2 1.67.0 had1ee68_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libnsl 2.0.1 hb9d3cd8_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libntlm 1.8 hb9d3cd8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libopenblas 0.3.30 pthreads_h94d23a6_4 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libopengl 1.7.0 ha4b6fd6_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libopentelemetry-cpp 1.21.0 hb9b0907_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libopentelemetry-cpp-headers 1.21.0 ha770c72_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libparquet 22.0.0 h31208bf_4_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libparu 1.0.0 h17147ab_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libpng 1.6.55 h421ea60_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libpq 18.3 h9abb657_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libprotobuf 6.31.1 h49aed37_4 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
librbio 4.3.4 h32481e8_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libre2-11 2025.11.05 h7b12aa8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
librttopo 1.1.0 h46dd2a8_20 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libspatialite 5.1.0 gpl_h2abfd87_119 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libspex 3.2.3 had10066_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libspqr 4.3.4 h852d39f_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libsqlite 3.52.0 hf4e2dac_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libssh2 1.11.1 hcf80075_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libstdcxx 15.2.0 h934c35e_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libstdcxx-ng 15.2.0 hdf11a46_18 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libsuitesparseconfig 7.10.1 h92d6892_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libthrift 0.22.0 h454ac66_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libtiff 4.7.1 h9d88235_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libumfpack 6.3.5 heb53515_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
liburing 2.14 hb700be7_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libutf8proc 2.11.3 hfe17d71_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libuuid 2.41.3 h5347b49_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libwebp-base 1.6.0 hd42ef1d_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libxcb 1.17.0 h8a09558_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libxcrypt 4.4.36 hd590300_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libxml2 2.15.2 he237659_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libxml2-16 2.15.2 hca6bf5a_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libxml2-devel 2.15.2 he237659_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libxslt 1.1.43 h711ed8c_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libzip 1.11.2 h6991a6a_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libzlib 1.3.1 hb9d3cd8_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
libzopfli 1.0.3 h9c3ff4c_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
locket 1.0.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lxml 6.0.2 py311h8840267_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lz4 4.4.5 py311h1c460e0_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lz4-c 1.10.0 h5888daf_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
lzo 2.10 h280c20c_1002 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
markdown-it-py 4.0.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
markupsafe 3.0.3 py311h3778330_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
matplotlib-base 3.10.8 py311h0f3be63_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
mdurl 0.1.2 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
metis 5.1.0 hd0bcaf9_1007 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
minizip 4.0.10 h05a5f5f_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
mintpy 1.6.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
mpfr 4.2.2 he0a73b1_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
msgpack-python 1.1.2 py311hdf67eae_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
multiurl 0.3.7 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
munkres 1.1.4 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
narwhals 2.18.1 pyhcf101f3_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
ncurses 6.5 h2d0b736_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
networkx 3.6.1 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
nlohmann_json 3.12.0 h54a6638_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
nodeenv 1.10.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
nspr 4.38 h29cc59b_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
nss 3.118 h445c969_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
numpy 1.26.4 py311h64a7726_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
openjpeg 2.5.4 h55fea9a_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
openjph 0.26.3 h8d634f6_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
openldap 2.6.10 hbde042b_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
openmotif 2.3.8 he4bd66d_6 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
openssl 3.6.1 h35e630c_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
orc 2.2.1 hd747db4_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
packaging 26.0 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pandas 3.0.2 py311h8032f78_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
partd 1.4.2 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pcre2 10.47 haa7fec5_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pillow 12.1.1 py311hf88fc01_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pip 26.0.1 pyh8b19718_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pixman 0.46.4 h54a6638_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
platformdirs 4.9.4 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
poppler 25.07.0 h13eef12_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
poppler-data 0.4.12 hd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
postgresql 18.3 h9d31465_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pre-commit 4.5.1 pyha770c72_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
proj 9.7.1 he0df7b0_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
prometheus-cpp 1.3.0 ha5d0236_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
psutil 7.2.2 py311haee01d2_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pthread-stubs 0.4 hb9d3cd8_1002 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyaps3 0.3.7 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyarrow 22.0.0 py311h38be061_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyarrow-core 22.0.0 py311hbabfba9_2_cuda https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pycparser 2.22 pyh29332c3_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pygments 2.20.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pygrib 2.1.8 py311he4f3390_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pykdtree 1.4.3 py311h0372a8f_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pykml 0.2.0 pyhd8ed1ab_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyparsing 3.3.2 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyproj 3.7.2 py311h400b93a_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyresample 1.35.0 py311h1ddb823_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyshp 3.0.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pysocks 1.7.1 pyha55dd90_7 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pysolid 0.3.4 py311h9bb1bfa_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
python 3.11.15 hd63d673_0_cpython https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
python-dateutil 2.9.0.post0 pyhe01879c_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
python-discovery 1.2.1 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
python_abi 3.11 8_cp311 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pytz 2026.1.post1 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
pyyaml 6.0.3 py311h3778330_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
qhull 2020.2 h434a139_5 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
rav1e 0.8.1 h1fbca29_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
re2 2025.11.05 h5301d42_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
readline 8.3 h853b02a_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
requests 2.32.5 pyhcf101f3_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
rich 14.3.3 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
s2n 1.6.2 he8a4886_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
scikit-image 0.26.0 np2py311h2a99c40_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
scipy 1.17.1 py311hbe70eeb_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
setuptools 82.0.1 pyh332efcf_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
shapely 2.1.2 py311h8a92878_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
six 1.17.0 pyhe01879c_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
snappy 1.2.2 h03e3b7b_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
sortedcontainers 2.4.0 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
spdlog 1.16.0 hffee6e0_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
sqlite 3.52.0 h04a0ce9_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
suitesparse 7.10.1 ha0f6916_7100102 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
svt-av1 4.0.1 hecca717_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tblib 3.2.2 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tifffile 2026.3.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tiledb 2.29.2 h8821262_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tk 8.6.13 noxft_h366c992_103 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
toolz 1.1.0 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tornado 6.5.5 py311h49ec1c0_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tqdm 4.67.3 pyh8f84b5b_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
typing_extensions 4.15.0 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tzcode 2026a h280c20c_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
tzdata 2025c hc9c84f9_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
ukkonen 1.1.0 py311hdf67eae_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
unicodedata2 17.0.1 py311h49ec1c0_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
uriparser 0.9.8 hac33072_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
urllib3 2.6.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
utm 0.7.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
virtualenv 21.2.0 pyhcf101f3_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
wheel 0.46.3 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xerces-c 3.3.0 hd9031aa_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libice 1.1.2 hb9d3cd8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libsm 1.2.6 he73a12e_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libx11 1.8.13 he1eb515_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxau 1.0.12 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxdmcp 1.1.5 hb03c661_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxext 1.3.7 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxfixes 6.0.2 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxft 2.3.9 h355ab9f_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxi 1.8.2 hb9d3cd8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxmu 1.3.1 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxp 1.0.4 hb03c661_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxrender 0.9.12 hb9d3cd8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xorg-libxt 1.3.1 hb9d3cd8_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
xyzservices 2026.3.0 pyhd8ed1ab_0 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
yaml 0.2.5 h280c20c_3 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
zfp 1.0.1 h909a3a2_5 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
zict 3.0.0 pyhd8ed1ab_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
zipp 3.23.0 pyhcf101f3_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
zlib 1.3.1 hb9d3cd8_2 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
zlib-ng 2.3.3 hceb46e0_1 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
zstd 1.5.7 hb78ec9c_6 https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
-352
@@ -1,352 +0,0 @@
|
||||
# This file may be used to create an environment using:
|
||||
# $ conda create --name <env> --file <this file>
|
||||
# platform: linux-64
|
||||
# created-by: conda 26.1.1
|
||||
@EXPLICIT
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/_x86_64-microarch-level-3-3_skylake.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/ca-certificates-2026.2.25-hbd8a1cb_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/font-ttf-dejavu-sans-mono-2.37-hab24e00_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/font-ttf-inconsolata-3.000-h77eed37_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/font-ttf-source-code-pro-2.038-h77eed37_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/font-ttf-ubuntu-0.83-h77eed37_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libglvnd-1.7.0-ha4b6fd6_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgomp-15.2.0-he0feb66_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libopentelemetry-cpp-headers-1.21.0-ha770c72_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/nlohmann_json-3.12.0-h54a6638_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/poppler-data-0.4.12-hd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/python_abi-3.11-8_cp311.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/fonts-conda-forge-1-hc364b38_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libopengl-1.7.0-ha4b6fd6_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/fonts-conda-ecosystem-1-0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgcc-15.2.0-he0feb66_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-common-0.12.6-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/c-ares-1.34.6-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/json-c-0.18-h6688a6e_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/keyutils-1.6.3-hb9d3cd8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libattr-2.5.2-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libbrotlicommon-1.2.0-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libdeflate-1.25-h17f619e_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libexpat-2.7.4-hecca717_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgcc-ng-15.2.0-h69a702a_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgfortran5-15.2.0-h68bc16d_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libiconv-1.18-h3b78370_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libjpeg-turbo-3.1.2-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/liblzma-5.8.2-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libnsl-2.0.1-hb9d3cd8_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libntlm-1.8-hb9d3cd8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libutf8proc-2.11.3-hfe17d71_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libuuid-2.41.3-h5347b49_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libwebp-base-1.6.0-hd42ef1d_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libzlib-1.3.1-hb9d3cd8_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/lzo-2.10-h280c20c_1002.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/ncurses-6.5-h2d0b736_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/openssl-3.6.1-h35e630c_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pthread-stubs-0.4-hb9d3cd8_1002.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/rav1e-0.8.1-h1fbca29_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/tzcode-2026a-h280c20c_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libice-1.1.2-hb9d3cd8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxau-1.0.12-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxdmcp-1.1.5-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/attr-2.5.2-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-cal-0.9.13-h2c9d079_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-compression-0.3.1-h8b1a151_9.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-sdkutils-0.2.4-h8b1a151_4.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-checksums-0.2.7-h8b1a151_5.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/capnproto-1.2.0-hfc315d8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/charls-2.4.3-hecca717_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/dav1d-1.2.1-hd590300_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/fmt-12.0.0-h2b0788b_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/geos-3.14.1-h480dda7_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/gflags-2.2.2-h5888daf_1005.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/giflib-5.2.2-hd590300_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/icu-78.2-h33c6efd_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/jxrlib-1.1-hd590300_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/lerc-4.1.0-hdb68285_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libabseil-20250512.1-cxx17_hba17884_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libaec-1.1.5-h088129d_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libbrotlidec-1.2.0-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libbrotlienc-1.2.0-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libedit-3.1.20250104-pl5321h7949ede_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libev-4.33-hd590300_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libevent-2.1.12-hf998b51_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgfortran-15.2.0-h69a702a_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libglu-9.0.3-h5888daf_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libhwy-1.3.0-h4c17acf_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libpng-1.6.55-h421ea60_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libssh2-1.11.1-hcf80075_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libstdcxx-ng-15.2.0-hdf11a46_18.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/liburing-2.14-hb700be7_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libxcb-1.17.0-h8a09558_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libxcrypt-4.4.36-hd590300_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libzip-1.11.2-h6991a6a_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/lz4-c-1.10.0-h5888daf_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/metis-5.1.0-hd0bcaf9_1007.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/nspr-4.38-h29cc59b_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pcre2-10.47-haa7fec5_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pixman-0.46.4-h54a6638_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/readline-8.3-h853b02a_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/s2n-1.6.2-he8a4886_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/snappy-1.2.2-h03e3b7b_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/svt-av1-4.0.1-hecca717_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libsm-1.2.6-he73a12e_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/zfp-1.0.1-h909a3a2_5.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/zlib-1.3.1-hb9d3cd8_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/zlib-ng-2.3.3-hceb46e0_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aom-3.9.1-hac33072_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-io-0.23.3-hdaf4b65_5.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/blosc-1.21.6-he440d0b_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/brotli-bin-1.2.0-hb03c661_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/brunsli-0.1-hd1e3526_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/c-blosc2-2.23.1-hc31b594_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/fftw-3.3.10-nompi_h3b011a4_112.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/glog-0.7.1-hbabe93e_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/gmp-6.3.0-hac33072_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/hdf4-4.2.15-h2a13503_7.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/krb5-1.22.2-ha1258a1_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libacl-2.3.2-h0f662aa_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcrc32c-1.1.2-h9c3ff4c_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libfreetype6-2.14.2-h73754d4_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libglib-2.86.4-h6548e54_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libjxl-0.11.2-ha09017c_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libnghttp2-1.67.0-had1ee68_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libopenblas-0.3.30-pthreads_h94d23a6_4.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libprotobuf-6.31.1-h49aed37_4.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libre2-11-2025.11.05-h7b12aa8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/librttopo-1.1.0-h46dd2a8_20.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libsqlite-3.52.0-hf4e2dac_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libsuitesparseconfig-7.10.1-h92d6892_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libthrift-0.22.0-h454ac66_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libtiff-4.7.1-h9d88235_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libxml2-16-2.15.2-hca6bf5a_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libzopfli-1.0.3-h9c3ff4c_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/minizip-4.0.10-h05a5f5f_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/spdlog-1.16.0-hffee6e0_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/uriparser-0.9.8-hac33072_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xerces-c-3.3.0-hd9031aa_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libx11-1.8.13-he1eb515_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-event-stream-0.5.7-h28f887f_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-http-0.10.7-ha8fc4e3_5.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/brotli-1.2.0-hed03a55_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cyrus-sasl-2.1.28-hac629b4_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/freexl-2.0.0-h9dce30a_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/glpk-5.0-h445213a_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/lcms2-2.18-h0c24ade_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libamd-3.3.3-haaf9dc3_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libavif16-1.4.0-hcfa2d63_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libblas-3.11.0-5_h4a7cf45_openblas.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libbtf-2.3.2-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcamd-3.3.3-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libccolamd-3.3.4-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcolamd-3.3.4-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcurl-8.18.0-hcf29cc6_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcxsparse-4.4.1-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libfreetype-2.14.2-ha770c72_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libglx-1.7.0-ha4b6fd6_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libkml-1.3.0-haa4a5bd_1022.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libldl-3.3.2-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/librbio-4.3.4-h32481e8_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libxml2-2.15.2-he237659_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/mpfr-4.2.2-he0a73b1_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/nss-3.118-h445c969_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/openjpeg-2.5.4-h55fea9a_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/openjph-0.26.3-h8d634f6_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/orc-2.2.1-hd747db4_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/python-3.11.15-hd63d673_0_cpython.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/re2-2025.11.05-h5301d42_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/sqlite-3.52.0-h04a0ce9_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxext-1.3.7-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxfixes-6.0.2-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxrender-0.9.12-hb9d3cd8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxt-1.3.1-hb9d3cd8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/argcomplete-3.6.3-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/attrs-26.1.0-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-auth-0.9.3-hef928c7_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-mqtt-0.13.3-hc63082f_11.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/azure-core-cpp-1.16.1-h3a458e0_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/backports.zstd-1.3.0-py311h6b1f9c4_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/brotli-python-1.2.0-py311h66f275b_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/cached_property-1.5.2-pyha770c72_1.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/certifi-2026.2.25-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cfitsio-4.6.3-ha0b56bc_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/charset-normalizer-3.4.5-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/click-8.3.1-pyh8f84b5b_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/cloudpickle-3.1.2-pyhcf101f3_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/cycler-0.12.1-pyhcf101f3_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/distlib-0.4.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/filelock-3.25.2-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/fontconfig-2.17.1-h27c8c51_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/freetype-2.14.2-ha770c72_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/fsspec-2026.3.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/hdf5-1.14.6-nompi_h19486de_106.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/hpack-4.1.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/hyperframe-6.1.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/idna-3.11-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/kiwisolver-1.5.0-py311h724c32c_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libarchive-3.8.5-gpl_hc2c16d8_100.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcblas-3.11.0-5_h0358290_openblas.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgl-1.7.0-ha4b6fd6_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgrpc-1.73.1-h3288cfb_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/liblapack-3.11.0-5_h47877c9_openblas.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libspex-3.2.3-had10066_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libxml2-devel-2.15.2-he237659_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libxslt-1.1.43-h711ed8c_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/locket-1.0.0-pyhd8ed1ab_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/lz4-4.4.5-py311h1c460e0_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/markupsafe-3.0.3-py311h3778330_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/mdurl-0.1.2-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/msgpack-python-1.1.2-py311hdf67eae_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/munkres-1.1.4-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/narwhals-2.18.1-pyhcf101f3_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/networkx-3.6.1-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/openldap-2.6.10-hbde042b_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/packaging-26.0-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pillow-12.1.1-py311hf88fc01_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/platformdirs-4.9.4-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/proj-9.7.1-he0df7b0_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/prometheus-cpp-1.3.0-ha5d0236_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/psutil-7.2.2-py311haee01d2_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pycparser-2.22-pyh29332c3_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pygments-2.20.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pyparsing-3.3.2-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pyshp-3.0.3-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pysocks-1.7.1-pyha55dd90_7.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pytz-2026.1.post1-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pyyaml-6.0.3-py311h3778330_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/sortedcontainers-2.4.0-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/tblib-3.2.2-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/toolz-1.1.0-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/tornado-6.5.5-py311h49ec1c0_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/tqdm-4.67.3-pyh8f84b5b_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/unicodedata2-17.0.1-py311h49ec1c0_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/utm-0.7.0-pyhd8ed1ab_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxi-1.8.2-hb9d3cd8_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxmu-1.3.1-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxp-1.0.4-hb03c661_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/xyzservices-2026.3.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/zict-3.0.0-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/zipp-3.23.0-pyhcf101f3_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-c-s3-0.11.3-h06ab39a_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/azure-identity-cpp-1.13.2-h3a5f585_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/azure-storage-common-cpp-12.11.0-h3d7a050_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/cached-property-1.5.2-hd8ed1ab_1.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cairo-1.18.4-he90730b_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cffi-2.0.0-py311h03d9500_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/configobj-5.0.9-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cytoolz-1.1.0-py311h49ec1c0_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/donfig-0.8.1.post1-pyhd8ed1ab_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/dsdp-5.8-hd9d9efa_1203.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/fonttools-4.62.0-py311h3778330_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/freeglut-3.2.2-ha6d2627_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/geotiff-1.7.4-h1000f5c_4.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/gsl-2.7-he838d99_0.tar.bz2
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/h2-4.3.0-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/importlib-metadata-8.8.0-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/jinja2-3.1.6-pyhcf101f3_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/joblib-1.5.3-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/kealib-1.6.2-hb2f3951_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/lazy-loader-0.5-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libcholmod-5.3.1-h59ddab4_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgoogle-cloud-2.39.0-hdb79228_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libnetcdf-4.9.3-nompi_hbf2fc22_104.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libopentelemetry-cpp-1.21.0-hb9b0907_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libpq-18.3-h9abb657_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libspatialite-5.1.0-gpl_h2abfd87_119.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/lxml-6.0.2-py311h8840267_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/markdown-it-py-4.0.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/numpy-1.26.4-py311h64a7726_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/partd-1.4.2-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pyproj-3.7.2-py311h400b93a_3.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/python-dateutil-2.9.0.post0-pyhe01879c_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/python-discovery-1.2.1-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/wheel-0.46.3-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/xorg-libxft-2.3.9-h355ab9f_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-crt-cpp-0.35.2-h8824e59_6.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/azure-storage-blobs-cpp-12.15.0-h2a74896_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/contourpy-1.3.3-py311h724c32c_4.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/dask-core-2026.3.0-pyhc364b38_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/h5py-3.15.1-nompi_py311h0b2f468_101.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/imagecodecs-2026.3.6-py311h9837d23_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/imageio-2.37.0-pyhfb79c49_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/jasper-4.2.9-h1588d4d_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-core-3.10.3-h1f481a6_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgoogle-cloud-storage-2.39.0-hdbdcf42_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libklu-2.3.5-hf24d653_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libspqr-4.3.4-h852d39f_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libumfpack-6.3.5-heb53515_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/openmotif-2.3.8-he4bd66d_6.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pandas-3.0.2-py311h8032f78_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pip-26.0.1-pyh8b19718_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/poppler-25.07.0-h13eef12_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/postgresql-18.3-h9d31465_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pykdtree-1.4.3-py311h0372a8f_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pykml-0.2.0-pyhd8ed1ab_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/rich-14.3.3-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/scipy-1.17.1-py311hbe70eeb_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/shapely-2.1.2-py311h8a92878_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/ukkonen-1.1.0-py311hdf67eae_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/urllib3-2.6.3-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/virtualenv-21.2.0-pyhcf101f3_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/aws-sdk-cpp-1.11.606-hf38915e_9.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/azure-storage-files-datalake-cpp-12.13.0-hf38f1be_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/bokeh-3.9.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/distributed-2026.3.0-pyhc364b38_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/eccodes-2.46.0-h83bc92c_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/gdal-3.10.3-py311h34ccccb_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/identify-2.6.18-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-fits-3.10.3-hec9d828_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-grib-3.10.3-hb20eef8_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-hdf4-3.10.3-ha810028_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-hdf5-3.10.3-h966a9c2_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-jp2openjpeg-3.10.3-hdd07572_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-pdf-3.10.3-h20efda7_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-pg-3.10.3-h55c2262_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-postgisraster-3.10.3-h55c2262_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-xls-3.10.3-hdee084c_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libparu-1.0.0-h17147ab_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/matplotlib-base-3.10.8-py311h0f3be63_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pyresample-1.35.0-py311h1ddb823_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pysolid-0.3.4-py311h9bb1bfa_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/requests-2.32.5-pyhcf101f3_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/tifffile-2026.3.3-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cartopy-0.25.0-py311hed34c8f_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/dask-jobqueue-0.9.0-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libarrow-22.0.0-h2937f24_4_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-kea-3.10.3-h2bf108d_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-netcdf-3.10.3-ha526aae_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/multiurl-0.3.7-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pre-commit-4.5.1-pyha770c72_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pygrib-2.1.8-py311he4f3390_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/scikit-image-0.26.0-np2py311h2a99c40_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/suitesparse-7.10.1-ha0f6916_7100102.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/tiledb-2.29.2-h8821262_1.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/cvxopt-1.3.3-py311h3d1f434_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/ecmwf-datastores-client-0.5.1-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libarrow-compute-22.0.0-h58682fd_4_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-tiledb-3.10.3-h6c35068_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libparquet-22.0.0-h31208bf_4_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/cdsapi-0.7.7-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libarrow-acero-22.0.0-hb826db4_4_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libgdal-3.10.3-h3b705f5_27.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pyarrow-core-22.0.0-py311hbabfba9_2_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/isce2-2.6.4-py311h916084f_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libarrow-dataset-22.0.0-hb826db4_4_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/pyaps3-0.3.7-pyhd8ed1ab_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/libarrow-substrait-22.0.0-h9d9f3f8_4_cuda.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/linux-64/pyarrow-22.0.0-py311h38be061_2.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/dask-2026.3.0-pyhc364b38_0.conda
|
||||
https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/noarch/mintpy-1.6.3-pyhd8ed1ab_0.conda
|
||||
-354
@@ -1,354 +0,0 @@
|
||||
name: isce2_mintpy_v1
|
||||
channels:
|
||||
- https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge
|
||||
- defaults
|
||||
dependencies:
|
||||
- _openmp_mutex=4.5
|
||||
- _x86_64-microarch-level=3
|
||||
- aom=3.9.1
|
||||
- argcomplete=3.6.3
|
||||
- attr=2.5.2
|
||||
- attrs=26.1.0
|
||||
- aws-c-auth=0.9.3
|
||||
- aws-c-cal=0.9.13
|
||||
- aws-c-common=0.12.6
|
||||
- aws-c-compression=0.3.1
|
||||
- aws-c-event-stream=0.5.7
|
||||
- aws-c-http=0.10.7
|
||||
- aws-c-io=0.23.3
|
||||
- aws-c-mqtt=0.13.3
|
||||
- aws-c-s3=0.11.3
|
||||
- aws-c-sdkutils=0.2.4
|
||||
- aws-checksums=0.2.7
|
||||
- aws-crt-cpp=0.35.2
|
||||
- aws-sdk-cpp=1.11.606
|
||||
- azure-core-cpp=1.16.1
|
||||
- azure-identity-cpp=1.13.2
|
||||
- azure-storage-blobs-cpp=12.15.0
|
||||
- azure-storage-common-cpp=12.11.0
|
||||
- azure-storage-files-datalake-cpp=12.13.0
|
||||
- backports.zstd=1.3.0
|
||||
- blosc=1.21.6
|
||||
- bokeh=3.9.0
|
||||
- brotli=1.2.0
|
||||
- brotli-bin=1.2.0
|
||||
- brotli-python=1.2.0
|
||||
- brunsli=0.1
|
||||
- bzip2=1.0.8
|
||||
- c-ares=1.34.6
|
||||
- c-blosc2=2.23.1
|
||||
- ca-certificates=2026.2.25
|
||||
- cached-property=1.5.2
|
||||
- cached_property=1.5.2
|
||||
- cairo=1.18.4
|
||||
- capnproto=1.2.0
|
||||
- cartopy=0.25.0
|
||||
- cdsapi=0.7.7
|
||||
- certifi=2026.2.25
|
||||
- cffi=2.0.0
|
||||
- cfgv=3.5.0
|
||||
- cfitsio=4.6.3
|
||||
- charls=2.4.3
|
||||
- charset-normalizer=3.4.5
|
||||
- click=8.3.1
|
||||
- cloudpickle=3.1.2
|
||||
- configobj=5.0.9
|
||||
- contourpy=1.3.3
|
||||
- cvxopt=1.3.3
|
||||
- cycler=0.12.1
|
||||
- cyrus-sasl=2.1.28
|
||||
- cytoolz=1.1.0
|
||||
- dask=2026.3.0
|
||||
- dask-core=2026.3.0
|
||||
- dask-jobqueue=0.9.0
|
||||
- dav1d=1.2.1
|
||||
- distlib=0.4.0
|
||||
- distributed=2026.3.0
|
||||
- donfig=0.8.1.post1
|
||||
- dsdp=5.8
|
||||
- eccodes=2.46.0
|
||||
- ecmwf-datastores-client=0.5.1
|
||||
- fftw=3.3.10
|
||||
- filelock=3.25.2
|
||||
- fmt=12.0.0
|
||||
- font-ttf-dejavu-sans-mono=2.37
|
||||
- font-ttf-inconsolata=3.000
|
||||
- font-ttf-source-code-pro=2.038
|
||||
- font-ttf-ubuntu=0.83
|
||||
- fontconfig=2.17.1
|
||||
- fonts-conda-ecosystem=1
|
||||
- fonts-conda-forge=1
|
||||
- freeglut=3.2.2
|
||||
- freetype=2.14.2
|
||||
- freexl=2.0.0
|
||||
- fsspec=2026.3.0
|
||||
- gdal=3.10.3
|
||||
- geos=3.14.1
|
||||
- geotiff=1.7.4
|
||||
- gflags=2.2.2
|
||||
- giflib=5.2.2
|
||||
- glog=0.7.1
|
||||
- glpk=5.0
|
||||
- gmp=6.3.0
|
||||
- gsl=2.7
|
||||
- h2=4.3.0
|
||||
- h5py=3.15.1
|
||||
- hdf4=4.2.15
|
||||
- hdf5=1.14.6
|
||||
- hpack=4.1.0
|
||||
- hyperframe=6.1.0
|
||||
- icu=78.2
|
||||
- identify=2.6.18
|
||||
- idna=3.11
|
||||
- imagecodecs=2026.3.6
|
||||
- imageio=2.37.0
|
||||
- importlib-metadata=8.8.0
|
||||
- isce2=2.6.4
|
||||
- jasper=4.2.9
|
||||
- jinja2=3.1.6
|
||||
- joblib=1.5.3
|
||||
- json-c=0.18
|
||||
- jxrlib=1.1
|
||||
- kealib=1.6.2
|
||||
- keyutils=1.6.3
|
||||
- kiwisolver=1.5.0
|
||||
- krb5=1.22.2
|
||||
- lazy-loader=0.5
|
||||
- lcms2=2.18
|
||||
- ld_impl_linux-64=2.45.1
|
||||
- lerc=4.1.0
|
||||
- libabseil=20250512.1
|
||||
- libacl=2.3.2
|
||||
- libaec=1.1.5
|
||||
- libamd=3.3.3
|
||||
- libarchive=3.8.5
|
||||
- libarrow=22.0.0
|
||||
- libarrow-acero=22.0.0
|
||||
- libarrow-compute=22.0.0
|
||||
- libarrow-dataset=22.0.0
|
||||
- libarrow-substrait=22.0.0
|
||||
- libattr=2.5.2
|
||||
- libavif16=1.4.0
|
||||
- libblas=3.11.0
|
||||
- libbrotlicommon=1.2.0
|
||||
- libbrotlidec=1.2.0
|
||||
- libbrotlienc=1.2.0
|
||||
- libbtf=2.3.2
|
||||
- libcamd=3.3.3
|
||||
- libcblas=3.11.0
|
||||
- libccolamd=3.3.4
|
||||
- libcholmod=5.3.1
|
||||
- libcolamd=3.3.4
|
||||
- libcrc32c=1.1.2
|
||||
- libcurl=8.18.0
|
||||
- libcxsparse=4.4.1
|
||||
- libdeflate=1.25
|
||||
- libedit=3.1.20250104
|
||||
- libev=4.33
|
||||
- libevent=2.1.12
|
||||
- libexpat=2.7.4
|
||||
- libffi=3.5.2
|
||||
- libfreetype=2.14.2
|
||||
- libfreetype6=2.14.2
|
||||
- libgcc=15.2.0
|
||||
- libgcc-ng=15.2.0
|
||||
- libgdal=3.10.3
|
||||
- libgdal-core=3.10.3
|
||||
- libgdal-fits=3.10.3
|
||||
- libgdal-grib=3.10.3
|
||||
- libgdal-hdf4=3.10.3
|
||||
- libgdal-hdf5=3.10.3
|
||||
- libgdal-jp2openjpeg=3.10.3
|
||||
- libgdal-kea=3.10.3
|
||||
- libgdal-netcdf=3.10.3
|
||||
- libgdal-pdf=3.10.3
|
||||
- libgdal-pg=3.10.3
|
||||
- libgdal-postgisraster=3.10.3
|
||||
- libgdal-tiledb=3.10.3
|
||||
- libgdal-xls=3.10.3
|
||||
- libgfortran=15.2.0
|
||||
- libgfortran5=15.2.0
|
||||
- libgl=1.7.0
|
||||
- libglib=2.86.4
|
||||
- libglu=9.0.3
|
||||
- libglvnd=1.7.0
|
||||
- libglx=1.7.0
|
||||
- libgomp=15.2.0
|
||||
- libgoogle-cloud=2.39.0
|
||||
- libgoogle-cloud-storage=2.39.0
|
||||
- libgrpc=1.73.1
|
||||
- libhwy=1.3.0
|
||||
- libiconv=1.18
|
||||
- libjpeg-turbo=3.1.2
|
||||
- libjxl=0.11.2
|
||||
- libklu=2.3.5
|
||||
- libkml=1.3.0
|
||||
- liblapack=3.11.0
|
||||
- libldl=3.3.2
|
||||
- liblzma=5.8.2
|
||||
- libnetcdf=4.9.3
|
||||
- libnghttp2=1.67.0
|
||||
- libnsl=2.0.1
|
||||
- libntlm=1.8
|
||||
- libopenblas=0.3.30
|
||||
- libopengl=1.7.0
|
||||
- libopentelemetry-cpp=1.21.0
|
||||
- libopentelemetry-cpp-headers=1.21.0
|
||||
- libparquet=22.0.0
|
||||
- libparu=1.0.0
|
||||
- libpng=1.6.55
|
||||
- libpq=18.3
|
||||
- libprotobuf=6.31.1
|
||||
- librbio=4.3.4
|
||||
- libre2-11=2025.11.05
|
||||
- librttopo=1.1.0
|
||||
- libspatialite=5.1.0
|
||||
- libspex=3.2.3
|
||||
- libspqr=4.3.4
|
||||
- libsqlite=3.52.0
|
||||
- libssh2=1.11.1
|
||||
- libstdcxx=15.2.0
|
||||
- libstdcxx-ng=15.2.0
|
||||
- libsuitesparseconfig=7.10.1
|
||||
- libthrift=0.22.0
|
||||
- libtiff=4.7.1
|
||||
- libumfpack=6.3.5
|
||||
- liburing=2.14
|
||||
- libutf8proc=2.11.3
|
||||
- libuuid=2.41.3
|
||||
- libwebp-base=1.6.0
|
||||
- libxcb=1.17.0
|
||||
- libxcrypt=4.4.36
|
||||
- libxml2=2.15.2
|
||||
- libxml2-16=2.15.2
|
||||
- libxml2-devel=2.15.2
|
||||
- libxslt=1.1.43
|
||||
- libzip=1.11.2
|
||||
- libzlib=1.3.1
|
||||
- libzopfli=1.0.3
|
||||
- locket=1.0.0
|
||||
- lxml=6.0.2
|
||||
- lz4=4.4.5
|
||||
- lz4-c=1.10.0
|
||||
- lzo=2.10
|
||||
- markdown-it-py=4.0.0
|
||||
- markupsafe=3.0.3
|
||||
- matplotlib-base=3.10.8
|
||||
- mdurl=0.1.2
|
||||
- metis=5.1.0
|
||||
- minizip=4.0.10
|
||||
- mintpy=1.6.3
|
||||
- mpfr=4.2.2
|
||||
- msgpack-python=1.1.2
|
||||
- multiurl=0.3.7
|
||||
- munkres=1.1.4
|
||||
- narwhals=2.18.1
|
||||
- ncurses=6.5
|
||||
- networkx=3.6.1
|
||||
- nlohmann_json=3.12.0
|
||||
- nodeenv=1.10.0
|
||||
- nspr=4.38
|
||||
- nss=3.118
|
||||
- numpy=1.26.4
|
||||
- openjpeg=2.5.4
|
||||
- openjph=0.26.3
|
||||
- openldap=2.6.10
|
||||
- openmotif=2.3.8
|
||||
- openssl=3.6.1
|
||||
- orc=2.2.1
|
||||
- packaging=26.0
|
||||
- pandas=3.0.2
|
||||
- partd=1.4.2
|
||||
- pcre2=10.47
|
||||
- pillow=12.1.1
|
||||
- pip=26.0.1
|
||||
- pixman=0.46.4
|
||||
- platformdirs=4.9.4
|
||||
- poppler=25.07.0
|
||||
- poppler-data=0.4.12
|
||||
- postgresql=18.3
|
||||
- pre-commit=4.5.1
|
||||
- proj=9.7.1
|
||||
- prometheus-cpp=1.3.0
|
||||
- psutil=7.2.2
|
||||
- pthread-stubs=0.4
|
||||
- pyaps3=0.3.7
|
||||
- pyarrow=22.0.0
|
||||
- pyarrow-core=22.0.0
|
||||
- pycparser=2.22
|
||||
- pygments=2.20.0
|
||||
- pygrib=2.1.8
|
||||
- pykdtree=1.4.3
|
||||
- pykml=0.2.0
|
||||
- pyparsing=3.3.2
|
||||
- pyproj=3.7.2
|
||||
- pyresample=1.35.0
|
||||
- pyshp=3.0.3
|
||||
- pysocks=1.7.1
|
||||
- pysolid=0.3.4
|
||||
- python=3.11.15
|
||||
- python-dateutil=2.9.0.post0
|
||||
- python-discovery=1.2.1
|
||||
- python_abi=3.11
|
||||
- pytz=2026.1.post1
|
||||
- pyyaml=6.0.3
|
||||
- qhull=2020.2
|
||||
- rav1e=0.8.1
|
||||
- re2=2025.11.05
|
||||
- readline=8.3
|
||||
- requests=2.32.5
|
||||
- rich=14.3.3
|
||||
- s2n=1.6.2
|
||||
- scikit-image=0.26.0
|
||||
- scipy=1.17.1
|
||||
- setuptools=82.0.1
|
||||
- shapely=2.1.2
|
||||
- six=1.17.0
|
||||
- snappy=1.2.2
|
||||
- sortedcontainers=2.4.0
|
||||
- spdlog=1.16.0
|
||||
- sqlite=3.52.0
|
||||
- suitesparse=7.10.1
|
||||
- svt-av1=4.0.1
|
||||
- tblib=3.2.2
|
||||
- tifffile=2026.3.3
|
||||
- tiledb=2.29.2
|
||||
- tk=8.6.13
|
||||
- toolz=1.1.0
|
||||
- tornado=6.5.5
|
||||
- tqdm=4.67.3
|
||||
- typing_extensions=4.15.0
|
||||
- tzcode=2026a
|
||||
- tzdata=2025c
|
||||
- ukkonen=1.1.0
|
||||
- unicodedata2=17.0.1
|
||||
- uriparser=0.9.8
|
||||
- urllib3=2.6.3
|
||||
- utm=0.7.0
|
||||
- virtualenv=21.2.0
|
||||
- wheel=0.46.3
|
||||
- xerces-c=3.3.0
|
||||
- xorg-libice=1.1.2
|
||||
- xorg-libsm=1.2.6
|
||||
- xorg-libx11=1.8.13
|
||||
- xorg-libxau=1.0.12
|
||||
- xorg-libxdmcp=1.1.5
|
||||
- xorg-libxext=1.3.7
|
||||
- xorg-libxfixes=6.0.2
|
||||
- xorg-libxft=2.3.9
|
||||
- xorg-libxi=1.8.2
|
||||
- xorg-libxmu=1.3.1
|
||||
- xorg-libxp=1.0.4
|
||||
- xorg-libxrender=0.9.12
|
||||
- xorg-libxt=1.3.1
|
||||
- xyzservices=2026.3.0
|
||||
- yaml=0.2.5
|
||||
- zfp=1.0.1
|
||||
- zict=3.0.0
|
||||
- zipp=3.23.0
|
||||
- zlib=1.3.1
|
||||
- zlib-ng=2.3.3
|
||||
- zstd=1.5.7
|
||||
- pip:
|
||||
- fonttools==4.62.1
|
||||
prefix: /home/administrator/miniconda3/envs/isce2_mintpy_v1
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
python_executable=/home/administrator/miniconda3/envs/isce2_mintpy_v1/bin/python
|
||||
python_version=3.11.15
|
||||
isce_present=True
|
||||
mintpy_present=True
|
||||
h5py_present=True
|
||||
isce_file=/home/administrator/miniconda3/envs/isce2_mintpy_v1/lib/python3.11/site-packages/isce/__init__.py
|
||||
isce_version=2.6.3
|
||||
mintpy_file=/home/administrator/miniconda3/envs/isce2_mintpy_v1/lib/python3.11/site-packages/mintpy/__init__.py
|
||||
mintpy_version=1.6.2
|
||||
2026-04-06 15:31:20,151 - h5py._conv - DEBUG - Creating converter from 7 to 5
|
||||
2026-04-06 15:31:20,152 - h5py._conv - DEBUG - Creating converter from 5 to 7
|
||||
2026-04-06 15:31:20,153 - h5py._conv - DEBUG - Creating converter from 7 to 5
|
||||
2026-04-06 15:31:20,153 - h5py._conv - DEBUG - Creating converter from 5 to 7
|
||||
h5py_version=3.15.1
|
||||
-64
@@ -1,64 +0,0 @@
|
||||
# vim: set filetype=cfg:
|
||||
## LT-1 stripmapStack -> MintPy SBAS smoke-test config
|
||||
## Workspace:
|
||||
## phase2_bridge_smoketest_20260406
|
||||
## Sample stack:
|
||||
## LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1
|
||||
## dates: 20250118, 20250315, 20250510, 20250705, 20250830
|
||||
## Work dir suggestion:
|
||||
## /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/mintpy_sbas_unified_phase2_20260407
|
||||
|
||||
########## computing resource configuration
|
||||
mintpy.compute.cluster = none
|
||||
mintpy.compute.numWorker = 4
|
||||
mintpy.compute.maxMemory = 8.0
|
||||
|
||||
########## 1. load_data
|
||||
mintpy.load.processor = isce
|
||||
mintpy.load.autoPath = no
|
||||
mintpy.load.updateMode = yes
|
||||
mintpy.load.compression = lzf
|
||||
mintpy.load.metaFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/merged/SLC/20250510/referenceShelve/data.dat
|
||||
mintpy.load.baselineDir = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/baselines
|
||||
mintpy.load.unwFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/Igrams/*/filt*_snaphu.unw
|
||||
mintpy.load.corFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/Igrams/*/filt_*.cor
|
||||
mintpy.load.connCompFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/Igrams/*/filt*_snaphu.unw.conncomp
|
||||
mintpy.load.intFile = None
|
||||
mintpy.load.demFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/hgt.rdr
|
||||
mintpy.load.lookupYFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/lat.rdr
|
||||
mintpy.load.lookupXFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/lon.rdr
|
||||
mintpy.load.incAngleFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/los.rdr
|
||||
mintpy.load.azAngleFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/los.rdr
|
||||
mintpy.load.shadowMaskFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/shadowMask.rdr
|
||||
mintpy.load.waterMaskFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/geom_reference/waterMask.rdr
|
||||
|
||||
########## 2. modify_network
|
||||
mintpy.network.coherenceBased = no
|
||||
mintpy.network.areaRatioBased = no
|
||||
|
||||
########## 3. reference_point
|
||||
mintpy.reference.yx = 1994,52
|
||||
mintpy.reference.maskFile = maskAllValid.h5
|
||||
|
||||
########## 4. correct_unwrap_error
|
||||
mintpy.unwrapError.method = no
|
||||
|
||||
########## 5. invert_network
|
||||
mintpy.networkInversion.weightFunc = no
|
||||
mintpy.networkInversion.maskDataset = no
|
||||
mintpy.networkInversion.minRedundancy = 1.0
|
||||
mintpy.networkInversion.waterMaskFile = maskAllValid.h5
|
||||
|
||||
########## 6-10. optional corrections disabled for the first unified-env replay
|
||||
mintpy.solidEarthTides = no
|
||||
mintpy.ionosphericDelay.method = no
|
||||
mintpy.troposphericDelay.method = no
|
||||
mintpy.deramp = no
|
||||
mintpy.topographicResidual = no
|
||||
|
||||
########## 11-13. outputs
|
||||
mintpy.reference.date = 20250510
|
||||
mintpy.geocode = no
|
||||
mintpy.save.kmz = no
|
||||
mintpy.save.hdfEos5 = no
|
||||
mintpy.plot = no
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
{
|
||||
"schema_version": "psinsar.sbas.v1",
|
||||
"catalog_name": "psinsar",
|
||||
"mode": "sbas",
|
||||
"engine_code": "isce2",
|
||||
"processor_code": "isce2_stack_mintpy",
|
||||
"sample_group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"reference_date": "20250510",
|
||||
"reference_point_yx": [
|
||||
1994,
|
||||
52
|
||||
],
|
||||
"stack_dates": [
|
||||
"20250118",
|
||||
"20250315",
|
||||
"20250510",
|
||||
"20250705",
|
||||
"20250830"
|
||||
],
|
||||
"network_pair_count": 10,
|
||||
"mintpy_work_dir_wsl": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_v5",
|
||||
"publish_dir_wsl": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_v5",
|
||||
"quality_summary": {
|
||||
"strict_valid_pixels": 1219001,
|
||||
"strict_valid_pixel_ratio": 0.2991,
|
||||
"mask_temp_coh_pixels": 62987,
|
||||
"mask_temp_coh_threshold": 0.7
|
||||
},
|
||||
"artifacts": [
|
||||
{
|
||||
"product_type": "timeseries_cube",
|
||||
"role": "primary",
|
||||
"dataset": "timeseries",
|
||||
"publish_relpath": "assets/geo_timeseries.h5",
|
||||
"source_relpath": "assets/geo_timeseries.h5"
|
||||
},
|
||||
{
|
||||
"product_type": "velocity_map",
|
||||
"role": "primary",
|
||||
"dataset": "velocity",
|
||||
"publish_relpath": "assets/geo_velocity.h5",
|
||||
"source_relpath": "assets/geo_velocity.h5"
|
||||
},
|
||||
{
|
||||
"product_type": "velocity_geotiff",
|
||||
"role": "primary",
|
||||
"dataset": "velocity",
|
||||
"publish_relpath": "assets/velocity.tif",
|
||||
"source_relpath": "assets/velocity.tif"
|
||||
},
|
||||
{
|
||||
"product_type": "temporal_coherence",
|
||||
"role": "quality",
|
||||
"dataset": "temporalCoherence",
|
||||
"publish_relpath": "assets/geo_temporalCoherence.h5",
|
||||
"source_relpath": "assets/geo_temporalCoherence.h5"
|
||||
},
|
||||
{
|
||||
"product_type": "temporal_coherence_geotiff",
|
||||
"role": "quality",
|
||||
"dataset": "temporalCoherence",
|
||||
"publish_relpath": "assets/temporalCoherence.tif",
|
||||
"source_relpath": "assets/temporalCoherence.tif"
|
||||
},
|
||||
{
|
||||
"product_type": "quality_mask",
|
||||
"role": "quality",
|
||||
"dataset": "mask",
|
||||
"publish_relpath": "assets/geo_maskTempCoh.h5",
|
||||
"source_relpath": "assets/geo_maskTempCoh.h5"
|
||||
},
|
||||
{
|
||||
"product_type": "quality_mask_geotiff",
|
||||
"role": "quality",
|
||||
"dataset": "mask",
|
||||
"publish_relpath": "assets/maskTempCoh.tif",
|
||||
"source_relpath": "assets/maskTempCoh.tif"
|
||||
},
|
||||
{
|
||||
"product_type": "ifgram_network",
|
||||
"role": "diagnostic",
|
||||
"dataset": "mask",
|
||||
"publish_relpath": "runtime/numTriNonzeroIntAmbiguity.h5",
|
||||
"source_relpath": "numTriNonzeroIntAmbiguity.h5"
|
||||
},
|
||||
{
|
||||
"product_type": "preview_png",
|
||||
"role": "primary",
|
||||
"publish_relpath": "preview/velocity_preview.png",
|
||||
"source_relpath": "preview/velocity_preview.png"
|
||||
},
|
||||
{
|
||||
"product_type": "diagnostic_png",
|
||||
"role": "diagnostic",
|
||||
"publish_relpath": "preview/numTriNonzeroIntAmbiguity.png",
|
||||
"source_relpath": "preview/numTriNonzeroIntAmbiguity.png"
|
||||
}
|
||||
],
|
||||
"retained_runtime_artifacts": [
|
||||
{
|
||||
"purpose": "strict_all_ifgram_mask",
|
||||
"source_relpath": "maskAllValid.h5"
|
||||
},
|
||||
{
|
||||
"purpose": "average_spatial_coherence",
|
||||
"source_relpath": "avgSpatialCoh.h5"
|
||||
},
|
||||
{
|
||||
"purpose": "config_backup",
|
||||
"source_relpath": "smallbaselineApp.cfg"
|
||||
}
|
||||
],
|
||||
"notes": [
|
||||
"This is a sample experiment manifest for system-integration design only.",
|
||||
"Current experiment includes geocoded HDF5 outputs, GeoTIFF exports, and a publish-style manifest bundle."
|
||||
]
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
# vim: set filetype=cfg:
|
||||
## LT-1 stripmapStack -> MintPy SBAS smoke-test config
|
||||
## Sample stack:
|
||||
## LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1
|
||||
## dates: 20250118, 20250315, 20250510, 20250705, 20250830
|
||||
## Work dir suggestion:
|
||||
## /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas
|
||||
|
||||
########## computing resource configuration
|
||||
mintpy.compute.cluster = none
|
||||
mintpy.compute.numWorker = 4
|
||||
mintpy.compute.maxMemory = 8.0
|
||||
|
||||
########## 1. load_data
|
||||
mintpy.load.processor = isce
|
||||
mintpy.load.autoPath = no
|
||||
mintpy.load.updateMode = yes
|
||||
mintpy.load.compression = lzf
|
||||
mintpy.load.metaFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/merged/SLC/20250510/referenceShelve/data.dat
|
||||
mintpy.load.baselineDir = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/baselines
|
||||
mintpy.load.unwFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/Igrams/*/filt*_snaphu.unw
|
||||
mintpy.load.corFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/Igrams/*/filt_*.cor
|
||||
mintpy.load.connCompFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/Igrams/*/filt*_snaphu.unw.conncomp
|
||||
mintpy.load.intFile = None
|
||||
mintpy.load.demFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/hgt.rdr
|
||||
mintpy.load.lookupYFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/lat.rdr
|
||||
mintpy.load.lookupXFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/lon.rdr
|
||||
mintpy.load.incAngleFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/los.rdr
|
||||
mintpy.load.azAngleFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/los.rdr
|
||||
mintpy.load.shadowMaskFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/shadowMask.rdr
|
||||
mintpy.load.waterMaskFile = /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference/waterMask.rdr
|
||||
|
||||
########## 2. modify_network
|
||||
mintpy.network.coherenceBased = no
|
||||
mintpy.network.areaRatioBased = no
|
||||
|
||||
########## 3. reference_point
|
||||
mintpy.reference.yx = 1994,52
|
||||
mintpy.reference.maskFile = maskAllValid.h5
|
||||
|
||||
########## 4. correct_unwrap_error
|
||||
mintpy.unwrapError.method = no
|
||||
|
||||
########## 5. invert_network
|
||||
mintpy.networkInversion.weightFunc = no
|
||||
mintpy.networkInversion.maskDataset = no
|
||||
mintpy.networkInversion.minRedundancy = 1.0
|
||||
mintpy.networkInversion.waterMaskFile = maskAllValid.h5
|
||||
|
||||
########## 6-10. optional corrections disabled for first offline LT-1 smoke test
|
||||
mintpy.solidEarthTides = no
|
||||
mintpy.ionosphericDelay.method = no
|
||||
mintpy.troposphericDelay.method = no
|
||||
mintpy.deramp = no
|
||||
mintpy.topographicResidual = no
|
||||
|
||||
########## 11-13. outputs
|
||||
mintpy.reference.date = 20250510
|
||||
mintpy.geocode = no
|
||||
mintpy.save.kmz = no
|
||||
mintpy.save.hdfEos5 = no
|
||||
mintpy.plot = no
|
||||
@@ -1,175 +0,0 @@
|
||||
{
|
||||
"source_root_windows": "F:\\Insar_data_pool_1",
|
||||
"source_root_wsl": "/mnt/f/Insar_data_pool_1",
|
||||
"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"tile_key": "E123.3_N46.1",
|
||||
"scene_count": 5,
|
||||
"reference_strategy": "middle_by_date",
|
||||
"reference_date": "20250510",
|
||||
"stack_group": {
|
||||
"satellite": "LT1A",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"receiving_stations": [
|
||||
"KSC",
|
||||
"SYC"
|
||||
]
|
||||
},
|
||||
"proposed_scratch_windows": "Z:\\Code\\Insar_management_system_v2\\experiments\\isce2_sbas_timeseries\\scratch\\lt1a_strip1_hh_descending_e123p3_n46p1",
|
||||
"proposed_scratch_wsl": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1",
|
||||
"proposed_layout": {
|
||||
"stack_input_manifest": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_input_manifest.json",
|
||||
"slc_dir": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/SLC",
|
||||
"orbits_dir": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/orbits",
|
||||
"logs_dir": "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/logs"
|
||||
},
|
||||
"stack_prep_assessment": {
|
||||
"current_scene_layout": "per_scene_folder_with_tiff_meta_rpc",
|
||||
"official_stripmapStack_expected_layout": "SLC/YYYYMMDD/YYYYMMDD.raw or YYYYMMDD.slc",
|
||||
"direct_compatibility": "unproven",
|
||||
"lt1_adapter_required_likely": true,
|
||||
"notes": [
|
||||
"Current repo can read these scene folders as RadarData assets.",
|
||||
"Official stripmapStack helper scripts do not advertise LT-1/LUTAN1 preparation hooks.",
|
||||
"A custom LT-1 stack preparation layer is likely needed before official stack execution."
|
||||
]
|
||||
},
|
||||
"scenes": [
|
||||
{
|
||||
"folder_name": "LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780",
|
||||
"folder_path": "F:\\Insar_data_pool_1\\LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780",
|
||||
"folder_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780",
|
||||
"tiff_path": "F:\\Insar_data_pool_1\\LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780\\LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780.tiff",
|
||||
"tiff_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780/LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780.tiff",
|
||||
"meta_path": "F:\\Insar_data_pool_1\\LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780\\LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780.meta.xml",
|
||||
"meta_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780/LT1A_MONO_SYC_STRIP1_016197_E123.3_N46.1_20250118_SLC_HH_S2A_0000623780.meta.xml",
|
||||
"file_size_bytes": 1632365702,
|
||||
"satellite": "LT1A",
|
||||
"imaging_date": "20250118",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"satellite_mode": "MONOSTATIC",
|
||||
"receiving_station": "SYC",
|
||||
"orbit_circle": "16197",
|
||||
"scene_center_lon": 123.3290291621,
|
||||
"scene_center_lat": 46.0963941396,
|
||||
"acquisition_time_utc": "2025-01-18T22:5:18.778600",
|
||||
"product_type": "COMPLEX",
|
||||
"product_level": "LEVEL2A",
|
||||
"product_unique_id": "0000623780",
|
||||
"tile_key": "E123.3_N46.1",
|
||||
"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"orbit_txt_expected_name": "LT1A_GpsData_GAS_C_20250118.txt"
|
||||
},
|
||||
{
|
||||
"folder_name": "LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238",
|
||||
"folder_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238",
|
||||
"folder_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238",
|
||||
"tiff_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238\\LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238.tiff",
|
||||
"tiff_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238/LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238.tiff",
|
||||
"meta_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238\\LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238.meta.xml",
|
||||
"meta_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238/LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238.meta.xml",
|
||||
"file_size_bytes": 1630628342,
|
||||
"satellite": "LT1A",
|
||||
"imaging_date": "20250315",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"satellite_mode": "MONOSTATIC",
|
||||
"receiving_station": "KSC",
|
||||
"orbit_circle": "17030",
|
||||
"scene_center_lon": 123.3320867599,
|
||||
"scene_center_lat": 46.1149596404,
|
||||
"acquisition_time_utc": "2025-03-15T22:5:19.382029",
|
||||
"product_type": "COMPLEX",
|
||||
"product_level": "LEVEL2A",
|
||||
"product_unique_id": "0000678238",
|
||||
"tile_key": "E123.3_N46.1",
|
||||
"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"orbit_txt_expected_name": "LT1A_GpsData_GAS_C_20250315.txt"
|
||||
},
|
||||
{
|
||||
"folder_name": "LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820",
|
||||
"folder_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820",
|
||||
"folder_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820",
|
||||
"tiff_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820\\LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820.tiff",
|
||||
"tiff_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820/LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820.tiff",
|
||||
"meta_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820\\LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820.meta.xml",
|
||||
"meta_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820/LT1A_MONO_KSC_STRIP1_017863_E123.3_N46.1_20250510_SLC_HH_S2A_0000738820.meta.xml",
|
||||
"file_size_bytes": 1631554934,
|
||||
"satellite": "LT1A",
|
||||
"imaging_date": "20250510",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"satellite_mode": "MONOSTATIC",
|
||||
"receiving_station": "KSC",
|
||||
"orbit_circle": "17863",
|
||||
"scene_center_lon": 123.3311389524,
|
||||
"scene_center_lat": 46.1155150436,
|
||||
"acquisition_time_utc": "2025-05-10T22:5:20.466535",
|
||||
"product_type": "COMPLEX",
|
||||
"product_level": "LEVEL2A",
|
||||
"product_unique_id": "0000738820",
|
||||
"tile_key": "E123.3_N46.1",
|
||||
"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"orbit_txt_expected_name": "LT1A_GpsData_GAS_C_20250510.txt"
|
||||
},
|
||||
{
|
||||
"folder_name": "LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680",
|
||||
"folder_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680",
|
||||
"folder_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680",
|
||||
"tiff_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680\\LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680.tiff",
|
||||
"tiff_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680/LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680.tiff",
|
||||
"meta_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680\\LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680.meta.xml",
|
||||
"meta_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680/LT1A_MONO_KSC_STRIP1_018697_E123.3_N46.1_20250705_SLC_HH_S2A_0000796680.meta.xml",
|
||||
"file_size_bytes": 1633523942,
|
||||
"satellite": "LT1A",
|
||||
"imaging_date": "20250705",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"satellite_mode": "MONOSTATIC",
|
||||
"receiving_station": "KSC",
|
||||
"orbit_circle": "18697",
|
||||
"scene_center_lon": 123.3345082568,
|
||||
"scene_center_lat": 46.1000329747,
|
||||
"acquisition_time_utc": "2025-07-05T22:5:20.665803",
|
||||
"product_type": "COMPLEX",
|
||||
"product_level": "LEVEL2A",
|
||||
"product_unique_id": "0000796680",
|
||||
"tile_key": "E123.3_N46.1",
|
||||
"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"orbit_txt_expected_name": "LT1A_GpsData_GAS_C_20250705.txt"
|
||||
},
|
||||
{
|
||||
"folder_name": "LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029",
|
||||
"folder_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029",
|
||||
"folder_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029",
|
||||
"tiff_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029\\LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029.tiff",
|
||||
"tiff_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029/LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029.tiff",
|
||||
"meta_path": "F:\\Insar_data_pool_1\\LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029\\LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029.meta.xml",
|
||||
"meta_path_wsl": "/mnt/f/Insar_data_pool_1/LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029/LT1A_MONO_KSC_STRIP1_019530_E123.3_N46.1_20250830_SLC_HH_S2A_0000857029.meta.xml",
|
||||
"file_size_bytes": 1629875486,
|
||||
"satellite": "LT1A",
|
||||
"imaging_date": "20250830",
|
||||
"imaging_mode": "STRIP1",
|
||||
"polarization": "HH",
|
||||
"orbit_direction": "DESCENDING",
|
||||
"satellite_mode": "MONOSTATIC",
|
||||
"receiving_station": "KSC",
|
||||
"orbit_circle": "19530",
|
||||
"scene_center_lon": 123.3286377886,
|
||||
"scene_center_lat": 46.1152894101,
|
||||
"acquisition_time_utc": "2025-08-30T22:5:26.558015",
|
||||
"product_type": "COMPLEX",
|
||||
"product_level": "LEVEL2A",
|
||||
"product_unique_id": "0000857029",
|
||||
"tile_key": "E123.3_N46.1",
|
||||
"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1",
|
||||
"orbit_txt_expected_name": "LT1A_GpsData_GAS_C_20250830.txt"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
# Phase 0 Environment Check
|
||||
|
||||
Updated: 2026-04-03
|
||||
|
||||
## Confirmed
|
||||
|
||||
- Project workspace:
|
||||
- Windows repo root: `Z:\Code\Insar_management_system_v2`
|
||||
- WSL mount path: `/mnt/z/Code/Insar_management_system_v2`
|
||||
- Windows project Python env:
|
||||
- `C:\Users\Administrator\.conda\envs\InSAR`
|
||||
- WSL experiment distro:
|
||||
- `Ubuntu-24.04`
|
||||
- WSL project access:
|
||||
- `/mnt/z/Code/Insar_management_system_v2`
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries`
|
||||
- WSL system Python:
|
||||
- `Python 3.12.3`
|
||||
- WSL conda root:
|
||||
- `/home/administrator/miniconda3`
|
||||
- WSL conda envs found:
|
||||
- `base`
|
||||
- `isce2`
|
||||
- ISCE2 env package:
|
||||
- `isce2 2.6.4`
|
||||
- ISCE2 Python import path:
|
||||
- `/home/administrator/miniconda3/envs/isce2/lib/python3.11/site-packages/isce/__init__.py`
|
||||
- Lutan1 sensor module:
|
||||
- `/home/administrator/miniconda3/envs/isce2/lib/python3.11/site-packages/isce/components/isceobj/Sensor/Lutan1.py`
|
||||
- Official stack directories present:
|
||||
- `/home/administrator/miniconda3/envs/isce2/share/isce2/stripmapStack`
|
||||
- `/home/administrator/miniconda3/envs/isce2/share/isce2/topsStack`
|
||||
|
||||
## Confirmed Gaps
|
||||
|
||||
- `conda` is not currently on the default shell `PATH` inside `Ubuntu-24.04`.
|
||||
- Use `/home/administrator/miniconda3/bin/conda` directly in scripts.
|
||||
- `MintPy` is not installed in the `isce2` env yet.
|
||||
- `conda list -n isce2 mintpy` returned no match.
|
||||
- Calling `conda list -n isce2 ...` from a WSL bash script triggered a segmentation fault once.
|
||||
- For experiment scripts, prefer `conda run -n isce2 python ...` checks over `conda list`.
|
||||
|
||||
## Implication
|
||||
|
||||
Phase 0 can start immediately for:
|
||||
|
||||
- LT-1 / ISCE2 stack compatibility checks
|
||||
- workspace and path validation
|
||||
- command-chain drafting
|
||||
|
||||
But the full SBAS chain cannot run end to end until one of these is true:
|
||||
|
||||
- `MintPy` is installed into `isce2`, or
|
||||
- a separate WSL env with `MintPy` is prepared
|
||||
|
||||
## Next Checks
|
||||
|
||||
1. Verify ISCE2 stack scripts actually exist in `Ubuntu-24.04`.
|
||||
2. Read `stripmapStack/README.md` and `stackStripMap.py` to identify required stack inputs.
|
||||
3. Decide whether `MintPy` should share the `isce2` env or live in a separate env.
|
||||
4. Verify LT-1 / LUTAN1 support is usable for stack-mode inputs, not only single-pair mode.
|
||||
5. Draft a minimal stack experiment command chain under this folder.
|
||||
@@ -1,123 +0,0 @@
|
||||
# Phase 0 Repo Reader Findings
|
||||
|
||||
Updated: 2026-04-03
|
||||
|
||||
## Existing repo reader path
|
||||
|
||||
The current repository already has a stable LT-1 single-scene metadata ingestion path.
|
||||
|
||||
Main code path:
|
||||
|
||||
- `backend/app/services/data_service.py`
|
||||
- `scan_radar_data()`
|
||||
- `backend/app/utils.py`
|
||||
- `parse_lt1_radar_filename()`
|
||||
- `find_xml_file()`
|
||||
- `parse_xml_metadata()`
|
||||
|
||||
## What the existing reader does
|
||||
|
||||
### 1. Folder-name parsing
|
||||
|
||||
`parse_lt1_radar_filename()` extracts from the directory name:
|
||||
|
||||
- `satellite`
|
||||
- `satellite_mode`
|
||||
- `receiving_station`
|
||||
- `imaging_mode`
|
||||
- `orbit_circle`
|
||||
- `scene_center_lon`
|
||||
- `scene_center_lat`
|
||||
- `imaging_date`
|
||||
- `acquisition_time_utc`
|
||||
- `product_type`
|
||||
- `polarization`
|
||||
- `product_level`
|
||||
- `product_unique_id`
|
||||
|
||||
Example supported name:
|
||||
|
||||
```text
|
||||
LT1B_MONO_SYC_STRIP1_018153_E135.4_N48.3_20250701_SLC_HH_S2A_0000790171
|
||||
```
|
||||
|
||||
### 2. XML discovery
|
||||
|
||||
`find_xml_file()` prefers:
|
||||
|
||||
- `*.meta.xml`
|
||||
|
||||
and falls back to:
|
||||
|
||||
- the only XML file in the directory, if there is just one
|
||||
|
||||
### 3. XML parsing
|
||||
|
||||
`parse_xml_metadata()` extracts:
|
||||
|
||||
- `orbit_direction`
|
||||
- `imaging_mode`
|
||||
- `polarization`
|
||||
- `receiving_station`
|
||||
- `satellite_mode`
|
||||
- `orbit_circle` from `absOrbit`
|
||||
- `scene_center_lon`
|
||||
- `scene_center_lat`
|
||||
- `acquisition_time_utc`
|
||||
- `product_type`
|
||||
- `product_level`
|
||||
- `product_unique_id`
|
||||
- `look_direction`
|
||||
- corner coordinates and coverage polygon
|
||||
|
||||
### 4. Merge rule
|
||||
|
||||
`scan_radar_data()` merges:
|
||||
|
||||
- folder-name metadata
|
||||
- XML metadata
|
||||
|
||||
with XML preferred for most fields, except `product_unique_id` where the folder-name value is preserved if present.
|
||||
|
||||
## Why this matters for SBAS experiments
|
||||
|
||||
This means the SBAS experiment should not invent a separate metadata interpretation unless absolutely necessary.
|
||||
|
||||
Recommended rule:
|
||||
|
||||
- reuse the same field semantics already used by `RadarDataORM`
|
||||
- reuse the same `.meta.xml` discovery logic
|
||||
- treat `scan_radar_data()` output as the canonical single-scene asset layer
|
||||
|
||||
## Data layout check against `F:\Insar_data_pool_1`
|
||||
|
||||
Sample scene directories under `F:\Insar_data_pool_1` are compatible with the current single-scene reader:
|
||||
|
||||
- one folder per scene
|
||||
- directory name matches LT-1 parser expectations
|
||||
- contains `*.meta.xml`
|
||||
- contains `*.tiff`
|
||||
- contains preview and auxiliary files
|
||||
|
||||
Example sample directory:
|
||||
|
||||
```text
|
||||
F:\Insar_data_pool_1\LT1A_MONO_KSC_STRIP1_017030_E123.3_N46.1_20250315_SLC_HH_S2A_0000678238
|
||||
```
|
||||
|
||||
Example files inside:
|
||||
|
||||
- `...meta.xml`
|
||||
- `...tiff`
|
||||
- `...rpc`
|
||||
- `...browse.jpg`
|
||||
- `...thumb.jpg`
|
||||
|
||||
## Practical implication
|
||||
|
||||
For phase 1 design and experiments:
|
||||
|
||||
- the current repo already knows how to ingest these LT-1 scene folders as `RadarData`
|
||||
- stack preparation should build on top of this asset layer
|
||||
- the real unknown is not scene metadata parsing
|
||||
- the real unknown is how to transform these scene folders into a stack layout acceptable to `stripmapStack`
|
||||
@@ -1,92 +0,0 @@
|
||||
# Phase 0 Sample Stack Selection
|
||||
|
||||
Updated: 2026-04-03
|
||||
|
||||
## Selected baseline sample
|
||||
|
||||
Current baseline sample stack:
|
||||
|
||||
- group key:
|
||||
- `LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1`
|
||||
- manifest:
|
||||
- `experiments/isce2_sbas_timeseries/configs/sample_stack_e123p3_n46p1.json`
|
||||
|
||||
## Sample summary
|
||||
|
||||
- satellite:
|
||||
- `LT1A`
|
||||
- mode:
|
||||
- `STRIP1`
|
||||
- polarization:
|
||||
- `HH`
|
||||
- orbit direction:
|
||||
- `DESCENDING`
|
||||
- scene count:
|
||||
- `5`
|
||||
- dates:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- recommended reference date:
|
||||
- `20250510`
|
||||
- receiving stations observed:
|
||||
- `SYC`
|
||||
- `KSC`
|
||||
|
||||
## Why this sample is useful
|
||||
|
||||
- It already satisfies a minimal SBAS smoke-test stack size.
|
||||
- All scenes share the same:
|
||||
- satellite
|
||||
- imaging mode
|
||||
- polarization
|
||||
- orbit direction
|
||||
- tile key
|
||||
- The dates are evenly spaced enough to act as a first time-series experiment set.
|
||||
|
||||
## Important adjacent-tile signal
|
||||
|
||||
This sample is not isolated.
|
||||
|
||||
The same date sequence also appears in multiple neighboring descending tiles, including:
|
||||
|
||||
- `E123.5_N46.6`
|
||||
- `E123.6_N47.0`
|
||||
- `E123.8_N47.5`
|
||||
- `E123.9_N48.0`
|
||||
- `E124.5_N49.9`
|
||||
- `E124.7_N50.3`
|
||||
- `E124.8_N50.8`
|
||||
- `E125.0_N51.3`
|
||||
- `E125.1_N51.8`
|
||||
- `E125.3_N52.2`
|
||||
- `E125.5_N52.7`
|
||||
|
||||
These neighboring tiles share the same 5 acquisition dates:
|
||||
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
|
||||
## Implication
|
||||
|
||||
This strongly suggests the data pool contains a larger repeated strip-family, not just isolated scenes.
|
||||
|
||||
Recommended experiment order:
|
||||
|
||||
1. Start with one tile-level stack smoke test using `E123.3_N46.1`.
|
||||
2. If stack-prep works, expand to multiple adjacent tiles with the same date family.
|
||||
3. Only after that, test a wider strip or mosaic strategy.
|
||||
|
||||
## Current risk judgment
|
||||
|
||||
The main remaining uncertainty is still not scene selection.
|
||||
|
||||
The main uncertainty is:
|
||||
|
||||
- how to convert LT-1 per-scene `tiff + meta.xml` folders
|
||||
- into a stack layout and sensor input form acceptable to the ISCE2 stripmap stack workflow
|
||||
@@ -1,140 +0,0 @@
|
||||
# Phase 0 Stack Findings
|
||||
|
||||
Updated: 2026-04-03
|
||||
|
||||
## Confirmed
|
||||
|
||||
- Official stack tooling exists in the `isce2` env:
|
||||
- `/home/administrator/miniconda3/envs/isce2/share/isce2/stripmapStack`
|
||||
- `/home/administrator/miniconda3/envs/isce2/share/isce2/topsStack`
|
||||
- `stackStripMap.py` exists and is the stripmap stack entry point.
|
||||
- `prepStripmap4timeseries.py` exists in the official `stripmapStack` toolset.
|
||||
- `stackStripMap.py` expects:
|
||||
- an SLC root directory via `-s/--slc_directory`
|
||||
- a DEM via `-d/--dem`
|
||||
- an optional reference date via `-m/--reference_date`
|
||||
- temporal and baseline thresholds
|
||||
- The script scans date subdirectories under the SLC root.
|
||||
- Default behavior looks for `<date>.raw` inside each acquisition directory.
|
||||
- With `--nofocus`, it instead looks for `<date>.slc`.
|
||||
- Deeper code inspection confirms:
|
||||
- `topo.py` opens `<date>/data`
|
||||
- `geo2rdr.py` opens each secondary `<date>/data`
|
||||
- `refineSecondaryTiming` uses both `<date>.slc` and the acquisition directory as metadata roots
|
||||
|
||||
## Important implication
|
||||
|
||||
Official stack processing expects a stack-style input layout such as:
|
||||
|
||||
```text
|
||||
SLC/
|
||||
YYYYMMDD/
|
||||
YYYYMMDD.raw
|
||||
```
|
||||
|
||||
or, when data are already focused:
|
||||
|
||||
```text
|
||||
SLC/
|
||||
YYYYMMDD/
|
||||
YYYYMMDD.slc
|
||||
YYYYMMDD.slc.xml
|
||||
data
|
||||
```
|
||||
|
||||
This is different from the current repository's custom LT-1 single-pair production flow.
|
||||
|
||||
## Time-series bridge signal
|
||||
|
||||
- `prepStripmap4timeseries.py` takes:
|
||||
- pair/interferogram directories
|
||||
- baseline directory
|
||||
- geometry directory
|
||||
- shelve metadata directory
|
||||
- The script writes `.rsc` sidecars and explicitly references `pysar`-style downstream usage.
|
||||
|
||||
This is useful because it confirms the official stripmap stack toolset already contains a bridge from stack outputs toward time-series preparation.
|
||||
The weak point is still the LT-1 stack input/preparation stage, not the existence of a downstream time-series bridge.
|
||||
|
||||
## Existing repo bridge signal
|
||||
|
||||
The repository's current LT-1 single-pair pipeline already proves one important thing:
|
||||
|
||||
- `stripmapApp.py` can be driven with:
|
||||
- `sensor name = LUTAN1`
|
||||
- direct `tiff` input path
|
||||
- direct `orbitFile` XML path
|
||||
|
||||
See:
|
||||
|
||||
- `backend/app/isce2_pipeline/run_lt1_dinsar_pipeline.py`
|
||||
|
||||
The generated XML writes:
|
||||
|
||||
- `Reference -> tiff`
|
||||
- `Reference -> orbitFile`
|
||||
- `Secondary -> tiff`
|
||||
- `Secondary -> orbitFile`
|
||||
|
||||
This suggests a promising adapter direction:
|
||||
|
||||
- do not try to pretend LT-1 is ALOS or another officially prepared raw sensor
|
||||
- instead, explore generating LT-1-aware stack configs directly from:
|
||||
- scene `tiff`
|
||||
- scene `meta.xml`
|
||||
- converted orbit XML
|
||||
|
||||
That does not prove the official stack driver will accept this without modification.
|
||||
But it is the strongest current indication for how a custom LT-1 `stack-prep` layer should be shaped.
|
||||
|
||||
## LT-1 / LUTAN1 signal so far
|
||||
|
||||
- ISCE core does include a `Lutan1.py` sensor module.
|
||||
- But no direct `lutan` match was found in the `stripmapStack` helper scripts.
|
||||
- The `stripmapStack` README examples and preparation hints mention:
|
||||
- `prepRawALOS.py`
|
||||
- `prepRawSensor.py`
|
||||
- The README explicitly states automatic raw-data preparation support is currently oriented to:
|
||||
- ALOS
|
||||
- CSK
|
||||
- `prepRawSensors.py` automatic raw detection currently covers:
|
||||
- Envisat
|
||||
- ERS CEOS
|
||||
- ERS ENV
|
||||
- ALOS1
|
||||
- CSK
|
||||
- `prepSlcSensors.py` automatic SLC detection currently covers:
|
||||
- Envisat
|
||||
- ALOS1
|
||||
- CSK
|
||||
- RSAT2
|
||||
- TSX/TDX
|
||||
- No LT-1 or LUTAN1 hook was found in these official stack preparation scripts.
|
||||
|
||||
## Interim conclusion
|
||||
|
||||
Current evidence suggests:
|
||||
|
||||
- ISCE2 core can parse LT-1/LUTAN1 at the sensor level.
|
||||
- Official `stripmapStack` tooling is present.
|
||||
- But the official stack preparation helpers do not currently advertise LT-1/LUTAN1 support.
|
||||
- There is no direct evidence yet that LT-1 can be fed into the official stack helpers without an adapter step.
|
||||
- `--nofocus` does not remove the need for acquisition metadata preparation.
|
||||
- It still needs a per-date `data` shelve and an ISCE-style `.slc` image.
|
||||
|
||||
This means the working assumption should be:
|
||||
|
||||
- `LT-1 stack via official stripmapStack` is possible but unproven
|
||||
- an LT-1-specific stack preparation or conversion layer is required unless an existing hidden tool can materialize `data` + `.slc` directly for LUTAN1
|
||||
|
||||
## Next checks
|
||||
|
||||
1. Implement a dry-run LT-1 stack-prep workspace generator against the selected sample manifest.
|
||||
2. Design a scene materializer that transforms one LT-1 scene into:
|
||||
- `YYYYMMDD.slc`
|
||||
- `YYYYMMDD.slc.xml`
|
||||
- `data`
|
||||
3. Decide whether that materializer should:
|
||||
- call ISCE/LUTAN1 directly, or
|
||||
- reuse parts of the existing pair pipeline
|
||||
4. After materialization is proven, run `stackStripMap.py --nofocus` on one tile-level stack
|
||||
@@ -1,285 +0,0 @@
|
||||
# Phase 1 Stack Generation Smoke Test
|
||||
|
||||
Updated: 2026-04-05
|
||||
|
||||
Follow-up note:
|
||||
|
||||
- MintPy SBAS continuation is now recorded separately in:
|
||||
- `notes/PHASE2_MINTPY_SBAS_SMOKETEST.md`
|
||||
|
||||
## Goal
|
||||
|
||||
Validate that one LT-1 stack can be transformed from:
|
||||
|
||||
- per-scene `tiff + meta.xml + orbit.xml`
|
||||
|
||||
into:
|
||||
|
||||
- `stripmapStack --nofocus` compatible acquisition directories
|
||||
- a generated stripmap stack work plan
|
||||
|
||||
without changing production code yet.
|
||||
|
||||
## Sample
|
||||
|
||||
- group key:
|
||||
- `LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1`
|
||||
- dates:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- reference date:
|
||||
- `20250510`
|
||||
|
||||
## Commands Used
|
||||
|
||||
1. Build dry-run stack workspace:
|
||||
|
||||
```text
|
||||
C:\Users\Administrator\.conda\envs\InSAR\python.exe experiments\isce2_sbas_timeseries\scripts\build_lt1_stack_prep.py --manifest-path experiments\isce2_sbas_timeseries\configs\sample_stack_e123p3_n46p1.json
|
||||
```
|
||||
|
||||
2. Materialize LT-1 acquisitions inside `Ubuntu-24.04`:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 /home/administrator/miniconda3/bin/conda run -n isce2 python /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/materialize_lt1_stack_scenes.py --stack-manifest /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_input_manifest.json
|
||||
```
|
||||
|
||||
3. Run generated wrapper:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/run_stripmap_stack_dryrun.sh
|
||||
```
|
||||
|
||||
4. Execute the frozen stack step chain inside `Ubuntu-24.04`:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_01_reference
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_02_focus_split
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_03_geo2rdr_coarseResamp
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_04_refineSecondaryTiming
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_05_invertMisreg
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_06_fineResamp
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_07_grid_baseline
|
||||
```
|
||||
|
||||
5. Regenerate the stack in `interferogram` workflow mode and execute the new pair-processing stage:
|
||||
|
||||
```text
|
||||
C:\Users\Administrator\.conda\envs\InSAR\python.exe experiments\isce2_sbas_timeseries\scripts\build_lt1_stack_prep.py --manifest-path experiments\isce2_sbas_timeseries\configs\sample_stack_e123p3_n46p1.json --workflow interferogram
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/run_stripmap_stack_dryrun.sh
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_generated_stack_runfile_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_08_igram
|
||||
```
|
||||
|
||||
6. Prepare MintPy metadata in the dedicated `mintpy` env while bridging the working `isce2` Python package:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/install_mintpy_runtime_ubuntu2404.sh
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_mintpy_with_isce_ubuntu2404.sh prep_isce.py -f "/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/Igrams/*/filt_*.unw" -m /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/Igrams/20250118_20250315/referenceShelve/data.dat -b /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/baselines -g /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/geom_reference
|
||||
```
|
||||
|
||||
## Confirmed Results
|
||||
|
||||
- All 5 acquisitions were materialized into:
|
||||
- `scratch/lt1a_strip1_hh_descending_e123p3_n46p1/SLC/YYYYMMDD/`
|
||||
- Each acquisition directory now contains:
|
||||
- `YYYYMMDD.slc`
|
||||
- `YYYYMMDD.slc.xml`
|
||||
- `YYYYMMDD.slc.vrt`
|
||||
- `data.dat/.dir/.bak`
|
||||
- Example materialized output:
|
||||
- `20250510.slc`
|
||||
- size: `3262658784` bytes
|
||||
- `stackStripMap.py --nofocus` ran successfully far enough to:
|
||||
- discover all 5 acquisitions
|
||||
- estimate stack baselines
|
||||
- select interferometric pairs
|
||||
- generate stack config files
|
||||
- generate run files
|
||||
|
||||
## Baseline Snapshot
|
||||
|
||||
Relative to reference date `20250510`, the generated stack reported:
|
||||
|
||||
- `20250118`
|
||||
- `-199.6873591838194`
|
||||
- `20250315`
|
||||
- `-89.0330513325973`
|
||||
- `20250705`
|
||||
- `-561.9056433404087`
|
||||
- `20250830`
|
||||
- `215.98283570831154`
|
||||
|
||||
The generated network reported:
|
||||
|
||||
- minimum connection degree:
|
||||
- `4.0`
|
||||
- number of pairs:
|
||||
- `10`
|
||||
|
||||
## Generated Stack Work Products
|
||||
|
||||
Under `scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/`:
|
||||
|
||||
- `baselines/`
|
||||
- `configs/`
|
||||
- `run_files/`
|
||||
- `pairs.pdf`
|
||||
|
||||
Generated run files:
|
||||
|
||||
- `run_01_reference`
|
||||
- `run_02_focus_split`
|
||||
- `run_03_geo2rdr_coarseResamp`
|
||||
- `run_04_refineSecondaryTiming`
|
||||
- `run_05_invertMisreg`
|
||||
- `run_06_fineResamp`
|
||||
- `run_07_grid_baseline`
|
||||
|
||||
## Important Runtime Fixes
|
||||
|
||||
- `matplotlib` was missing from the `isce2` env.
|
||||
- fixed by installing it with `pip` inside the WSL `isce2` environment
|
||||
- `stackStripMap.py` could not import `stripmapStack.Stack` by default.
|
||||
- fixed by exporting:
|
||||
- `PYTHONPATH=/home/administrator/miniconda3/envs/isce2/share/isce2`
|
||||
- `PATH=/home/administrator/miniconda3/envs/isce2/share/isce2/stripmapStack:$PATH`
|
||||
- the generated run files now include these prefixes automatically
|
||||
- `run_01_reference` reached `topo` successfully but `createWaterMask.py` failed without Earthdata credentials.
|
||||
- root cause:
|
||||
- `SWBD` download requires `~/.netrc` for `urs.earthdata.nasa.gov`
|
||||
- current judgment:
|
||||
- local DEM is already sufficient for this experiment
|
||||
- the only missing optional online input is the water-body mask download
|
||||
- experimental fallback:
|
||||
- `scripts/run_generated_stack_runfile_ubuntu2404.sh` now auto-generates a synthetic all-land `geom_reference/waterMask.rdr`
|
||||
- the helper script is `scripts/create_synthetic_watermask.py`
|
||||
- limitation:
|
||||
- this fallback preserves stack execution but does not provide a true coastline mask
|
||||
- LT-1 input preparation now has a shared helper:
|
||||
- `backend/app/isce2_pipeline/lt1_input_resolver.py`
|
||||
- purpose:
|
||||
- centralize DEM resolution
|
||||
- centralize orbit-pool resolution
|
||||
- centralize LT-1 precise-orbit XML reuse or generation
|
||||
- compatibility rule:
|
||||
- this is a refactor of shared input-prep logic
|
||||
- the original D-InSAR execution path was not removed
|
||||
- `run_lt1_dinsar_pipeline.py` still keeps its original public workflow entry and now calls the helper internally
|
||||
|
||||
## Latest Execution Status
|
||||
|
||||
- `run_01_reference`
|
||||
- `topo` completed successfully in `Ubuntu-24.04`
|
||||
- local `geom_reference/waterMask.rdr` was synthesized from `shadowMask.rdr`
|
||||
- `run_02_focus_split`
|
||||
- completed successfully
|
||||
- generated configs were effectively no-op under the current `--nofocus` contract
|
||||
- `run_03_geo2rdr_coarseResamp`
|
||||
- completed successfully in `Ubuntu-24.04`
|
||||
- generated `offsets/<date>/range.off` and `azimuth.off` for:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- generated `coregSLC/Coarse/<date>/YYYYMMDD.slc` products for:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- runtime observation:
|
||||
- this stage is long-running and mostly silent in the log file
|
||||
- progress is easier to confirm from product directories than from stdout
|
||||
- `run_04_refineSecondaryTiming`
|
||||
- completed successfully in `Ubuntu-24.04`
|
||||
- generated pair-level `refineSecondaryTiming/pairs/<pair>/misreg.*` for all 10 pairs
|
||||
- log observation:
|
||||
- `Bad match at level 1` and `correlation error` appeared in the log
|
||||
- despite that noise, the stage exited `0` and downstream inversion succeeded
|
||||
- `run_05_invertMisreg`
|
||||
- completed successfully in `Ubuntu-24.04`
|
||||
- generated date-level `refineSecondaryTiming/dates/<date>/misreg.*` for:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- inversion observation:
|
||||
- design matrix was reported as full rank
|
||||
- RMSE in azimuth was `0.002341399255443996` pixels
|
||||
- RMSE in range was `0.0027480408593210303` pixels
|
||||
- `run_06_fineResamp`
|
||||
- completed successfully in `Ubuntu-24.04`
|
||||
- generated fine coregistered `merged/SLC/<date>/YYYYMMDD.slc` for all 5 dates
|
||||
- each merged date directory now also includes:
|
||||
- `referenceShelve/`
|
||||
- `secondaryShelve/`
|
||||
- `run_07_grid_baseline`
|
||||
- completed successfully in `Ubuntu-24.04`
|
||||
- generated `merged/baselines/<date>/` baseline grids for all 5 dates
|
||||
- each date-level baseline directory now includes:
|
||||
- raw baseline raster
|
||||
- `.xml`
|
||||
- `.vrt`
|
||||
- `.full.vrt`
|
||||
- `build_lt1_stack_prep.py --workflow interferogram`
|
||||
- now regenerates the official stripmapStack command in `interferogram` mode instead of hard-coding `slc`
|
||||
- regenerated run files now include:
|
||||
- `run_08_igram`
|
||||
- `run_08_igram`
|
||||
- completed successfully in `Ubuntu-24.04`
|
||||
- generated 10 pair directories under `stack_work/Igrams/`
|
||||
- each pair now includes:
|
||||
- wrapped interferogram `.int`
|
||||
- amplitude `.amp`
|
||||
- filtered interferogram `filt_*.int`
|
||||
- coherence `filt_*.cor`
|
||||
- unwrapped phase `filt_*_snaphu.unw`
|
||||
- connected components `*.unw.conncomp`
|
||||
- `referenceShelve/data.*`
|
||||
- MintPy runtime bootstrap
|
||||
- `scripts/install_mintpy_runtime_ubuntu2404.sh` created a dedicated WSL env:
|
||||
- `mintpy`
|
||||
- verified commands:
|
||||
- `smallbaselineApp.py`
|
||||
- `prep_isce.py`
|
||||
- installed MintPy version:
|
||||
- `1.6.2`
|
||||
- `prep_isce.py`
|
||||
- first run in the clean `mintpy` env failed because `mintpy.utils.isce_utils` imports `isce`
|
||||
- experimental resolution:
|
||||
- `scripts/run_mintpy_with_isce_ubuntu2404.sh` now bridges only the top-level `isce` package from the WSL `isce2` env into the `mintpy` env
|
||||
- result:
|
||||
- `prep_isce.py` completed successfully over the LT-1 `stripmapStack` outputs
|
||||
- geometry `.rsc` files were written under `stack_work/geom_reference/`
|
||||
- observation `.rsc` files were written for all 10 unwrapped interferograms under `stack_work/Igrams/*/`
|
||||
|
||||
## Current Boundary
|
||||
|
||||
This smoke test confirms:
|
||||
|
||||
- LT-1 scenes can be materialized into `stripmapStack` acquisition directories
|
||||
- the official stripmap stack driver can build the stack work plan over those LT-1 products
|
||||
- the generated `run_01` to `run_07` chain can complete offline in `Ubuntu-24.04` over the sample LT-1 stack
|
||||
- local DEM plus local orbit data are sufficient for this stack-preparation stage
|
||||
- Earthdata credentials are not a hard blocker for this experiment track because the wrapper can recover `run_01_reference` with a synthetic all-land `waterMask`
|
||||
- the same LT-1 stack can be regenerated in `interferogram` workflow mode to produce 10 filtered and unwrapped pair products
|
||||
- MintPy metadata preparation is now viable through the dedicated `mintpy` env plus the explicit ISCE bridge wrapper
|
||||
|
||||
This smoke test does not yet confirm:
|
||||
|
||||
- `smallbaselineApp.py` execution beyond `prep_isce.py`
|
||||
- final time-series or velocity products
|
||||
|
||||
Follow-up status:
|
||||
|
||||
- both of the above were later confirmed in:
|
||||
- `notes/PHASE2_MINTPY_SBAS_SMOKETEST.md`
|
||||
|
||||
## Next Tasks
|
||||
|
||||
1. Keep this note focused on stack-generation findings only.
|
||||
2. Use `notes/PHASE2_MINTPY_SBAS_SMOKETEST.md` for MintPy SBAS runtime conclusions.
|
||||
3. Promote the stable runtime and artifact contract into backend workflow code and `docs/`.
|
||||
@@ -1,157 +0,0 @@
|
||||
# Phase 2 Bridge Smoketest
|
||||
|
||||
Date: 2026-04-06
|
||||
|
||||
## Scope
|
||||
|
||||
Validate the current SBAS bridge chain with the previously verified LT-1 sample stack:
|
||||
|
||||
1. `build_lt1_stack_prep.py`
|
||||
2. `materialize_lt1_stack_scenes.py`
|
||||
3. `build_lt1_stack_prep.py` refresh
|
||||
|
||||
This run validates the current bridge boundary only:
|
||||
|
||||
- raw LT-1 scenes
|
||||
- local precise orbit pool
|
||||
- local prepared DEM
|
||||
- fresh scratch workspace
|
||||
|
||||
It does not run:
|
||||
|
||||
- `stripmapStack`
|
||||
- MintPy
|
||||
- geocode/export/publish
|
||||
|
||||
## Inputs
|
||||
|
||||
- sample manifest:
|
||||
- `experiments/isce2_sbas_timeseries/configs/sample_stack_e123p3_n46p1.json`
|
||||
- orbit pool:
|
||||
- `/mnt/d/orbit_pools/isce2`
|
||||
- DEM:
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/inputs/dem/stack_dem_window.wgs84`
|
||||
|
||||
## Workspace
|
||||
|
||||
- scratch root:
|
||||
- `experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406`
|
||||
|
||||
## Result
|
||||
|
||||
- final readiness: `True`
|
||||
- scene count: `5`
|
||||
- reference date: `20250510`
|
||||
- all orbits resolved: `True`
|
||||
- all `.slc/.slc.xml` present: `True`
|
||||
- all `data` shelves present: `True`
|
||||
|
||||
## Materialization Summary
|
||||
|
||||
- dates:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- status counts:
|
||||
- `materialized: 5`
|
||||
- total bytes written:
|
||||
- `16313641344`
|
||||
|
||||
## Artifacts
|
||||
|
||||
- selected manifest used for this WSL run:
|
||||
- `experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/selected_stack_manifest_wsl.json`
|
||||
- generated stack manifest:
|
||||
- `experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_input_manifest.json`
|
||||
- materialization summary:
|
||||
- `experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/materialization_summary.json`
|
||||
- generated stack dry-run wrapper:
|
||||
- `experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/run_stripmap_stack_dryrun.sh`
|
||||
- synthetic water-mask recovery report:
|
||||
- `experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/logs/run_01_reference.synthetic_watermask.json`
|
||||
|
||||
## Finding
|
||||
|
||||
`build_lt1_stack_prep.py` currently reads `scene["tiff_path"]` and `scene["meta_path"]` directly.
|
||||
When the script is run inside WSL against the sample manifest, the original `F:\...` Windows paths are not readable as Linux paths.
|
||||
|
||||
For this smoketest, a temporary WSL-path manifest copy was generated and used:
|
||||
|
||||
- `selected_stack_manifest_wsl.json`
|
||||
|
||||
This is an experiment-side workaround only.
|
||||
No production/system logic was changed for this run.
|
||||
|
||||
## Update 2026-04-07
|
||||
|
||||
The same fresh workspace was then continued through the stripmap stack run files.
|
||||
|
||||
### Additional Result
|
||||
|
||||
- `run_01_reference`
|
||||
- reached `createWaterMask`
|
||||
- failed on remote `SWBD` retrieval from:
|
||||
- `https://e4ftl01.cr.usgs.gov/MEASURES/SRTMSWBD.003/...`
|
||||
- recovered with a local synthetic all-land `waterMask.rdr`
|
||||
- `run_02_focus_split`
|
||||
- completed
|
||||
- `run_03_geo2rdr_coarseResamp`
|
||||
- completed
|
||||
- `run_04_refineSecondaryTiming`
|
||||
- completed
|
||||
- `run_05_invertMisreg`
|
||||
- completed
|
||||
- `run_06_fineResamp`
|
||||
- completed
|
||||
- `run_07_grid_baseline`
|
||||
- completed
|
||||
- `run_08_igram`
|
||||
- completed through interferogram generation, filtering, coherence, and `snaphu` unwrapping
|
||||
|
||||
### Interferogram Snapshot
|
||||
|
||||
- pair count on disk:
|
||||
- `10`
|
||||
- verified pair folders:
|
||||
- `20250118_20250315`
|
||||
- `20250118_20250510`
|
||||
- `20250118_20250705`
|
||||
- `20250118_20250830`
|
||||
- `20250315_20250510`
|
||||
- `20250315_20250705`
|
||||
- `20250315_20250830`
|
||||
- `20250510_20250705`
|
||||
- `20250510_20250830`
|
||||
- `20250705_20250830`
|
||||
- verified key files in every pair directory:
|
||||
- `filt_<date12>.int`
|
||||
- `filt_<date12>.cor`
|
||||
- `filt_<date12>_snaphu.unw`
|
||||
- `filt_<date12>_snaphu.unw.conncomp`
|
||||
|
||||
### Finding Update
|
||||
|
||||
The original `run_generated_stack_runfile_ubuntu2404.sh` fallback only matched the `.netrc` credential failure text.
|
||||
This workspace showed a second offline failure mode:
|
||||
|
||||
- `createWaterMask` started normally
|
||||
- ISCE2 `DataRetriever` failed during `SWBD` file retrieval
|
||||
- the wrapper therefore did not auto-recover on the first attempt
|
||||
|
||||
The experiment helper has now been widened to recognize both:
|
||||
|
||||
- missing Earthdata credential text
|
||||
- direct `SWBD` retrieval failure text from `createWaterMask`
|
||||
|
||||
No production/system runtime was changed by this fix.
|
||||
|
||||
## Recommended Next Step
|
||||
|
||||
Use this fresh workspace to continue with:
|
||||
|
||||
1. unified-env MintPy smoketest using:
|
||||
- `configs/phase2_bridge_smoketest_20260406_smallbaseline.cfg`
|
||||
2. publish-style geocode/export if MintPy succeeds
|
||||
3. compare this fresh replay with the earlier baseline workspace
|
||||
@@ -1,200 +0,0 @@
|
||||
# Phase 2 MintPy SBAS Smoke Test
|
||||
|
||||
Updated: 2026-04-05
|
||||
|
||||
Follow-up note:
|
||||
|
||||
- publish-style geocode/export continuation is now recorded separately in:
|
||||
- `notes/PHASE3_PUBLISH_EXPORT_SMOKETEST.md`
|
||||
|
||||
## Goal
|
||||
|
||||
Validate that the LT-1 sample stack can continue from `stripmapStack` interferogram products into MintPy SBAS outputs under `Ubuntu-24.04`.
|
||||
|
||||
## Sample
|
||||
|
||||
- group key:
|
||||
- `LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1`
|
||||
- dates:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
- pair count:
|
||||
- `10`
|
||||
- reference date:
|
||||
- `20250510`
|
||||
- reference point:
|
||||
- `y/x = 1994,52`
|
||||
|
||||
## Successful Run
|
||||
|
||||
Successful SBAS smoke-test work directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_v5`
|
||||
|
||||
Successful WSL command:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_mintpy_sbas_smoketest_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/configs/sample_smallbaseline_lt1_e123p3_n46p1.cfg /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_v5
|
||||
```
|
||||
|
||||
This run completed through:
|
||||
|
||||
- `load_data`
|
||||
- `modify_network`
|
||||
- `reference_point`
|
||||
- `quick_overview`
|
||||
- `invert_network`
|
||||
- `reference_date`
|
||||
- `velocity`
|
||||
|
||||
Disabled for this first offline smoke test:
|
||||
|
||||
- unwrap-error correction
|
||||
- solid-earth-tide correction
|
||||
- ionosphere correction
|
||||
- troposphere correction
|
||||
- deramp
|
||||
- topographic residual correction
|
||||
- geocode
|
||||
|
||||
## Output Snapshot
|
||||
|
||||
Generated under `mintpy_sbas_v5/`:
|
||||
|
||||
- `timeseries.h5`
|
||||
- size: `82576752` bytes
|
||||
- `velocity.h5`
|
||||
- size: `83086408` bytes
|
||||
- `temporalCoherence.h5`
|
||||
- size: `16632424` bytes
|
||||
- `maskTempCoh.h5`
|
||||
- size: `4136792` bytes
|
||||
- `avgSpatialCoh.h5`
|
||||
- size: `16631784` bytes
|
||||
- `numTriNonzeroIntAmbiguity.h5`
|
||||
- size: `16632000` bytes
|
||||
- `numTriNonzeroIntAmbiguity.png`
|
||||
- size: `232878` bytes
|
||||
|
||||
Quality summary from the successful run:
|
||||
|
||||
- strict valid pixels for inversion:
|
||||
- `1219001 / 4076199`
|
||||
- `29.91%`
|
||||
- reliable pixels in `maskTempCoh.h5` with threshold `0.7`:
|
||||
- `62987`
|
||||
|
||||
## Required Runtime Decisions
|
||||
|
||||
### 1. Keep MintPy separate from ISCE2
|
||||
|
||||
- keep stack processing in WSL conda env:
|
||||
- `isce2`
|
||||
- keep MintPy in WSL conda env:
|
||||
- `mintpy`
|
||||
|
||||
Reason:
|
||||
|
||||
- avoids mutating the already working ISCE2 processing env on the development machine
|
||||
|
||||
### 2. Bridge only the top-level `isce` package
|
||||
|
||||
Required helper:
|
||||
|
||||
- `scripts/run_mintpy_with_isce_ubuntu2404.sh`
|
||||
|
||||
Current rule:
|
||||
|
||||
- do not add the entire `isce2` `site-packages` into `PYTHONPATH`
|
||||
- only bridge the top-level `isce` package into a cache directory
|
||||
|
||||
Reason:
|
||||
|
||||
- adding the whole `site-packages` caused MintPy to import `h5py` from the wrong env and fail during `load_data`
|
||||
|
||||
### 3. Do not load `wrapPhase` for this LT-1 smoke test
|
||||
|
||||
Current config rule:
|
||||
|
||||
- `mintpy.load.intFile = None`
|
||||
|
||||
Reason:
|
||||
|
||||
- loading `filt_*.int` into MintPy `wrapPhase` caused HDF5 type-conversion failure during `load_data`
|
||||
|
||||
### 4. Build a strict `maskAllValid.h5` before inversion
|
||||
|
||||
Required helper:
|
||||
|
||||
- `scripts/create_mintpy_all_ifgram_mask.py`
|
||||
|
||||
Current rule:
|
||||
|
||||
- keep only pixels that are finite and non-zero in all unwrapped interferograms
|
||||
- also require non-zero connected components in all interferograms
|
||||
|
||||
Reason:
|
||||
|
||||
- this reduces unstable partial-network pixels before SBAS inversion
|
||||
|
||||
### 5. Use the repo-local patched launcher
|
||||
|
||||
Required helper:
|
||||
|
||||
- `scripts/run_smallbaselineApp_patched.py`
|
||||
|
||||
Current workaround:
|
||||
|
||||
- patch `mintpy.ifgram_inversion.estimate_timeseries()` at runtime
|
||||
- coerce shape-`(1,)` inversion-quality output into a scalar for the single-pixel partial-network branch
|
||||
|
||||
Reason:
|
||||
|
||||
- MintPy `1.6.2` hit a `ValueError: setting an array element with a sequence`
|
||||
- failure point:
|
||||
- `mintpy/ifgram_inversion.py`
|
||||
- partial-network pixel branch inside `run_ifgram_inversion_patch()`
|
||||
|
||||
Current judgment:
|
||||
|
||||
- this is a MintPy runtime issue in the current environment
|
||||
- it is better to keep the workaround in repo-local launcher code than silently editing the third-party env
|
||||
|
||||
## Current Boundary
|
||||
|
||||
This smoke test now confirms:
|
||||
|
||||
- LT-1 `stripmapStack` outputs can be loaded by MintPy in the dedicated `mintpy` env
|
||||
- the LT-1 sample stack can be inverted into radar-coordinate `timeseries.h5`
|
||||
- the LT-1 sample stack can generate radar-coordinate `velocity.h5`
|
||||
- the current repo-local workaround chain is reproducible in `Ubuntu-24.04`
|
||||
|
||||
This smoke test does not yet confirm:
|
||||
|
||||
- geocoded SBAS exports
|
||||
- atmospheric or DEM-residual correction quality
|
||||
- product publishing into backend `psinsar` catalog
|
||||
- frontend rendering of published SBAS products
|
||||
|
||||
## System Embedding Implications
|
||||
|
||||
The current experiment suggests the future backend runtime contract should be:
|
||||
|
||||
1. Run ISCE2 stack workflow in WSL `isce2`.
|
||||
2. Run MintPy through the repo-controlled bridge runner instead of calling upstream `smallbaselineApp.py` directly.
|
||||
3. Generate a strict inversion mask after `load_data`.
|
||||
4. Persist the following files as first-class workflow artifacts:
|
||||
- `timeseries.h5`
|
||||
- `velocity.h5`
|
||||
- `temporalCoherence.h5`
|
||||
- `maskTempCoh.h5`
|
||||
- `numTriNonzeroIntAmbiguity.h5`
|
||||
- `numTriNonzeroIntAmbiguity.png`
|
||||
5. Convert these into a stable publish manifest before catalog registration.
|
||||
|
||||
Current sample publish-manifest draft:
|
||||
|
||||
- `configs/sample_psinsar_manifest_lt1_e123p3_n46p1.json`
|
||||
@@ -1,142 +0,0 @@
|
||||
# Phase 3 Publish Export Smoke Test
|
||||
|
||||
Updated: 2026-04-06
|
||||
|
||||
## Goal
|
||||
|
||||
Validate that the successful MintPy SBAS experiment can be converted into a publish-style artifact bundle without touching the main system.
|
||||
|
||||
## Inputs
|
||||
|
||||
Source MintPy work directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_v5`
|
||||
|
||||
Source stack:
|
||||
|
||||
- group key:
|
||||
- `LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1`
|
||||
- dates:
|
||||
- `20250118`
|
||||
- `20250315`
|
||||
- `20250510`
|
||||
- `20250705`
|
||||
- `20250830`
|
||||
|
||||
## Successful Command
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/export_mintpy_publish_products_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_v5 /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_v5
|
||||
```
|
||||
|
||||
## Current Export Scripts
|
||||
|
||||
- `scripts/export_mintpy_publish_products_ubuntu2404.sh`
|
||||
- geocode core MintPy outputs
|
||||
- convert selected outputs to GeoTIFF
|
||||
- copy preview and metadata files
|
||||
- build root `manifest.json`
|
||||
- `scripts/build_mintpy_publish_bundle.py`
|
||||
- generate `preview/velocity_preview.png`
|
||||
- generate `metadata/source_quality_summary.json`
|
||||
- generate publish-style root `manifest.json`
|
||||
|
||||
## Geocode Contract
|
||||
|
||||
Current experiment settings:
|
||||
|
||||
- lookup source:
|
||||
- `inputs/geometryRadar.h5`
|
||||
- output pixel size:
|
||||
- latitude step:
|
||||
- `-0.000185185`
|
||||
- longitude step:
|
||||
- `0.000185185`
|
||||
- interpolation:
|
||||
- `nearest`
|
||||
|
||||
Observed geocoded grid:
|
||||
|
||||
- extent:
|
||||
- south:
|
||||
- `45.80391`
|
||||
- north:
|
||||
- `46.42206`
|
||||
- west:
|
||||
- `122.930244`
|
||||
- east:
|
||||
- `123.76654`
|
||||
- shape:
|
||||
- rows:
|
||||
- `3338`
|
||||
- columns:
|
||||
- `4516`
|
||||
|
||||
## Generated Publish Bundle
|
||||
|
||||
Successful publish-style directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_v5`
|
||||
|
||||
Main outputs:
|
||||
|
||||
- `manifest.json`
|
||||
- `assets/geo_timeseries.h5`
|
||||
- `assets/geo_velocity.h5`
|
||||
- `assets/geo_temporalCoherence.h5`
|
||||
- `assets/geo_maskTempCoh.h5`
|
||||
- `assets/velocity.tif`
|
||||
- `assets/temporalCoherence.tif`
|
||||
- `assets/maskTempCoh.tif`
|
||||
- `preview/velocity_preview.png`
|
||||
- `preview/numTriNonzeroIntAmbiguity.png`
|
||||
- `metadata/smallbaselineApp.cfg`
|
||||
- `metadata/source_quality_summary.json`
|
||||
|
||||
## Current Interpretation
|
||||
|
||||
This confirms:
|
||||
|
||||
- the experiment now supports radar-coordinate MintPy inversion
|
||||
- the experiment also supports geocoded HDF5 exports
|
||||
- the experiment can produce publish-style GeoTIFF outputs
|
||||
- the experiment can build a stable manifest-driven bundle outside the MintPy work directory
|
||||
|
||||
This does not yet confirm:
|
||||
|
||||
- direct backend catalog registration
|
||||
- frontend rendering against the real system APIs
|
||||
- whether `EPSG:4326` should remain the final publish CRS decision
|
||||
|
||||
## Important Notes
|
||||
|
||||
### 1. Current CRS assumption
|
||||
|
||||
`save_gdal.py` warned that no explicit `EPSG` metadata was found and assumed:
|
||||
|
||||
- `EPSG:4326`
|
||||
|
||||
Current judgment:
|
||||
|
||||
- acceptable for this experiment because the geocoded outputs are in latitude/longitude grids
|
||||
- should still be checked when formalizing the production publish contract
|
||||
|
||||
### 2. Group key in the generated manifest
|
||||
|
||||
Because PowerShell treats `|` specially, passing group keys on the command line is awkward from Windows.
|
||||
|
||||
Current practical rule:
|
||||
|
||||
- the sample manifest stored in git remains the clean reference:
|
||||
- `configs/sample_psinsar_manifest_lt1_e123p3_n46p1.json`
|
||||
- the generated publish bundle manifest can be post-filled or generated from backend metadata later
|
||||
|
||||
## System Embedding Implication
|
||||
|
||||
At this point the experiment-layer chain is split cleanly into three stages:
|
||||
|
||||
1. `stripmapStack` preprocessing
|
||||
2. MintPy SBAS inversion
|
||||
3. geocode + publish-bundle export
|
||||
|
||||
That means the future system workflow can wire them as separate workflow steps without changing the validated experiment logic first.
|
||||
@@ -1,120 +0,0 @@
|
||||
# Phase 4 Unified-Environment Decision
|
||||
|
||||
Updated: 2026-04-06
|
||||
|
||||
## Decision
|
||||
|
||||
Current experiment preference:
|
||||
|
||||
- prefer the unified WSL environment for SBAS experiment work
|
||||
|
||||
Current production safety rule:
|
||||
|
||||
- do not replace or mutate the existing D-InSAR production environment
|
||||
- keep pair-oriented D-InSAR on the existing WSL `isce2` env
|
||||
- keep the current backend/public D-InSAR entry unchanged
|
||||
|
||||
Current environment split:
|
||||
|
||||
- D-InSAR production baseline:
|
||||
- `isce2`
|
||||
- SBAS experiment preferred runtime:
|
||||
- `isce2_mintpy_v1`
|
||||
|
||||
## Why This Decision Is Reasonable
|
||||
|
||||
The unified env has now completed the full current experiment chain:
|
||||
|
||||
- MintPy command invocation without the `isce` bridge
|
||||
- `load_data`
|
||||
- strict-mask generation
|
||||
- `modify_network -> velocity`
|
||||
- publish export to geocoded HDF5, GeoTIFF, preview, and `manifest.json`
|
||||
|
||||
This makes the unified env a valid experiment baseline.
|
||||
|
||||
At the same time, the existing pair-oriented D-InSAR route is already working and should not be destabilized just to simplify the SBAS experiment runtime.
|
||||
|
||||
The safest rule is therefore:
|
||||
|
||||
- let SBAS experiments move forward in a separate unified env
|
||||
- do not touch the current `isce2` production env used by D-InSAR
|
||||
|
||||
## Evidence
|
||||
|
||||
Successful unified env:
|
||||
|
||||
- `/home/administrator/miniconda3/envs/isce2_mintpy_v1`
|
||||
|
||||
Successful unified SBAS work directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_unified_v1`
|
||||
|
||||
Successful unified publish directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_unified_v1`
|
||||
|
||||
Matched quality indicators:
|
||||
|
||||
- `maskAllValid`:
|
||||
- `1219001 / 4076199`
|
||||
- `29.91%`
|
||||
- `maskTempCoh`:
|
||||
- `62987 / 4076199`
|
||||
- `1.55%`
|
||||
|
||||
Key package difference:
|
||||
|
||||
- current `isce2` env does not provide the MintPy-side package set needed for this SBAS route
|
||||
- current `isce2_mintpy_v1` env includes:
|
||||
- `mintpy`
|
||||
- `cartopy`
|
||||
- `pyaps3`
|
||||
- `pykml`
|
||||
- `cvxopt`
|
||||
|
||||
## What This Decision Does Not Mean
|
||||
|
||||
It does not mean:
|
||||
|
||||
- the backend should immediately switch to unified-env execution
|
||||
- the bridge route must be deleted now
|
||||
- the current D-InSAR runtime should be modified
|
||||
|
||||
It only means:
|
||||
|
||||
- for the next experiment steps, unified env is the preferred path
|
||||
- for current production safety, `isce2` remains untouched
|
||||
|
||||
## Required Guardrails
|
||||
|
||||
For the next phase, keep these rules:
|
||||
|
||||
- do not install MintPy into the existing `isce2` env
|
||||
- do not redirect current D-InSAR scripts to `isce2_mintpy_v1`
|
||||
- do not remove the bridge-based helpers yet
|
||||
- keep all SBAS work in experiment scripts, notes, and scratch directories
|
||||
|
||||
## Reproducibility
|
||||
|
||||
Environment snapshots should be exported and kept with the experiment record.
|
||||
|
||||
Current snapshot command:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/export_phase4_env_snapshots_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/configs/env_snapshots/20260406
|
||||
```
|
||||
|
||||
## Next Stable Experiment Steps
|
||||
|
||||
Before any system integration work:
|
||||
|
||||
1. Keep the unified env as the default SBAS experiment runtime.
|
||||
2. Preserve environment snapshots for both `isce2` and `isce2_mintpy_v1`.
|
||||
3. Write one comparison note focused on:
|
||||
- runtime simplicity
|
||||
- reproducibility
|
||||
- remaining workarounds
|
||||
- risk to D-InSAR production
|
||||
4. Optionally repeat the chain on one more LT-1 sample stack.
|
||||
5. Only after the experiment is stable, design the system integration boundary.
|
||||
@@ -1,221 +0,0 @@
|
||||
# Phase 4 Unified-Environment Experiment
|
||||
|
||||
Updated: 2026-04-06
|
||||
|
||||
## Goal
|
||||
|
||||
Validate whether the current WSL `isce2` runtime can be cloned and extended with MintPy so that the SBAS experiment can run without the temporary `isce` bridge helper.
|
||||
|
||||
This is still an experiment-layer task.
|
||||
|
||||
Do not change the production backend yet.
|
||||
|
||||
## Why run this phase
|
||||
|
||||
The bridge-based route is already validated, but a unified environment may be cleaner because:
|
||||
|
||||
- many ISCE2 + MintPy users operate in one environment
|
||||
- command invocation becomes simpler
|
||||
- future worker deployment may be easier if one runtime is stable
|
||||
|
||||
The bridge-based route still remains the fallback baseline until this phase is verified.
|
||||
|
||||
## Current Known Starting Point
|
||||
|
||||
WSL distro:
|
||||
|
||||
- `Ubuntu-24.04`
|
||||
|
||||
Current environments observed on 2026-04-06:
|
||||
|
||||
- `isce2`
|
||||
- `mintpy`
|
||||
|
||||
Observed package state:
|
||||
|
||||
- `isce2` env:
|
||||
- `isce2 2.6.4`
|
||||
- `h5py 3.15.1`
|
||||
- `mintpy` not installed
|
||||
- dedicated `mintpy` env:
|
||||
- `mintpy 1.6.3`
|
||||
|
||||
## Initial Hypothesis
|
||||
|
||||
Expected best-case outcome:
|
||||
|
||||
- clone `isce2` into `isce2_mintpy`
|
||||
- install `mintpy` directly into the clone
|
||||
- reuse the same repo-local strict-mask and patched-launcher helpers
|
||||
- run the same LT-1 smoke test without the `isce` bridge wrapper
|
||||
|
||||
Main risk areas:
|
||||
|
||||
- package solver may replace or downgrade key ISCE2-side numeric dependencies
|
||||
- MintPy may still require the same repo-local runtime workaround even in a unified env
|
||||
- GDAL / h5py / pyaps3 dependency changes may alter the known-good stack behavior
|
||||
|
||||
## Reproducible Commands
|
||||
|
||||
### 1. Bootstrap the unified env
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 env TARGET_ENV=isce2_mintpy_v1 BOOTSTRAP_MODE=recreate USE_TUNA_MIRROR=1 MINTPY_SPEC=mintpy=1.6.3 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/install_mintpy_into_cloned_isce2_env_ubuntu2404.sh
|
||||
```
|
||||
|
||||
Why `BOOTSTRAP_MODE=recreate`:
|
||||
|
||||
- direct `conda create --clone` was not stable enough for this machine
|
||||
- it still followed source-package URLs and hit channel/TOS friction
|
||||
- the successful path was:
|
||||
- export the current `isce2` dependency list
|
||||
- recreate the env through Tsinghua mirror channels
|
||||
- reinstall exported pip packages
|
||||
- install MintPy into the recreated env
|
||||
|
||||
Optional environment override:
|
||||
|
||||
```text
|
||||
TARGET_ENV=isce2_mintpy_v1 MINTPY_SPEC='mintpy=1.6.3'
|
||||
```
|
||||
|
||||
### 2. Run MintPy commands directly inside the unified env
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 env MINTPY_ENV=isce2_mintpy_v1 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_mintpy_unified_env_ubuntu2404.sh prep_isce.py -h
|
||||
```
|
||||
|
||||
### 3. Re-run the current LT-1 SBAS smoke test in the unified env
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 env MINTPY_ENV=isce2_mintpy_v1 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_mintpy_sbas_unified_env_smoketest_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/configs/sample_smallbaseline_lt1_e123p3_n46p1.cfg /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_unified_v1
|
||||
```
|
||||
|
||||
### 4. Export publish bundle in the unified env
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 env MINTPY_ENV=isce2_mintpy_v1 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/export_mintpy_publish_products_unified_env_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_unified_v1 /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_unified_v1
|
||||
```
|
||||
|
||||
## Comparison Checklist
|
||||
|
||||
When this phase is executed, compare it against the bridge route on:
|
||||
|
||||
- package versions after install
|
||||
- whether `prep_isce.py` imports cleanly without bridge
|
||||
- whether `load_data` succeeds
|
||||
- whether the strict-mask step is still required
|
||||
- whether the patched launcher is still required
|
||||
- whether output files match the existing bridge-based artifact set
|
||||
- whether geocode/export still succeeds from the unified env
|
||||
|
||||
## Current Status
|
||||
|
||||
Successful environment:
|
||||
|
||||
- `/home/administrator/miniconda3/envs/isce2_mintpy_v1`
|
||||
|
||||
Observed package/version state in the successful unified env:
|
||||
|
||||
- `conda list` shows:
|
||||
- `mintpy 1.6.3`
|
||||
- runtime `mintpy.__version__` reports:
|
||||
- `1.6.2`
|
||||
- `isce` import path:
|
||||
- `/home/administrator/miniconda3/envs/isce2_mintpy_v1/lib/python3.11/site-packages/isce/__init__.py`
|
||||
- `mintpy` import path:
|
||||
- `/home/administrator/miniconda3/envs/isce2_mintpy_v1/lib/python3.11/site-packages/mintpy/__init__.py`
|
||||
- `h5py`:
|
||||
- `3.15.1`
|
||||
|
||||
Successful unified-env SBAS work directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/stack_work/mintpy_sbas_unified_v1`
|
||||
|
||||
Successful unified-env publish directory:
|
||||
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1/publish/mintpy_sbas_unified_v1`
|
||||
|
||||
Validated in the unified env:
|
||||
|
||||
- `prep_isce.py -h` works without the `isce` bridge
|
||||
- `load_data` succeeded
|
||||
- strict-mask generation succeeded
|
||||
- `modify_network -> velocity` succeeded
|
||||
- publish export succeeded through geocoded HDF5, GeoTIFF, preview, and `manifest.json`
|
||||
|
||||
Observed unified-env output set under `mintpy_sbas_unified_v1/`:
|
||||
|
||||
- `timeseries.h5`
|
||||
- `velocity.h5`
|
||||
- `temporalCoherence.h5`
|
||||
- `maskTempCoh.h5`
|
||||
- `maskAllValid.h5`
|
||||
- `avgSpatialCoh.h5`
|
||||
- `numTriNonzeroIntAmbiguity.h5`
|
||||
- `numTriNonzeroIntAmbiguity.png`
|
||||
|
||||
Observed publish bundle under `publish/mintpy_sbas_unified_v1/`:
|
||||
|
||||
- `manifest.json`
|
||||
- `assets/geo_timeseries.h5`
|
||||
- `assets/geo_velocity.h5`
|
||||
- `assets/geo_temporalCoherence.h5`
|
||||
- `assets/geo_maskTempCoh.h5`
|
||||
- `assets/velocity.tif`
|
||||
- `assets/temporalCoherence.tif`
|
||||
- `assets/maskTempCoh.tif`
|
||||
- `preview/velocity_preview.png`
|
||||
- `preview/numTriNonzeroIntAmbiguity.png`
|
||||
- `metadata/smallbaselineApp.cfg`
|
||||
- `metadata/source_quality_summary.json`
|
||||
|
||||
Quality summary matched the bridge-based route:
|
||||
|
||||
- `maskAllValid`:
|
||||
- `1219001 / 4076199`
|
||||
- `29.91%`
|
||||
- `maskTempCoh`:
|
||||
- `62987 / 4076199`
|
||||
- `1.55%`
|
||||
|
||||
Still required in the unified env:
|
||||
|
||||
- strict `maskAllValid.h5` before inversion
|
||||
- repo-local patched `smallbaselineApp` launcher
|
||||
|
||||
Prepared:
|
||||
|
||||
- unified-env bootstrap script
|
||||
- unified-env MintPy runner
|
||||
- unified-env SBAS smoke-test runner
|
||||
- unified-env publish-export wrapper
|
||||
|
||||
Completed:
|
||||
|
||||
- actual clone + install execution
|
||||
- actual smoke-test result capture
|
||||
- actual publish-export capture
|
||||
|
||||
Pending:
|
||||
|
||||
- deeper comparison of output metadata against the bridge route
|
||||
- decide whether unified env or bridge env should be the default production candidate
|
||||
- decide whether to pin the runtime to the conda package label `1.6.3` or the internal MintPy version string `1.6.2`
|
||||
|
||||
## Current Judgment
|
||||
|
||||
At experiment level, the unified environment is now viable.
|
||||
|
||||
This phase confirms:
|
||||
|
||||
- the current LT-1 SBAS route does not fundamentally require the `isce` bridge
|
||||
- a recreated `isce2 + mintpy` WSL env can complete:
|
||||
- MintPy load/inversion
|
||||
- geocode/export
|
||||
- publish-bundle generation
|
||||
|
||||
Current recommendation:
|
||||
|
||||
- keep the bridge route as the already-known baseline until a fuller diff is written
|
||||
- but treat the unified env as a valid candidate for the future production runtime
|
||||
@@ -1,193 +0,0 @@
|
||||
# Phase 4 Unified-Env Replay On Fresh Phase-2 Workspace
|
||||
|
||||
Updated: 2026-04-08
|
||||
|
||||
## Goal
|
||||
|
||||
Re-run the already validated unified-env SBAS route on the fresh workspace:
|
||||
|
||||
- `scratch/phase2_bridge_smoketest_20260406`
|
||||
|
||||
This checks that the current experiment does not rely on the older sample workspace only.
|
||||
|
||||
## Inputs
|
||||
|
||||
- WSL distro:
|
||||
- `Ubuntu-24.04`
|
||||
- unified env:
|
||||
- `/home/administrator/miniconda3/envs/isce2_mintpy_v1`
|
||||
- stack config:
|
||||
- `configs/phase2_bridge_smoketest_20260406_smallbaseline.cfg`
|
||||
- stack workspace:
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406`
|
||||
- MintPy work dir:
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/mintpy_sbas_unified_phase2_20260407`
|
||||
- publish dir:
|
||||
- `/mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/publish/mintpy_sbas_unified_phase2_20260407`
|
||||
|
||||
## Successful Commands
|
||||
|
||||
Unified-env MintPy smoke test:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 env MINTPY_ENV=isce2_mintpy_v1 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/run_mintpy_sbas_unified_env_smoketest_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/configs/phase2_bridge_smoketest_20260406_smallbaseline.cfg /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/mintpy_sbas_unified_phase2_20260407
|
||||
```
|
||||
|
||||
Unified-env publish export:
|
||||
|
||||
```text
|
||||
wsl -d Ubuntu-24.04 env MINTPY_ENV=isce2_mintpy_v1 bash /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scripts/export_mintpy_publish_products_unified_env_ubuntu2404.sh /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/stack_work/mintpy_sbas_unified_phase2_20260407 /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/phase2_bridge_smoketest_20260406/publish/mintpy_sbas_unified_phase2_20260407
|
||||
```
|
||||
|
||||
## Result
|
||||
|
||||
The fresh workspace replay succeeded through:
|
||||
|
||||
- `load_data`
|
||||
- strict `maskAllValid.h5` generation
|
||||
- `modify_network`
|
||||
- `reference_point`
|
||||
- `quick_overview`
|
||||
- `invert_network`
|
||||
- `reference_date`
|
||||
- `velocity`
|
||||
- geocode/export
|
||||
- publish-bundle generation
|
||||
|
||||
This confirms the current fresh workspace now reaches the same experiment boundary as the earlier baseline sample:
|
||||
|
||||
- radar-coordinate MintPy runtime products
|
||||
- geocoded publish bundle
|
||||
|
||||
## Runtime Output Snapshot
|
||||
|
||||
Generated under `stack_work/mintpy_sbas_unified_phase2_20260407/`:
|
||||
|
||||
- `timeseries.h5`
|
||||
- `82579888` bytes
|
||||
- `velocity.h5`
|
||||
- `83086408` bytes
|
||||
- `temporalCoherence.h5`
|
||||
- `16632424` bytes
|
||||
- `maskTempCoh.h5`
|
||||
- `4136848` bytes
|
||||
- `maskAllValid.h5`
|
||||
- `4095215` bytes
|
||||
- `avgSpatialCoh.h5`
|
||||
- `16631784` bytes
|
||||
- `numTriNonzeroIntAmbiguity.h5`
|
||||
- `16632000` bytes
|
||||
- `numTriNonzeroIntAmbiguity.png`
|
||||
- `232923` bytes
|
||||
|
||||
## Publish Bundle Snapshot
|
||||
|
||||
Generated under `publish/mintpy_sbas_unified_phase2_20260407/`:
|
||||
|
||||
- `manifest.json`
|
||||
- `32442` bytes
|
||||
- `assets/geo_timeseries.h5`
|
||||
- `304443360` bytes
|
||||
- `assets/geo_velocity.h5`
|
||||
- `305627744` bytes
|
||||
- `assets/geo_temporalCoherence.h5`
|
||||
- `61141152` bytes
|
||||
- `assets/geo_maskTempCoh.h5`
|
||||
- `15260536` bytes
|
||||
- `assets/velocity.tif`
|
||||
- `60318026` bytes
|
||||
- `assets/temporalCoherence.tif`
|
||||
- `60318026` bytes
|
||||
- `assets/maskTempCoh.tif`
|
||||
- `15094802` bytes
|
||||
- `preview/velocity_preview.png`
|
||||
- `813928` bytes
|
||||
- `preview/numTriNonzeroIntAmbiguity.png`
|
||||
- `232923` bytes
|
||||
- `metadata/smallbaselineApp.cfg`
|
||||
- `26419` bytes
|
||||
- `metadata/source_quality_summary.json`
|
||||
- `403` bytes
|
||||
|
||||
## Quality Summary
|
||||
|
||||
From `metadata/source_quality_summary.json`:
|
||||
|
||||
- `maskAllValid`
|
||||
- `1219067 / 4076199`
|
||||
- `29.91%`
|
||||
- `maskTempCoh`
|
||||
- `63092 / 4076199`
|
||||
- `1.55%`
|
||||
- preview stretch:
|
||||
- `vmin = -0.2251889556646347`
|
||||
- `vmax = 0.2251889556646347`
|
||||
|
||||
## Findings
|
||||
|
||||
### 1. The fresh workspace replay is reproducible
|
||||
|
||||
The new workspace produced:
|
||||
|
||||
- the full 10-pair interferogram stack
|
||||
- MintPy `timeseries.h5`
|
||||
- MintPy `velocity.h5`
|
||||
- publish-layer geocoded HDF5 / GeoTIFF / preview / `manifest.json`
|
||||
|
||||
This is the current strongest experiment proof that the SBAS route is not tied to the earlier historical scratch directory.
|
||||
|
||||
### 2. The same two MintPy experiment helpers are still required
|
||||
|
||||
The unified env still depends on:
|
||||
|
||||
- `create_mintpy_all_ifgram_mask.py`
|
||||
- `run_smallbaselineApp_patched.py`
|
||||
|
||||
Current interpretation:
|
||||
|
||||
- unified env removes the temporary `isce` bridge
|
||||
- it does not remove the current strict-mask or patched-launcher workarounds
|
||||
|
||||
### 3. Offline water-mask strategy remains valid
|
||||
|
||||
This replay consumed the synthetic all-land `waterMask.rdr` created earlier in the fresh workspace.
|
||||
|
||||
No Earthdata / `SWBD` download was needed for the MintPy or publish stages.
|
||||
|
||||
### 4. Geocode/export completed with a tolerable warning
|
||||
|
||||
`save_gdal.py` warned that no EPSG / UTM metadata was found and assumed:
|
||||
|
||||
- `EPSG:4326`
|
||||
|
||||
For this experiment chain, that is acceptable because the export was already driven by latitude / longitude lookup plus explicit `--lalo` sampling.
|
||||
|
||||
This warning should still be recorded for later production hardening.
|
||||
|
||||
### 5. `group_key` should come from system metadata
|
||||
|
||||
This host-side replay exported a valid publish bundle, and the bundle should carry:
|
||||
|
||||
- `"group_key": "LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1"`
|
||||
|
||||
Reason:
|
||||
|
||||
- the bundle builder accepts `group_key` as a CLI argument
|
||||
- the LT-1 group key contains pipe characters:
|
||||
- `LT1A|STRIP1|HH|DESCENDING|E123.3_N46.1`
|
||||
- when invoked naively from Windows PowerShell into WSL, the value may be truncated or split by the host shell
|
||||
|
||||
Current judgment:
|
||||
|
||||
- this is not a blocker for the SBAS scientific chain
|
||||
- future system embedding should write `group_key` from task/run metadata inside backend code instead of relying on manual shell arguments
|
||||
|
||||
## Current Judgment
|
||||
|
||||
The current fresh workspace now confirms the full experiment chain:
|
||||
|
||||
- `raw LT-1 -> stripmapStack -> MintPy SBAS -> geocode/export -> publish bundle`
|
||||
|
||||
At experiment level, the unified env remains the preferred SBAS runtime.
|
||||
|
||||
At production-safety level, the existing D-InSAR `isce2` environment should still remain untouched.
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,647 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from pathlib import Path, PurePosixPath
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
DEFAULT_MANIFEST_PATH = (
|
||||
REPO_ROOT
|
||||
/ "experiments"
|
||||
/ "isce2_sbas_timeseries"
|
||||
/ "configs"
|
||||
/ "sample_stack_e123p3_n46p1.json"
|
||||
)
|
||||
DEFAULT_SHARED_ENV_NAME = "insar_wsl_v1"
|
||||
DEFAULT_CONDA_ROOT_WSL = "/home/administrator/miniconda3"
|
||||
DEFAULT_CONDA_WSL = f"{DEFAULT_CONDA_ROOT_WSL}/bin/conda"
|
||||
SUPPORTED_STACK_WORKFLOWS = ("slc", "interferogram", "ionosphere")
|
||||
|
||||
|
||||
def windows_to_wsl(path: str | Path) -> str:
|
||||
text = str(path)
|
||||
match = re.match(r"^([A-Za-z]):[\\/](.*)$", text)
|
||||
if not match:
|
||||
return text.replace("\\", "/")
|
||||
drive = match.group(1).lower()
|
||||
tail = match.group(2).replace("\\", "/").lstrip("/")
|
||||
return f"/mnt/{drive}/{tail}"
|
||||
|
||||
|
||||
def load_isce2_input_helper_module():
|
||||
helper_path = REPO_ROOT / "backend" / "app" / "isce2_pipeline" / "lt1_input_resolver.py"
|
||||
spec = importlib.util.spec_from_file_location("lt1_orbit_helper", helper_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Unable to load orbit helper module: {helper_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
ISCE2_INPUT_HELPER = load_isce2_input_helper_module()
|
||||
|
||||
|
||||
def _default_python_wsl(env_name: str) -> str:
|
||||
normalized_env = str(env_name or "").strip() or DEFAULT_SHARED_ENV_NAME
|
||||
return f"{DEFAULT_CONDA_ROOT_WSL}/envs/{normalized_env}/bin/python"
|
||||
|
||||
|
||||
def _resolve_runtime_paths(env_values: Dict[str, Any]) -> Dict[str, str]:
|
||||
env_name = str(
|
||||
env_values.get("TIMESERIES_ENV_NAME")
|
||||
or env_values.get("WSL_SHARED_CONDA_ENV")
|
||||
or DEFAULT_SHARED_ENV_NAME
|
||||
).strip() or DEFAULT_SHARED_ENV_NAME
|
||||
python_wsl = str(
|
||||
env_values.get("TIMESERIES_PYTHON")
|
||||
or env_values.get("WSL_SHARED_PYTHON")
|
||||
or env_values.get("ISCE2_PYTHON")
|
||||
or _default_python_wsl(env_name)
|
||||
).strip() or _default_python_wsl(env_name)
|
||||
|
||||
python_path = PurePosixPath(python_wsl)
|
||||
env_root = python_path.parent.parent
|
||||
conda_root = env_root.parent.parent
|
||||
conda_bin_wsl = str(conda_root / "bin" / "conda")
|
||||
isce2_share_wsl = str(env_root / "share" / "isce2")
|
||||
stripmap_stack_dir_wsl = str(PurePosixPath(isce2_share_wsl) / "stripmapStack")
|
||||
stack_script_wsl = str(PurePosixPath(stripmap_stack_dir_wsl) / "stackStripMap.py")
|
||||
stack_text_cmd = (
|
||||
f"export PATH={stripmap_stack_dir_wsl}:$PATH; "
|
||||
f"export PYTHONPATH={stripmap_stack_dir_wsl}:{isce2_share_wsl}${{PYTHONPATH:+:$PYTHONPATH}}; "
|
||||
)
|
||||
|
||||
return {
|
||||
"env_name": env_name,
|
||||
"python_wsl": python_wsl,
|
||||
"conda_bin_wsl": conda_bin_wsl,
|
||||
"isce2_share_wsl": isce2_share_wsl,
|
||||
"stripmap_stack_dir_wsl": stripmap_stack_dir_wsl,
|
||||
"stack_script_wsl": stack_script_wsl,
|
||||
"stack_text_cmd": stack_text_cmd,
|
||||
}
|
||||
|
||||
|
||||
def require_file(path: Path, label: str) -> None:
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"Missing {label}: {path}")
|
||||
|
||||
|
||||
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 ScenePlan:
|
||||
date: str
|
||||
target_dir_windows: str
|
||||
target_dir_wsl: str
|
||||
source_scene_json_windows: str
|
||||
source_scene_json_wsl: str
|
||||
source_tiff_windows: str
|
||||
source_tiff_wsl: str
|
||||
source_meta_windows: str
|
||||
source_meta_wsl: str
|
||||
orbit_xml_windows: Optional[str]
|
||||
orbit_xml_wsl: Optional[str]
|
||||
orbit_xml_exists: bool
|
||||
orbit_resolution_mode: Optional[str]
|
||||
orbit_resolution_error: Optional[str]
|
||||
source_exists: bool
|
||||
scene_start_utc: str
|
||||
scene_stop_utc: str
|
||||
orbit_window_start_utc: str
|
||||
orbit_window_stop_utc: str
|
||||
expected_slc_windows: str
|
||||
expected_slc_wsl: str
|
||||
expected_slc_xml_windows: str
|
||||
expected_slc_xml_wsl: str
|
||||
expected_data_shelve_windows: str
|
||||
expected_data_shelve_wsl: str
|
||||
materialized_slc_exists: bool
|
||||
materialized_data_exists: bool
|
||||
stack_ready: bool
|
||||
status: str
|
||||
|
||||
|
||||
def build_scene_plan(
|
||||
scene: Dict[str, Any],
|
||||
slc_root: Path,
|
||||
orbit_pool: Optional[Path],
|
||||
orbit_stage_dir: Path,
|
||||
margin_sec: float,
|
||||
) -> ScenePlan:
|
||||
date = str(scene["imaging_date"])
|
||||
satellite = str(scene["satellite"])
|
||||
source_tiff = Path(scene["tiff_path"])
|
||||
source_meta = Path(scene["meta_path"])
|
||||
require_file(source_tiff, f"scene TIFF for {date}")
|
||||
require_file(source_meta, f"scene meta XML for {date}")
|
||||
|
||||
scene_start_dt, scene_stop_dt = ISCE2_INPUT_HELPER.parse_scene_window(source_meta, margin_sec=0.0)
|
||||
orbit_window_start_dt, orbit_window_stop_dt = ISCE2_INPUT_HELPER.parse_scene_window(
|
||||
source_meta,
|
||||
margin_sec=margin_sec,
|
||||
)
|
||||
scene_start_utc = scene_start_dt.isoformat()
|
||||
scene_stop_utc = scene_stop_dt.isoformat()
|
||||
orbit_window_start_utc = orbit_window_start_dt.isoformat()
|
||||
orbit_window_stop_utc = orbit_window_stop_dt.isoformat()
|
||||
|
||||
target_dir = slc_root / date
|
||||
expected_slc = target_dir / f"{date}.slc"
|
||||
expected_slc_xml = target_dir / f"{date}.slc.xml"
|
||||
expected_data = target_dir / "data"
|
||||
source_scene_json = target_dir / "source_scene.json"
|
||||
|
||||
orbit_xml: Optional[Path] = None
|
||||
orbit_resolution_mode: Optional[str] = None
|
||||
orbit_resolution_error: Optional[str] = None
|
||||
if orbit_pool is not None:
|
||||
try:
|
||||
orbit_resolution = ISCE2_INPUT_HELPER.ensure_lt1_orbit_xml(
|
||||
date_yyyymmdd=date,
|
||||
satellite=satellite,
|
||||
annotation_xml=source_meta,
|
||||
orbit_root=orbit_pool,
|
||||
orbit_output_dir=orbit_stage_dir,
|
||||
margin_sec=margin_sec,
|
||||
)
|
||||
orbit_xml = orbit_resolution.path
|
||||
orbit_resolution_mode = orbit_resolution.source
|
||||
except Exception as exc:
|
||||
orbit_resolution_error = str(exc)
|
||||
|
||||
materialized_slc_exists = expected_slc.exists() and expected_slc_xml.exists()
|
||||
materialized_data_exists = shelve_stem_exists(expected_data)
|
||||
stack_ready = bool(orbit_xml and materialized_slc_exists and materialized_data_exists)
|
||||
|
||||
if not orbit_xml:
|
||||
status = "missing_orbit_xml"
|
||||
elif not materialized_slc_exists and not materialized_data_exists:
|
||||
status = "waiting_for_scene_materializer"
|
||||
elif not materialized_slc_exists:
|
||||
status = "missing_slc"
|
||||
elif not materialized_data_exists:
|
||||
status = "missing_data_shelve"
|
||||
else:
|
||||
status = "ready"
|
||||
|
||||
return ScenePlan(
|
||||
date=date,
|
||||
target_dir_windows=str(target_dir),
|
||||
target_dir_wsl=windows_to_wsl(target_dir),
|
||||
source_scene_json_windows=str(source_scene_json),
|
||||
source_scene_json_wsl=windows_to_wsl(source_scene_json),
|
||||
source_tiff_windows=str(source_tiff),
|
||||
source_tiff_wsl=windows_to_wsl(source_tiff),
|
||||
source_meta_windows=str(source_meta),
|
||||
source_meta_wsl=windows_to_wsl(source_meta),
|
||||
orbit_xml_windows=str(orbit_xml) if orbit_xml else None,
|
||||
orbit_xml_wsl=windows_to_wsl(orbit_xml) if orbit_xml else None,
|
||||
orbit_xml_exists=bool(orbit_xml),
|
||||
orbit_resolution_mode=orbit_resolution_mode,
|
||||
orbit_resolution_error=orbit_resolution_error,
|
||||
source_exists=True,
|
||||
scene_start_utc=scene_start_utc,
|
||||
scene_stop_utc=scene_stop_utc,
|
||||
orbit_window_start_utc=orbit_window_start_utc,
|
||||
orbit_window_stop_utc=orbit_window_stop_utc,
|
||||
expected_slc_windows=str(expected_slc),
|
||||
expected_slc_wsl=windows_to_wsl(expected_slc),
|
||||
expected_slc_xml_windows=str(expected_slc_xml),
|
||||
expected_slc_xml_wsl=windows_to_wsl(expected_slc_xml),
|
||||
expected_data_shelve_windows=str(expected_data),
|
||||
expected_data_shelve_wsl=windows_to_wsl(expected_data),
|
||||
materialized_slc_exists=materialized_slc_exists,
|
||||
materialized_data_exists=materialized_data_exists,
|
||||
stack_ready=stack_ready,
|
||||
status=status,
|
||||
)
|
||||
|
||||
|
||||
def render_stack_command(
|
||||
slc_dir_wsl: str,
|
||||
dem_wsl: str,
|
||||
work_dir_wsl: str,
|
||||
reference_date: str,
|
||||
workflow: str,
|
||||
runtime: Dict[str, str],
|
||||
) -> List[str]:
|
||||
return [
|
||||
runtime["conda_bin_wsl"],
|
||||
"run",
|
||||
"-n",
|
||||
runtime["env_name"],
|
||||
"python",
|
||||
runtime["stack_script_wsl"],
|
||||
"-s",
|
||||
slc_dir_wsl,
|
||||
"-d",
|
||||
dem_wsl,
|
||||
"-w",
|
||||
work_dir_wsl,
|
||||
"-m",
|
||||
reference_date,
|
||||
"--nofocus",
|
||||
"-W",
|
||||
workflow,
|
||||
"-u",
|
||||
"snaphu",
|
||||
"-c",
|
||||
runtime["stack_text_cmd"],
|
||||
]
|
||||
|
||||
|
||||
def shell_quote(value: str) -> str:
|
||||
return "'" + value.replace("'", "'\"'\"'") + "'"
|
||||
|
||||
|
||||
def render_shell_command(argv: List[str]) -> str:
|
||||
return " ".join(shell_quote(item) for item in argv)
|
||||
|
||||
|
||||
def build_blockers(scene_plans: List[ScenePlan], orbit_pool: Optional[Path], dem_path: Optional[Path]) -> List[str]:
|
||||
blockers: List[str] = []
|
||||
if orbit_pool is None:
|
||||
blockers.append("ORBIT_POOL_ISCE2 was not resolved.")
|
||||
if dem_path is None:
|
||||
blockers.append("Prepared DEM with .xml sidecar was not resolved.")
|
||||
|
||||
missing_orbit = [item.date for item in scene_plans if not item.orbit_xml_exists]
|
||||
if missing_orbit:
|
||||
blockers.append("Missing orbit XML for dates: " + ", ".join(missing_orbit))
|
||||
orbit_errors = [f"{item.date}: {item.orbit_resolution_error}" for item in scene_plans if item.orbit_resolution_error]
|
||||
if orbit_errors:
|
||||
blockers.append("Orbit resolution errors: " + "; ".join(orbit_errors))
|
||||
|
||||
missing_slc = [item.date for item in scene_plans if not item.materialized_slc_exists]
|
||||
if missing_slc:
|
||||
blockers.append("Materialized .slc/.slc.xml are missing for dates: " + ", ".join(missing_slc))
|
||||
|
||||
missing_data = [item.date for item in scene_plans if not item.materialized_data_exists]
|
||||
if missing_data:
|
||||
blockers.append("ISCE data shelve is missing for dates: " + ", ".join(missing_data))
|
||||
|
||||
return blockers
|
||||
|
||||
|
||||
def render_contract_markdown(report: Dict[str, Any]) -> str:
|
||||
lines: List[str] = []
|
||||
ready = bool(report["readiness"]["ready_for_stackStripMap_nofocus"])
|
||||
lines.append("# LT-1 Stack Prep Contract")
|
||||
lines.append("")
|
||||
lines.append(f"Generated: {report['generated_at_utc']}")
|
||||
lines.append("")
|
||||
lines.append("## Selected Stack")
|
||||
lines.append("")
|
||||
lines.append(f"- Group key: `{report['group_key']}`")
|
||||
lines.append(f"- Reference date: `{report['reference_date']}`")
|
||||
lines.append(f"- Workflow: `{report['processing_workflow']}`")
|
||||
lines.append(f"- Scene count: `{report['scene_count']}`")
|
||||
lines.append("")
|
||||
lines.append("## Resolved Runtime Inputs")
|
||||
lines.append("")
|
||||
lines.append(f"- Orbit pool (Windows): `{report['resolved_dependencies']['orbit_pool_windows'] or 'UNRESOLVED'}`")
|
||||
lines.append(f"- Orbit pool (WSL): `{report['resolved_dependencies']['orbit_pool_wsl'] or 'UNRESOLVED'}`")
|
||||
lines.append(f"- DEM (Windows): `{report['resolved_dependencies']['dem_path_windows'] or 'UNRESOLVED'}`")
|
||||
lines.append(f"- DEM (WSL): `{report['resolved_dependencies']['dem_path_wsl'] or 'UNRESOLVED'}`")
|
||||
lines.append("")
|
||||
lines.append("## Confirmed stripmapStack Contract")
|
||||
lines.append("")
|
||||
lines.append("- `stackStripMap.py --nofocus` discovers dates from `SLC/YYYYMMDD/YYYYMMDD.slc`.")
|
||||
lines.append("- `topo.py` opens `SLC/YYYYMMDD/data` for the reference acquisition.")
|
||||
lines.append("- `geo2rdr.py` opens `SLC/YYYYMMDD/data` for each secondary acquisition.")
|
||||
lines.append("- Therefore each acquisition directory must contain at least:")
|
||||
lines.append(" - `YYYYMMDD.slc`")
|
||||
lines.append(" - `YYYYMMDD.slc.xml`")
|
||||
lines.append(" - `data` shelve with `frame` and optional `doppler`")
|
||||
lines.append("")
|
||||
lines.append("## Scene Status")
|
||||
lines.append("")
|
||||
lines.append("| Date | Orbit XML | SLC | Data | Status |")
|
||||
lines.append("| --- | --- | --- | --- | --- |")
|
||||
for scene in report["scenes"]:
|
||||
orbit_ok = "yes" if scene["orbit_xml_exists"] else "no"
|
||||
slc_ok = "yes" if scene["materialized_slc_exists"] else "no"
|
||||
data_ok = "yes" if scene["materialized_data_exists"] else "no"
|
||||
lines.append(f"| {scene['date']} | {orbit_ok} | {slc_ok} | {data_ok} | `{scene['status']}` |")
|
||||
lines.append("")
|
||||
lines.append("## Draft stackStripMap Command")
|
||||
lines.append("")
|
||||
lines.append("```bash")
|
||||
lines.append(report["stack_command"]["shell"])
|
||||
lines.append("```")
|
||||
lines.append("")
|
||||
lines.append("## Current Blockers")
|
||||
lines.append("")
|
||||
blockers = report["readiness"]["blocking_reasons"]
|
||||
if blockers:
|
||||
for blocker in blockers:
|
||||
lines.append(f"- {blocker}")
|
||||
else:
|
||||
lines.append("- none")
|
||||
lines.append("")
|
||||
lines.append("## Next Tasks")
|
||||
lines.append("")
|
||||
if ready:
|
||||
lines.append("- Execute `run_01_reference` and confirm geometry generation succeeds.")
|
||||
lines.append("- Execute `run_02` to `run_07` step by step and record any LT-1-specific failures.")
|
||||
lines.append("- Inspect `baselines/`, `configs/`, and the first coarse coregistration outputs.")
|
||||
lines.append("- Install MintPy only after the stack run outputs are stable.")
|
||||
else:
|
||||
lines.append("- Use the LT-1 scene materializer to finish the remaining acquisitions under the generated `SLC/` root.")
|
||||
lines.append("- Re-run the generated preflight script, then execute `stackStripMap.py --nofocus`.")
|
||||
lines.append("- Install MintPy only after the stack materializer contract is working end to end.")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def render_run_script(report: Dict[str, Any]) -> str:
|
||||
slc_dir = report["workspace"]["slc_dir_wsl"]
|
||||
work_dir = report["workspace"]["stack_work_dir_wsl"]
|
||||
dem_path = report["resolved_dependencies"]["dem_path_wsl"] or "__MISSING_DEM__"
|
||||
reference_date = report["reference_date"]
|
||||
dates = " ".join(scene["date"] for scene in report["scenes"])
|
||||
command = report["stack_command"]["shell"]
|
||||
runtime = report["runtime"]
|
||||
|
||||
return f"""#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SLC_DIR={shell_quote(slc_dir)}
|
||||
WORK_DIR={shell_quote(work_dir)}
|
||||
DEM={shell_quote(dem_path)}
|
||||
REFERENCE_DATE={shell_quote(reference_date)}
|
||||
CONDA_ENV={shell_quote(runtime["env_name"])}
|
||||
CONDA_BIN={shell_quote(runtime["conda_bin_wsl"])}
|
||||
ISCE2_SHARE={shell_quote(runtime["isce2_share_wsl"])}
|
||||
STRIPMAP_STACK_DIR={shell_quote(runtime["stripmap_stack_dir_wsl"])}
|
||||
DATES=({dates})
|
||||
|
||||
export PYTHONPATH="$STRIPMAP_STACK_DIR:$ISCE2_SHARE${{PYTHONPATH:+:$PYTHONPATH}}"
|
||||
export PATH="$STRIPMAP_STACK_DIR:$PATH"
|
||||
|
||||
echo "LT-1 stripmap stack dry-run preflight"
|
||||
echo "SLC root: $SLC_DIR"
|
||||
echo "Work dir: $WORK_DIR"
|
||||
echo "DEM: $DEM"
|
||||
echo "Reference date: $REFERENCE_DATE"
|
||||
echo "Conda env: $CONDA_ENV"
|
||||
echo "Conda bin: $CONDA_BIN"
|
||||
echo "PYTHONPATH: $PYTHONPATH"
|
||||
echo "PATH prefix: $STRIPMAP_STACK_DIR"
|
||||
|
||||
missing=0
|
||||
for d in "${{DATES[@]}}"; do
|
||||
if [[ ! -f "$SLC_DIR/$d/$d.slc" ]]; then
|
||||
echo "MISSING: $SLC_DIR/$d/$d.slc"
|
||||
missing=1
|
||||
fi
|
||||
if [[ ! -f "$SLC_DIR/$d/$d.slc.xml" ]]; then
|
||||
echo "MISSING: $SLC_DIR/$d/$d.slc.xml"
|
||||
missing=1
|
||||
fi
|
||||
if [[ ! -e "$SLC_DIR/$d/data" && ! -e "$SLC_DIR/$d/data.db" && ! -e "$SLC_DIR/$d/data.dat" && ! -e "$SLC_DIR/$d/data.dir" && ! -e "$SLC_DIR/$d/data.bak" ]]; then
|
||||
echo "MISSING: $SLC_DIR/$d/data"
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$missing" -ne 0 ]]; then
|
||||
echo "Dry-run only. LT-1 scene materialization is still missing."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo "Preflight passed. Running stackStripMap."
|
||||
{command}
|
||||
"""
|
||||
|
||||
|
||||
def write_json(path: Path, payload: Dict[str, Any]) -> None:
|
||||
path.write_text(json.dumps(payload, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Build a dry-run LT-1 SBAS stack-prep workspace for ISCE2 stripmapStack."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--manifest-path",
|
||||
default=str(DEFAULT_MANIFEST_PATH),
|
||||
help="Path to the selected stack manifest JSON.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--scratch-root",
|
||||
default=None,
|
||||
help="Override the stack scratch root directory. Defaults to proposed_scratch_windows in the manifest.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--orbit-pool",
|
||||
default=None,
|
||||
help="Override ORBIT_POOL_ISCE2 (Windows path containing LT1A_GpsData_GAS_C_YYYYMMDD.xml).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dem-path",
|
||||
default=None,
|
||||
help="Override the prepared DEM base path (must have a .xml sidecar).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--orbit-margin-sec",
|
||||
type=float,
|
||||
default=60.0,
|
||||
help="Margin used when reporting the recommended orbit clip window.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--workflow",
|
||||
default="slc",
|
||||
choices=SUPPORTED_STACK_WORKFLOWS,
|
||||
help="stripmapStack workflow to generate: slc, interferogram, or ionosphere.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
env_values = ISCE2_INPUT_HELPER.load_env_file(REPO_ROOT / ".env")
|
||||
runtime = _resolve_runtime_paths(env_values)
|
||||
|
||||
manifest_path = Path(args.manifest_path).resolve()
|
||||
require_file(manifest_path, "stack manifest")
|
||||
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
|
||||
|
||||
scratch_root = Path(args.scratch_root or manifest["proposed_scratch_windows"]).resolve()
|
||||
slc_root = scratch_root / "SLC"
|
||||
orbits_dir = scratch_root / "orbits"
|
||||
logs_dir = scratch_root / "logs"
|
||||
notes_dir = scratch_root / "notes"
|
||||
inputs_dir = scratch_root / "inputs"
|
||||
stack_work_dir = scratch_root / "stack_work"
|
||||
|
||||
for path in (scratch_root, slc_root, orbits_dir, logs_dir, notes_dir, inputs_dir, stack_work_dir):
|
||||
path.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
orbit_pool = ISCE2_INPUT_HELPER.resolve_orbit_pool_path(
|
||||
explicit_path=args.orbit_pool,
|
||||
env_values=env_values,
|
||||
default_candidates=ISCE2_INPUT_HELPER.DEFAULT_WINDOWS_ORBIT_POOL_CANDIDATES,
|
||||
)
|
||||
local_dem_candidate = inputs_dir / "dem" / "stack_dem_window.wgs84"
|
||||
dem_path = ISCE2_INPUT_HELPER.resolve_prepared_dem_path(
|
||||
explicit_path=args.dem_path,
|
||||
env_values=env_values,
|
||||
extra_candidates=[local_dem_candidate],
|
||||
default_candidates=ISCE2_INPUT_HELPER.DEFAULT_WINDOWS_DEM_CANDIDATES,
|
||||
)
|
||||
|
||||
scene_plans = [
|
||||
build_scene_plan(
|
||||
scene,
|
||||
slc_root=slc_root,
|
||||
orbit_pool=orbit_pool,
|
||||
orbit_stage_dir=orbits_dir,
|
||||
margin_sec=args.orbit_margin_sec,
|
||||
)
|
||||
for scene in manifest["scenes"]
|
||||
]
|
||||
scene_plans.sort(key=lambda item: item.date)
|
||||
|
||||
for plan, source_scene in zip(scene_plans, sorted(manifest["scenes"], key=lambda item: item["imaging_date"])):
|
||||
target_dir = Path(plan.target_dir_windows)
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
scene_payload = dict(source_scene)
|
||||
scene_payload["stack_prep"] = {
|
||||
"date": plan.date,
|
||||
"target_dir_windows": plan.target_dir_windows,
|
||||
"target_dir_wsl": plan.target_dir_wsl,
|
||||
"orbit_xml_windows": plan.orbit_xml_windows,
|
||||
"orbit_xml_wsl": plan.orbit_xml_wsl,
|
||||
"orbit_resolution_mode": plan.orbit_resolution_mode,
|
||||
"orbit_resolution_error": plan.orbit_resolution_error,
|
||||
"scene_start_utc": plan.scene_start_utc,
|
||||
"scene_stop_utc": plan.scene_stop_utc,
|
||||
"orbit_window_start_utc": plan.orbit_window_start_utc,
|
||||
"orbit_window_stop_utc": plan.orbit_window_stop_utc,
|
||||
"expected_slc_windows": plan.expected_slc_windows,
|
||||
"expected_slc_xml_windows": plan.expected_slc_xml_windows,
|
||||
"expected_data_shelve_windows": plan.expected_data_shelve_windows,
|
||||
"status": plan.status,
|
||||
}
|
||||
write_json(target_dir / "source_scene.json", scene_payload)
|
||||
|
||||
stack_command_argv = render_stack_command(
|
||||
slc_dir_wsl=windows_to_wsl(slc_root),
|
||||
dem_wsl=windows_to_wsl(dem_path) if dem_path else "__MISSING_DEM__",
|
||||
work_dir_wsl=windows_to_wsl(stack_work_dir),
|
||||
reference_date=manifest["reference_date"],
|
||||
workflow=args.workflow,
|
||||
runtime=runtime,
|
||||
)
|
||||
|
||||
blockers = build_blockers(scene_plans, orbit_pool=orbit_pool, dem_path=dem_path)
|
||||
readiness = {
|
||||
"all_orbits_resolved": all(item.orbit_xml_exists for item in scene_plans),
|
||||
"all_materialized_slc_present": all(item.materialized_slc_exists for item in scene_plans),
|
||||
"all_data_shelves_present": all(item.materialized_data_exists for item in scene_plans),
|
||||
"ready_for_stackStripMap_nofocus": not blockers,
|
||||
"blocking_reasons": blockers,
|
||||
}
|
||||
|
||||
report: Dict[str, Any] = {
|
||||
"manifest_version": 1,
|
||||
"generated_at_utc": datetime.utcnow().replace(microsecond=0).isoformat() + "Z",
|
||||
"source_manifest_windows": str(manifest_path),
|
||||
"source_manifest_wsl": windows_to_wsl(manifest_path),
|
||||
"group_key": manifest["group_key"],
|
||||
"tile_key": manifest["tile_key"],
|
||||
"scene_count": manifest["scene_count"],
|
||||
"reference_date": manifest["reference_date"],
|
||||
"reference_strategy": manifest["reference_strategy"],
|
||||
"processing_workflow": args.workflow,
|
||||
"sensor_name": "LUTAN1",
|
||||
"stack_driver": "isce2.stripmapStack.stackStripMap",
|
||||
"runtime": runtime,
|
||||
"workspace": {
|
||||
"root_windows": str(scratch_root),
|
||||
"root_wsl": windows_to_wsl(scratch_root),
|
||||
"slc_dir_windows": str(slc_root),
|
||||
"slc_dir_wsl": windows_to_wsl(slc_root),
|
||||
"orbits_dir_windows": str(orbits_dir),
|
||||
"orbits_dir_wsl": windows_to_wsl(orbits_dir),
|
||||
"logs_dir_windows": str(logs_dir),
|
||||
"logs_dir_wsl": windows_to_wsl(logs_dir),
|
||||
"notes_dir_windows": str(notes_dir),
|
||||
"notes_dir_wsl": windows_to_wsl(notes_dir),
|
||||
"inputs_dir_windows": str(inputs_dir),
|
||||
"inputs_dir_wsl": windows_to_wsl(inputs_dir),
|
||||
"stack_work_dir_windows": str(stack_work_dir),
|
||||
"stack_work_dir_wsl": windows_to_wsl(stack_work_dir),
|
||||
},
|
||||
"resolved_dependencies": {
|
||||
"orbit_pool_windows": str(orbit_pool) if orbit_pool else None,
|
||||
"orbit_pool_wsl": windows_to_wsl(orbit_pool) if orbit_pool else None,
|
||||
"dem_path_windows": str(dem_path) if dem_path else None,
|
||||
"dem_path_wsl": windows_to_wsl(dem_path) if dem_path else None,
|
||||
},
|
||||
"stack_contract": {
|
||||
"mode": "nofocus",
|
||||
"workflow": args.workflow,
|
||||
"required_per_acquisition_files": [
|
||||
"YYYYMMDD.slc",
|
||||
"YYYYMMDD.slc.xml",
|
||||
"data shelve",
|
||||
],
|
||||
"current_source_layout": "per_scene_folder_with_tiff_meta_rpc",
|
||||
"adapter_needed": True,
|
||||
"adapter_goal": "materialize a stripmapStack-ready date directory from LT-1 TIFF/meta/orbit inputs",
|
||||
},
|
||||
"stack_command": {
|
||||
"argv": stack_command_argv,
|
||||
"shell": render_shell_command(stack_command_argv),
|
||||
},
|
||||
"readiness": readiness,
|
||||
"scenes": [plan.__dict__ for plan in scene_plans],
|
||||
"next_tasks": [
|
||||
"Use the LT-1 scene materializer to build YYYYMMDD.slc and data shelve for the remaining acquisitions.",
|
||||
"Keep raw scene data external and store only lightweight source manifests plus generated ISCE products under scratch/SLC/YYYYMMDD.",
|
||||
f"Run stripmapStack in --nofocus mode with workflow={args.workflow} once every date directory is materialized.",
|
||||
"Install MintPy only after stackStripMap produces stable interferogram outputs.",
|
||||
],
|
||||
}
|
||||
|
||||
report_path = scratch_root / "stack_input_manifest.json"
|
||||
contract_path = scratch_root / "stack_prep_contract.md"
|
||||
run_script_path = scratch_root / "run_stripmap_stack_dryrun.sh"
|
||||
|
||||
write_json(report_path, report)
|
||||
contract_path.write_text(render_contract_markdown(report), encoding="utf-8")
|
||||
run_script_path.write_text(render_run_script(report), encoding="utf-8", newline="\n")
|
||||
|
||||
print(f"Manifest: {report_path}")
|
||||
print(f"Contract: {contract_path}")
|
||||
print(f"Run script: {run_script_path}")
|
||||
print(f"Scratch root: {scratch_root}")
|
||||
print(f"Orbit pool: {orbit_pool if orbit_pool else 'UNRESOLVED'}")
|
||||
print(f"DEM: {dem_path if dem_path else 'UNRESOLVED'}")
|
||||
print(f"Ready: {readiness['ready_for_stackStripMap_nofocus']}")
|
||||
if blockers:
|
||||
print("Blockers:")
|
||||
for blocker in blockers:
|
||||
print(f" - {blocker}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,202 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build a publish-style manifest and preview bundle from MintPy outputs."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import h5py
|
||||
import matplotlib
|
||||
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
def _decode_date(value):
|
||||
return value.decode() if isinstance(value, (bytes, np.bytes_)) else str(value)
|
||||
|
||||
|
||||
def _read_h5_summary(h5_path: Path) -> dict:
|
||||
with h5py.File(h5_path, "r") as f:
|
||||
datasets = sorted(f.keys())
|
||||
attrs = {k: (v.item() if hasattr(v, "item") else v) for k, v in f.attrs.items()}
|
||||
serializable_attrs = {}
|
||||
for key, value in attrs.items():
|
||||
if isinstance(value, bytes):
|
||||
serializable_attrs[key] = value.decode()
|
||||
elif isinstance(value, np.ndarray):
|
||||
serializable_attrs[key] = value.tolist()
|
||||
else:
|
||||
serializable_attrs[key] = value
|
||||
|
||||
summary = {
|
||||
"path": h5_path.name,
|
||||
"datasets": datasets,
|
||||
"attrs": serializable_attrs,
|
||||
}
|
||||
|
||||
if "date" in f:
|
||||
summary["dates"] = [_decode_date(x) for x in f["date"][:]]
|
||||
|
||||
return summary
|
||||
|
||||
|
||||
def _write_velocity_preview(geo_velocity_h5: Path, output_png: Path) -> dict:
|
||||
with h5py.File(geo_velocity_h5, "r") as f:
|
||||
velocity = f["velocity"][:]
|
||||
|
||||
finite = np.isfinite(velocity)
|
||||
valid = velocity[finite]
|
||||
|
||||
if valid.size == 0:
|
||||
raise RuntimeError(f"No finite velocity values found in {geo_velocity_h5}")
|
||||
|
||||
vmax = float(np.nanpercentile(np.abs(valid), 98))
|
||||
vmax = max(vmax, 1e-6)
|
||||
vmin = -vmax
|
||||
|
||||
fig = plt.figure(figsize=(10, 7), dpi=150)
|
||||
ax = fig.add_subplot(111)
|
||||
im = ax.imshow(velocity, cmap="RdBu_r", vmin=vmin, vmax=vmax)
|
||||
ax.set_title("Velocity Preview (m/year)")
|
||||
ax.set_xticks([])
|
||||
ax.set_yticks([])
|
||||
cbar = fig.colorbar(im, ax=ax, shrink=0.82)
|
||||
cbar.set_label("m/year")
|
||||
fig.tight_layout()
|
||||
output_png.parent.mkdir(parents=True, exist_ok=True)
|
||||
fig.savefig(output_png, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
|
||||
return {
|
||||
"vmin": vmin,
|
||||
"vmax": vmax,
|
||||
"valid_pixels": int(valid.size),
|
||||
}
|
||||
|
||||
|
||||
def _count_mask_pixels(mask_h5: Path) -> dict:
|
||||
with h5py.File(mask_h5, "r") as f:
|
||||
dataset_name = "mask" if "mask" in f else "waterMask"
|
||||
data = f[dataset_name][:]
|
||||
|
||||
total = int(data.size)
|
||||
valid = int(np.count_nonzero(data))
|
||||
return {
|
||||
"dataset": dataset_name,
|
||||
"valid_pixels": valid,
|
||||
"total_pixels": total,
|
||||
"valid_ratio": valid / total if total else 0.0,
|
||||
}
|
||||
|
||||
|
||||
def build_bundle(mintpy_work_dir: Path, publish_dir: Path, group_key: str | None) -> None:
|
||||
assets_dir = publish_dir / "assets"
|
||||
preview_dir = publish_dir / "preview"
|
||||
metadata_dir = publish_dir / "metadata"
|
||||
|
||||
geo_velocity_h5 = assets_dir / "geo_velocity.h5"
|
||||
geo_timeseries_h5 = assets_dir / "geo_timeseries.h5"
|
||||
geo_temporal_coh_h5 = assets_dir / "geo_temporalCoherence.h5"
|
||||
geo_mask_temp_coh_h5 = assets_dir / "geo_maskTempCoh.h5"
|
||||
|
||||
preview_stats = _write_velocity_preview(
|
||||
geo_velocity_h5=geo_velocity_h5,
|
||||
output_png=preview_dir / "velocity_preview.png",
|
||||
)
|
||||
|
||||
with h5py.File(mintpy_work_dir / "timeseries.h5", "r") as ts_file:
|
||||
ref_date = ts_file.attrs.get("REF_DATE")
|
||||
ref_x = ts_file.attrs.get("REF_X")
|
||||
ref_y = ts_file.attrs.get("REF_Y")
|
||||
stack_dates = [_decode_date(x) for x in ts_file["date"][:]]
|
||||
|
||||
manifest = {
|
||||
"schema_version": "psinsar.publish.v1",
|
||||
"catalog_name": "psinsar",
|
||||
"mode": "sbas",
|
||||
"engine_code": "isce2",
|
||||
"processor_code": "isce2_stack_mintpy",
|
||||
"group_key": group_key,
|
||||
"mintpy_work_dir": str(mintpy_work_dir),
|
||||
"publish_dir": str(publish_dir),
|
||||
"reference_date": _decode_date(ref_date) if ref_date is not None else None,
|
||||
"reference_point": {
|
||||
"x": int(ref_x) if ref_x is not None else None,
|
||||
"y": int(ref_y) if ref_y is not None else None,
|
||||
},
|
||||
"stack_dates": stack_dates,
|
||||
"artifacts": [
|
||||
{"product_type": "timeseries_cube", "path": "assets/geo_timeseries.h5"},
|
||||
{"product_type": "velocity_map", "path": "assets/geo_velocity.h5"},
|
||||
{"product_type": "velocity_geotiff", "path": "assets/velocity.tif"},
|
||||
{"product_type": "temporal_coherence", "path": "assets/geo_temporalCoherence.h5"},
|
||||
{"product_type": "temporal_coherence_geotiff", "path": "assets/temporalCoherence.tif"},
|
||||
{"product_type": "quality_mask", "path": "assets/geo_maskTempCoh.h5"},
|
||||
{"product_type": "quality_mask_geotiff", "path": "assets/maskTempCoh.tif"},
|
||||
{"product_type": "preview_png", "path": "preview/velocity_preview.png"},
|
||||
{"product_type": "diagnostic_png", "path": "preview/numTriNonzeroIntAmbiguity.png"},
|
||||
],
|
||||
"quality": {
|
||||
"mask_all_valid": _count_mask_pixels(mintpy_work_dir / "maskAllValid.h5"),
|
||||
"mask_temp_coh": _count_mask_pixels(mintpy_work_dir / "maskTempCoh.h5"),
|
||||
"velocity_preview": preview_stats,
|
||||
},
|
||||
"summaries": {
|
||||
"geo_velocity": _read_h5_summary(geo_velocity_h5),
|
||||
"geo_timeseries": _read_h5_summary(geo_timeseries_h5),
|
||||
"geo_temporal_coherence": _read_h5_summary(geo_temporal_coh_h5),
|
||||
"geo_mask_temp_coh": _read_h5_summary(geo_mask_temp_coh_h5),
|
||||
},
|
||||
"metadata_files": [
|
||||
"metadata/smallbaselineApp.cfg",
|
||||
"metadata/source_quality_summary.json",
|
||||
],
|
||||
}
|
||||
|
||||
summary_json = {
|
||||
"maskAllValid": manifest["quality"]["mask_all_valid"],
|
||||
"maskTempCoh": manifest["quality"]["mask_temp_coh"],
|
||||
"preview": manifest["quality"]["velocity_preview"],
|
||||
}
|
||||
|
||||
publish_dir.mkdir(parents=True, exist_ok=True)
|
||||
metadata_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
(publish_dir / "manifest.json").write_text(
|
||||
json.dumps(manifest, indent=2, ensure_ascii=False),
|
||||
encoding="utf-8",
|
||||
)
|
||||
(metadata_dir / "source_quality_summary.json").write_text(
|
||||
json.dumps(summary_json, indent=2, ensure_ascii=False),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
print(f"Wrote manifest: {publish_dir / 'manifest.json'}")
|
||||
print(f"Wrote quality summary: {metadata_dir / 'source_quality_summary.json'}")
|
||||
print(f"Wrote preview: {preview_dir / 'velocity_preview.png'}")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Build publish-style artifacts for MintPy SBAS outputs.")
|
||||
parser.add_argument("--mintpy-work-dir", required=True, help="MintPy work directory containing timeseries.h5, velocity.h5, etc.")
|
||||
parser.add_argument("--publish-dir", required=True, help="Publish output directory.")
|
||||
parser.add_argument("--group-key", default=None, help="Optional stack group key to embed in manifest.")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
build_bundle(
|
||||
mintpy_work_dir=Path(args.mintpy_work_dir),
|
||||
publish_dir=Path(args.publish_dir),
|
||||
group_key=args.group_key,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
REPO_ROOT="${REPO_ROOT:-/mnt/z/Code/Insar_management_system_v2}"
|
||||
EXP_ROOT="${EXP_ROOT:-$REPO_ROOT/experiments/isce2_sbas_timeseries}"
|
||||
|
||||
echo "== repo =="
|
||||
echo "$REPO_ROOT"
|
||||
test -d "$REPO_ROOT"
|
||||
|
||||
echo "== experiment root =="
|
||||
echo "$EXP_ROOT"
|
||||
test -d "$EXP_ROOT"
|
||||
|
||||
echo "== python3 =="
|
||||
python3 --version
|
||||
|
||||
echo "== conda env list =="
|
||||
"$CONDA_BIN" env list
|
||||
|
||||
echo "== isce2 runtime =="
|
||||
"$CONDA_BIN" run -n isce2 python -c "import sys; import isce; print(sys.executable); print(isce.__file__)"
|
||||
|
||||
echo "== Lutan1 sensor module =="
|
||||
"$CONDA_BIN" run -n isce2 python -c "from isce.components.isceobj.Sensor import Lutan1; print(Lutan1.__file__)"
|
||||
|
||||
echo "== mintpy import check =="
|
||||
"$CONDA_BIN" run -n isce2 python -c "import importlib.util; print('mintpy:present' if importlib.util.find_spec('mintpy') else 'mintpy:missing')"
|
||||
|
||||
echo "== candidate ISCE stack directories =="
|
||||
find /home/administrator/miniconda3/envs/isce2 -maxdepth 6 \
|
||||
\( -iname 'stripmapStack' -o -iname 'topsStack' -o -iname 'stack' \) 2>/dev/null || true
|
||||
@@ -1,83 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create a strict MintPy mask containing only pixels valid in all interferograms."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
import h5py
|
||||
import numpy as np
|
||||
|
||||
|
||||
def build_mask(ifgram_stack: Path, output_path: Path, block_rows: int) -> None:
|
||||
with h5py.File(ifgram_stack, "r") as src:
|
||||
unwrap = src["unwrapPhase"]
|
||||
conn = src.get("connectComponent")
|
||||
|
||||
num_ifg, length, width = unwrap.shape
|
||||
mask = np.ones((length, width), dtype=np.bool_)
|
||||
|
||||
print(f"Input stack: {ifgram_stack}")
|
||||
print(f"Interferograms: {num_ifg}")
|
||||
print(f"Shape: {length} x {width}")
|
||||
print(f"Block rows: {block_rows}")
|
||||
|
||||
for row0 in range(0, length, block_rows):
|
||||
row1 = min(row0 + block_rows, length)
|
||||
block = unwrap[:, row0:row1, :]
|
||||
block_mask = np.all(np.isfinite(block) & (block != 0.0), axis=0)
|
||||
|
||||
if conn is not None:
|
||||
conn_block = conn[:, row0:row1, :]
|
||||
block_mask &= np.all(conn_block != 0, axis=0)
|
||||
|
||||
mask[row0:row1, :] = block_mask
|
||||
print(f"Processed rows {row0}:{row1}")
|
||||
|
||||
attrs = dict(src.attrs)
|
||||
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with h5py.File(output_path, "w") as dst:
|
||||
dst.create_dataset("mask", data=mask, dtype=np.bool_)
|
||||
for key, value in attrs.items():
|
||||
dst.attrs[key] = value
|
||||
dst.attrs["FILE_TYPE"] = "mask"
|
||||
dst.attrs["DATASET_NAME"] = "mask"
|
||||
dst.attrs["SOURCE_FILE"] = str(ifgram_stack)
|
||||
dst.attrs["MASK_RULE"] = "all_ifgrams_finite_nonzero_and_conncomp_nonzero"
|
||||
|
||||
valid_pixels = int(mask.sum())
|
||||
total_pixels = int(mask.size)
|
||||
print(f"Output mask: {output_path}")
|
||||
print(f"Valid pixels: {valid_pixels}/{total_pixels} ({valid_pixels / total_pixels * 100:.2f}%)")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Create a strict mask of pixels valid in all MintPy interferograms."
|
||||
)
|
||||
parser.add_argument("--ifgram-stack", required=True, help="Path to MintPy inputs/ifgramStack.h5")
|
||||
parser.add_argument("--output", required=True, help="Output HDF5 path, e.g. maskAllValid.h5")
|
||||
parser.add_argument(
|
||||
"--block-rows",
|
||||
type=int,
|
||||
default=256,
|
||||
help="Number of image rows processed per block.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
build_mask(
|
||||
ifgram_stack=Path(args.ifgram_stack),
|
||||
output_path=Path(args.output),
|
||||
block_rows=args.block_rows,
|
||||
)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,145 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Create a synthetic stripmapStack water mask in radar coordinates. "
|
||||
"The default fill value 1 means all-land, which preserves downstream pixels."
|
||||
)
|
||||
)
|
||||
parser.add_argument(
|
||||
"--like-image",
|
||||
required=True,
|
||||
help="Existing ISCE image base path or .xml path used only for shape/metadata, for example shadowMask.rdr",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
required=True,
|
||||
help="Output water-mask base path, for example .../geom_reference/waterMask.rdr",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--fill-value",
|
||||
type=int,
|
||||
default=1,
|
||||
choices=(0, 1),
|
||||
help="Pixel value to write. 1 keeps all pixels, 0 masks all pixels.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
action="store_true",
|
||||
help="Overwrite an existing output mask.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--report",
|
||||
default=None,
|
||||
help="Optional JSON report path.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def resolve_like_paths(value: str) -> tuple[Path, Path]:
|
||||
candidate = Path(value)
|
||||
if candidate.suffix == ".xml":
|
||||
xml_path = candidate
|
||||
image_path = Path(str(candidate)[:-4])
|
||||
else:
|
||||
image_path = candidate
|
||||
xml_path = Path(str(candidate) + ".xml")
|
||||
|
||||
if not xml_path.exists():
|
||||
raise FileNotFoundError(f"Template image XML not found: {xml_path}")
|
||||
return image_path, xml_path
|
||||
|
||||
|
||||
def maybe_unlink(path: Path) -> None:
|
||||
if path.exists():
|
||||
path.unlink()
|
||||
|
||||
|
||||
def require_xml_value(root: ET.Element, property_name: str) -> str:
|
||||
value_node = root.find(f"./property[@name='{property_name}']/value")
|
||||
if value_node is None or value_node.text is None:
|
||||
raise ValueError(f"Missing XML property '{property_name}'")
|
||||
return value_node.text.strip()
|
||||
|
||||
|
||||
def write_template_metadata(template_image: Path, template_xml: Path, output: Path) -> tuple[int, int]:
|
||||
root = ET.parse(template_xml).getroot()
|
||||
width = int(require_xml_value(root, "width"))
|
||||
length = int(require_xml_value(root, "length"))
|
||||
|
||||
file_name_node = root.find("./property[@name='file_name']/value")
|
||||
if file_name_node is None:
|
||||
raise ValueError(f"Missing XML file_name entry: {template_xml}")
|
||||
file_name_node.text = str(output)
|
||||
|
||||
xml_output = Path(str(output) + ".xml")
|
||||
ET.indent(root, space=" ")
|
||||
ET.ElementTree(root).write(xml_output, encoding="utf-8")
|
||||
|
||||
hdr_template = template_image.with_suffix(".hdr")
|
||||
hdr_output = output.with_suffix(".hdr")
|
||||
if hdr_template.exists():
|
||||
hdr_text = hdr_template.read_text(encoding="utf-8", errors="ignore")
|
||||
hdr_output.write_text(hdr_text.replace(str(template_image), str(output)), encoding="utf-8")
|
||||
|
||||
vrt_template = Path(str(template_image) + ".vrt")
|
||||
vrt_output = Path(str(output) + ".vrt")
|
||||
if vrt_template.exists():
|
||||
vrt_text = vrt_template.read_text(encoding="utf-8", errors="ignore")
|
||||
vrt_text = vrt_text.replace(template_image.name, output.name)
|
||||
vrt_output.write_text(vrt_text, encoding="utf-8")
|
||||
|
||||
return width, length
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
template_image, template_xml = resolve_like_paths(args.like_image)
|
||||
output = Path(args.output)
|
||||
|
||||
if output.exists() and not args.force:
|
||||
raise FileExistsError(f"Output already exists, use --force to overwrite: {output}")
|
||||
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
width, length = write_template_metadata(template_image=template_image, template_xml=template_xml, output=output)
|
||||
|
||||
mask = np.full((length, width), args.fill_value, dtype=np.uint8)
|
||||
mask.tofile(output)
|
||||
|
||||
maybe_unlink(output.with_suffix(".rdr.aux.xml"))
|
||||
|
||||
report = {
|
||||
"generated_at_utc": datetime.utcnow().replace(microsecond=0).isoformat() + "Z",
|
||||
"template_xml": str(template_xml),
|
||||
"output": str(output),
|
||||
"width": width,
|
||||
"length": length,
|
||||
"fill_value": args.fill_value,
|
||||
"data_type": "BYTE",
|
||||
"note": "Synthetic all-land water mask for local stripmapStack experiments without Earthdata SWBD access.",
|
||||
}
|
||||
|
||||
report_path = Path(args.report) if args.report else output.parent / "synthetic_watermask_report.json"
|
||||
report_path.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
print(f"Template: {template_xml}")
|
||||
print(f"Output: {output}")
|
||||
print(f"Shape: {length} x {width}")
|
||||
print(f"Value: {args.fill_value}")
|
||||
print(f"Report: {report_path}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,76 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 <env-name> <output-dir-wsl>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
ENV_NAME="$1"
|
||||
OUTPUT_DIR="$2"
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
SAFE_NAME="${ENV_NAME//[^A-Za-z0-9._-]/_}"
|
||||
YAML_PATH="$OUTPUT_DIR/${SAFE_NAME}.no_builds.yml"
|
||||
EXPLICIT_PATH="$OUTPUT_DIR/${SAFE_NAME}.explicit.txt"
|
||||
LIST_PATH="$OUTPUT_DIR/${SAFE_NAME}.conda_list.txt"
|
||||
RUNTIME_PATH="$OUTPUT_DIR/${SAFE_NAME}.runtime_versions.txt"
|
||||
|
||||
echo "Exporting conda environment snapshot"
|
||||
echo "Env: $ENV_NAME"
|
||||
echo "Output dir: $OUTPUT_DIR"
|
||||
|
||||
"$CONDA_BIN" env export -n "$ENV_NAME" --no-builds > "$YAML_PATH"
|
||||
"$CONDA_BIN" list -n "$ENV_NAME" --explicit > "$EXPLICIT_PATH"
|
||||
"$CONDA_BIN" list -n "$ENV_NAME" > "$LIST_PATH"
|
||||
|
||||
"$CONDA_BIN" run -n "$ENV_NAME" python -c "
|
||||
import importlib.util
|
||||
import logging
|
||||
import platform
|
||||
import sys
|
||||
|
||||
logging.getLogger().setLevel(logging.WARNING)
|
||||
|
||||
def version_of(name):
|
||||
try:
|
||||
mod = __import__(name)
|
||||
return getattr(mod, '__version__', '<missing>')
|
||||
except Exception as exc:
|
||||
return f'<import failed: {exc}>'
|
||||
|
||||
for line in [
|
||||
f'python_executable={sys.executable}',
|
||||
f'python_version={platform.python_version()}',
|
||||
f'isce_present={importlib.util.find_spec(\"isce\") is not None}',
|
||||
f'mintpy_present={importlib.util.find_spec(\"mintpy\") is not None}',
|
||||
f'h5py_present={importlib.util.find_spec(\"h5py\") is not None}',
|
||||
]:
|
||||
print(line)
|
||||
|
||||
if importlib.util.find_spec('isce') is not None:
|
||||
import isce
|
||||
print(f'isce_file={isce.__file__}')
|
||||
print(f'isce_version={getattr(isce, \"__version__\", \"<missing>\")}')
|
||||
|
||||
if importlib.util.find_spec('mintpy') is not None:
|
||||
import mintpy
|
||||
print(f'mintpy_file={mintpy.__file__}')
|
||||
print(f'mintpy_version={getattr(mintpy, \"__version__\", \"<missing>\")}')
|
||||
|
||||
if importlib.util.find_spec('h5py') is not None:
|
||||
import h5py
|
||||
print(f'h5py_version={h5py.__version__}')
|
||||
" > "$RUNTIME_PATH"
|
||||
|
||||
echo "Wrote: $YAML_PATH"
|
||||
echo "Wrote: $EXPLICIT_PATH"
|
||||
echo "Wrote: $LIST_PATH"
|
||||
echo "Wrote: $RUNTIME_PATH"
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 || $# -gt 3 ]]; then
|
||||
echo "Usage: $0 <mintpy-work-dir-wsl> <publish-dir-wsl> [group-key]" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MINTPY_WORK_DIR="$1"
|
||||
PUBLISH_DIR="$2"
|
||||
GROUP_KEY="${3:-}"
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
MINTPY_RUNNER="${MINTPY_RUNNER:-$SCRIPT_DIR/run_mintpy_with_isce_ubuntu2404.sh}"
|
||||
PUBLISH_BUILDER="$SCRIPT_DIR/build_mintpy_publish_bundle.py"
|
||||
|
||||
GEO_LAT_STEP="${GEO_LAT_STEP:--0.000185185}"
|
||||
GEO_LON_STEP="${GEO_LON_STEP:-0.000185185}"
|
||||
GEO_INTERP_METHOD="${GEO_INTERP_METHOD:-nearest}"
|
||||
|
||||
ASSETS_DIR="$PUBLISH_DIR/assets"
|
||||
PREVIEW_DIR="$PUBLISH_DIR/preview"
|
||||
METADATA_DIR="$PUBLISH_DIR/metadata"
|
||||
|
||||
mkdir -p "$ASSETS_DIR" "$PREVIEW_DIR" "$METADATA_DIR"
|
||||
|
||||
LOOKUP_FILE="$MINTPY_WORK_DIR/inputs/geometryRadar.h5"
|
||||
|
||||
echo "MintPy publish export"
|
||||
echo "Work dir: $MINTPY_WORK_DIR"
|
||||
echo "Publish dir: $PUBLISH_DIR"
|
||||
echo "Lookup file: $LOOKUP_FILE"
|
||||
echo "Runner: $MINTPY_RUNNER"
|
||||
echo "Geo step: $GEO_LAT_STEP, $GEO_LON_STEP"
|
||||
echo "Interp: $GEO_INTERP_METHOD"
|
||||
|
||||
for src in velocity.h5 temporalCoherence.h5 maskTempCoh.h5 timeseries.h5; do
|
||||
bash "$MINTPY_RUNNER" geocode.py \
|
||||
"$MINTPY_WORK_DIR/$src" \
|
||||
-l "$LOOKUP_FILE" \
|
||||
--lalo "$GEO_LAT_STEP" "$GEO_LON_STEP" \
|
||||
-i "$GEO_INTERP_METHOD" \
|
||||
--outdir "$ASSETS_DIR" \
|
||||
--update
|
||||
done
|
||||
|
||||
bash "$MINTPY_RUNNER" save_gdal.py "$ASSETS_DIR/geo_velocity.h5" -d velocity -o "$ASSETS_DIR/velocity.tif"
|
||||
bash "$MINTPY_RUNNER" save_gdal.py "$ASSETS_DIR/geo_temporalCoherence.h5" -d temporalCoherence -o "$ASSETS_DIR/temporalCoherence.tif"
|
||||
bash "$MINTPY_RUNNER" save_gdal.py "$ASSETS_DIR/geo_maskTempCoh.h5" -d mask -o "$ASSETS_DIR/maskTempCoh.tif"
|
||||
|
||||
cp "$MINTPY_WORK_DIR/smallbaselineApp.cfg" "$METADATA_DIR/smallbaselineApp.cfg"
|
||||
cp "$MINTPY_WORK_DIR/numTriNonzeroIntAmbiguity.png" "$PREVIEW_DIR/numTriNonzeroIntAmbiguity.png"
|
||||
|
||||
if [[ -n "$GROUP_KEY" ]]; then
|
||||
bash "$MINTPY_RUNNER" python "$PUBLISH_BUILDER" \
|
||||
--mintpy-work-dir "$MINTPY_WORK_DIR" \
|
||||
--publish-dir "$PUBLISH_DIR" \
|
||||
--group-key "$GROUP_KEY"
|
||||
else
|
||||
bash "$MINTPY_RUNNER" python "$PUBLISH_BUILDER" \
|
||||
--mintpy-work-dir "$MINTPY_WORK_DIR" \
|
||||
--publish-dir "$PUBLISH_DIR"
|
||||
fi
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
GENERIC_EXPORTER="$SCRIPT_DIR/export_mintpy_publish_products_ubuntu2404.sh"
|
||||
|
||||
export MINTPY_RUNNER="${MINTPY_RUNNER:-$SCRIPT_DIR/run_mintpy_unified_env_ubuntu2404.sh}"
|
||||
|
||||
bash "$GENERIC_EXPORTER" "$@"
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <output-dir-wsl>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
OUTPUT_DIR="$1"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
EXPORTER="$SCRIPT_DIR/export_conda_env_snapshot_ubuntu2404.sh"
|
||||
|
||||
bash "$EXPORTER" isce2 "$OUTPUT_DIR"
|
||||
bash "$EXPORTER" isce2_mintpy_v1 "$OUTPUT_DIR"
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
CONDA_ENV="${CONDA_ENV:-isce2}"
|
||||
PIP_INDEX_URL="${PIP_INDEX_URL:-https://pypi.tuna.tsinghua.edu.cn/simple}"
|
||||
PACKAGES=(
|
||||
matplotlib
|
||||
)
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "ISCE2 stack runtime bootstrap"
|
||||
echo "Conda: $CONDA_BIN"
|
||||
echo "Env: $CONDA_ENV"
|
||||
echo "Index: $PIP_INDEX_URL"
|
||||
|
||||
for pkg in "${PACKAGES[@]}"; do
|
||||
echo "Installing $pkg into $CONDA_ENV"
|
||||
"$CONDA_BIN" run -n "$CONDA_ENV" python -m pip install -i "$PIP_INDEX_URL" "$pkg"
|
||||
done
|
||||
|
||||
echo "Runtime bootstrap complete"
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
SOURCE_ENV="${SOURCE_ENV:-isce2}"
|
||||
TARGET_ENV="${TARGET_ENV:-isce2_mintpy}"
|
||||
PYTHON_VERSION="${PYTHON_VERSION:-3.11}"
|
||||
BOOTSTRAP_MODE="${BOOTSTRAP_MODE:-clone}"
|
||||
USE_TUNA_MIRROR="${USE_TUNA_MIRROR:-1}"
|
||||
CHANNEL_CONDA_FORGE="${CHANNEL_CONDA_FORGE:-https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge}"
|
||||
CHANNEL_MAIN="${CHANNEL_MAIN:-https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main}"
|
||||
CHANNEL_R="${CHANNEL_R:-https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r}"
|
||||
MINTPY_SPEC="${MINTPY_SPEC:-mintpy}"
|
||||
CLONE_OFFLINE="${CLONE_OFFLINE:-1}"
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
channel_args=()
|
||||
if [[ "$USE_TUNA_MIRROR" == "1" ]]; then
|
||||
channel_args=(
|
||||
--override-channels
|
||||
-c "$CHANNEL_CONDA_FORGE"
|
||||
-c "$CHANNEL_MAIN"
|
||||
-c "$CHANNEL_R"
|
||||
)
|
||||
fi
|
||||
|
||||
env_exists() {
|
||||
"$CONDA_BIN" env list | awk '{print $1}' | grep -Fxq "$1"
|
||||
}
|
||||
|
||||
echo "Unified ISCE2 + MintPy runtime bootstrap"
|
||||
echo "Conda: $CONDA_BIN"
|
||||
echo "Source env: $SOURCE_ENV"
|
||||
echo "Target env: $TARGET_ENV"
|
||||
echo "Python: $PYTHON_VERSION"
|
||||
echo "Mode: $BOOTSTRAP_MODE"
|
||||
echo "MintPy spec: $MINTPY_SPEC"
|
||||
echo "Use mirror: $USE_TUNA_MIRROR"
|
||||
echo "Clone offline:$CLONE_OFFLINE"
|
||||
|
||||
if ! env_exists "$SOURCE_ENV"; then
|
||||
echo "Missing source environment: $SOURCE_ENV" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$BOOTSTRAP_MODE" != "clone" && "$BOOTSTRAP_MODE" != "recreate" ]]; then
|
||||
echo "Unsupported BOOTSTRAP_MODE: $BOOTSTRAP_MODE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if env_exists "$TARGET_ENV"; then
|
||||
echo "Environment $TARGET_ENV already exists. Reusing it."
|
||||
else
|
||||
if [[ "$BOOTSTRAP_MODE" == "clone" ]]; then
|
||||
echo "Cloning $SOURCE_ENV into $TARGET_ENV"
|
||||
clone_args=("${channel_args[@]}" -y -n "$TARGET_ENV" --clone "$SOURCE_ENV")
|
||||
if [[ "$CLONE_OFFLINE" == "1" ]]; then
|
||||
clone_args+=(--offline)
|
||||
fi
|
||||
"$CONDA_BIN" create "${clone_args[@]}"
|
||||
else
|
||||
tmp_export="$(mktemp)"
|
||||
tmp_conda_specs="$(mktemp)"
|
||||
tmp_pip_specs="$(mktemp)"
|
||||
trap 'rm -f "$tmp_export" "$tmp_conda_specs" "$tmp_pip_specs"' EXIT
|
||||
|
||||
echo "Exporting $SOURCE_ENV into a recreate spec"
|
||||
"$CONDA_BIN" env export -n "$SOURCE_ENV" --no-builds > "$tmp_export"
|
||||
|
||||
awk \
|
||||
'
|
||||
/^dependencies:/ {
|
||||
in_dependencies = 1
|
||||
next
|
||||
}
|
||||
/^prefix:/ {
|
||||
exit
|
||||
}
|
||||
in_dependencies == 1 && /^ - pip:$/ {
|
||||
exit
|
||||
}
|
||||
in_dependencies == 1 && /^ - / {
|
||||
print substr($0, 5)
|
||||
}
|
||||
' "$tmp_export" > "$tmp_conda_specs"
|
||||
|
||||
awk \
|
||||
'
|
||||
/^ - pip:$/ {
|
||||
in_pip = 1
|
||||
next
|
||||
}
|
||||
/^prefix:/ {
|
||||
exit
|
||||
}
|
||||
in_pip == 1 && /^ - / {
|
||||
print substr($0, 7)
|
||||
}
|
||||
' "$tmp_export" > "$tmp_pip_specs"
|
||||
|
||||
mapfile -t conda_specs < "$tmp_conda_specs"
|
||||
if [[ ${#conda_specs[@]} -eq 0 ]]; then
|
||||
echo "Failed to extract conda dependency specs from $SOURCE_ENV export" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Recreating $TARGET_ENV from exported dependency list"
|
||||
"$CONDA_BIN" create -y -n "$TARGET_ENV" "${channel_args[@]}" "${conda_specs[@]}"
|
||||
|
||||
if [[ -s "$tmp_pip_specs" ]]; then
|
||||
mapfile -t pip_specs < "$tmp_pip_specs"
|
||||
echo "Reinstalling exported pip packages into $TARGET_ENV"
|
||||
"$CONDA_BIN" run -n "$TARGET_ENV" python -m pip install "${pip_specs[@]}"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Installing MintPy into $TARGET_ENV"
|
||||
"$CONDA_BIN" install -y -n "$TARGET_ENV" "${channel_args[@]}" "$MINTPY_SPEC"
|
||||
|
||||
echo "Verifying unified runtime imports"
|
||||
"$CONDA_BIN" run -n "$TARGET_ENV" python -c "import sys; import isce; import mintpy; import h5py; print(sys.executable); print(isce.__file__); print(mintpy.__file__); print('h5py=' + h5py.__version__)"
|
||||
|
||||
echo "Unified runtime bootstrap complete"
|
||||
@@ -1,47 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
TARGET_ENV="${TARGET_ENV:-mintpy}"
|
||||
PYTHON_VERSION="${PYTHON_VERSION:-3.11}"
|
||||
USE_TUNA_MIRROR="${USE_TUNA_MIRROR:-1}"
|
||||
CHANNEL_CONDA_FORGE="${CHANNEL_CONDA_FORGE:-https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge}"
|
||||
CHANNEL_MAIN="${CHANNEL_MAIN:-https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main}"
|
||||
CHANNEL_R="${CHANNEL_R:-https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r}"
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
channel_args=()
|
||||
if [[ "$USE_TUNA_MIRROR" == "1" ]]; then
|
||||
channel_args=(
|
||||
--override-channels
|
||||
-c "$CHANNEL_CONDA_FORGE"
|
||||
-c "$CHANNEL_MAIN"
|
||||
-c "$CHANNEL_R"
|
||||
)
|
||||
fi
|
||||
|
||||
env_exists() {
|
||||
"$CONDA_BIN" env list | awk '{print $1}' | grep -Fxq "$TARGET_ENV"
|
||||
}
|
||||
|
||||
echo "MintPy runtime bootstrap"
|
||||
echo "Conda: $CONDA_BIN"
|
||||
echo "Target env: $TARGET_ENV"
|
||||
echo "Python: $PYTHON_VERSION"
|
||||
echo "Use mirror: $USE_TUNA_MIRROR"
|
||||
|
||||
if env_exists; then
|
||||
echo "Environment $TARGET_ENV already exists. Installing or updating MintPy."
|
||||
"$CONDA_BIN" install -y -n "$TARGET_ENV" "${channel_args[@]}" mintpy
|
||||
else
|
||||
echo "Creating environment $TARGET_ENV with MintPy."
|
||||
"$CONDA_BIN" create -y -n "$TARGET_ENV" "${channel_args[@]}" "python=$PYTHON_VERSION" mintpy
|
||||
fi
|
||||
|
||||
echo "Verifying MintPy import"
|
||||
"$CONDA_BIN" run -n "$TARGET_ENV" python -c "import mintpy; print(mintpy.__file__)"
|
||||
echo "MintPy runtime bootstrap complete"
|
||||
@@ -1,201 +0,0 @@
|
||||
#!/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())
|
||||
@@ -1,59 +0,0 @@
|
||||
# Phase 0 Practical TODO
|
||||
|
||||
## Immediate
|
||||
|
||||
- [x] Run `scripts/check_env_ubuntu2404.sh` inside `Ubuntu-24.04`.
|
||||
- [x] Use `scripts/scan_lt1_stack_candidates.py` to keep one baseline sample stack manifest current.
|
||||
- [x] Treat `E123.3_N46.1` as the first tile-level smoke-test sample unless a better sample appears.
|
||||
- [x] Confirm ISCE2 stack-processing scripts are present.
|
||||
- [x] Confirm the official helper scripts do not advertise LT-1/LUTAN1 stack prep.
|
||||
- [x] Record required orbit, DEM, and metadata adaptations.
|
||||
- [x] Run `scripts/build_lt1_stack_prep.py` to keep the dry-run stack workspace current.
|
||||
|
||||
## Before first end-to-end run
|
||||
|
||||
- [x] Implement an LT-1 scene materializer that creates `YYYYMMDD.slc`, `YYYYMMDD.slc.xml`, and `data`.
|
||||
- [x] Materialize the remaining acquisitions for `E123.3_N46.1` under `scratch/.../SLC/`.
|
||||
- [x] Smoke-test the materializer on the reference date `20250510`.
|
||||
- [x] Run the generated `run_stripmap_stack_dryrun.sh` preflight and then `stackStripMap.py --nofocus`.
|
||||
- [x] Inspect the produced `baseline/`, `configs/`, and `run_files/` outputs.
|
||||
- [x] Prepare a stack-local DEM to avoid global-DEM bbox behavior during `createWaterMask`.
|
||||
- [x] Add a reproducible synthetic `waterMask` fallback for `run_01_reference` when Earthdata credentials are unavailable.
|
||||
Working rule: DEM is already local and sufficient; do not download `SWBD` during this experiment stage.
|
||||
- [x] Extract shared LT-1 input preparation helper for DEM/orbit resolution.
|
||||
Compatibility rule: original D-InSAR entry logic remains in place; only the duplicated input-prep internals were consolidated.
|
||||
- [x] Decide MintPy installation strategy after stack generation is stable.
|
||||
Decision: default to a dedicated WSL conda env named `mintpy` so the working `isce2` processing env stays unchanged on the development machine.
|
||||
- [x] Freeze the first smoke-test command chain.
|
||||
Frozen chain: `run_01_reference -> run_02_focus_split -> run_03_geo2rdr_coarseResamp -> run_04_refineSecondaryTiming -> run_05_invertMisreg -> run_06_fineResamp -> run_07_grid_baseline`
|
||||
- [x] Execute `run_01_reference` through the WSL wrapper and verify the fallback-recovered geometry outputs.
|
||||
- [x] Execute `run_02` to `run_07` and record LT-1-specific failures if they appear.
|
||||
Result: all stages exited `0` in `Ubuntu-24.04`. `run_04_refineSecondaryTiming` logs still contain `Bad match at level 1` and `correlation error`, but pair-level `misreg`, date-level `misreg`, merged SLC, and merged baseline products were all generated successfully.
|
||||
|
||||
## Next Focus
|
||||
|
||||
- [x] Run `scripts/install_mintpy_runtime_ubuntu2404.sh` in `Ubuntu-24.04` and verify the new env.
|
||||
Result: dedicated WSL env `mintpy` was created successfully and `smallbaselineApp.py` / `prep_isce.py` are available.
|
||||
- [x] Validate MintPy ingestion against the current `stack_work/merged/` outputs.
|
||||
Result: `build_lt1_stack_prep.py --workflow interferogram` plus `run_08_igram` produced `Igrams/*/filt_*_snaphu.unw`, and `prep_isce.py` completed successfully after bridging the working `isce2` Python package into the `mintpy` env.
|
||||
- [x] Draft the first `smallbaselineApp.cfg` for the LT-1 sample stack.
|
||||
Result: `configs/sample_smallbaseline_lt1_e123p3_n46p1.cfg` now records the first runnable LT-1 stripmapStack -> MintPy SBAS contract.
|
||||
- [x] Execute the first MintPy workflow steps after `prep_isce.py`.
|
||||
Result: the repo-local smoke-test chain now reaches radar-coordinate `timeseries.h5` and `velocity.h5` in `stack_work/mintpy_sbas_v5/`.
|
||||
Current helper chain:
|
||||
- `scripts/run_mintpy_with_isce_ubuntu2404.sh`
|
||||
- `scripts/create_mintpy_all_ifgram_mask.py`
|
||||
- `scripts/run_smallbaselineApp_patched.py`
|
||||
- `scripts/run_mintpy_sbas_smoketest_ubuntu2404.sh`
|
||||
- [x] Draft the first production-side SBAS artifact manifest and publish contract.
|
||||
Result:
|
||||
- `configs/sample_psinsar_manifest_lt1_e123p3_n46p1.json`
|
||||
- `docs/ISCE2_SBAS_TIMESERIES_DESIGN.md`
|
||||
|
||||
## New Follow-up
|
||||
|
||||
- [ ] Decide whether production should keep the repo-local patched MintPy launcher or pin an upstream-fixed MintPy version.
|
||||
- [x] Add the geocode/export stage needed for publishable SBAS rasters and previews.
|
||||
Result: experiment-layer publish export now succeeds into `publish/mintpy_sbas_v5/` with geocoded HDF5, GeoTIFF, preview PNG, and `manifest.json`.
|
||||
- [ ] Wire the validated SBAS runtime chain into backend workflow submission and artifact publishing.
|
||||
- [ ] Run a separate unified-environment experiment by cloning the current WSL `isce2` env and installing MintPy directly inside it.
|
||||
@@ -1,152 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
def load_manifest(path: Path) -> Dict[str, Any]:
|
||||
return json.loads(path.read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def resolve_dem_source(arg_value: str | None, manifest: Dict[str, Any]) -> Path:
|
||||
candidates: List[str] = []
|
||||
if arg_value:
|
||||
candidates.append(arg_value)
|
||||
resolved = manifest.get("resolved_dependencies", {})
|
||||
for key in ("dem_path_wsl", "dem_path_windows"):
|
||||
value = resolved.get(key)
|
||||
if value:
|
||||
candidates.append(value)
|
||||
|
||||
for candidate in candidates:
|
||||
path = Path(candidate)
|
||||
if path.exists() and Path(str(path) + ".xml").exists():
|
||||
return path
|
||||
raise FileNotFoundError("Unable to resolve source DEM from arguments or stack manifest")
|
||||
|
||||
|
||||
def compute_bbox(manifest: Dict[str, Any], margin_deg: float) -> List[float]:
|
||||
lons: List[float] = []
|
||||
lats: List[float] = []
|
||||
for scene in manifest["scenes"]:
|
||||
lon = scene.get("scene_center_lon")
|
||||
lat = scene.get("scene_center_lat")
|
||||
if lon is None or lat is None:
|
||||
source_scene_json = scene.get("source_scene_json_wsl") or scene.get("source_scene_json_windows")
|
||||
if source_scene_json and Path(source_scene_json).exists():
|
||||
source_payload = json.loads(Path(source_scene_json).read_text(encoding="utf-8"))
|
||||
lon = source_payload.get("scene_center_lon")
|
||||
lat = source_payload.get("scene_center_lat")
|
||||
if lon is not None and lat is not None:
|
||||
lons.append(float(lon))
|
||||
lats.append(float(lat))
|
||||
if not lons or not lats:
|
||||
raise ValueError("Stack manifest does not include usable scene center coordinates")
|
||||
west = min(lons) - margin_deg
|
||||
east = max(lons) + margin_deg
|
||||
south = min(lats) - margin_deg
|
||||
north = max(lats) + margin_deg
|
||||
return [south, north, west, east]
|
||||
|
||||
|
||||
def prepare_dem(source_dem: Path, output_dem: Path, bbox: List[float]) -> None:
|
||||
from osgeo import gdal
|
||||
from isce.applications.gdal2isce_xml import gdal2isce_xml
|
||||
|
||||
south, north, west, east = bbox
|
||||
src_open_path = Path(str(source_dem) + ".vrt")
|
||||
if not src_open_path.exists():
|
||||
src_open_path = source_dem
|
||||
|
||||
output_dem.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_vrt = Path(str(output_dem) + ".vrt")
|
||||
output_xml = Path(str(output_dem) + ".xml")
|
||||
output_hdr = Path(str(output_dem) + ".hdr")
|
||||
fallback_hdr = output_dem.with_suffix(".hdr")
|
||||
|
||||
src_ds = gdal.Open(str(src_open_path), gdal.GA_ReadOnly)
|
||||
if src_ds is None:
|
||||
raise RuntimeError(f"Unable to open DEM source: {src_open_path}")
|
||||
|
||||
translate_options = gdal.TranslateOptions(
|
||||
format="ENVI",
|
||||
projWin=[west, north, east, south],
|
||||
)
|
||||
out_ds = gdal.Translate(str(output_dem), src_ds, options=translate_options)
|
||||
if out_ds is None:
|
||||
raise RuntimeError("gdal.Translate failed while clipping the DEM")
|
||||
out_ds = None
|
||||
src_ds = None
|
||||
|
||||
vrt_ds = gdal.Open(str(output_dem), gdal.GA_ReadOnly)
|
||||
if vrt_ds is None:
|
||||
raise RuntimeError(f"Unable to reopen clipped DEM: {output_dem}")
|
||||
gdal.Translate(str(output_vrt), vrt_ds, options=gdal.TranslateOptions(format="VRT"))
|
||||
vrt_ds = None
|
||||
|
||||
gdal2isce_xml(str(output_vrt))
|
||||
if not output_xml.exists():
|
||||
raise RuntimeError(f"Expected ISCE XML was not created: {output_xml}")
|
||||
if not output_hdr.exists() and not fallback_hdr.exists():
|
||||
raise RuntimeError(f"Expected ENVI header was not created: {output_hdr} or {fallback_hdr}")
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Clip a local DEM window for one LT-1 stack workspace."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--stack-manifest",
|
||||
required=True,
|
||||
help="Path to stack_input_manifest.json generated by build_lt1_stack_prep.py",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--source-dem",
|
||||
default=None,
|
||||
help="Override source DEM base path.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--margin-deg",
|
||||
type=float,
|
||||
default=1.0,
|
||||
help="Margin around stack scene-center extents in degrees.",
|
||||
)
|
||||
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)
|
||||
source_dem = resolve_dem_source(args.source_dem, manifest)
|
||||
bbox = compute_bbox(manifest, margin_deg=args.margin_deg)
|
||||
|
||||
workspace = manifest["workspace"]
|
||||
dem_dir = Path(workspace["inputs_dir_wsl"]) / "dem"
|
||||
output_dem = dem_dir / "stack_dem_window.wgs84"
|
||||
prepare_dem(source_dem=source_dem, output_dem=output_dem, bbox=bbox)
|
||||
|
||||
report = {
|
||||
"stack_manifest": str(manifest_path),
|
||||
"source_dem": str(source_dem),
|
||||
"output_dem": str(output_dem),
|
||||
"bbox_south_north_west_east": bbox,
|
||||
}
|
||||
report_path = dem_dir / "stack_dem_window_report.json"
|
||||
report_path.write_text(json.dumps(report, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
|
||||
print(f"Source DEM: {source_dem}")
|
||||
print(f"Output DEM: {output_dem}")
|
||||
print(f"BBox: {bbox}")
|
||||
print(f"Report: {report_path}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,106 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 2 ]]; then
|
||||
echo "Usage: $0 <scratch_root_wsl> <run_file_name>" >&2
|
||||
echo "Example: $0 /mnt/z/Code/Insar_management_system_v2/experiments/isce2_sbas_timeseries/scratch/lt1a_strip1_hh_descending_e123p3_n46p1 run_01_reference" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SCRATCH_ROOT="$1"
|
||||
RUN_FILE_NAME="$2"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONDA_ROOT="${CONDA_ROOT:-/home/administrator/miniconda3}"
|
||||
CONDA_ENV="${CONDA_ENV:-insar_wsl_v1}"
|
||||
CONDA_BIN="${CONDA_BIN:-$CONDA_ROOT/bin/conda}"
|
||||
ISCE2_SHARE="${ISCE2_SHARE:-$CONDA_ROOT/envs/$CONDA_ENV/share/isce2}"
|
||||
STRIPMAP_STACK_DIR="${STRIPMAP_STACK_DIR:-$ISCE2_SHARE/stripmapStack}"
|
||||
SYNTHETIC_WATERMASK_SCRIPT="${SYNTHETIC_WATERMASK_SCRIPT:-$SCRIPT_DIR/create_synthetic_watermask.py}"
|
||||
ALLOW_SYNTHETIC_WATERMASK="${ALLOW_SYNTHETIC_WATERMASK:-1}"
|
||||
STACK_WORK="$SCRATCH_ROOT/stack_work"
|
||||
RUN_FILE="$STACK_WORK/run_files/$RUN_FILE_NAME"
|
||||
LOG_DIR="$STACK_WORK/logs"
|
||||
LOG_FILE="$LOG_DIR/$RUN_FILE_NAME.log"
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$RUN_FILE" ]]; then
|
||||
echo "Run file not found: $RUN_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
export PYTHONPATH="$STRIPMAP_STACK_DIR:$ISCE2_SHARE${PYTHONPATH:+:$PYTHONPATH}"
|
||||
export PATH="$STRIPMAP_STACK_DIR:$PATH"
|
||||
|
||||
recover_reference_watermask() {
|
||||
local like_image="$STACK_WORK/geom_reference/shadowMask.rdr"
|
||||
local output_mask="$STACK_WORK/geom_reference/waterMask.rdr"
|
||||
local report_path="$LOG_DIR/$RUN_FILE_NAME.synthetic_watermask.json"
|
||||
local watermask_failure_pattern='Please create a \.netrc file|Running: createWaterMask|DataRetriever - ERROR|There was a problem in retrieving the file|SRTMSWBD\.003|SWBD'
|
||||
|
||||
if [[ "$RUN_FILE_NAME" != "run_01_reference" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$ALLOW_SYNTHETIC_WATERMASK" != "1" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$LOG_FILE" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Recover only the known offline water-mask failure modes observed in this
|
||||
# experiment: missing Earthdata credentials or SWBD retrieval failure.
|
||||
if ! grep -Eq "$watermask_failure_pattern" "$LOG_FILE"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$like_image" || ! -f "$like_image.xml" ]]; then
|
||||
echo "Synthetic water-mask fallback could not find template image: $like_image" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$SYNTHETIC_WATERMASK_SCRIPT" ]]; then
|
||||
echo "Synthetic water-mask helper script not found: $SYNTHETIC_WATERMASK_SCRIPT" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "Earthdata credentials are unavailable. Creating a synthetic all-land water mask."
|
||||
"$CONDA_BIN" run -n "$CONDA_ENV" python "$SYNTHETIC_WATERMASK_SCRIPT" \
|
||||
--like-image "$like_image" \
|
||||
--output "$output_mask" \
|
||||
--fill-value 1 \
|
||||
--force \
|
||||
--report "$report_path"
|
||||
}
|
||||
|
||||
echo "Executing stripmap stack run file"
|
||||
echo "Scratch root: $SCRATCH_ROOT"
|
||||
echo "Run file: $RUN_FILE"
|
||||
echo "Log file: $LOG_FILE"
|
||||
echo "Conda env: $CONDA_ENV"
|
||||
echo "Conda bin: $CONDA_BIN"
|
||||
echo "ISCE2 share: $ISCE2_SHARE"
|
||||
echo "PYTHONPATH: $PYTHONPATH"
|
||||
echo "PATH prefix: $STRIPMAP_STACK_DIR"
|
||||
|
||||
set -o pipefail
|
||||
"$CONDA_BIN" run -n "$CONDA_ENV" bash "$RUN_FILE" 2>&1 | tee "$LOG_FILE"
|
||||
RUN_STATUS=${PIPESTATUS[0]}
|
||||
|
||||
if [[ "$RUN_STATUS" -eq 0 ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if recover_reference_watermask; then
|
||||
echo "Recovered $RUN_FILE_NAME with a synthetic all-land water mask."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit "$RUN_STATUS"
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 <smallbaseline-config-wsl> <mintpy-work-dir-wsl>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CFG_PATH="$1"
|
||||
WORK_DIR="$2"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BRIDGE_RUNNER="$SCRIPT_DIR/run_mintpy_with_isce_ubuntu2404.sh"
|
||||
PATCHED_APP="$SCRIPT_DIR/run_smallbaselineApp_patched.py"
|
||||
STRICT_MASK_BUILDER="$SCRIPT_DIR/create_mintpy_all_ifgram_mask.py"
|
||||
|
||||
echo "MintPy SBAS smoketest"
|
||||
echo "Config: $CFG_PATH"
|
||||
echo "Work dir: $WORK_DIR"
|
||||
|
||||
bash "$BRIDGE_RUNNER" python "$PATCHED_APP" "$CFG_PATH" --dir "$WORK_DIR" --dostep load_data
|
||||
|
||||
bash "$BRIDGE_RUNNER" python "$STRICT_MASK_BUILDER" \
|
||||
--ifgram-stack "$WORK_DIR/inputs/ifgramStack.h5" \
|
||||
--output "$WORK_DIR/maskAllValid.h5"
|
||||
|
||||
bash "$BRIDGE_RUNNER" python "$PATCHED_APP" "$CFG_PATH" --dir "$WORK_DIR" --start modify_network --end velocity
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 <smallbaseline-config-wsl> <mintpy-work-dir-wsl>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CFG_PATH="$1"
|
||||
WORK_DIR="$2"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
UNIFIED_RUNNER="$SCRIPT_DIR/run_mintpy_unified_env_ubuntu2404.sh"
|
||||
PATCHED_APP="$SCRIPT_DIR/run_smallbaselineApp_patched.py"
|
||||
STRICT_MASK_BUILDER="$SCRIPT_DIR/create_mintpy_all_ifgram_mask.py"
|
||||
|
||||
echo "MintPy SBAS unified-env smoketest"
|
||||
echo "Config: $CFG_PATH"
|
||||
echo "Work dir: $WORK_DIR"
|
||||
|
||||
bash "$UNIFIED_RUNNER" python "$PATCHED_APP" "$CFG_PATH" --dir "$WORK_DIR" --dostep load_data
|
||||
|
||||
bash "$UNIFIED_RUNNER" python "$STRICT_MASK_BUILDER" \
|
||||
--ifgram-stack "$WORK_DIR/inputs/ifgramStack.h5" \
|
||||
--output "$WORK_DIR/maskAllValid.h5"
|
||||
|
||||
bash "$UNIFIED_RUNNER" python "$PATCHED_APP" "$CFG_PATH" --dir "$WORK_DIR" --start modify_network --end velocity
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <mintpy-command> [args...]" >&2
|
||||
echo "Example: $0 prep_isce.py -h" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
MINTPY_ENV="${MINTPY_ENV:-isce2_mintpy}"
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "MintPy command in unified env"
|
||||
echo "Conda: $CONDA_BIN"
|
||||
echo "Target env: $MINTPY_ENV"
|
||||
echo "Command: $*"
|
||||
|
||||
"$CONDA_BIN" run -n "$MINTPY_ENV" "$@"
|
||||
@@ -1,45 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
echo "Usage: $0 <mintpy-command> [args...]" >&2
|
||||
echo "Example: $0 prep_isce.py -h" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONDA_BIN="${CONDA_BIN:-/home/administrator/miniconda3/bin/conda}"
|
||||
MINTPY_ENV="${MINTPY_ENV:-mintpy}"
|
||||
ISCE_SITE_PACKAGES="${ISCE_SITE_PACKAGES:-/home/administrator/miniconda3/envs/isce2/lib/python3.11/site-packages}"
|
||||
ISCE_PACKAGE_DIR="${ISCE_PACKAGE_DIR:-$ISCE_SITE_PACKAGES/isce}"
|
||||
ISCE_BRIDGE_DIR="${ISCE_BRIDGE_DIR:-$HOME/.cache/mintpy_isce_bridge}"
|
||||
|
||||
if [[ ! -x "$CONDA_BIN" ]]; then
|
||||
echo "Missing conda binary: $CONDA_BIN" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$ISCE_SITE_PACKAGES" ]]; then
|
||||
echo "Missing ISCE site-packages directory: $ISCE_SITE_PACKAGES" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$ISCE_PACKAGE_DIR" ]]; then
|
||||
echo "Missing ISCE package directory: $ISCE_PACKAGE_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$ISCE_BRIDGE_DIR"
|
||||
ln -sfn "$ISCE_PACKAGE_DIR" "$ISCE_BRIDGE_DIR/isce"
|
||||
|
||||
# Bridge only the top-level ISCE package into the MintPy env.
|
||||
# The package itself extends sys.path to its internal components on import,
|
||||
# which avoids shadowing MintPy's own numpy/h5py stack with the isce2 env.
|
||||
export PYTHONPATH="$ISCE_BRIDGE_DIR${PYTHONPATH:+:$PYTHONPATH}"
|
||||
|
||||
echo "MintPy command bridge"
|
||||
echo "Conda: $CONDA_BIN"
|
||||
echo "MintPy env: $MINTPY_ENV"
|
||||
echo "ISCE bridge: $ISCE_BRIDGE_DIR -> $ISCE_PACKAGE_DIR"
|
||||
echo "Command: $*"
|
||||
|
||||
"$CONDA_BIN" run -n "$MINTPY_ENV" "$@"
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Run MintPy smallbaselineApp with a local workaround for a single-pixel inversion bug."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
|
||||
import numpy as np
|
||||
|
||||
import mintpy.ifgram_inversion as ifgram_inversion
|
||||
from mintpy.cli.smallbaselineApp import main as mintpy_smallbaseline_main
|
||||
|
||||
|
||||
_ORIGINAL_ESTIMATE_TIMESERIES = ifgram_inversion.estimate_timeseries
|
||||
|
||||
|
||||
def _patched_estimate_timeseries(*args, **kwargs):
|
||||
ts, inv_quality, num_inv_obs = _ORIGINAL_ESTIMATE_TIMESERIES(*args, **kwargs)
|
||||
|
||||
# MintPy 1.6.2 may return a shape-(1,) inversion quality array for the
|
||||
# single-pixel partial-network branch, while the caller expects a scalar.
|
||||
if isinstance(inv_quality, np.ndarray) and inv_quality.size == 1:
|
||||
inv_quality = np.asarray(inv_quality).reshape(-1)[0].item()
|
||||
|
||||
if isinstance(num_inv_obs, np.ndarray) and num_inv_obs.size == 1:
|
||||
num_inv_obs = int(np.asarray(num_inv_obs).reshape(-1)[0])
|
||||
|
||||
return ts, inv_quality, num_inv_obs
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
ifgram_inversion.estimate_timeseries = _patched_estimate_timeseries
|
||||
print("Applied local MintPy estimate_timeseries single-pixel fix.")
|
||||
return mintpy_smallbaseline_main(argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main(sys.argv[1:]))
|
||||
@@ -1,373 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
|
||||
def _repo_root() -> Path:
|
||||
return Path(__file__).resolve().parents[3]
|
||||
|
||||
|
||||
def _load_utils_module():
|
||||
utils_path = _repo_root() / "backend" / "app" / "utils.py"
|
||||
spec = importlib.util.spec_from_file_location("repo_utils", utils_path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Unable to load repo utils module: {utils_path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
UTILS = _load_utils_module()
|
||||
|
||||
|
||||
LT1_NAME_RE = re.compile(
|
||||
r"^(?P<satellite>LT1[AB])_"
|
||||
r"(?P<satellite_mode>[^_]+)_"
|
||||
r"(?P<receiving_station>[^_]+)_"
|
||||
r"(?P<imaging_mode>[^_]+)_"
|
||||
r"(?P<abs_orbit>\d+)_"
|
||||
r"(?P<lon>E\d+\.\d+)_"
|
||||
r"(?P<lat>N\d+\.\d+)_"
|
||||
r"(?P<date>\d{8})_"
|
||||
r"(?P<product_type>[^_]+)_"
|
||||
r"(?P<polarization>[^_]+)_"
|
||||
r"(?P<product_level>[^_]+)_"
|
||||
r"(?P<product_unique_id>\d+)$"
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class SceneRecord:
|
||||
folder_name: str
|
||||
folder_path: str
|
||||
folder_path_wsl: str
|
||||
tiff_path: str
|
||||
tiff_path_wsl: str
|
||||
meta_path: str
|
||||
meta_path_wsl: str
|
||||
file_size_bytes: int
|
||||
satellite: str
|
||||
imaging_date: str
|
||||
imaging_mode: Optional[str]
|
||||
polarization: Optional[str]
|
||||
orbit_direction: Optional[str]
|
||||
satellite_mode: Optional[str]
|
||||
receiving_station: Optional[str]
|
||||
orbit_circle: Optional[str]
|
||||
scene_center_lon: Optional[float]
|
||||
scene_center_lat: Optional[float]
|
||||
acquisition_time_utc: Optional[str]
|
||||
product_type: Optional[str]
|
||||
product_level: Optional[str]
|
||||
product_unique_id: Optional[str]
|
||||
tile_key: str
|
||||
group_key: str
|
||||
orbit_txt_expected_name: str
|
||||
|
||||
|
||||
def windows_to_wsl(path: str | Path) -> str:
|
||||
text = str(path)
|
||||
match = re.match(r"^([A-Za-z]):[\\/](.*)$", os.path.normpath(text))
|
||||
if not match:
|
||||
return text.replace("\\", "/")
|
||||
drive = match.group(1).lower()
|
||||
normalized_tail = match.group(2).replace("\\", "/").lstrip("/")
|
||||
return f"/mnt/{drive}/{normalized_tail}"
|
||||
|
||||
|
||||
def choose_tiff(folder: Path) -> Optional[Path]:
|
||||
candidates = sorted(folder.glob("*.tiff"))
|
||||
if not candidates:
|
||||
return None
|
||||
slc_candidates = [path for path in candidates if "_SLC_" in path.name]
|
||||
if len(slc_candidates) == 1:
|
||||
return slc_candidates[0]
|
||||
if len(candidates) == 1:
|
||||
return candidates[0]
|
||||
return candidates[0]
|
||||
|
||||
|
||||
def merge_metadata(name_meta: Dict[str, Any], xml_meta: Dict[str, Any]) -> Dict[str, Any]:
|
||||
merged = dict(name_meta or {})
|
||||
prefer_name_keys = {"product_unique_id"}
|
||||
for key, value in (xml_meta or {}).items():
|
||||
if value in (None, ""):
|
||||
continue
|
||||
if key in prefer_name_keys and merged.get(key):
|
||||
continue
|
||||
merged[key] = value
|
||||
return merged
|
||||
|
||||
|
||||
def parse_scene(folder: Path) -> Optional[SceneRecord]:
|
||||
match = LT1_NAME_RE.match(folder.name)
|
||||
if not match:
|
||||
return None
|
||||
|
||||
name_meta = UTILS.get_parser(folder.name, UTILS.RADAR_PARSERS)
|
||||
if not name_meta:
|
||||
return None
|
||||
|
||||
xml_file_path = UTILS.find_xml_file(str(folder))
|
||||
if not xml_file_path:
|
||||
return None
|
||||
|
||||
coverage_polygon, xml_meta = UTILS.parse_xml_metadata(xml_file_path)
|
||||
if not coverage_polygon:
|
||||
return None
|
||||
|
||||
tiff_path = choose_tiff(folder)
|
||||
if tiff_path is None:
|
||||
return None
|
||||
|
||||
merged = merge_metadata(name_meta, xml_meta or {})
|
||||
tile_key = f"{match.group('lon')}_{match.group('lat')}"
|
||||
orbit_direction = str(merged.get("orbit_direction") or "").upper() or None
|
||||
group_key = "|".join(
|
||||
[
|
||||
str(merged.get("satellite") or ""),
|
||||
str(merged.get("imaging_mode") or ""),
|
||||
str(merged.get("polarization") or ""),
|
||||
str(orbit_direction or ""),
|
||||
tile_key,
|
||||
]
|
||||
)
|
||||
satellite = str(merged.get("satellite") or "")
|
||||
imaging_date = str(merged.get("imaging_date") or "")
|
||||
|
||||
return SceneRecord(
|
||||
folder_name=folder.name,
|
||||
folder_path=str(folder),
|
||||
folder_path_wsl=windows_to_wsl(folder),
|
||||
tiff_path=str(tiff_path),
|
||||
tiff_path_wsl=windows_to_wsl(tiff_path),
|
||||
meta_path=str(xml_file_path),
|
||||
meta_path_wsl=windows_to_wsl(xml_file_path),
|
||||
file_size_bytes=tiff_path.stat().st_size,
|
||||
satellite=satellite,
|
||||
imaging_date=imaging_date,
|
||||
imaging_mode=merged.get("imaging_mode"),
|
||||
polarization=merged.get("polarization"),
|
||||
orbit_direction=orbit_direction,
|
||||
satellite_mode=merged.get("satellite_mode"),
|
||||
receiving_station=merged.get("receiving_station"),
|
||||
orbit_circle=merged.get("orbit_circle"),
|
||||
scene_center_lon=merged.get("scene_center_lon"),
|
||||
scene_center_lat=merged.get("scene_center_lat"),
|
||||
acquisition_time_utc=merged.get("acquisition_time_utc"),
|
||||
product_type=merged.get("product_type"),
|
||||
product_level=merged.get("product_level"),
|
||||
product_unique_id=merged.get("product_unique_id"),
|
||||
tile_key=tile_key,
|
||||
group_key=group_key,
|
||||
orbit_txt_expected_name=f"{satellite}_GpsData_GAS_C_{imaging_date}.txt",
|
||||
)
|
||||
|
||||
|
||||
def scan_scenes(root_dir: Path) -> List[SceneRecord]:
|
||||
scenes: List[SceneRecord] = []
|
||||
for entry in sorted(root_dir.iterdir()):
|
||||
if not entry.is_dir():
|
||||
continue
|
||||
scene = parse_scene(entry)
|
||||
if scene:
|
||||
scenes.append(scene)
|
||||
return scenes
|
||||
|
||||
|
||||
def build_group_summary(scenes: List[SceneRecord]) -> List[Dict[str, Any]]:
|
||||
groups: Dict[str, List[SceneRecord]] = {}
|
||||
for scene in scenes:
|
||||
groups.setdefault(scene.group_key, []).append(scene)
|
||||
|
||||
summary: List[Dict[str, Any]] = []
|
||||
for key, items in groups.items():
|
||||
items.sort(key=lambda item: item.imaging_date)
|
||||
first = items[0]
|
||||
summary.append(
|
||||
{
|
||||
"group_key": key,
|
||||
"count": len(items),
|
||||
"satellite": first.satellite,
|
||||
"imaging_mode": first.imaging_mode,
|
||||
"polarization": first.polarization,
|
||||
"orbit_direction": first.orbit_direction,
|
||||
"tile_key": first.tile_key,
|
||||
"dates": [item.imaging_date for item in items],
|
||||
"receiving_stations": sorted({item.receiving_station for item in items if item.receiving_station}),
|
||||
}
|
||||
)
|
||||
summary.sort(key=lambda item: (-item["count"], item["group_key"]))
|
||||
return summary
|
||||
|
||||
|
||||
def select_group(
|
||||
summary: List[Dict[str, Any]],
|
||||
tile_key: Optional[str],
|
||||
group_key: Optional[str],
|
||||
min_scenes: int,
|
||||
) -> Optional[str]:
|
||||
if group_key:
|
||||
return group_key
|
||||
if tile_key:
|
||||
for item in summary:
|
||||
if item["tile_key"] == tile_key and item["count"] >= min_scenes:
|
||||
return item["group_key"]
|
||||
return None
|
||||
for item in summary:
|
||||
if item["count"] >= min_scenes:
|
||||
return item["group_key"]
|
||||
return None
|
||||
|
||||
|
||||
def build_manifest(root_dir: Path, group_key: str, scenes: List[SceneRecord]) -> Dict[str, Any]:
|
||||
group_scenes = [scene for scene in scenes if scene.group_key == group_key]
|
||||
if not group_scenes:
|
||||
raise ValueError(f"Group not found: {group_key}")
|
||||
group_scenes.sort(key=lambda item: item.imaging_date)
|
||||
|
||||
first = group_scenes[0]
|
||||
reference_index = len(group_scenes) // 2
|
||||
reference_scene = group_scenes[reference_index]
|
||||
slug = (
|
||||
f"{first.satellite.lower()}_"
|
||||
f"{(first.imaging_mode or 'unknown').lower()}_"
|
||||
f"{(first.polarization or 'unknown').lower()}_"
|
||||
f"{(first.orbit_direction or 'unknown').lower()}_"
|
||||
f"{first.tile_key.lower().replace('.', 'p')}"
|
||||
)
|
||||
|
||||
scratch_root = _repo_root() / "experiments" / "isce2_sbas_timeseries" / "scratch" / slug
|
||||
scratch_root_wsl = windows_to_wsl(scratch_root)
|
||||
|
||||
return {
|
||||
"source_root_windows": str(root_dir),
|
||||
"source_root_wsl": windows_to_wsl(root_dir),
|
||||
"group_key": group_key,
|
||||
"tile_key": first.tile_key,
|
||||
"scene_count": len(group_scenes),
|
||||
"reference_strategy": "middle_by_date",
|
||||
"reference_date": reference_scene.imaging_date,
|
||||
"stack_group": {
|
||||
"satellite": first.satellite,
|
||||
"imaging_mode": first.imaging_mode,
|
||||
"polarization": first.polarization,
|
||||
"orbit_direction": first.orbit_direction,
|
||||
"receiving_stations": sorted({item.receiving_station for item in group_scenes if item.receiving_station}),
|
||||
},
|
||||
"proposed_scratch_windows": str(scratch_root),
|
||||
"proposed_scratch_wsl": scratch_root_wsl,
|
||||
"proposed_layout": {
|
||||
"stack_input_manifest": f"{scratch_root_wsl}/stack_input_manifest.json",
|
||||
"slc_dir": f"{scratch_root_wsl}/SLC",
|
||||
"orbits_dir": f"{scratch_root_wsl}/orbits",
|
||||
"logs_dir": f"{scratch_root_wsl}/logs",
|
||||
},
|
||||
"stack_prep_assessment": {
|
||||
"current_scene_layout": "per_scene_folder_with_tiff_meta_rpc",
|
||||
"official_stripmapStack_expected_layout": "SLC/YYYYMMDD/YYYYMMDD.raw or YYYYMMDD.slc",
|
||||
"direct_compatibility": "unproven",
|
||||
"lt1_adapter_required_likely": True,
|
||||
"notes": [
|
||||
"Current repo can read these scene folders as RadarData assets.",
|
||||
"Official stripmapStack helper scripts do not advertise LT-1/LUTAN1 preparation hooks.",
|
||||
"A custom LT-1 stack preparation layer is likely needed before official stack execution.",
|
||||
],
|
||||
},
|
||||
"scenes": [asdict(scene) for scene in group_scenes],
|
||||
}
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Scan LT-1 scene folders and build a dry-run SBAS stack-prep manifest."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--root-dir",
|
||||
default=r"F:\Insar_data_pool_1",
|
||||
help="Windows root directory containing LT-1 scene folders.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--min-scenes",
|
||||
type=int,
|
||||
default=4,
|
||||
help="Minimum scenes required for candidate groups.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--top-n",
|
||||
type=int,
|
||||
default=20,
|
||||
help="How many candidate groups to print.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tile-key",
|
||||
default=None,
|
||||
help="Pick one candidate by tile key, for example E123.3_N46.1.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--group-key",
|
||||
default=None,
|
||||
help="Pick one candidate by full group key.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--manifest-path",
|
||||
default=None,
|
||||
help="Optional JSON output path for the selected group's dry-run manifest.",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = build_parser().parse_args()
|
||||
root_dir = Path(args.root_dir)
|
||||
if not root_dir.exists():
|
||||
raise FileNotFoundError(f"Root directory does not exist: {root_dir}")
|
||||
|
||||
scenes = scan_scenes(root_dir)
|
||||
summary = build_group_summary(scenes)
|
||||
|
||||
print(f"scanned_scenes={len(scenes)}")
|
||||
print(f"candidate_groups={len(summary)}")
|
||||
print("top_candidates:")
|
||||
for item in summary[: args.top_n]:
|
||||
print(
|
||||
json.dumps(
|
||||
{
|
||||
"count": item["count"],
|
||||
"tile_key": item["tile_key"],
|
||||
"group_key": item["group_key"],
|
||||
"dates": item["dates"],
|
||||
"receiving_stations": item["receiving_stations"],
|
||||
},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
)
|
||||
|
||||
selected_group = select_group(summary, args.tile_key, args.group_key, args.min_scenes)
|
||||
if not selected_group:
|
||||
print("selected_group=None")
|
||||
return 0
|
||||
|
||||
manifest = build_manifest(root_dir, selected_group, scenes)
|
||||
print(f"selected_group={selected_group}")
|
||||
print(f"reference_date={manifest['reference_date']}")
|
||||
|
||||
if args.manifest_path:
|
||||
manifest_path = Path(args.manifest_path)
|
||||
manifest_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False), encoding="utf-8")
|
||||
print(f"manifest_written={manifest_path}")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -129,6 +129,7 @@ function epochSeconds(value) {
|
||||
|
||||
function taskToRunRow(task) {
|
||||
const taskId = task?.task_id || '';
|
||||
const message = task?.message || task?.task_name || '';
|
||||
return {
|
||||
run_id: taskId,
|
||||
record_type: 'task',
|
||||
@@ -145,7 +146,8 @@ function taskToRunRow(task) {
|
||||
workflow_run_id: '',
|
||||
root_dir: '',
|
||||
publish_root_dir: '',
|
||||
message: task?.message || task?.task_name || '',
|
||||
message,
|
||||
inferred_paths: inferTaskPaths(task),
|
||||
total_items: null,
|
||||
completed_items: null,
|
||||
failed_items: null,
|
||||
@@ -153,6 +155,17 @@ function taskToRunRow(task) {
|
||||
};
|
||||
}
|
||||
|
||||
function inferTaskPaths(task) {
|
||||
const message = String(task?.message || '').trim();
|
||||
const workMatch = message.match(/work_dir=([^)\s]+)/);
|
||||
const workDir = workMatch ? workMatch[1] : '';
|
||||
if (!workDir) return {};
|
||||
return {
|
||||
work_dir: workDir,
|
||||
ifgrams_dir: workDir ? `${workDir}\\<project>\\ifgrams` : '',
|
||||
};
|
||||
}
|
||||
|
||||
function mergeRunRows(productionRuns, recentTasks, limit = 20) {
|
||||
const rows = (productionRuns || []).map(run => ({
|
||||
...run,
|
||||
@@ -206,6 +219,49 @@ function formatPyintPreciseOrbitMode(mode) {
|
||||
return PYINT_PRECISE_ORBIT_MODE_LABEL[mode] || mode || '-';
|
||||
}
|
||||
|
||||
function getSchemaOptions(schema) {
|
||||
if (Array.isArray(schema?.enum) && schema.enum.length > 0) return schema.enum;
|
||||
if (Array.isArray(schema?.choices) && schema.choices.length > 0) return schema.choices;
|
||||
return [];
|
||||
}
|
||||
|
||||
function formatPathValue(value) {
|
||||
const text = String(value || '').trim();
|
||||
return text || '-';
|
||||
}
|
||||
|
||||
function RunPathBlock({ run }) {
|
||||
const items = Array.isArray(run?.items) ? run.items : [];
|
||||
const item = items.find(entry => entry?.status === 'RUNNING') || items[0] || null;
|
||||
const paths = item?.paths || run?.inferred_paths || {};
|
||||
if (!item && Object.keys(paths).length === 0) return null;
|
||||
const rows = [
|
||||
['任务', item?.task_alias || item?.task_name || run?.message || '-'],
|
||||
['运行目录', paths.run_dir],
|
||||
['native', paths.native_dir],
|
||||
['assets', paths.assets_dir],
|
||||
];
|
||||
if (run?.engine === 'pyint') {
|
||||
rows.push(['work', paths.work_dir]);
|
||||
rows.push(['project', paths.project_dir]);
|
||||
rows.push(['ifgrams', paths.ifgrams_dir]);
|
||||
rows.push(['重去平日志', paths.reflatten_dir]);
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: 4, display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
{rows.filter(([, value]) => String(value || '').trim()).map(([label, value]) => (
|
||||
<div key={label} style={{ display: 'flex', gap: 6, alignItems: 'flex-start' }}>
|
||||
<span style={{ minWidth: 58, color: '#94a3b8' }}>{label}</span>
|
||||
<span style={{ fontFamily: 'monospace', color: '#334155', wordBreak: 'break-all' }}>
|
||||
{formatPathValue(value)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function PreviewIssueList({ title, items, tone = 'warning' }) {
|
||||
if (!Array.isArray(items) || items.length === 0) {
|
||||
return null;
|
||||
@@ -387,7 +443,8 @@ function ParamField({ name, schema, value, disabled, onChange }) {
|
||||
);
|
||||
}
|
||||
|
||||
if (Array.isArray(schema.enum) && schema.enum.length > 0) {
|
||||
const options = getSchemaOptions(schema);
|
||||
if (options.length > 0) {
|
||||
return (
|
||||
<div style={{ minWidth: 180, flex: '0 1 220px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 4 }}>
|
||||
@@ -407,12 +464,12 @@ function ParamField({ name, schema, value, disabled, onChange }) {
|
||||
)}
|
||||
</div>
|
||||
<select
|
||||
value={value ?? schema.default ?? schema.enum[0]}
|
||||
value={value ?? schema.default ?? options[0]}
|
||||
disabled={disabled || isReadonly}
|
||||
onChange={event => onChange(name, event.target.value)}
|
||||
style={inputStyle}
|
||||
>
|
||||
{schema.enum.map(option => (
|
||||
{options.map(option => (
|
||||
<option key={option} value={option}>{option}</option>
|
||||
))}
|
||||
</select>
|
||||
@@ -493,7 +550,7 @@ export default function DinsarProductionPanel({ readOnly = false, onJobQueued })
|
||||
const currentParamSections = buildParamSections(currentParamSchema);
|
||||
const currentDefaultTimeoutSec = Number(currentEngineObj?.default_timeout_seconds || 0) || 0;
|
||||
const currentParamHelpText = selectedEngine === 'pyint'
|
||||
? 'PyINT/Gamma 默认按目标网格尺寸自动换算多视,逻辑与 ENVI/SARscape 自定义流程一致;通常只需要设置目标网格、并行度和是否执行解缠/地理编码。'
|
||||
? 'PyINT/Gamma 会按目标网格尺寸自动换算多视;新增 Gamma 残余重去平在解缠后执行 rascc_mask/quad_fit/quad_sub,再导出 native 和标准 GeoTIFF。'
|
||||
: selectedEngine === 'isce2'
|
||||
? '这些参数现在按执行、交付、增强分组展示。结果异常时,优先尝试关闭增强项,再回看基础几何和配对质量。'
|
||||
: '这些参数影响当前引擎的生产模板。建议先使用默认值,只有在结果边界、噪声或几何表现异常时再逐项调整。';
|
||||
@@ -1090,7 +1147,7 @@ export default function DinsarProductionPanel({ readOnly = false, onJobQueued })
|
||||
)}
|
||||
{selectedEngine === 'pyint' && currentDefaultTimeoutSec > 0 && (
|
||||
<div style={{ fontSize: 11, color: '#94a3b8', marginTop: 4 }}>
|
||||
PyINT 默认按单对任务使用 {currentDefaultTimeoutSec} 秒;当前会逐对串行创建工作区并运行外部 PyINT / Gamma 流程。
|
||||
PyINT 默认按单对任务使用 {currentDefaultTimeoutSec} 秒;当前会逐对串行创建工作区并运行外部 PyINT / Gamma 流程,native 会在主流程和重去平后统一写入。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -1512,7 +1569,7 @@ export default function DinsarProductionPanel({ readOnly = false, onJobQueued })
|
||||
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12 }}>
|
||||
<thead>
|
||||
<tr style={{ background: '#f8fafc' }}>
|
||||
{['运行ID', '引擎', '状态', '时间', '操作'].map(header => (
|
||||
{['运行ID', '引擎', '状态', '时间', '路径', '操作'].map(header => (
|
||||
<th
|
||||
key={header}
|
||||
style={{ padding: '4px 8px', textAlign: 'left', borderBottom: '1px solid #e2e8f0', color: '#64748b' }}
|
||||
@@ -1538,6 +1595,9 @@ export default function DinsarProductionPanel({ readOnly = false, onJobQueued })
|
||||
<td style={{ padding: '4px 8px', color: '#94a3b8' }}>
|
||||
{run.started_at ? new Date(run.started_at * 1000).toLocaleString() : '-'}
|
||||
</td>
|
||||
<td style={{ padding: '4px 8px', maxWidth: 520, fontSize: 11 }}>
|
||||
<RunPathBlock run={run} />
|
||||
</td>
|
||||
<td style={{ padding: '4px 8px' }}>
|
||||
<button
|
||||
onClick={() => handleViewLog(run)}
|
||||
|
||||
@@ -1,17 +1,38 @@
|
||||
@echo off
|
||||
setlocal
|
||||
chcp 65001 >nul
|
||||
cd /d "%~dp0"
|
||||
|
||||
set "APP=%~dp0license_issuer_gui.pyw"
|
||||
set "PYTHONDONTWRITEBYTECODE=1"
|
||||
if not defined PYTHON_PATH set "PYTHON_PATH=C:\ProgramData\anaconda3\envs\InSAR\python.exe"
|
||||
for %%I in ("%PYTHON_PATH%") do set "PYTHONW_PATH=%%~dpIpythonw.exe"
|
||||
|
||||
if exist "%PYTHONW_PATH%" (
|
||||
start "" "%PYTHONW_PATH%" "%APP%"
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
if exist "%PYTHON_PATH%" (
|
||||
"%PYTHON_PATH%" "%APP%"
|
||||
if errorlevel 1 pause
|
||||
exit /b %errorlevel%
|
||||
)
|
||||
|
||||
where pyw >nul 2>nul
|
||||
if %errorlevel%==0 (
|
||||
start "" pyw -3 "%~dp0license_issuer_gui.pyw"
|
||||
start "" pyw -3 "%APP%"
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
where pythonw >nul 2>nul
|
||||
if %errorlevel%==0 (
|
||||
start "" pythonw "%~dp0license_issuer_gui.pyw"
|
||||
start "" pythonw "%APP%"
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
python "%~dp0license_issuer_gui.pyw"
|
||||
echo [!] Python not found.
|
||||
echo Expected: %PYTHON_PATH%
|
||||
echo Or install Python Launcher / pythonw and add it to PATH.
|
||||
pause
|
||||
exit /b 1
|
||||
|
||||
Vendored
+1
@@ -135,6 +135,7 @@ def update_template(template_file):
|
||||
|
||||
templateDict['atmcor_all'] = '0' # if 1, run atmospheric correction
|
||||
templateDict['atmcor_all_parallel'] = '1' # multi-processor number used
|
||||
templateDict['atmcor_use_for_disp'] = '0' # if 1, use atmcor unw as dispmap input
|
||||
|
||||
templateDict['geocode_all'] = '0'
|
||||
templateDict['geocode_all_parallel'] = '1' # multi-processor number used
|
||||
|
||||
+25
-6
@@ -16,6 +16,13 @@ import argparse
|
||||
from pyint import _utils as ut
|
||||
|
||||
|
||||
def _run_or_raise(call_str, stage):
|
||||
rc = os.system(call_str)
|
||||
if rc != 0:
|
||||
raise RuntimeError('%s failed with rc=%s: %s' % (stage, rc, call_str))
|
||||
return rc
|
||||
|
||||
|
||||
INTRODUCTION = '''
|
||||
-------------------------------------------------------------------
|
||||
Unwrap differential interferogram using GAMMA.
|
||||
@@ -74,10 +81,22 @@ def main(argv):
|
||||
|
||||
################ prepare file for parallel processing ###############
|
||||
HGTSIM = demDir + '/' + masterDate + '_' + rlks + 'rlks.rdc.dem'
|
||||
Mamp0 = rslcDir + '/' + Mdate + '/' + Mdate + '_' + rlks + 'rlks.amp'
|
||||
Samp0 = rslcDir + '/' + Sdate + '/' + Sdate + '_' + rlks + 'rlks.amp'
|
||||
MampPar0 = rslcDir + '/' + Mdate + '/' + Mdate + '_' + rlks + 'rlks.amp.par'
|
||||
SampPar0 = rslcDir + '/' + Sdate + '/' + Sdate + '_' + rlks + 'rlks.amp.par'
|
||||
Mamp = workDir + '/' + Mdate + '_' + rlks + 'rlks.amp'
|
||||
MampPar = workDir + '/' + Mdate + '_' + rlks + 'rlks.amp.par'
|
||||
Samp = workDir + '/' + Sdate + '_' + rlks + 'rlks.amp'
|
||||
SampPar = workDir + '/' + Sdate + '_' + rlks + 'rlks.amp.par'
|
||||
if not os.path.isfile(Mamp):
|
||||
ut.copy_file(Mamp0, Mamp)
|
||||
if not os.path.isfile(Samp):
|
||||
ut.copy_file(Samp0, Samp)
|
||||
if not os.path.isfile(MampPar):
|
||||
ut.copy_file(MampPar0, MampPar)
|
||||
if not os.path.isfile(SampPar):
|
||||
ut.copy_file(SampPar0, SampPar)
|
||||
diff_par = workDir + '/' + Mdate + '_' + Sdate + '_diff_par'
|
||||
UNWlks = workDir + '/' + Pair + '_' +rlks + 'rlks.diff_filt.unw'
|
||||
CORMASK = workDir + '/' + Pair + '_' +rlks + 'rlks.diff_filt.cor'
|
||||
@@ -88,18 +107,18 @@ def main(argv):
|
||||
nLine = ut.read_gamma_par(MampPar, 'read', 'azimuth_lines')
|
||||
###############################################################
|
||||
call_str = "create_diff_par " + MampPar + " " + SampPar + " " + diff_par + " 1 0 "
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'create_diff_par_atmcor')
|
||||
call_str = "atm_mod_2d " + UNWlks + " " + HGTSIM + " " + CORMASK + " " + diff_par + " " + " - 0 a0 a1 sigma sigma_h s1"
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'atm_mod_2d')
|
||||
call_str = "atm_sim_2d " + diff_par + " " + HGTSIM + " a0 a1 " + ATM_PHASE
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'atm_sim_2d')
|
||||
call_str = "sub_phase " + UNWlks + " " + ATM_PHASE + " " + diff_par + " " + ATMCOR_UNW + " 0 0 0 "
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'sub_phase_atmcor')
|
||||
call_str = 'rasrmg ' + ATMCOR_UNW + ' ' + Mamp + ' ' + nWidth + ' - - - - - - - - - - '
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'rasrmg_atmcor_unw')
|
||||
|
||||
print("Correct atmospheric phase is done!")
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[:])
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ def main(argv):
|
||||
else:
|
||||
ifgList=ifgList0[:,0]
|
||||
|
||||
err_txt = scratchDir + '/' + projectName + '/unwrap_gamma_all.err'
|
||||
err_txt = scratchDir + '/' + projectName + '/atm_correction_gamma_all.err'
|
||||
if os.path.isfile(err_txt): os.remove(err_txt)
|
||||
|
||||
data_para = []
|
||||
@@ -114,7 +114,7 @@ def main(argv):
|
||||
print("Correct atmospheric phase for project %s is done! " % projectName)
|
||||
ut.print_process_time(start_time, time.time())
|
||||
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main(sys.argv[:])
|
||||
|
||||
+71
-2
@@ -23,6 +23,39 @@ def _run_or_raise(call_str, stage):
|
||||
return rc
|
||||
|
||||
|
||||
def _is_binary_all_zero(path, chunk_size=1024 * 1024):
|
||||
if not os.path.isfile(path):
|
||||
return False
|
||||
with open(path, 'rb') as handle:
|
||||
while True:
|
||||
chunk = handle.read(chunk_size)
|
||||
if not chunk:
|
||||
return True
|
||||
if any(chunk):
|
||||
return False
|
||||
|
||||
|
||||
def _run_slc_diff_intf(
|
||||
Mrslc,
|
||||
Srslc,
|
||||
MrslcPar,
|
||||
SrslcPar,
|
||||
OFF,
|
||||
SIM_UNW,
|
||||
DIFF_IFG,
|
||||
rlks,
|
||||
azlks,
|
||||
spsflg,
|
||||
azfflg,
|
||||
):
|
||||
call_str = (
|
||||
'SLC_diff_intf ' + Mrslc + ' ' + Srslc + ' ' + MrslcPar + ' ' + SrslcPar
|
||||
+ ' ' + OFF + ' ' + SIM_UNW + ' ' + DIFF_IFG + ' ' + rlks + ' ' + azlks
|
||||
+ ' ' + spsflg + ' ' + azfflg + ' - 1 1'
|
||||
)
|
||||
_run_or_raise(call_str, 'SLC_diff_intf')
|
||||
|
||||
|
||||
INTRODUCTION = '''
|
||||
-------------------------------------------------------------------
|
||||
Generate differential interferogram image from SLC using GAMMA.
|
||||
@@ -138,8 +171,44 @@ def main(argv):
|
||||
_run_or_raise(call_str, 'phase_sim_orb')
|
||||
|
||||
DIFF_IFG = workDir + '/' + Pair + '_' + rlks + 'rlks.diff'
|
||||
call_str = 'SLC_diff_intf ' + Mrslc + ' ' + Srslc + ' ' + MrslcPar + ' ' + SrslcPar + ' ' + OFF + ' ' + SIM_UNW + ' ' + DIFF_IFG + ' ' + rlks + ' ' + azlks + ' ' + templateDict['Igram_Spsflg'] + ' ' + templateDict['Igram_Azfflg'] + ' - 1 1'
|
||||
_run_or_raise(call_str, 'SLC_diff_intf')
|
||||
_run_slc_diff_intf(
|
||||
Mrslc,
|
||||
Srslc,
|
||||
MrslcPar,
|
||||
SrslcPar,
|
||||
OFF,
|
||||
SIM_UNW,
|
||||
DIFF_IFG,
|
||||
rlks,
|
||||
azlks,
|
||||
templateDict['Igram_Spsflg'],
|
||||
templateDict['Igram_Azfflg'],
|
||||
)
|
||||
if _is_binary_all_zero(DIFF_IFG):
|
||||
if templateDict['Igram_Azfflg'] == '1':
|
||||
print(
|
||||
'SLC_diff_intf produced an all-zero interferogram with azimuth common-band '
|
||||
'filtering enabled; retrying once with Igram_Azfflg=0.'
|
||||
)
|
||||
os.remove(DIFF_IFG)
|
||||
_run_slc_diff_intf(
|
||||
Mrslc,
|
||||
Srslc,
|
||||
MrslcPar,
|
||||
SrslcPar,
|
||||
OFF,
|
||||
SIM_UNW,
|
||||
DIFF_IFG,
|
||||
rlks,
|
||||
azlks,
|
||||
templateDict['Igram_Spsflg'],
|
||||
'0',
|
||||
)
|
||||
if _is_binary_all_zero(DIFF_IFG):
|
||||
raise RuntimeError(
|
||||
'SLC_diff_intf produced an invalid all-zero interferogram after one bounded '
|
||||
'azimuth-filter fallback; no further automatic retries will be attempted: %s' % DIFF_IFG
|
||||
)
|
||||
|
||||
##### filtering process & coherence estimation ###########
|
||||
DIFFFILT = workDir + '/' + Pair + '_' + rlks + 'rlks.diff_filt'
|
||||
|
||||
+46
-33
@@ -32,6 +32,26 @@ def _resolve_existing_master_date(slc_dir, requested_date):
|
||||
print('masterDate %s not found; using existing SLC date: %s' % (requested_date, resolved))
|
||||
return resolved
|
||||
|
||||
|
||||
def _run_or_raise(call_str, stage):
|
||||
rc = os.system(call_str)
|
||||
if rc != 0:
|
||||
raise RuntimeError('%s failed with rc=%s: %s' % (stage, rc, call_str))
|
||||
return rc
|
||||
|
||||
|
||||
def _run_or_warn(call_str, stage):
|
||||
rc = os.system(call_str)
|
||||
if rc != 0:
|
||||
print('WARNING: %s returned rc=%s; continuing with subsequent GAMMA refinement: %s' % (stage, rc, call_str))
|
||||
return rc
|
||||
|
||||
|
||||
def _remove_files(paths):
|
||||
for path in paths:
|
||||
if os.path.isfile(path):
|
||||
os.remove(path)
|
||||
|
||||
def cmdLineParse():
|
||||
parser = argparse.ArgumentParser(description='Generate radar-coordinates based DEM.',\
|
||||
formatter_class=argparse.RawTextHelpFormatter,\
|
||||
@@ -78,38 +98,32 @@ def main(argv):
|
||||
azlks = templateDict['azimuth_looks']
|
||||
|
||||
if not os.path.isdir(processDir):
|
||||
call_str = 'mkdir ' + processDir
|
||||
os.system(call_str)
|
||||
os.makedirs(processDir)
|
||||
|
||||
simDir = scratchDir + '/' + projectName + "/DEM"
|
||||
if not os.path.isdir(simDir):
|
||||
call_str='mkdir ' + simDir
|
||||
|
||||
|
||||
workDir = simDir
|
||||
|
||||
if 'DEM' in templateDict:
|
||||
dem = templateDict['DEM']
|
||||
if not os.path.isfile(dem):
|
||||
dem = DEMDir + '/' + projectName + '/' + projectName + '.dem'
|
||||
call_str = 'echo DEM= ' + dem + ' >> ' + templateFile
|
||||
os.system(call_str)
|
||||
with open(templateFile, 'a') as stream:
|
||||
stream.write('DEM= ' + dem + '\n')
|
||||
templateDict['DEM'] = dem
|
||||
else:
|
||||
dem = DEMDir + '/' + projectName + '/' + projectName + '.dem'
|
||||
call_str = 'echo DEM = ' + dem + ' >> ' + templateFile
|
||||
os.system(call_str)
|
||||
with open(templateFile, 'a') as stream:
|
||||
stream.write('DEM = ' + dem + '\n')
|
||||
|
||||
demPar = dem + ".par"
|
||||
|
||||
if not os.path.isfile(dem):
|
||||
call_str = 'makedem_pyint.py ' + projectName
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'makedem_pyint')
|
||||
|
||||
# Parameter setting for simPhase
|
||||
latovrSimphase = templateDict['dem_lat_ovr']
|
||||
lonovrSimphase = templateDict['dem_lon_ovr']
|
||||
|
||||
rposSimphase = templateDict['Simphase_rpos']
|
||||
azposSimphase = templateDict['Simphase_azpos']
|
||||
rwinSimphase = templateDict['Simphase_rwin']
|
||||
@@ -154,12 +168,7 @@ def main(argv):
|
||||
|
||||
### remove DEM look up table if it existed for considering gamma overlapping
|
||||
|
||||
if os.path.isfile(UTMDEM):
|
||||
os.remove(UTMDEM)
|
||||
if os.path.isfile(UTMDEMpar):
|
||||
os.remove(UTMDEMpar)
|
||||
if os.path.isfile(UTM2RDC):
|
||||
os.remove(UTM2RDC)
|
||||
_remove_files([UTMDEM, UTMDEMpar, UTM2RDC, SIMSARUTM, PIX, LSMAP])
|
||||
|
||||
nWidthUTMDEM0 = ut.read_gamma_par(demPar, 'read', 'width')
|
||||
DateFormat = ut.read_gamma_par(demPar, 'read', 'data_format:')
|
||||
@@ -174,42 +183,46 @@ def main(argv):
|
||||
|
||||
if not os.path.isfile(tmp_dem):
|
||||
call_str = 'replace_values ' + dem + ' -32767 0 ' + tmp_dem + ' ' + nWidthUTMDEM0 + ' 2 ' + DF_type
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'replace_values_dem_voids')
|
||||
call_str = 'cp ' + tmp_dem + ' ' + dem
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'copy_dem_without_voids')
|
||||
|
||||
call_str = "multi_look " + MslcImg + " " + MslcPar + " " + MamprlksImg + " " + MamprlksPar + " " + rlks + " " + azlks
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'multi_look_master_for_dem')
|
||||
|
||||
call_str = 'gc_map1 ' + MamprlksPar + ' ' + '-' + ' ' + demPar + ' ' + dem + ' ' + UTMDEMpar + ' ' + UTMDEM + ' ' + UTM2RDC + ' ' + latovrSimphase + ' ' + lonovrSimphase + ' ' + SIMSARUTM + ' - - - - ' + PIX + ' ' + LSMAP + ' - 3 128'
|
||||
#call_str = 'gc_map2 ' + MamprlksPar + ' ' + demPar + ' ' + dem + ' ' + UTMDEMpar + ' ' + UTMDEM + ' ' + UTM2RDC + ' ' + latovrSimphase + ' ' + lonovrSimphase + ' ' + ' ' + LSMAP + ' - - - - ' + SIMSARUTM + ' - - - ' + PIX
|
||||
os.system(call_str)
|
||||
def run_gc_map1(stage, lat_ovr, lon_ovr):
|
||||
call = 'gc_map1 ' + MamprlksPar + ' ' + '-' + ' ' + demPar + ' ' + dem + ' ' + UTMDEMpar + ' ' + UTMDEM + ' ' + UTM2RDC + ' ' + lat_ovr + ' ' + lon_ovr + ' ' + SIMSARUTM + ' - - - - ' + PIX + ' ' + LSMAP + ' - 3 128'
|
||||
_run_or_raise(call, stage)
|
||||
|
||||
run_gc_map1('gc_map1_initial_dem_segment', latovrSimphase, lonovrSimphase)
|
||||
|
||||
nWidthUTMDEM = ut.read_gamma_par(UTMDEMpar, 'read', 'width')
|
||||
nLinePWR1 = ut.read_gamma_par(MamprlksPar, 'read', 'azimuth_lines')
|
||||
nWidth = ut.read_gamma_par(MamprlksPar, 'read', 'range_samples')
|
||||
|
||||
call_str = 'geocode ' + UTM2RDC + ' ' + SIMSARUTM + ' ' + nWidthUTMDEM + ' ' + SIMSARRDC + ' ' + nWidth + ' ' + nLinePWR1 + ' 0 0'
|
||||
os.system(call_str)
|
||||
# 30 m DEM grids can be much sparser than LT-1 multi-look radar pixels.
|
||||
# Keep this in GAMMA by widening geocode's search radius for RDC filling.
|
||||
call_str = 'geocode ' + UTM2RDC + ' ' + SIMSARUTM + ' ' + nWidthUTMDEM + ' ' + SIMSARRDC + ' ' + nWidth + ' ' + nLinePWR1 + ' 0 0 - - 2 64 1'
|
||||
_run_or_raise(call_str, 'geocode_sim_sar_to_rdc')
|
||||
|
||||
call_str = 'create_diff_par ' + MamprlksPar + ' ' + MamprlksPar + ' ' + SIMDIFFpar + ' 1 < ' + BLANK
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'create_diff_par_sim')
|
||||
|
||||
call_str = 'init_offsetm ' + SIMSARRDC + ' ' + MamprlksImg + ' ' + SIMDIFFpar + ' 2 2 ' + rposSimphase + ' ' + azposSimphase #+ ' - - - 512'
|
||||
os.system(call_str)
|
||||
_run_or_warn(call_str, 'init_offsetm_sim')
|
||||
|
||||
call_str = 'offset_pwrm ' + SIMSARRDC + ' ' + MamprlksImg + ' ' + SIMDIFFpar + ' ' + SIMOFFS + ' ' + SIMSNR + ' ' + rwinSimphase + ' ' + azwinSimphase + ' ' + SIMOFFSET #+ ' - 128 128 ' + threshSimphase
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'offset_pwrm_sim')
|
||||
|
||||
call_str = 'offset_fitm ' + SIMOFFS + ' ' + SIMSNR + ' ' + SIMDIFFpar + ' ' + SIMCOFF + ' ' + SIMCOFFSETS + ' - > ' + OFFSTD
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'offset_fitm_sim')
|
||||
|
||||
call_str = 'gc_map_fine ' + UTM2RDC + ' ' + nWidthUTMDEM + ' ' + SIMDIFFpar + ' ' + UTMTORDC + ' 1'
|
||||
#print(call_str)
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'gc_map_fine')
|
||||
|
||||
call_str = 'geocode ' + UTMTORDC + ' ' + UTMDEM + ' ' + nWidthUTMDEM + ' ' + HGTSIM + ' ' + nWidth + ' ' + nLinePWR1 + ' 0 0 - - 1 1 1'
|
||||
os.system(call_str)
|
||||
call_str = 'geocode ' + UTMTORDC + ' ' + UTMDEM + ' ' + nWidthUTMDEM + ' ' + HGTSIM + ' ' + nWidth + ' ' + nLinePWR1 + ' 0 0 - - 2 64 1'
|
||||
_run_or_raise(call_str, 'geocode_dem_to_rdc')
|
||||
|
||||
|
||||
required_outputs = [UTMDEMpar, UTMDEM, UTMTORDC, HGTSIM]
|
||||
|
||||
+23
-26
@@ -8,21 +8,16 @@
|
||||
import os
|
||||
import sys
|
||||
import argparse
|
||||
import numpy as np
|
||||
|
||||
from pyint import _utils as ut
|
||||
|
||||
|
||||
def sanitize_gamma_float(filepath, valid_max=1e6):
|
||||
"""清理 GAMMA 浮点数据文件中的无效值 (NaN/Inf/极端值 → 0.0)"""
|
||||
data = np.fromfile(filepath, dtype=np.float32)
|
||||
bad_mask = ~np.isfinite(data) | (np.abs(data) > valid_max)
|
||||
n_bad = int(np.sum(bad_mask))
|
||||
if n_bad > 0:
|
||||
data[bad_mask] = 0.0
|
||||
data.tofile(filepath)
|
||||
print(f' [sanitize] {os.path.basename(filepath)}: '
|
||||
f'清理 {n_bad} 个无效像素')
|
||||
def _run_or_raise(call_str, stage):
|
||||
rc = os.system(call_str)
|
||||
if rc != 0:
|
||||
raise RuntimeError('%s failed with rc=%s: %s' % (stage, rc, call_str))
|
||||
return rc
|
||||
|
||||
|
||||
def geocode(inFile, outFile, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp='0'):
|
||||
|
||||
@@ -37,7 +32,7 @@ def geocode(inFile, outFile, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_in
|
||||
else:
|
||||
call_str = 'geocode_back ' + inFile + ' ' + nWidth + ' ' + UTMTORDC + ' ' + outFile + ' ' + nWidthUTMDEM + ' ' + nLineUTMDEM+ ' ' + geo_interp + ' 1'
|
||||
|
||||
os.system(call_str)
|
||||
_run_or_raise(call_str, 'geocode_back_' + os.path.basename(outFile))
|
||||
|
||||
return
|
||||
|
||||
@@ -160,13 +155,10 @@ def geocode_pot(projectName, Pair, templateDict):
|
||||
|
||||
if not os.path.isfile(geo_real):
|
||||
os.system(f'cpx_to_real {geo_disp} {geo_real} {eqa_width} 0')
|
||||
sanitize_gamma_float(geo_real, disp_max_m)
|
||||
if not os.path.isfile(geo_imag):
|
||||
os.system(f'cpx_to_real {geo_disp} {geo_imag} {eqa_width} 1')
|
||||
sanitize_gamma_float(geo_imag, disp_max_m)
|
||||
if not os.path.isfile(geo_mag):
|
||||
os.system(f'cpx_to_real {geo_disp} {geo_mag} {eqa_width} 3')
|
||||
sanitize_gamma_float(geo_mag, disp_max_m)
|
||||
|
||||
# ===== Step D: 地理编码 MLI 背景 =====
|
||||
geo_mli = workDir + '/geo_' + masterDate + '.mli'
|
||||
@@ -288,10 +280,13 @@ def main(argv):
|
||||
|
||||
# --- 基础产品地理编码 (hyp3/licsbas 均需) ---
|
||||
geo_interp = templateDict['geo_interp']
|
||||
atmcor_use_for_disp = str(templateDict.get('atmcor_use_for_disp', '0')).strip() == '1'
|
||||
geocode(Mamp, GeoMamp, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
geocode(CORIFG, GeoCOR, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
geocode(DIFFIFG, GeoDIFF, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
geocode(UNWIFG, GeoUNW, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
if os.path.isfile(ATMCOR_UNW):
|
||||
geocode(ATMCOR_UNW, GeoATMCOR_UNW, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
geocode(diffifg, geodiff, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
geocode(rdcdem, Geodem, UTMTORDC, nWidth, nWidthUTMDEM, nLineUTMDEM, geo_interp=geo_interp)
|
||||
|
||||
@@ -303,29 +298,31 @@ def main(argv):
|
||||
# --- hyp3 专属: dispmap (LOS/vert 位移场) ---
|
||||
if need_hyp3:
|
||||
print(' [hyp3] dispmap + geocode 位移场')
|
||||
los_disp_rdc = workDir + '/' + Pair + '_' + rlks + 'rlks.los_disp'
|
||||
vert_disp_rdc = workDir + '/' + Pair + '_' + rlks + 'rlks.vert_disp'
|
||||
disp_unw_source = ATMCOR_UNW if atmcor_use_for_disp and os.path.isfile(ATMCOR_UNW) else UNWIFG
|
||||
disp_tag = '.atmcor' if disp_unw_source == ATMCOR_UNW else ''
|
||||
los_disp_rdc = workDir + '/' + Pair + '_' + rlks + 'rlks' + disp_tag + '.los_disp'
|
||||
vert_disp_rdc = workDir + '/' + Pair + '_' + rlks + 'rlks' + disp_tag + '.vert_disp'
|
||||
|
||||
if os.path.isfile(UNWIFG) and os.path.isfile(SLCpar) and os.path.isfile(OFFpar):
|
||||
if os.path.isfile(disp_unw_source) and os.path.isfile(SLCpar) and os.path.isfile(OFFpar):
|
||||
hgt_arg = rdcdem if os.path.isfile(rdcdem) else '-'
|
||||
if not os.path.isfile(los_disp_rdc):
|
||||
os.system(f'dispmap {UNWIFG} {hgt_arg} {SLCpar} {OFFpar} {los_disp_rdc} 0')
|
||||
_run_or_raise(f'dispmap {disp_unw_source} {hgt_arg} {SLCpar} {OFFpar} {los_disp_rdc} 0', 'dispmap_los')
|
||||
if not os.path.isfile(vert_disp_rdc):
|
||||
os.system(f'dispmap {UNWIFG} {hgt_arg} {SLCpar} {OFFpar} {vert_disp_rdc} 1')
|
||||
_run_or_raise(f'dispmap {disp_unw_source} {hgt_arg} {SLCpar} {OFFpar} {vert_disp_rdc} 1', 'dispmap_vertical')
|
||||
|
||||
geo_los = workDir + '/geo_' + Pair + '_' + rlks + 'rlks.los_disp'
|
||||
geo_vert = workDir + '/geo_' + Pair + '_' + rlks + 'rlks.vert_disp'
|
||||
geo_los = workDir + '/geo_' + Pair + '_' + rlks + 'rlks' + disp_tag + '.los_disp'
|
||||
geo_vert = workDir + '/geo_' + Pair + '_' + rlks + 'rlks' + disp_tag + '.vert_disp'
|
||||
if os.path.isfile(los_disp_rdc) and not os.path.isfile(geo_los):
|
||||
os.system(f'geocode_back {los_disp_rdc} {nWidth} {UTMTORDC} {geo_los} {nWidthUTMDEM} {nLineUTMDEM} 1 0')
|
||||
_run_or_raise(f'geocode_back {los_disp_rdc} {nWidth} {UTMTORDC} {geo_los} {nWidthUTMDEM} {nLineUTMDEM} {geo_interp} 0', 'geocode_back_los_disp')
|
||||
if os.path.isfile(vert_disp_rdc) and not os.path.isfile(geo_vert):
|
||||
os.system(f'geocode_back {vert_disp_rdc} {nWidth} {UTMTORDC} {geo_vert} {nWidthUTMDEM} {nLineUTMDEM} 1 0')
|
||||
_run_or_raise(f'geocode_back {vert_disp_rdc} {nWidth} {UTMTORDC} {geo_vert} {nWidthUTMDEM} {nLineUTMDEM} {geo_interp} 0', 'geocode_back_vert_disp')
|
||||
|
||||
# --- hyp3 专属: 缠绕相位 ---
|
||||
if need_hyp3:
|
||||
print(' [hyp3] 提取缠绕相位')
|
||||
geo_wrapped_pha = workDir + '/geo_' + Pair + '_' + rlks + 'rlks.diff_filt.pha'
|
||||
if os.path.isfile(GeoDIFF) and not os.path.isfile(geo_wrapped_pha):
|
||||
os.system(f'cpx_to_real {GeoDIFF} {geo_wrapped_pha} {nWidthUTMDEM} 4')
|
||||
_run_or_raise(f'cpx_to_real {GeoDIFF} {geo_wrapped_pha} {nWidthUTMDEM} 4', 'cpx_to_real_wrapped_phase')
|
||||
|
||||
# --- hyp3/licsbas 共需: look_vector ---
|
||||
if need_hyp3 or need_licsbas:
|
||||
@@ -334,7 +331,7 @@ def main(argv):
|
||||
lv_phi = workDir + '/lv_phi'
|
||||
if not os.path.isfile(lv_theta) or not os.path.isfile(lv_phi):
|
||||
if os.path.isfile(SLCpar) and os.path.isfile(OFFpar) and os.path.isfile(UTMDEMpar0) and os.path.isfile(UTMDEM):
|
||||
os.system(f'look_vector {SLCpar} {OFFpar} {UTMDEMpar0} {UTMDEM} {lv_theta} {lv_phi}')
|
||||
_run_or_raise(f'look_vector {SLCpar} {OFFpar} {UTMDEMpar0} {UTMDEM} {lv_theta} {lv_phi}', 'look_vector')
|
||||
|
||||
# --- BMP 可视化 ---
|
||||
os.system('rasmph_pwr ' + GeoDIFF + ' ' + GeoMamp + ' ' + nWidthUTMDEM + ' - - - - ')
|
||||
|
||||
+1
-1
@@ -114,7 +114,6 @@ def _build_dem_from_existing_source(
|
||||
|
||||
print(f"Using prepared DEM source: {source_dem}")
|
||||
print(f"Clipping prepared DEM window: west={west}, south={south}, east={east}, north={north}")
|
||||
|
||||
_run_checked(
|
||||
[
|
||||
"gdal_translate",
|
||||
@@ -130,6 +129,7 @@ def _build_dem_from_existing_source(
|
||||
],
|
||||
cwd=str(work_dir),
|
||||
)
|
||||
|
||||
_run_checked(
|
||||
[
|
||||
"makedem.py",
|
||||
|
||||
+4
@@ -193,6 +193,10 @@ diff_all_parallel = 4 # Number of parallel processors
|
||||
unwrap_all = 1 # Unwrap interferograms [0: skip; 1: process]
|
||||
unwrap_all_parallel = 4 # Number of parallel processors
|
||||
|
||||
atmcor_all = 0 # Gamma atmospheric phase correction [0: skip; 1: process]
|
||||
atmcor_all_parallel = 1 # Number of parallel processors
|
||||
atmcor_use_for_disp = 0 # Use atmcor unwrapped phase for dispmap [0: no; 1: yes]
|
||||
|
||||
geocode_all = 1 # Geocode products [0: skip; 1: process]
|
||||
geocode_all_parallel = 4 # Number of parallel processors
|
||||
|
||||
|
||||
-1
@@ -108,7 +108,6 @@ def main(argv):
|
||||
CORMASK = workDir + '/' + Pair + '_' +rlks + 'rlks.diff_filt.cor'
|
||||
WRAPlks = workDir + '/' + Pair + '_' +rlks + 'rlks.diff_filt'
|
||||
UNWlks = workDir + '/' + Pair + '_' +rlks + 'rlks.diff_filt.unw'
|
||||
|
||||
CORMASKbmp = CORMASK.replace('.diff_filt.cor','.diff_filt.cor_mask.bmp')
|
||||
|
||||
if os.path.isfile(CORMASKbmp):
|
||||
|
||||
Reference in New Issue
Block a user