Files
Aislo/resources/tester/test_52_4_structure_spec_ford.py
T
eomsangdonandClaude Opus 5.5 209383ed17 feat(b05,b06,b07): 도수로/돌붙임 띠 = 낮은 쪽 끝단에서 · 원지반 닿으면 끝 · 길이 = 그 길이 · 모든 시설 같은 규칙과 길이 칸 (294-4)
- 공용 chuteRun(Wall_Hatch) — 길이 비움 = 원지반 닿으면 끝 · 넣음 = 사면 따라 그 길이 · 사면보다 길면 원지반 따라 이어 그 길이 · 끝단이 이미 원지반이면 안 그림
- 물넘이 — 띠 시작 = 늘인 노면 끝(294-3) · 아니면 유출 쪽 노견 끝 · 원지반 닿으면 끝(양측 절토 = 띠 없음)
- 배관 · 박스 · 세월교 — 띠 계산이 원지반(layout.ground)을 받아 같은 규칙 · 3D 띠도 같음 · 코리도 해시에 길이
- 명세 CHUTE_ITEMS 맨 아래 「길이 (m)」(chute_add_{n}_length_m · 그림 전용) · 물넘이는 공용 칸 그대로
- 면적 자동 = 물넘이 · 세월교만 월류 폭 × 길이(배관 · 박스 = 폭 정의 없어 손 입력 그대로 · 브레인 정함)
- 길이는 집계 열 · B08 수량(면적만)에 안 실림 · 마스터 정의 이름 표는 안 건드림(이름 표 대조 시험에서 이 칸만 밖)
- 시험 test_294_3 · 286_1 · 52 · 65 · 152_3 기대값

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TteK8mfYZetk5P3bEZkyVZ
2026-10-12 21:58:16 +09:00

120 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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)
# 그림 전용 길이 칸(294-4)은 마스터 정의 이름 표에 안 올림(마스터 손대지 않음) — 대조 밖
assert doc["종류"]["ford_bridge"]["이름"] == {
k: v for k, v in names.items() if k != "chute_add.length_m"
}