Files
Aislo/B08_Quantity/B08_Quantity_Router_Hydro.py
T
eomsangdonandClaude Opus 5.5 5f056ec661 feat(b08): 4탭 홍수량 계산서 — 배수지점 측점 보조 탭 · 견본 모양 한 장 · 서버 계산(PLAN 62-2 · 62-3)
- 측점 보조 탭 = 저장된 pipe_points 측점만 읽음 · 입력은 이 탭 자기 기본값(B05/B06 · 배수유역 값과 안 이음)
- 1-1 합리식(Qd = Q × 할증) · 1-2 Kirpich 도달시간(최소 5분) · 1-3 rt = (R24/24)·(24/T)^0.557
- 2 단면검토 — 관 단면 그림 · 단면적 · 윤변 · 경심 · 경사 · n · Manning 유속 · Q = A·V · OK/NG 점선 상자 · 유출율
- 선택지(할증 2.0/1.5/1.2 · 만관/240°/유효 70 % · 관 종류별 n) · 기본값 한 파일(B08_Quantity_Hydro_Defaults.py)
- 계산 = 서버 단독(B08_Quantity_Engine_Hydro · /quantity/hydro · /quantity/hydro/calc · 최신 응답만) · 입력은 캐시만 · 어떤 파일에도 안 씀
- 흰 종이 계산서(입력 빨강 · 계산 파랑 · 주요 입력 노랑) · 쪽 표시 · 시험 test_62_2_b08_hydro_engine.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UoSr2sqvYtBf1dtQdus88s
2026-10-06 18:15:29 +09:00

73 lines
2.9 KiB
Python

"""B08 4탭 홍수량 계산서 길 (PLAN 62-2 · 62-3) — 읽기 · 계산만, 아무 파일에도 쓰지 않음.
GET /api/projects/{id}/quantity/hydro 배수지점 측점(저장된 pipe_points) + 기본값 · 선택지
POST /api/projects/{id}/quantity/hydro/calc 화면 입력 → 계산서 값(B08_Quantity_Engine_Hydro)
측점 목록만 관 지점 정본에서 읽음 — 관경 · 관 종류 등 B05/B06 값은 잇지 않음(자기 기본값).
"""
from __future__ import annotations
from pathlib import Path
from typing import Any, Literal
from uuid import UUID
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel, Field
from B03_FileInput.B03_FileInput_Repository import get_project_storage_relative_path
from B08_Quantity.B08_Quantity_Engine_Hydro import compute
from B08_Quantity.B08_Quantity_Hydro_Defaults import FACTORS, PIPE_KINDS, options
from common_util.common_util_drainage_pipes import pipe_points_path_in, read_pipe_points_file
from common_util.common_util_storage import resolve_stored_project_path
from config.config_db import get_db_pool
router = APIRouter(prefix="/api/projects", tags=["B08 Hydro"])
class HydroInputs(BaseModel):
factor: float = Field(gt=0)
runoff: float = Field(gt=0, le=1)
area_km2: float = Field(gt=0)
length_m: float = Field(gt=0)
height_m: float = Field(gt=0)
tc_min_minutes: float = Field(ge=0)
r24_mm: float = Field(gt=0)
region: str = ""
return_period: float = Field(gt=0)
pipe_kind: Literal[tuple(PIPE_KINDS)] # type: ignore[valid-type]
n: float | None = Field(default=None, gt=0)
diameter_mm: float = Field(gt=0)
slope_denominator: float = Field(gt=0)
section: Literal["full", "arc240", "eff70"]
async def _project_root(project_id: UUID) -> Path:
try:
async with get_db_pool().acquire() as connection:
stored = await get_project_storage_relative_path(connection, project_id)
except LookupError:
stored = None
if not stored:
raise HTTPException(status_code=404, detail="프로젝트 저장 경로를 찾을 수 없습니다.")
return Path(resolve_stored_project_path(stored))
@router.get("/{project_id}/quantity/hydro")
async def hydro_sheet(project_id: UUID) -> dict[str, Any]:
root = await _project_root(project_id)
points = read_pipe_points_file(pipe_points_path_in(root))
stations = sorted(
({"chainage_m": p.chainage_m, "facility": p.facility} for p in points),
key=lambda s: s["chainage_m"],
)
return {"stations": stations, **options()}
@router.post("/{project_id}/quantity/hydro/calc")
async def hydro_calc(project_id: UUID, body: HydroInputs) -> dict[str, Any]:
await _project_root(project_id) # 없는 프로젝트는 404
if body.factor not in FACTORS:
raise HTTPException(status_code=400, detail=f"할증은 {FACTORS} 중 하나")
return compute(body.model_dump())