Files
Aislo/E05_StabReport/E05_StabReport_Area.py
T
eomsangdonandClaude Opus 5.5 cdd9fa3c0b feat(536-2): E07 광역 위험 기본값 재검토 — 기본 = SINMAP 표준 습윤지수(T/R 2,000~3,000 m · SI 하한/상한/확률) · 완전 포화 = 최악 선택지 · 뿌리 점착 1 kPa · E05 광역요약 · 범례 시나리오 이름(요구 351)
- 엔진: 포화비 W = min(x·a/sinβ, 1) · x = R/T 범위 · SI = 하한(c · φ 아래 · 가장 젖음) ≥ 1 → 그 값 · 상한 < 1 → 0 · 사이 = P(Fs > 1)(c · tanφ 닫힌 꼴 · x 중점 적분 20 마디)
- 옛 「강우 강도(정상류)」 시나리오 뺌 — 첨두 강우를 정상류 함양으로 넣어 거의 다 포화 · T/R 로 갈음 · 엔진 판 e07-2(옛 결과 = 다시 해석)
- 기본값 출처 = SINMAP 2 설명서 기본 보정 · 국내 적용 연구(뿌리 0~5 kPa) · 지식DB 예정노선/02 · 바꿀 수 있음
- 시험 536-2: 강우 포화비 시험을 습윤지수 · SI 하한/상한 Pack 원식 · 시나리오 둘로 바꿈 · 534-3 광역요약 B7 글 맞춤
- 검증 노선: 위험(SI<1) 91.7 % → 11.1 %

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 23:17:20 +09:00

86 lines
3.6 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, RISK_CLASS
from E07_StabArea.E07_StabArea_Router import RESULT, load
CLASS_NAMES = ("", "안정", "보통 안정", "준안정", "위험 하한", "위험 상한", "불안정")
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
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]]))
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"]))