Files
Aislo/resources/tester/test_347_1_descent_store.py
T

132 lines
5.3 KiB
Python

"""347-1 흐름 방향 · 도엽 좌표 저장 — 저장본을 읽어도 결과 같음 · 두 번째는 짓지 않음.
- 격자 원점 = 좌표 정수 m(셀 모서리 0,0) — 노선이 바뀌어도 같은 자리 셀은 같은 자리.
- 방향장 저장본: 입력 지문(도엽 지문 · 등고 단 · 셀) 같고 범위가 덮으면 읽기만 · 최근 2벌.
- 도엽 좌표 저장본: 원본 자국 · 좌표계가 같으면 다시 안 바꿈.
실측(검증_sub3 · 차이 0칸 · 108 → 10.8 s 붐빔 · 340 기준 약 6 s)은 bench_342_watershed.py.
"""
import math
import numpy as np
from shapely.geometry import LineString
from B04_PreProcess import B04_PreProcess_Engine_Watershed_Expand as expand
from B04_PreProcess import B04_PreProcess_Router_Watershed as router
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Descent import (
descent_input_key,
iter_saved_descents,
)
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Grid import (
GRID_ORIGIN_XY,
GridSpec,
grid_spec_from_bounds,
)
def _contours():
features = []
for radius in range(10, 200, 10):
coords = [
[150.0 + radius * math.cos(t), -150.0 + radius * math.sin(t)]
for t in np.linspace(0, 2 * math.pi, 241)
]
features.append(
{
"geometry": {"type": "LineString", "coordinates": coords},
"properties": {"elevation": 300.0 - radius},
}
)
return features
def test_grid_origin_is_integer_metre():
assert GRID_ORIGIN_XY == (0.0, 0.0)
spec = grid_spec_from_bounds(10.37, -80.6, 90.2, -3.4, 1.0, anchor_xy=GRID_ORIGIN_XY)
assert spec.x_min == 10.0 and spec.y_max == -3.0
def test_input_key_follows_contours():
contours = _contours()
base = descent_input_key("도엽-1", contours, 1.0)
assert base == descent_input_key("도엽-1", contours, 1.0)
assert base != descent_input_key("도엽-2", contours, 1.0) # 도엽 · 좌표계 바뀜
assert base != descent_input_key("도엽-1", contours[:-1], 1.0) # 등고 단 바뀜
def _run(store, monkeypatch, counter):
real = expand.build_contour_descent
def counting(*args, **kwargs):
counter.append(1)
return real(*args, **kwargs)
monkeypatch.setattr(expand, "build_contour_descent", counting)
spec = GridSpec(x_min=100.0, y_max=-100.0, cell_m=1.0, n_rows=100, n_cols=100)
domain = np.zeros((100, 100), bool)
domain[20:80, 20:80] = True
route = LineString([(110.0, -150.0), (190.0, -150.0)])
result = expand.expand_by_red_boundary(
spec, domain, _contours(), route, [], None, descent_store=store
)
return result.analysis
def test_store_gives_same_result_and_reads_second_time(tmp_path, monkeypatch):
monkeypatch.setattr(expand, "DESCENT_SPARE_M", 40.0)
built: list[int] = []
plain = _run(None, monkeypatch, built)
store = (tmp_path, "도엽-1")
first = _run(store, monkeypatch, built)
count_after_first = len(built)
second = _run(store, monkeypatch, built)
assert len(built) == count_after_first # 두 번째는 짓지 않음
for analysis in (first, second):
assert analysis.spec == plain.spec
assert np.array_equal(analysis.flow.reaches_road, plain.flow.reaches_road)
assert np.array_equal(analysis.descent.receiver, plain.descent.receiver)
saved = list(tmp_path.glob("descent_*.npz"))
assert 1 <= len(saved) <= 2
key = descent_input_key("도엽-1", _contours(), 1.0)
assert next(iter_saved_descents(tmp_path, key)).spec.n_rows >= plain.spec.n_rows
def test_store_keeps_two_newest(tmp_path, monkeypatch):
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Descent import save_descent
monkeypatch.setattr(expand, "DESCENT_SPARE_M", 0.0)
analysis = _run(None, monkeypatch, [])
for index in range(3):
moved = GridSpec(100.0 + index, -100.0, 1.0, analysis.spec.n_rows, analysis.spec.n_cols)
descent = analysis.descent
save_descent(tmp_path, "key", type(descent)(**{**descent.__dict__, "spec": moved}))
assert len(list(tmp_path.glob("descent_*.npz"))) == 2
def test_metric_sheets_cached_until_source_changes(tmp_path, monkeypatch):
sheets = tmp_path / "sheets"
sheets.mkdir()
feature = {
"type": "Feature",
"properties": {"elevation": 10},
"geometry": {"type": "LineString", "coordinates": [[0, 0], [1, 1]]},
}
import json
for name in (router.STREAM_FILE, router.CONTOUR_FILE):
(sheets / name).write_text(json.dumps({"features": [feature]}), "utf-8")
calls = []
real = router._reproject_features
monkeypatch.setattr(
router, "_reproject_features", lambda f, t: calls.append(1) or real(f, None)
)
first = router._metric_sheets(sheets, tmp_path / "drainage", "EPSG:5186", None)
again = router._metric_sheets(sheets, tmp_path / "drainage", "EPSG:5186", None)
assert len(calls) == 2 and first == again # 두 번째는 저장본
router._metric_sheets(sheets, tmp_path / "drainage", "EPSG:5179", None) # 좌표계 바뀜
assert len(calls) == 4
# 메모리 보관(520-2) — 저장본 파일이 없어도 다시 재투영하지 않음
(tmp_path / "drainage" / router.SHEET_METRIC_FILENAME).unlink()
router._metric_sheets(sheets, tmp_path / "drainage", "EPSG:5179", None)
assert len(calls) == 4