- 세월교 명세(design_structure_ford) — 세월교(관경 · 월류 폭 · 월류 높이 · 수량(련)) · 유입 구조 · 유출 구조(없음 · 날개벽 · 흙막이) · 모두 필수 · 컨테이너마다 구조물 조합 잇기(gford · gfordin · gfordout) - 구조 키 inlet_type · outlet_type + 옛 날개벽 설치 칸(wing_in · wing_out) 함께 씀 · 옛 저장 · B06 조정창 설치 칸으로 구조를 맞춤 · 옛 관종 · 날개벽 치수는 지난 정의 값 - 계산 파일 따로(design_structure_ford_calc) — 높이 = 설계유량을 그 폭으로 넘기는 Manning 필요 수심 · 0.01 올림 · 폭을 바꾸면 채움 · 그 아래는 안 받음 · 근거 통수단면.md:23~33 · :59 - B06 날개벽 조정 행 자리 = 유입 · 유출 구조 컨테이너 끝 · 세월교 옛 관종 · 관경 · 월류 칸 걷음 - 정의 종류.ford_bridge.이름 표 · 명세 등록(STRUCTURE_SPECS) · 52-1 시험 헬퍼가 같은 폴더 명세 import 를 읽음 - 시험 test_52_4_structure_spec_ford · 화면 시나리오 ui_checks/52-4_세월교_컨테이너 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPJGtfXo6GMbcpiboQC4uK
110 lines
3.9 KiB
Python
110 lines
3.9 KiB
Python
# -*- 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
|