- 04_detailed_basins + pipe_points → linked(A · L · H · 관경 · 박스 내공 · 월류 폭) · 참고 b05(Qd · T) - 측점 짝 carry_indices(±0.05 m) · 하상경사 · 관 종류 · n 은 안 이음 - 유출계수 · 할증 · 재현기간 · 최소 도달시간 = config DRAINAGE_* import - 시험 test_96_b08_hydro_linked(연결값 · Qd ≈ B05 설계유량) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
103 lines
4.6 KiB
Python
103 lines
4.6 KiB
Python
"""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]
|