- 엔진 E07_StabArea_Engine — DTM 고른 격자 · Horn 경사 · D8 집수면적(B04 웅덩이 채움 · 수신 셀 재사용) · 무한사면 Fs(포화비 m) · SINMAP 안정 지수(c · tanφ 고른 분포 닫힌 꼴) · 6 등급 · 노선 띠 · 측점표 - 길 E07_StabArea_Router — POST 해석(뒤에서 · 진행률 · 지문 같으면 cached) · GET 기본값(E02 붕적토 · 범위 위 +5 kPa · +3°) · 파생 저장본 _derived/area.json(격자 base64) - E05 보고서 s7 광역요약 — 조건 · 등급별 면적 · 위험 측점 줄 · 양식 · 자리표 덧붙임 · 해석 지문에 E07 저장본 - 시험 test_536_2 새로 · test_534_3 두 파일은 시트 7 · PDF 쪽 +1 로 고침(광역요약 시트 더함) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
79 lines
3.3 KiB
Python
79 lines
3.3 KiB
Python
"""E05 보고서 s7 광역요약 — E07 광역 자연사면 위험 저장본 → 시트 (PLAN 536-2).
|
||
|
||
칸 자리 = `resources/master_template/report/stab_report_slots.md` s7.
|
||
E07 저장본이 없으면 「광역 해석 전」.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from pathlib import Path
|
||
from typing import Any
|
||
|
||
from E07_StabArea.E07_StabArea_Engine import CLASS_KEYS, RISK_CLASS
|
||
from E07_StabArea.E07_StabArea_Router import RESULT, load
|
||
|
||
CLASS_NAMES = ("", "안정", "보통 안정", "준안정", "위험 하한", "위험 상한", "불안정")
|
||
|
||
|
||
def stamp(project_root: Path) -> list[int] | None:
|
||
"""해석 지문용 — 저장본 크기 · 고친 때."""
|
||
path = Path(project_root) / RESULT
|
||
return [path.stat().st_size, path.stat().st_mtime_ns] if path.is_file() else None
|
||
|
||
|
||
def read(project_root: Path) -> dict[str, Any] | None:
|
||
"""저장본에서 보고서에 쓰는 것만(격자 배열 뺌)."""
|
||
doc = load(project_root)
|
||
if not doc:
|
||
return None
|
||
return {k: doc[k] for k in ("settings", "computed_at", "stations", "summary")}
|
||
|
||
|
||
def _set(sheet: dict[str, Any], a1: str, value: Any, style: int | None = None) -> None:
|
||
cell = dict(sheet["칸"].get(a1) or {})
|
||
cell["값"] = round(value, 6) if isinstance(value, float) else value
|
||
if style is not None:
|
||
cell["서식"] = style
|
||
sheet["칸"][a1] = cell
|
||
|
||
|
||
def fill_area(sheet: dict[str, Any], area: dict[str, Any] | None, labels: dict[float, str]) -> None:
|
||
"""s7 — 조건 넷 · 등급별 면적 여섯 · 위험 측점(22 행부터 한 줄씩)."""
|
||
if not area:
|
||
_set(sheet, "B5", "광역 해석 전 — E07 광역에서 [해석] 뒤 [보고서 갱신]")
|
||
return
|
||
s, summary = area["settings"], area["summary"]
|
||
_set(sheet, "B5", f"중심선 ± {s['band_m']:g} m · 격자 {s['cell_m']:g} m")
|
||
_set(
|
||
sheet,
|
||
"B6",
|
||
f"γt {s['gamma_t']:g} · γsat {s['gamma_sat']:g} kN/m³ · c {s['c']:g}~{s['c_hi']:g} kPa · "
|
||
f"φ {s['phi']:g}~{s['phi_hi']:g}° · 뿌리 점착 {s['c_root']:g} kPa · "
|
||
f"토층 {s['soil_depth_m']:g} m",
|
||
)
|
||
rain = (
|
||
"지표 포화(m = 1)"
|
||
if s["scenario"] == "saturated"
|
||
else f"강우 {s['rain_mm_h']:g} mm/h · 투수계수 {s['k_m_s']:g} m/s(정상류 포화비)"
|
||
)
|
||
_set(sheet, "B7", rain)
|
||
_set(sheet, "B8", str(area["computed_at"]).replace("T", " "))
|
||
for k in range(1, 7):
|
||
_set(sheet, f"C{11 + k}", float(summary["areas_m2"][CLASS_KEYS[k]]))
|
||
rows = [r for r in area["stations"] if r.get("worst_class", 0) >= RISK_CLASS]
|
||
template = {col: dict(sheet["칸"].get(f"{col}22") or {}) for col in "ABCDEFG"}
|
||
if not rows:
|
||
_set(sheet, "A22", "위험 측점 없음")
|
||
for i, row in enumerate(rows):
|
||
r = 22 + i
|
||
for col, cell in template.items():
|
||
sheet["칸"][f"{col}{r}"] = dict(cell)
|
||
ch = float(row["chainage_m"])
|
||
_set(sheet, f"A{r}", row.get("label") or labels.get(round(ch, 3)) or f"{ch:.2f}")
|
||
_set(sheet, f"B{r}", ch)
|
||
_set(sheet, f"C{r}", float(row["fs_min"]))
|
||
_set(sheet, f"D{r}", float(row["si_min"]))
|
||
_set(sheet, f"E{r}", CLASS_NAMES[int(row["worst_class"])])
|
||
_set(sheet, f"F{r}", float(row["risk_area_m2"]))
|
||
_set(sheet, f"G{r}", float(row["slope_max_deg"]))
|