"""B08 4탭 홍수량 계산서 엔진 — 순수 식 (PLAN 62-2 · 계산 자리 ③ 서버 단독). 배수유역 계산 코드(`common_util_drainage_detail` 등)를 부르지 않음 — 화면 입력만으로 계산. 1-1 합리식 Q = (1/3.6)·f·rt·A[㎢] · Qd = Q × 할증 1-2 도달시간 Kirpich T = 0.0663·L[㎞]^0.77·s^-0.385 [hr] · s = H/L · 최소 도달시간 적용 1-3 강우강도 rt = (R24/24)·(24/T)^0.557 (Mononobe형) 2 단면검토 V = (1/n)·R^(2/3)·S^(1/2) · Q = A·V · 판정 Q ≥ Qd · 유출율 = Q/Qd """ from __future__ import annotations import math from typing import Any from B08_Quantity.B08_Quantity_Hydro_Defaults import PIPE_KINDS MONONOBE_EXPONENT = 0.557 EFFECTIVE_RATIO = 0.7 def section_props(section: str, diameter_m: float) -> dict[str, float]: """단면 가정별 단면적 A · 윤변 P · 경심 R.""" d = diameter_m full_area = math.pi * d * d / 4.0 if section == "arc240": # 240° 부채꼴 + 현 아래 삼각형(반지름 둘 · 끼인각 120°) — 수심 0.75D area = full_area * 240.0 / 360.0 + (d / 2.0) ** 2 * math.sin(math.radians(60)) * math.cos( math.radians(60) ) perimeter = math.pi * d * 240.0 / 360.0 return {"area": area, "perimeter": perimeter, "radius": area / perimeter} if section == "eff70": # 배관 제안 방식 — 유속은 만관 경심(D/4) · 통수단면은 70 % return {"area": EFFECTIVE_RATIO * full_area, "perimeter": math.pi * d, "radius": d / 4.0} return {"area": full_area, "perimeter": math.pi * d, "radius": d / 4.0} def _num(inputs: dict[str, Any], key: str) -> float | None: value = inputs.get(key) return None if value is None or value == "" else float(value) def compute(inputs: dict[str, Any]) -> dict[str, Any]: """입력 → 계산서 값 전부(반올림 없음 · 화면이 자릿수를 정함). 빈칸(None)이 있으면 그 값에 기대는 칸만 None — 화면은 「—」 (69-6). """ length_m, height_m = _num(inputs, "length_m"), _num(inputs, "height_m") r24, area_km2 = _num(inputs, "r24_mm"), _num(inputs, "area_km2") slope_ground = tc_raw_hr = tc_hr = intensity = flow = design_flow = None if length_m and height_m: slope_ground = height_m / length_m tc_raw_hr = 0.0663 * (length_m / 1000.0) ** 0.77 * slope_ground**-0.385 tc_hr = max(tc_raw_hr, float(inputs["tc_min_minutes"]) / 60.0) if tc_hr and r24: intensity = (r24 / 24.0) * (24.0 / tc_hr) ** MONONOBE_EXPONENT if intensity is not None and area_km2: flow = float(inputs["runoff"]) * intensity * area_km2 / 3.6 design_flow = flow * float(inputs["factor"]) n = _num(inputs, "n") or PIPE_KINDS[inputs["pipe_kind"]] diameter_mm, slope_den = _num(inputs, "diameter_mm"), _num(inputs, "slope_denominator") props = section_props(inputs["section"], diameter_mm / 1000.0) if diameter_mm else {} slope_bed = 1.0 / slope_den if slope_den else None velocity = capacity = None if props and slope_bed: velocity = (1.0 / n) * props["radius"] ** (2.0 / 3.0) * math.sqrt(slope_bed) capacity = props["area"] * velocity judged = capacity is not None and design_flow is not None return { "area_ha": area_km2 * 100.0 if area_km2 else None, "r24_mm": r24, "slope_ground": slope_ground, "tc_raw_hr": tc_raw_hr, "tc_hr": tc_hr, "tc_floored": tc_hr is not None and tc_hr > tc_raw_hr, "intensity": intensity, "flow": flow, "design_flow": design_flow, "n": n, "section_area": props.get("area"), "perimeter": props.get("perimeter"), "radius": props.get("radius"), "slope_bed": slope_bed, "velocity": velocity, "capacity": capacity, "ok": capacity >= design_flow if judged else None, "ratio_pct": capacity / design_flow * 100.0 if judged and design_flow > 0 else None, }