Files
Aislo/E05_StabReport/E05_StabReport_Area.py
T

99 lines
4.4 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.
"""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, LEVEL_KEYS
from E07_StabArea.E07_StabArea_Router import RESULT, load
LEVEL_NAMES = {"low": "낮음", "mid": "보통", "high": "높음"}
def scenario_text(s: dict[str, Any]) -> str:
"""시나리오 글 — 화면 시나리오 이름과 같은 말."""
if s.get("scenario") == "saturated":
return "최악 — 완전 포화(m = 1 · 강우 극한)"
if s.get("scenario") == "sinmap":
return (
f"표준 — SINMAP 습윤지수 W = min(R·a / (T·sinθ), 1) · "
f"T/R {s['tr_lo']:g}~{s['tr_hi']:g} m"
)
return f"옛 조건({s.get('scenario')}) — E07 에서 [다시 해석]"
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
if "station_levels" not in area["summary"]:
_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",
)
_set(sheet, "B7", scenario_text(s))
_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]]))
lo, hi = s["level_lo_pct"], s["level_hi_pct"]
bounds = {"low": f"< {lo:g} %", "mid": f"{lo:g} ~ {hi:g} %", "high": f"≥ {hi:g} %"}
for col, text in zip("EFG", ("측점 등급", "SI<1 셀 비율", "측점 수")):
_set(sheet, f"{col}11", text, 6)
for i, key in enumerate(LEVEL_KEYS):
_set(sheet, f"E{12 + i}", LEVEL_NAMES[key], 7)
_set(sheet, f"F{12 + i}", bounds[key], 7)
_set(sheet, f"G{12 + i}", int(summary["station_levels"][key]), 14)
_set(sheet, "A20", f"3. 위험 측점 — 보통 · 높음 (영향 구역 안 SI < 1 셀 비율 {lo:g} % 이상)")
_set(sheet, "E21", "측점 등급 (SI<1 비율)")
rows = [r for r in area["stations"] if r.get("level") in ("mid", "high")]
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}", f"{LEVEL_NAMES[row['level']]} ({row['risk_ratio'] * 100:.1f} %)")
_set(sheet, f"F{r}", float(row["risk_area_m2"]))
_set(sheet, f"G{r}", float(row["slope_max_deg"]))