"""Provision governed DHMV II terrain/surface rasters for the persisted Mol Area. The operator calls the canonical GeoIntel DHMV acquisition API. The backend performs the bounded official WCS request, exact Area clipping, validation, checksum storage and Dataset/Job persistence. No raster rows are written directly by this script. """ from __future__ import annotations import argparse import json import os from typing import Any, Iterable import requests DEFAULT_API_URL = "http://127.0.0.1:8000" DEFAULT_PROJECT_NAME = "Kempen Regional Workbench" DEFAULT_AREA_FRAGMENT = "Gemeente Mol" PRODUCTS = ("dtm_1m", "dsm_1m") def parse_args() -> argparse.Namespace: parser = argparse.ArgumentParser(description="Provision official DHMV II DTM/DSM rasters for Mol.") parser.add_argument("--base-url", default=os.environ.get("GEOINTEL_INTERNAL_API_URL", DEFAULT_API_URL)) parser.add_argument("--project-name", default=DEFAULT_PROJECT_NAME) parser.add_argument("--area-name", default=DEFAULT_AREA_FRAGMENT) parser.add_argument("--products", default=",".join(PRODUCTS), help="Comma-separated governed product keys.") parser.add_argument("--resolution-m", type=float, default=5.0) parser.add_argument("--timeout", type=int, default=1800) parser.add_argument("--force", action="store_true") return parser.parse_args() def unwrap(response: requests.Response) -> Any: response.raise_for_status() payload = response.json() if not isinstance(payload, dict) or "data" not in payload: raise RuntimeError(f"Non-canonical API response from {response.url}") return payload["data"] def coordinates(geometry: dict[str, Any]) -> Iterable[tuple[float, float]]: def walk(value: Any): if isinstance(value, list) and len(value) >= 2 and all(isinstance(item, (int, float)) for item in value[:2]): yield float(value[0]), float(value[1]) return if isinstance(value, list): for child in value: yield from walk(child) yield from walk(geometry.get("coordinates", [])) def geometry_bbox(geometry: dict[str, Any]) -> dict[str, float | str]: points = list(coordinates(geometry)) if not points: raise RuntimeError("Persisted Area geometry contains no coordinates") xs = [point[0] for point in points] ys = [point[1] for point in points] return { "min_x": min(xs), "min_y": min(ys), "max_x": max(xs), "max_y": max(ys), "crs": "EPSG:4326", } def main() -> int: args = parse_args() base_url = args.base_url.rstrip("/") session = requests.Session() session.headers.update({"User-Agent": "GeoIntel-DHMV-Operator/1.0"}) projects = unwrap(session.get(f"{base_url}/api/v1/projects", params={"limit": 200, "offset": 0}, timeout=60))["items"] project = next((item for item in projects if item["name"] == args.project_name), None) if project is None: raise RuntimeError(f"Project {args.project_name!r} was not found") areas = unwrap( session.get( f"{base_url}/api/v1/projects/{project['id']}/areas", params={"limit": 200, "offset": 0}, timeout=60, ) )["items"] fragment = args.area_name.casefold() area = next((item for item in areas if fragment in item["name"].casefold()), None) if area is None: raise RuntimeError(f"Area containing {args.area_name!r} was not found") bbox = geometry_bbox(area["geometry"]) requested_products = [item.strip() for item in args.products.split(",") if item.strip()] invalid = sorted(set(requested_products) - set(PRODUCTS)) if invalid: raise RuntimeError(f"Unsupported DHMV product keys: {', '.join(invalid)}") results = [] for product_key in requested_products: job = unwrap( session.post( f"{base_url}/api/v1/projects/{project['id']}/datasets/dhmv/acquire", json={ "bbox": bbox, "area_id": area["id"], "product_key": product_key, "resolution_m": args.resolution_m, "force_refresh": args.force, }, timeout=args.timeout, ) ) if job.get("status") != "success" or not job.get("output_dataset_id"): raise RuntimeError(f"DHMV acquisition failed for {product_key}: {job.get('error_message') or job}") analysis = unwrap( session.post( f"{base_url}/api/v1/projects/{project['id']}/datasets/{job['output_dataset_id']}/raster/terrain/select", json={"bbox": bbox, "area_id": area["id"]}, timeout=args.timeout, ) ) if sorted(analysis.get("unsupported_metrics", [])) != ["water_depth_m", "water_volume_m3"]: raise RuntimeError("DHMV terrain contract must explicitly keep water depth and volume unavailable") results.append( { "product_key": product_key, "dataset_id": job["output_dataset_id"], "reused": bool((job.get("result_json") or {}).get("reused")), "resolution_m": analysis["resolution_m"], "sample_count": analysis["sample_count"], "coverage_ratio": analysis["coverage_ratio"], "metrics": analysis["summary"]["metrics"], } ) print( json.dumps( { "status": "ok", "project_id": project["id"], "area_id": area["id"], "area_name": area["name"], "bbox": bbox, "products": results, }, ensure_ascii=False, indent=2, ) ) return 0 if __name__ == "__main__": raise SystemExit(main())