Files
Aislo/B08_Quantity/B08_Quantity_Hydro_Defaults.py
T
eomsangdonandClaude Opus 5.5 14c3f01f11 fix(B08): 임의 · 실무 값 빈칸 — 관경 · 련 미입력 · 1본 프로젝트 값만 · 거창 계수 비율 미정 · 수심비 빈칸(143-2)
- 집계표 — 관경 · 련 빈칸 = 「미입력」 열(or 1000 · or 1 지움) · 관경 빈칸 흙막이 빈 높이 미입력 · 1본 = 프로젝트 층 변수만(시스템 층 폴백 지움)
- 토공집계표 — 성토면다짐 · 초류종자살포 · 지장목제거 = 빈칸 + 「비율 미정」 · 구조물 쪽 늘 빈 줄 8 뺌(나머지 7 유지)
- 수리 박스 — 수심비 처음 값 빈칸 · 빈칸이면 수심 · 유출량 멈춤 · 칸 옆 알림
- 좌측 패널 1본 읽기 전 빈칸 · 시험 test_69 · 98 · 122 · 73_11 고침 + 새 test_143_2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
2026-10-09 14:56:57 +09:00

169 lines
7.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.
"""B08 4탭 홍수량 계산서 — 기본값 · 선택지 · B05 연결값 한 곳 (PLAN 62-3 · 73-11 · 73-12 · 96).
표준값(유출계수 · 할증 · 재현기간 · 최소 도달시간)은 B05 배수 설정(config DRAINAGE_*)과 같은 값.
측점 고유 값은 B05 배수유역 저장본의 연결값(linked · 96-1) · 하상경사는 B06 횡단 경사(110) ·
관 종류 · n 은 안 이음.
근거 후보: docs/raw/조사/2026-10-06_62-1_홍수량_방법.md (별표2 2.0배 · KDS 표 2.7-1 · 실무 견본).
"""
from __future__ import annotations
from typing import Any
from common_util.common_util_drainage_pipes import carry_indices
from config.config_system import FORD_MANNING_N, FORD_SLOPE
from config.config_system_design import (
DRAINAGE_DESIGN_FLOW_FACTOR,
DRAINAGE_DESIGN_RETURN_PERIOD_YR,
DRAINAGE_RUNOFF_COEFFICIENT,
DRAINAGE_TC_MIN_MINUTES,
)
from M02_MasterTemplete.M02_Table_Fill import _nearest
#: 할증(Qd = Q × 할증) — 2.0 별표2 법정 · 1.5 견본(울진 2공구) · 1.2 구기준
FACTORS = (2.0, 1.5, 1.2)
#: 단면 가정 — 만관 · 240° 유효(수심 0.75D) · 유효 70 %(배관 제안 방식)
SECTIONS = {"full": "만관", "arc240": "240° 유효단면", "eff70": "유효 70 %"}
#: 관 종류별 조도계수 n — 파형강관은 KDS 표에 없음(지금 배관 제안 0.024)
PIPE_KINDS = {"파형강관": 0.024, "흄관": 0.013, "콘크리트관": 0.015}
#: 처음 값 = 표준 값만(69-6) · 측점 고유 값(유역면적 · L · H · D · S)은 None(빈칸)
#: R24 · 지역은 공사지 자료(B08_Quantity_Hydro_Site) — 자료가 없을 때만 화면 입력
DEFAULTS: dict[str, Any] = {
"factor": DRAINAGE_DESIGN_FLOW_FACTOR,
"runoff": DRAINAGE_RUNOFF_COEFFICIENT, # 유출계수 f — KDS 가파른 산지
"area_km2": None,
"length_m": None, # 산정에서 하천시점까지 거리
"height_m": None, # 산정에서 하천시점까지 표고차
"tc_min_minutes": DRAINAGE_TC_MIN_MINUTES, # 최소 도달시간(KDS 2.4)
"r24_mm": None,
"region": "",
"return_period": DRAINAGE_DESIGN_RETURN_PERIOD_YR,
"pipe_kind": "파형강관",
"n": None, # None = 관 종류 값
"diameter_mm": None,
"slope_denominator": None, # 하상경사 S = 1 / 이 값
"section": "full",
}
#: 시설 → 계산서 장(73-11 · 73-12) — 박스 = 사각 단면 · 세월교 · 물넘이 = 월류 높이 · 그 밖 = 관
SHEETS = {
"box_culvert": ("box", "박스암거"),
"ford_bridge": ("ford", "세월교"),
"ford_pavement": ("ford", "물넘이포장"),
}
#: 장별 처음 값 — 박스 n 0.013(KDS 콘크리트관) · 수심비 · 내공 · 경사는 빈칸(수심비 0.8 = 울진 산출서 —
#: 근거 없어 안 채움 · 빈칸이면 단면 계산 멈춤 · 143-2)
#: 세월교 · 물넘이 월류 폭 10 m(사용자 10-7) · n · 경사 = B05 세월교 높이 계산과 같은 값
SHEET_DEFAULTS: dict[str, dict[str, Any]] = {
"box": {"n": 0.013, "depth_ratio": None, "box_width_m": None, "box_height_m": None},
"ford": {
"n": FORD_MANNING_N,
"overflow_width_m": 10.0,
"slope_denominator": round(1 / FORD_SLOPE, 6),
},
}
#: 장 → B06 횡단 정본 경사 키(110) — 관 = 관 바닥 두 끝 경사 · 박스 = 박스 두 끝 원지반 경사
#: (본체는 늘 수평) · 세월교 · 물넘이는 장 기본값(B05 세월교 높이 계산과 같은 값)
SLOPE_KEYS = {"pipe": "pipe_slope_pct", "box": "box_ground_slope_pct"}
def _positive(value: Any) -> float | None:
"""양수만 — 글 '1000' 도 숫자로 · 0 · 빈 값 · 글자는 None(빈칸)."""
try:
number = float(value)
except (TypeError, ValueError):
return None
return number if number > 0 else None
def bed_slopes(designs: list[dict[str, Any]] | None) -> dict[str, dict[float, float]]:
"""B06 횡단 설계 `[{chainage_m, design}]` → 장별 `{측점: 경사 %}` — 0 % 이하는 안 담음(빈칸)."""
found: dict[str, dict[float, float]] = {sheet: {} for sheet in SLOPE_KEYS}
for row in designs or []:
design = row.get("design") or {}
for sheet, key in SLOPE_KEYS.items():
pct = _positive(design.get(key))
if pct:
found[sheet][round(float(row.get("chainage_m") or 0.0), 3)] = pct
return found
def _linked(
sheet: str,
options: dict[str, Any],
basin: dict[str, Any] | None,
slope_pct: float | None = None,
) -> dict[str, Any]:
"""연결값 → 계산서 칸(96-1) — 값이 있는 칸만 · A · L · H 는 유역 · 치수는 시설 옵션 ·
하상경사 S = 1 / 분모 는 B06 경사(110 · 0 % 이하면 빈칸 · 손 입력)."""
values: dict[str, Any] = {}
if slope_pct:
values["slope_denominator"] = round(100 / slope_pct, 3)
if basin is not None:
area_m2 = _positive(basin.get("area_m2"))
values["area_km2"] = area_m2 / 1e6 if area_m2 else None
values["length_m"] = _positive(basin.get("flow_length_m"))
values["height_m"] = _positive(basin.get("relief_m"))
if sheet == "pipe":
values["diameter_mm"] = _positive(options.get("pipe_diameter_mm"))
elif sheet == "box":
values["box_width_m"] = _positive(options.get("body_width_m"))
values["box_height_m"] = _positive(options.get("body_height_m"))
else:
values["overflow_width_m"] = _positive(options.get("ford_width_m"))
return {k: v for k, v in values.items() if v is not None}
def station_rows(
points: list[Any],
basins: list[dict[str, Any]] | None = None,
designs: list[dict[str, Any]] | None = None,
) -> list[dict[str, Any]]:
"""관 지점 → 보조 탭 줄(측점 차례) · 장 종류(pipe · box · ford).
basins(B05 세부유역 속성) 를 주면 측점마다 연결값 `linked` · 비교용 `b05`(Qd · T) — 측점 짝은
`carry_indices`(±0.05 m) · 안 주면 둘 다 None. designs(B06 횡단 설계) 경사는 관 지점과
가장 가까운 횡단 측점(±0.5 m · 관 연장과 같은 짝)에서.
"""
slopes = bed_slopes(designs)
points = sorted(points, key=lambda p: p.chainage_m)
picks = (
carry_indices([p.chainage_m for p in points], [float(b["chainage_m"]) for b in basins])
if basins is not None
else [None] * len(points)
)
rows = []
for p, pick in zip(points, picks):
sheet, kind = SHEETS.get(p.facility, ("pipe", ""))
row = {"chainage_m": p.chainage_m, "facility": p.facility, "kind": kind, "sheet": sheet}
row["linked"] = row["b05"] = None
if basins is not None:
basin = basins[pick] if pick is not None else None
slope = _nearest(slopes.get(sheet, {}), p.chainage_m)
row["linked"] = _linked(sheet, getattr(p, "options", None) or {}, basin, slope)
if basin is not None:
row["b05"] = {
"design_flow_m3s": basin.get("design_flow_m3s"),
"tc_minutes": basin.get("tc_minutes"),
}
rows.append(row)
return rows
def options() -> dict[str, Any]:
"""화면 선택지 — 기본값 · 할증 · 단면 가정 · 관 종류 n."""
return {
"defaults": DEFAULTS,
"factors": list(FACTORS),
"sections": SECTIONS,
"pipe_kinds": PIPE_KINDS,
"sheet_defaults": SHEET_DEFAULTS,
}