perf(배수유역): 347-1 흐름 방향 · 도엽 좌표 저장 — 격자 원점 좌표 정수 m · 노선이 범위 안이면 읽기만
- 격자 원점 = 좌표 정수 m(GRID_ORIGIN_XY · 옛 「도로 시작점」 지시를 바꿈 · 사용자 확정) - 흐름 방향 저장본 drainage/descent_<입력 지문>_<범위>.npz — 입력 지문 = 도엽 등고선 지문 + 남긴 등고 단 + 셀 + 계산 규칙 · 덮으면 읽어 잘라 씀 · 최근 2벌 - 도엽(하천 · 등고선) 사업지 좌표 저장본 drainage/00_sheet_metric.pkl — 원본 자국 · 좌표계가 같으면 재투영 안 함 - 검증_sub3 실측: 저장본 읽기 = 지은 것과 칸마다 같음(적색 · 해석 영역 · 화살표 · 귀속 차이 0) · 108 → 10.8 s(붐빔 · 340 기준 약 6 s) · 원점 바뀜으로 적색 460,035 → 459,792칸(−0.05 %) · 관 자리 같음 - 시험 test_347_1_descent_store · 실측 bench 저장본 갈래 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
This commit is contained in:
@@ -22,10 +22,14 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import time
|
||||
import math
|
||||
import time
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
@@ -349,6 +353,99 @@ def build_contour_descent(
|
||||
)
|
||||
|
||||
|
||||
# ── 흐름 방향 저장본(347-1) ─────────────────────────────────────────────
|
||||
#
|
||||
# 방향장은 등고선 · 남긴 등고 단 · 격자(원점 · 셀 · 범위)만으로 정해진다. 원점이 좌표 정수 m 라
|
||||
# 노선이 저장 범위 안이면 읽어서 잘라 쓴다. 파일 이름 = descent_<입력 지문>_<범위 지문>.npz ·
|
||||
# 종류마다 최근 2벌만 남긴다. 계산 규칙이 바뀌면 `DESCENT_FILE_VERSION` 을 올린다.
|
||||
DESCENT_FILE_VERSION = 1
|
||||
_DESCENT_KEEP = 2
|
||||
|
||||
|
||||
def descent_input_key(
|
||||
contour_key: str,
|
||||
contour_features: list[dict[str, Any]],
|
||||
elevation_floor_m: float | None,
|
||||
cell_m: float,
|
||||
) -> str:
|
||||
"""방향장 입력 지문 — 도엽 등고선 지문 + 남긴 등고 단 + 셀 + 계산 규칙 값.
|
||||
|
||||
남긴 단은 속성 표고만 본다 — 같은 도엽 · 같은 단 집합이면 남는 선도 같다(길이 거름은 결정적).
|
||||
"""
|
||||
levels = sorted(
|
||||
{
|
||||
elevation
|
||||
for feature in contour_features
|
||||
if feature.get("geometry")
|
||||
and (elevation := _feature_elevation(feature.get("properties") or {})) is not None
|
||||
and (elevation_floor_m is None or elevation >= elevation_floor_m)
|
||||
}
|
||||
)
|
||||
text = json.dumps(
|
||||
[
|
||||
DESCENT_FILE_VERSION,
|
||||
contour_key,
|
||||
levels,
|
||||
cell_m,
|
||||
DRAINAGE_CONTOUR_MIN_LENGTH_M,
|
||||
DESCENT_WINDOW_MARGIN_CELLS,
|
||||
DESCENT_TILE_CELLS,
|
||||
]
|
||||
)
|
||||
return hashlib.sha1(text.encode(), usedforsecurity=False).hexdigest()[:16]
|
||||
|
||||
|
||||
def iter_saved_descents(directory: Path, input_key: str) -> Iterator[ContourDescent]:
|
||||
"""같은 입력 지문으로 저장한 방향장 — 최근 것부터. 못 읽는 파일은 건너뜀."""
|
||||
paths = sorted(
|
||||
directory.glob(f"descent_{input_key}_*.npz"),
|
||||
key=lambda path: path.stat().st_mtime,
|
||||
reverse=True,
|
||||
)
|
||||
for path in paths:
|
||||
try:
|
||||
with np.load(path, allow_pickle=False) as data:
|
||||
x_min, y_max, cell_m, n_rows, n_cols = data["spec"].tolist()
|
||||
yield ContourDescent(
|
||||
spec=GridSpec(
|
||||
float(x_min), float(y_max), float(cell_m), int(n_rows), int(n_cols)
|
||||
),
|
||||
band_elevation=data["band_elevation"],
|
||||
valid=data["valid"],
|
||||
receiver=data["receiver"],
|
||||
step_length=data["step_length"],
|
||||
azimuth=data["azimuth"],
|
||||
levels=data["levels"].tolist(),
|
||||
)
|
||||
except (OSError, KeyError, ValueError):
|
||||
logger.warning("배수유역: 흐름 방향 저장본을 읽지 못해 건너뜁니다 (%s).", path)
|
||||
|
||||
|
||||
def save_descent(directory: Path, input_key: str, descent: ContourDescent) -> None:
|
||||
"""방향장을 저장하고 최근 2벌만 남긴다. 실패는 로그만(계산은 이어감)."""
|
||||
spec = descent.spec
|
||||
extent = f"{spec.x_min:.3f},{spec.y_max:.3f},{spec.n_rows},{spec.n_cols}"
|
||||
extent_key = hashlib.sha1(extent.encode(), usedforsecurity=False).hexdigest()[:8]
|
||||
path = directory / f"descent_{input_key}_{extent_key}.npz"
|
||||
try:
|
||||
directory.mkdir(parents=True, exist_ok=True)
|
||||
np.savez(
|
||||
path,
|
||||
spec=np.array([spec.x_min, spec.y_max, spec.cell_m, spec.n_rows, spec.n_cols]),
|
||||
band_elevation=descent.band_elevation,
|
||||
valid=descent.valid,
|
||||
receiver=descent.receiver,
|
||||
step_length=descent.step_length,
|
||||
azimuth=descent.azimuth,
|
||||
levels=np.array(descent.levels, dtype=np.float64),
|
||||
)
|
||||
olds = sorted(directory.glob("descent_*.npz"), key=lambda item: item.stat().st_mtime)
|
||||
for old in olds[:-_DESCENT_KEEP]:
|
||||
old.unlink(missing_ok=True)
|
||||
except OSError:
|
||||
logger.warning("배수유역: 흐름 방향 저장본을 남기지 못했습니다 (%s).", path)
|
||||
|
||||
|
||||
def _route_by_potential(
|
||||
spec: GridSpec,
|
||||
potential: np.ndarray,
|
||||
|
||||
Reference in New Issue
Block a user