- 흙막이 양식 한 벌(design_structure_guard) — 배관 · 박스 · 세월교가 같은 칸(형태 · 길이 · 높이 · 측점 전후) · 추가 흙막이 · 도수로/돌붙임 상자
- 세월교 · 박스 유입 · 유출: 흙막이 고르면 흙막이 칸(키 {side}_revet_* · 기본 찰 10 · 1.5 · 5 · 5) · [연동][경사] 옵션 줄
- B06 측벽 높이 · 좌우 · 상하 · 바닥판 읽기 줄을 세월교 · 박스 유입 · 유출 칸에 안 옮김(강조만)
- 유입 · 유출 「없음」 = 목록 램프 · 구조물 조합 잇기 줄 없음(명세 none)
- 세월교: 수량(련) 관경 바로 뒤 · 련 기본 2 · 새 시설 빈 월류 높이 = 유량 오면 필요 수심 · 종류 바꿀 때 유량 넘김
- 물넘이 포장: 경사각 기본 3° · 월류 폭 · 높이 칸(세월교와 같은 키 ford_width_m · ford_height_m · 같은 계산)
- 구조물정의 판 18(판_17 이력) · 이름 표 · 집계표 선택 컨테이너 짝 · 저장 병합 키
- 시험: 세월교 · 박스 · 물넘이 명세 기대값 · 흙막이 짝 자리 옮김
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BVPp2o6Mh2FZJr72yW3ofZ
113 lines
4.0 KiB
Python
113 lines
4.0 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],
|
||
["soil_add", "흙막이", False],
|
||
["chute_add", "도수로/돌붙임", False],
|
||
]
|
||
# 수량(련) = 관경 바로 뒤(65-4)
|
||
assert out["items"][0] == [
|
||
["diameter", "select", "pipe_diameter_mm"],
|
||
["count", "number", "pipe_count"],
|
||
["width", "number", "ford_width_m"],
|
||
["height", "number", "ford_height_m"],
|
||
]
|
||
assert [c[0] for c in out["choices"][:3]] == [
|
||
["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", "gsoiladd1", "gchuteadd1"]
|
||
|
||
|
||
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
|