feat(B05): 배수 추천 구조물·관경 자동 설정 + 물넘이·세월교 개략 단면
지시 2 — 배수유역도가 유효직경 다음에 추천을 보여 주고, 초기 전처리 계산이 그 값으로 관 지점을 설정한다: - recommend_structure(): 유효직경 임계로 구조물·관경을 고른다. D≤1500 배관(규격 스냅 800·1000·1200·1500), 1500<D≤2000 BOX암거 후보, D>2000 세월교 검토. 판정 근거는 유량뿐 — 계곡 횡단경사·하천 차수는 지형 계산이 필요해 뺐고 화면이 "현장 확인"으로 안내한다(2026-08-17 사용자 확정) - WatershedBasin에 recommended_facility·recommended_diameter_mm·required_area_m2 추가, 응답 payload와 DetailBasin 타입까지 배선 - _apply_recommendations(): 자동 배치 관의 **빈칸에만** 추천을 채운다. 사용자가 놓은 관(source=user)·이미 바꾼 시설·이미 있는 옵션 키는 건드리지 않는다. carry_facility_attributes 뒤에 얹어 승계값이 덮이지 않게 했다 - 유역 목록 표기: `Ø1234mm → 추천 Ø1500 배관` / `→ BOX암거 후보` - 추천 관경 목록은 레지스트리 pipe_diameter_mm 선택지와 같아야 한다 — 폼에서 못 고르는 값을 추천하지 않도록 테스트로 묶었다 지시 1 — 물넘이포장·세월교는 지정할 옵션이 거의 없으니 계산값이라도 보여 준다: - 레지스트리에 ford_width_m(월류 폭) 신설. 기본값 없음 — 지식DB에 폭 근거가 없어 프로그램이 지어내지 않는다 - fordSection(): 설계유량과 폭으로 필요 수심을 되짚는다. 광폭 근사로 출발해 실제 동수반경(R=A/P)으로 수렴시킨다 — 근사값을 그대로 쓰면 통수능이 늘 설계유량에 못 미쳐 판정이 무의미해진다. n=0.017·S=10%는 실무 수리계산서 역산값 (울진1 물넘이·관 시트가 둘 다 S=0.10에서 검산 일치) - 폼에 월류 폭 한 칸 + 읽기전용 요약(설계유량·필요 수심·필요 단면·유속). 설계유량은 유역 payload에서 폼까지 배선(onPipesChanged → Page → setFacility) ⚠ 실무 시트의 수심 0.27m는 Qd 역산값이 아니라 가정 수심이다(B=20·h=0.27의 통수능 41.2㎥/s ≫ 그 시트 Qd 2.54㎥/s). 실무는 단면을 가정해 통수능을 검증하고, 프로그램은 필요 최소 수심을 낸다 — 화면 문구도 "필요 수심"으로 적었다. 검증: pytest tmp/tests 124 passed·7 skipped(신규 17건), npm run typecheck 무오류, npm run build 성공. 물넘이 산식은 프론트 전용이라 수치 손검증으로 대신했다 — Qd=2.54·B=20에서 필요 수심 0.0503m·유속 2.526m/s, 통수능이 2.5400㎥/s로 Qd와 일치. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,11 @@ from B04_PreProcess.B04_PreProcess_Engine_Watershed_Analyze import find_inflow_h
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Export import STAGES
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Flow import largest_ring, polygonize_labels
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Watershed_Grid import GridSpec
|
||||
from common_util.common_util_drainage_pipes import (
|
||||
PIPE_FACILITY_BOX,
|
||||
PIPE_FACILITY_FORD_BRIDGE,
|
||||
PIPE_FACILITY_PIPE,
|
||||
)
|
||||
from common_util.common_util_route_geometry import (
|
||||
RouteVertex,
|
||||
StructureCandidate,
|
||||
@@ -44,11 +49,13 @@ from common_util.common_util_route_geometry import (
|
||||
)
|
||||
from common_util.common_util_wamis_rainfall import idf_intensity
|
||||
from config.config_system import (
|
||||
DRAINAGE_BOX_THRESHOLD_MM,
|
||||
DRAINAGE_BRIDGE_THRESHOLD_MM,
|
||||
DRAINAGE_DESIGN_FLOW_FACTOR,
|
||||
DRAINAGE_DITCH_SAMPLE_M,
|
||||
DRAINAGE_FLOW_AREA_RATIO,
|
||||
DRAINAGE_MANNING_N,
|
||||
DRAINAGE_RECOMMEND_DIAMETERS_MM,
|
||||
DRAINAGE_PIPE_MAX_SPACING_M,
|
||||
DRAINAGE_PIPE_MIN_SPACING_M,
|
||||
DRAINAGE_PIPE_SLOPE_DEG,
|
||||
@@ -57,6 +64,7 @@ from config.config_system import (
|
||||
DRAINAGE_TC_MIN_MINUTES,
|
||||
DRAINAGE_VELOCITY_MAX_MS,
|
||||
DRAINAGE_VELOCITY_MIN_MS,
|
||||
PIPE_DEFAULT_DIAMETER_MM,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -108,6 +116,12 @@ class WatershedBasin:
|
||||
# 유효직경이 관 최대 규격을 넘는 계류 유역 — 관이 아니라 세월교·물넘이·교량 대상
|
||||
# (임도설치규정 제12조). 화면은 "세월교 검토"로 표기하고 관경 자동 지정을 하지 않는다.
|
||||
bridge_required: bool = False
|
||||
# 필요 통수단면적(㎡) = 설계유량 / 유속. 물넘이·세월교 개략 단면의 출발값이다.
|
||||
required_area_m2: float | None = None
|
||||
# 유효직경으로 고른 추천 구조물·관경 (2026-08-17 사용자 확정: 유량 근거만).
|
||||
# 배관이면 레지스트리 선택지로 스냅한 관경이 붙고, BOX암거·세월교면 None이다.
|
||||
recommended_facility: str = "pipe"
|
||||
recommended_diameter_mm: int | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -519,6 +533,7 @@ def assemble_basins(
|
||||
relief = max(0.0, highest - outlet_z)
|
||||
flow_length = float(routing.path_length[member].max())
|
||||
sizing = size_pipe(area, relief, flow_length, idf)
|
||||
facility, recommended = recommend_structure(sizing["diameter_mm"] if sizing else None)
|
||||
basins.append(
|
||||
WatershedBasin(
|
||||
index=len(basins) + 1,
|
||||
@@ -536,6 +551,9 @@ def assemble_basins(
|
||||
bridge_required=bool(
|
||||
sizing and sizing["diameter_mm"] > DRAINAGE_BRIDGE_THRESHOLD_MM
|
||||
),
|
||||
required_area_m2=sizing["required_area_m2"] if sizing else None,
|
||||
recommended_facility=facility,
|
||||
recommended_diameter_mm=recommended,
|
||||
)
|
||||
)
|
||||
return basins
|
||||
@@ -617,9 +635,38 @@ def size_pipe(
|
||||
"intensity_mm_hr": round(intensity, 1),
|
||||
"design_flow_m3s": round(design_flow, 4),
|
||||
"diameter_mm": round(diameter * 1000.0, 1),
|
||||
# 물넘이·세월교는 관이 아니라 개수로라 직경 대신 이 단면적에서 출발한다.
|
||||
"required_area_m2": round(required_area, 4),
|
||||
}
|
||||
|
||||
|
||||
def recommend_structure(diameter_mm: float | None) -> tuple[str, int | None]:
|
||||
"""유효직경으로 추천 구조물과 관경을 고른다 (2026-08-17 사용자 확정: 유량 근거만).
|
||||
|
||||
지식DB 선정 트리(개거_세월시설 §5·횡단배수관_암거 §5)에서 유량 조건만 취했다 —
|
||||
계곡 횡단경사·하천 차수는 지형 계산이 필요해 화면이 "현장 확인"으로 안내한다.
|
||||
|
||||
D ≤ 1,500㎜ 배관 (레지스트리 선택지로 스냅, 하한 800㎜)
|
||||
1,500 < D ≤ 2,000 BOX암거 후보
|
||||
D > 2,000㎜ 세월교·물넘이 검토 (관 최대 규격 초과)
|
||||
|
||||
유효직경을 못 구한 유역(강우량표 없음)은 배관·관경 미정으로 둔다.
|
||||
"""
|
||||
if diameter_mm is None:
|
||||
return PIPE_FACILITY_PIPE, None
|
||||
if diameter_mm > DRAINAGE_BRIDGE_THRESHOLD_MM:
|
||||
return PIPE_FACILITY_FORD_BRIDGE, None
|
||||
if diameter_mm > DRAINAGE_BOX_THRESHOLD_MM:
|
||||
return PIPE_FACILITY_BOX, None
|
||||
# 별표2 (나) 예외 하한 800㎜ — 계산값이 더 작아도 그 아래로는 내리지 않는다.
|
||||
need = max(float(PIPE_DEFAULT_DIAMETER_MM), diameter_mm)
|
||||
size = next(
|
||||
(value for value in DRAINAGE_RECOMMEND_DIAMETERS_MM if value >= need),
|
||||
DRAINAGE_RECOMMEND_DIAMETERS_MM[-1],
|
||||
)
|
||||
return PIPE_FACILITY_PIPE, int(size)
|
||||
|
||||
|
||||
def estimate_pipe_diameter_mm(
|
||||
area_m2: float,
|
||||
relief_m: float,
|
||||
|
||||
Reference in New Issue
Block a user