diff --git a/.env.example b/.env.example index 4e9e677..0c5ff04 100644 --- a/.env.example +++ b/.env.example @@ -23,9 +23,11 @@ DB_SCHEMA_RESET_CONFIRM=false AUTH_SESSION_COOKIE_NAME=ims_session AUTH_COOKIE_SAMESITE=lax AUTH_COOKIE_SECURE=false +AUTH_PBKDF2_ITERATIONS=240000 AUTH_LOGIN_MAX_FAILURES=5 AUTH_LOGIN_WINDOW_SECONDS=300 AUTH_LOGIN_LOCK_SECONDS=600 +TRUSTED_PROXY_IPS=127.0.0.1 # ----------------------------------------------------------------------------- @@ -41,10 +43,12 @@ CONDA_ENV_NAME= NGINX_PATH=C:\nginx\nginx.exe NGINX_HEALTH_URL=http://127.0.0.1/ +LICENSE_PATH= CORS_ORIGINS=http://127.0.0.1:5173,http://localhost CORS_ALLOW_CREDENTIALS=true CORS_STRICT_MODE=false +ALLOWED_EXPORT_DIRS= # ----------------------------------------------------------------------------- @@ -61,6 +65,8 @@ GF3_STORAGE_DIRS=D:\GF3_L2_Image HAZARD_POINTS_DIR=D:\Code\Insar_management_system_v2\backend\Point HAZARD_POINTS_FILENAME=Point.shp +AOI_REGION_INDEX_FILE= +AOI_REGION_GEOJSON_FILE= # ----------------------------------------------------------------------------- @@ -69,6 +75,7 @@ HAZARD_POINTS_FILENAME=Point.shp RESULT_PUBLISH_ROOT=D:\production_results DINSAR_PRODUCT_DIR=D:\production_results\dinsar TIMESERIES_PRODUCT_DIR=D:\production_results\timeseries +PSINSAR_PRODUCT_DIR=D:\production_results\timeseries RESULT_QUARANTINE_ROOT=D:\production_results\_quarantine RESULT_CATALOG_AUTO_REBUILD_ON_STARTUP=true @@ -80,6 +87,7 @@ RESULT_CATALOG_AUTO_REBUILD_ON_STARTUP=true ORBIT_POOL_ENVI=D:\orbit_pools\envi ORBIT_POOL_ISCE2=D:\orbit_pools\isce2 ORBIT_POOL_LANDSAR= +ORBIT_QUARANTINE_DIR= # ----------------------------------------------------------------------------- @@ -112,6 +120,7 @@ IDL_DINSAR_CUSTOM_GEOCODING_COH_THRESHOLD=0.0 IDL_DINSAR_CUSTOM_GEOCODING_PIXEL_SIZE_M=10.0 ENVI_TASK_TIMEOUT_SECONDS=21600 +ENVI_PER_TASK_TIMEOUT=21600 ENVI_FILE_STALE_SECONDS=43200 ENVI_STABILITY_CHECK_INTERVAL=15 ENVI_STABILITY_ROUNDS=3 @@ -169,6 +178,7 @@ PYINT_FABDEM_ROOT= # When PYINT_DEM_MODE=prepared_file, point this to the same prepared WGS84 DEM. PYINT_PREPARED_DEM_PATH= PYINT_OPENTOPO_DEM_TYPE=SRTMGL1 +PYINT_OPENTOPO_API_KEY= PYINT_DEM_STRICT=true PYINT_ORBIT_POLICY=require_txt PYINT_ORBIT_POOL_TXT=D:\orbit_pools\envi @@ -202,8 +212,13 @@ TIMESERIES_STACK_RUNNER_SCRIPT= TIMESERIES_MINTPY_SBAS_SCRIPT= TIMESERIES_EXPORT_PUBLISH_SCRIPT= TIMESERIES_STACK_WORKFLOW=interferogram +TIMESERIES_DEFAULT_PROCESSOR_CODE=isce2_stack_mintpy TIMESERIES_WSL_STEP_TIMEOUT_SECONDS=7200 TIMESERIES_ALLOW_SYNTHETIC_WATER_MASK=true +SARSCAPE_SBAS_PARAMETER_TEMPLATE_PATH= +SARSCAPE_SBAS_ALLOW_EXECUTION=false +SARSCAPE_SBAS_DISCOVERY_TIMEOUT_SECONDS=120 +SARSCAPE_SBAS_STEP_TIMEOUT_SECONDS=21600 # ----------------------------------------------------------------------------- diff --git a/backend/app/isce2_pipeline/run_lt1_dinsar_pipeline.py b/backend/app/isce2_pipeline/run_lt1_dinsar_pipeline.py index ae87d67..93ef86b 100644 --- a/backend/app/isce2_pipeline/run_lt1_dinsar_pipeline.py +++ b/backend/app/isce2_pipeline/run_lt1_dinsar_pipeline.py @@ -968,6 +968,59 @@ def has_pickle_state(work_dir: Path, state_name: str) -> bool: return (pickle_dir / state_name).exists() and (pickle_dir / f"{state_name}.xml").exists() +def copy_pickle_state(work_dir: Path, source_state: str, target_state: str) -> Path: + pickle_dir = work_dir / "PICKLE" + src = pickle_dir / source_state + src_xml = pickle_dir / f"{source_state}.xml" + dst = pickle_dir / target_state + dst_xml = pickle_dir / f"{target_state}.xml" + + if not src.exists() or not src_xml.exists(): + raise FileNotFoundError( + f"PICKLE/{source_state} state is missing; cannot prepare PICKLE/{target_state}." + ) + + shutil.copy2(src, dst) + shutil.copy2(src_xml, dst_xml) + return dst_xml + + +def prepare_no_ionosphere_snaphu_resume(work_dir: Path, bbox: list[float] | None) -> None: + dst_xml = copy_pickle_state(work_dir, "filter", "filter_high_band") + root = ET.fromstring(dst_xml.read_text(encoding="utf-8")) + props = {prop.attrib.get("name"): prop for prop in root.findall("property")} + + required = { + "referenceslccroppedproduct": "reference_slc.xml", + "secondaryslccroppedproduct": "secondary_slc.xml", + "referenceslcproduct": "reference_slc.xml", + "secondaryslcproduct": "secondary_slc.xml", + "referencegeometrysystem": "Zero Doppler", + "secondarygeometrysystem": "Zero Doppler", + } + if bbox is not None: + required["estimatedboundingbox"] = str(bbox) + + for name, value in required.items(): + if name in props: + node = props[name].find("value") + if node is None: + node = ET.SubElement(props[name], "value") + node.text = value + continue + + prop = ET.SubElement(root, "property", {"name": name}) + ET.SubElement(prop, "value").text = value + + dst_xml.write_text(ET.tostring(root, encoding="unicode"), encoding="utf-8") + print("Prepared no-ionosphere SNAPHU resume state: PICKLE/filter_high_band", flush=True) + + +def prepare_no_ionosphere_geocode_resume(work_dir: Path) -> None: + copy_pickle_state(work_dir, "unwrap", "ionosphere") + print("Prepared no-ionosphere geocode resume state: PICKLE/ionosphere", flush=True) + + def resolve_unwrap_start_step(work_dir: Path, *, ionosphere_correction: bool) -> str: if ionosphere_correction: if has_pickle_state(work_dir, "ionosphere"): @@ -1181,6 +1234,8 @@ def main() -> int: write_stripmap_xml(xml_path, config) if should_run_stage(start_stage, "unwrap"): + if not config.ionosphere_correction: + prepare_no_ionosphere_snaphu_resume(work_dir, config.bbox) unwrap_start_step = resolve_unwrap_start_step( work_dir, ionosphere_correction=config.ionosphere_correction, @@ -1202,6 +1257,8 @@ def main() -> int: ) if should_run_stage(start_stage, "geocode"): + if not config.ionosphere_correction: + prepare_no_ionosphere_geocode_resume(work_dir) geocode_start_step = resolve_geocode_start_step( work_dir, ionosphere_correction=config.ionosphere_correction,