"""B08 수리 표 ← B05 배수유역 연결값 (PLAN 96-1 · 96-3). 견본 세부유역 + 관 지점 → 측점마다 linked(A · L · H · 관경 · 박스 내공 · 월류 폭) · 그 값으로 계산한 Qd ≈ B05 설계유량 · 표준값은 B05 배수 설정 하나. """ from __future__ import annotations import json import sys from pathlib import Path import pytest ROOT = Path(__file__).resolve().parents[2] sys.path.insert(0, str(ROOT)) from B08_Quantity.B08_Quantity_Engine_Hydro import compute # noqa: E402 from B08_Quantity.B08_Quantity_Hydro_Defaults import DEFAULTS, station_rows # noqa: E402 from B08_Quantity.B08_Quantity_Hydro_Site import BASINS_FILE, read_basins # noqa: E402 from common_util.common_util_drainage_detail import size_pipe # noqa: E402 from common_util.common_util_drainage_pipes import PipePoint # noqa: E402 from common_util.common_util_wamis_station import mononobe_idf # noqa: E402 from config import config_system_design as cfg # noqa: E402 R24 = 231.56 BASINS = [ # B05 저장 꼴 — 측점 0.01 반올림 · 면적 0.1 · 표고차 0.01 · 길이 0.1 {"kind": "detail_basin", "chainage_m": 85.05, "area_m2": 10717.0, "flow_length_m": 163.9, "relief_m": 120.0}, {"kind": "detail_basin", "chainage_m": 173.09, "area_m2": 141145.0, "flow_length_m": 603.3, "relief_m": 320.0}, {"kind": "detail_basin", "chainage_m": 300.0, "area_m2": 52000.0, "flow_length_m": 410.0, "relief_m": 0.0}, ] # fmt: skip for _b in BASINS: _out = size_pipe( _b["area_m2"], max(_b["relief_m"], 0.1), _b["flow_length_m"], mononobe_idf(R24) ) _b.update(design_flow_m3s=_out["design_flow_m3s"], tc_minutes=_out["tc_minutes"]) POINTS = [ PipePoint(chainage_m=300.004, facility="box_culvert", options={"body_width_m": 2.0, "body_height_m": 1.5}), PipePoint(chainage_m=85.052, options={"pipe_diameter_mm": "1000", "pipe_kind": "파형강관"}), PipePoint(chainage_m=173.09, facility="ford_bridge", options={"ford_width_m": 10}), PipePoint(chainage_m=500.0, options={"pipe_diameter_mm": 800}), # 유역 짝 없음 ] # fmt: skip def test_측점마다_연결값() -> None: rows = station_rows(POINTS, BASINS) assert [r["chainage_m"] for r in rows] == [85.052, 173.09, 300.004, 500.0] pipe, ford, box, lone = (r["linked"] for r in rows) assert pipe == { "area_km2": 0.010717, "length_m": 163.9, "height_m": 120.0, "diameter_mm": 1000.0, } assert ford == {"area_km2": 0.141145, "length_m": 603.3, "height_m": 320.0, "overflow_width_m": 10.0} # fmt: skip # 표고차 0 은 빈칸(저장 검사 gt 0) · 박스는 내공 assert box == {"area_km2": 0.052, "length_m": 410.0, "box_width_m": 2.0, "box_height_m": 1.5} # 유역 짝이 없으면 시설 치수만 · B05 참고값 없음 assert lone == {"diameter_mm": 800.0} and rows[3]["b05"] is None assert rows[0]["b05"] == {"design_flow_m3s": BASINS[0]["design_flow_m3s"], "tc_minutes": 5.0} def test_잇지_않는_칸() -> None: for row in station_rows(POINTS, BASINS): assert not {"slope_denominator", "pipe_kind", "n"} & set(row["linked"]) def test_basins_를_안_주면_linked_없음() -> None: rows = station_rows(POINTS) assert all(r["linked"] is None and r["b05"] is None for r in rows) @pytest.mark.parametrize("index", [0, 1]) def test_연결값으로_계산한_Qd_는_B05_설계유량(index: int) -> None: row = station_rows(POINTS, BASINS)[index] out = compute({**DEFAULTS, **row["linked"], "r24_mm": R24, "sheet": row["sheet"]}) assert out["design_flow"] == pytest.approx(row["b05"]["design_flow_m3s"], abs=1e-4) assert out["tc_hr"] * 60 == pytest.approx(row["b05"]["tc_minutes"], abs=0.05) def test_표준값은_B05_배수_설정() -> None: assert DEFAULTS["runoff"] == cfg.DRAINAGE_RUNOFF_COEFFICIENT == 0.8 assert DEFAULTS["factor"] == cfg.DRAINAGE_DESIGN_FLOW_FACTOR == 2.0 assert DEFAULTS["return_period"] == cfg.DRAINAGE_DESIGN_RETURN_PERIOD_YR == 100 assert DEFAULTS["tc_min_minutes"] == cfg.DRAINAGE_TC_MIN_MINUTES == 5.0 def test_세부유역_파일_읽기(tmp_path: Path) -> None: assert read_basins(tmp_path) == [] # 분석 저장 전 features = [{"type": "Feature", "properties": b, "geometry": None} for b in BASINS] features.append({"type": "Feature", "properties": {"kind": "pipe", "chainage_m": 85.05}}) path = tmp_path / BASINS_FILE path.parent.mkdir(parents=True) path.write_text(json.dumps({"type": "FeatureCollection", "features": features}), "utf-8") assert [b["chainage_m"] for b in read_basins(tmp_path)] == [85.05, 173.09, 300.0]