Files
Aislo/E03_StabSection/E03_StabSection_Engine_Station.py
T
eomsangdonandClaude Opus 5.5 bfd87f3e3e feat(E03): 2D 지층 모델 빌더 · 한계평형 솔버(Fellenius · Bishop · Janbu 보정 · Spencer) · 원호 · 비원호 탐색 (532-2)
- 모델: B06 횡단(지반선 · 설계선 · 암 경계 · 성토체 · 벽) → 지층 폴리곤 · 지하수 · 노면 하중 · 비탈별 방향 · 탐색 한계
- 솔버: 한 벌 절편 식(λ = 0 Bishop · Janbu / Spencer 모멘트 · 힘 동시) · 간극수압 none · r_u · 지하수위선 · kh · 상재하중 · 인장균열
- 탐색: Entry & Exit · Grid & Radius · 차분진화 다듬기 · 블록 씨앗 + 꼭짓점 국부 최적화 + Nelder-Mead
- 출력: 방법별 최소 안전율 · 임계면 좌표 · 절편표 · 등안전율 격자 · 수렴 정보
- 시험: Slide2 검증 예제 12 문제(ACADS 1a~4 · F&K · Loukidis · Arai & Tagyo · Yamagami & Ueta) ±3 % · 면적 = B06

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

76 lines
2.7 KiB
Python

"""E03 측점 하나 해석 — 좌 · 우 비탈 × 조건(건기 · 우기 · 지진) × 방법.
조건 = KDS 11 70 05 표 4.3-3: 건기 u = 0 · 우기 지하수위 = 지표 · 지진 = 건기 수위 + kh.
판정(기준안전율 대조)은 화면 · 보고서 몫 — 여기는 값만 냄.
"""
import time
from E03_StabSection.E03_StabSection_Engine_Model import section_model_from_b06
from E03_StabSection.E03_StabSection_Engine_Search import METHODS, analyze
#: 활동면 최소 깊이(m) — 지표를 얇게 긁는 면(표토 박리)은 사면 붕괴로 보지 않음.
MIN_DEPTH_M = 0.3
def analyze_station(
cross: dict,
design: dict,
*,
materials=None,
layers=None,
ground=None,
conditions=("dry", "wet"),
seismic_kh: float = 0.0,
methods=METHODS,
noncircular: bool = True,
min_depth: float = MIN_DEPTH_M,
**model_kw,
) -> dict:
t0 = time.perf_counter()
out = {"chainage_m": cross.get("chainage_m"), "label": cross.get("label"), "cases": []}
for cond in conditions:
model = section_model_from_b06(
cross,
design,
materials=materials,
layers=layers,
ground=ground,
wet=cond == "wet",
seismic_kh=seismic_kh if cond == "seismic" else 0.0,
**model_kw,
)
out.setdefault("areas", model["areas"])
for side in model["sides"]:
res = analyze(
model,
direction=side["direction"],
limits=side["limits"],
methods=methods,
noncircular=noncircular,
min_depth=min_depth,
)
mins = {m: (res["methods"][m]["min"] or {}).get("F") for m in methods}
out["cases"].append({"condition": cond, **side, "min_F": mins, "result": res})
out["elapsed_s"] = round(time.perf_counter() - t0, 3)
return out
def analyze_stations(items: list[dict], workers: int | None = None, **kw) -> list[dict]:
"""전 측점 — 측점마다 따로 도니 프로세스로 나눠 돎. items = [{"cross", "design", "ground"?}, …] · 순서 그대로."""
import os
from concurrent.futures import ProcessPoolExecutor
workers = workers or max(1, (os.cpu_count() or 2) - 2)
if workers == 1 or len(items) < 2:
return [
analyze_station(it["cross"], it["design"], ground=it.get("ground"), **kw)
for it in items
]
with ProcessPoolExecutor(max_workers=workers) as pool:
futures = [
pool.submit(analyze_station, it["cross"], it["design"], ground=it.get("ground"), **kw)
for it in items
]
return [f.result() for f in futures]