# -*- coding: utf-8 -*- """횡단배수 › 세월교(표 04) 명세 + 월류 폭 ↔ 높이 연동 — PLAN 52-4. 순수 규칙은 Node 헬퍼(`helper_52_4_ford.cjs`)가 돌림 · 화면은 ORCA `ui_checks/52-4_세월교_컨테이너.js`. 높이 거울 = 이 파일이 Manning(통수단면.md §2 · n 0.017 · S 0.10)을 따로 풀어 같은 값인지 봄. """ import json import math import os import subprocess import pytest HERE = os.path.dirname(os.path.abspath(__file__)) ROOT = os.path.dirname(os.path.dirname(HERE)) N, S = 0.017, 0.10 def _node(*args): proc = subprocess.run( ["node", os.path.join(HERE, "helper_52_4_ford.cjs"), *args], capture_output=True, text=True, encoding="utf-8", timeout=60, ) assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) @pytest.fixture(scope="module") def out(): return _node() def test_컨테이너_셋_모두_필수(out): assert out["containers"] == [ ["ford", "세월교", True], ["inlet", "유입 구조", True], ["outlet", "유출 구조", True], ] assert out["items"][0] == [ ["diameter", "select", "pipe_diameter_mm"], ["width", "number", "ford_width_m"], ["height", "number", "ford_height_m"], ["count", "number", "pipe_count"], ] assert out["choices"] == [ [["800", "1000", "1200", "1500"]], [["없음", "날개벽", "흙막이"]], [["없음", "날개벽", "흙막이"]], ] def test_옛_날개벽_칸으로_구조를_세우고_같은_키로_씀(out): assert out["legacy"] == {"inlet": "날개벽", "outlet": "없음"} assert out["keepSoil"] == "흙막이" # 흙막이는 설치 칸 없음이어도 그대로 assert out["b06Off"] == "없음" and out["b06On"] == "날개벽" # B06 조정창 설치 칸을 따름 back = out["back"] assert back["pipe_diameter_mm"] == 1000 and back["pipe_count"] == 2 assert back["ford_width_m"] == 10 and back["ford_height_m"] == 0.3 assert back["wing_in"] == "있음" and back["wing_out"] == "없음" # 표 04 에 없는 옛 칸은 폼이 안 적음(병합이 이어 붙임 = 지난 정의 값) assert "pipe_kind" not in back and "wing_in_height_m" not in back assert "pipe_kind" in out["retired"] def test_흙막이_날개벽_고르면_옛_설치_칸도_맞춰_씀(out): s = out["soilOut"] assert s["inlet_type"] == "흙막이" and s["wing_in"] == "없음" assert s["outlet_type"] == "날개벽" and s["wing_out"] == "있음" def test_잇기_키_컨테이너마다(out): assert out["links"] == ["gford", "gfordin", "gfordout"] def _manning_depth(q, b): """넓은 직사각 수로 Manning 을 h 에 대해 이분법으로 풂 — 헬퍼와 다른 풀이.""" def cap(h): return b * h * (1 / N) * ((b * h) / (b + 2 * h)) ** (2 / 3) * math.sqrt(S) lo, hi = 0.0, 5.0 for _ in range(100): mid = (lo + hi) / 2 lo, hi = (mid, hi) if cap(mid) < q else (lo, mid) return hi def test_월류_높이는_폭과_연동_필요_수심_올림(out): for q, b, h in out["table"]: need = _manning_depth(q, b) assert h == pytest.approx(math.ceil(need * 100 - 1e-9) / 100), (q, b) # 폭이 넓을수록 높이가 낮아짐 row = [h for q, b, h in out["table"] if q == 2.54] assert row == sorted(row, reverse=True) and len(set(row)) == len(row) assert out["none"] == [None, None] # 설계유량 · 폭이 없으면 손 입력 assert out["hints"] == ["필요 수심 0.08 이상", "월류 폭을 넣으면 셈", "설계유량 없음 — 손 입력"] def test_정의_파일에_세월교_이름_표가_올라_있음(): names = _node("names") with open( os.path.join(ROOT, "resources", "master_template", "구조물정의.json"), encoding="utf-8" ) as f: doc = json.load(f) assert doc["종류"]["ford_bridge"]["이름"] == names