Files
Aislo/resources/tester/test_533_2_stab3d_column.py
T
eomsangdonandClaude Opus 5.5 b97ddf4783 feat(533-1 · 533-2): E04 3D 기둥 솔버 · 구 · 타원체 탐색 · 합성 DEM · 지층 격자
- Column: Hovland · Hungr 3D Bishop · Hungr 3D Janbu 간편 + 보정(f0) · 활동 방향 자동(지표 낙하) · r_u · 지하수위면 · kh · 노면 하중 · 못 뚫는 층에서 잘림 · 부분 기둥
- Search: Scoops3D 방식 구 격자(노드 = 지표 + h · 반지름 증분 · 부피/면적 제약 · 거친→고운) + 타원체(축 방향 ratio 배) · 덩이 나눔 · 셀별 최소 F · 임계 체적 래스터
- 잘린 면 ≥ 10 % → Janbu 보정 전환 · Bishop 이 낮으면 Bishop
- Grid: 측점 사이 선직면 보간 δ(설계 − 원지형) · 띠 밖 원지형 · 흙 두께(암 경계 · 토사 3 m) · 리핑암 뚫림 · 발파암 못 뚫음 · 노면 하중 · 1 m 정사각 재표본
- 공용 꼴 = E03_StabSection_Types import(칸 이름 그대로) · 새 의존 없음(NumPy · SciPy)
- 시험: Gens 구 1.402 · Zhang 1988 경우 1 · 2(Hungr 2.167 · 1.620) · Scoops3D 제방 1.32 · D&G 1a 1.04 · 합성 DEM 단면 · 띠 밖 · 지층

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

106 lines
4.5 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.
"""533-2 E04 3D 기둥 솔버 — 문헌 기준 문제 ±3 %.
- Gens 외(1988) · Hungr 외(1989) · Scoops3D 6.1: 2:1 평면 사면 · 구 R=1 · 중심-지표 0.5
· c=0.1 γ=1 φ=0 → 해석해 1.402 · 부피 0.654.
- Zhang(1988) 경우 1 · 2(PLoS ONE 18(7) e0287998 그림 5 · 표 2): 1:2 사면 H 12.2 m
· 타원체 중심 (6.1, 0, 21.3)
Rx=Rz=24.4 · Ry=78.2 · c 29 kPa φ 20° γ 18.8 → Hungr 3D Bishop 2.167 · Zhang 2.122 /
약층(c 0 · φ 10°, 발끝 아래 0.94 m — 그림 화소로 잼) → Hungr 1.620 · Zhang 1.533.
"""
import numpy as np
import pytest
from E04_Stab3D.E04_Stab3D_Engine_Column import Strata
from E04_Stab3D.E04_Stab3D_Engine_Search import evaluate_surface, governing
def _mat(gamma, c, phi, mid="m"):
return {"id": mid, "name": mid, "gamma_t": gamma, "gamma_sat": gamma, "c": c, "phi": phi}
def _gens(dx=0.02, angle=0.0):
"""2:1 평면 사면 — 아래로 향하는 방향을 angle(rad) 만큼 돌림."""
beta = np.arctan(0.5)
x = np.arange(-2, 2 + 1e-9, dx)
xx, yy = np.meshgrid(x, x)
down = np.array([np.cos(angle), np.sin(angle)])
z = -(xx * down[0] + yy * down[1]) * np.tan(beta)
st = Strata(x, x, z, np.zeros((0,) + z.shape), [_mat(1.0, 0.1, 0.0)])
c = np.r_[0.5 * np.sin(beta) * down, 0.5 * np.cos(beta)]
return st, c
def test_gens_sphere_analytic():
st, c = _gens()
r = evaluate_surface(st, c, 1.0)
assert r["bishop"] == pytest.approx(1.402, rel=0.01)
assert r["hovland"] == pytest.approx(1.402, rel=0.01)
assert r["volume"] == pytest.approx(np.pi * 0.25 * 2.5 / 3, rel=0.01) # 구 모자 부피 0.6545
def test_rotated_slope_same_factor():
"""Scoops3D 6.7 대칭 — 낙하 방향이 격자 축과 어긋나도 같은 F."""
f0 = evaluate_surface(*_gens(0.02), 1.0)["bishop"]
f1 = evaluate_surface(*_gens(0.02, np.radians(33.0)), 1.0)["bishop"]
assert f1 == pytest.approx(f0, rel=0.01)
def _zhang(weak: bool, dx=0.5):
x = np.arange(-15, 45 + 1e-9, dx)
y = np.arange(-90, 90 + 1e-9, dx)
xx, _ = np.meshgrid(x, y)
z = np.clip(xx * 0.5, 0, 12.2)
soil = _mat(18.8, 29.0, 20.0, "soil")
if not weak:
return Strata(x, y, z, np.zeros((0,) + z.shape), [soil])
zw = -0.94
bottoms = np.stack([np.full(z.shape, zw + 0.3), np.full(z.shape, zw)])
mats = [soil, _mat(18.8, 0.0, 10.0, "weak"), _mat(18.8, 1000.0, 45.0, "hard")]
return Strata(x, y, z, bottoms, mats, hard=[False, False, True])
def test_zhang_case1_ellipsoid():
r = evaluate_surface(_zhang(False), [6.1, 0.0, 21.3], 24.4, 78.2 / 24.4, [-1.0, 0.0])
assert r["bishop"] == pytest.approx(2.167, rel=0.03) # Hungr 외 1989
assert r["bishop"] == pytest.approx(2.122, rel=0.03) # Zhang 1988
assert r["hovland"] < r["bishop"] # Hovland 은 보수적
def test_zhang_case2_weak_layer_truncated():
r = evaluate_surface(_zhang(True), [6.1, 0.0, 21.3], 24.4, 78.2 / 24.4, [-1.0, 0.0])
assert r["bishop"] == pytest.approx(1.620, rel=0.03) # Hungr 외 1989
assert r["truncated_ratio"] > 0.1
# 잘린 면 → Janbu 보정으로 전환하되 Bishop 이 낮으면 Bishop(작은 쪽)
assert r["governing"] == pytest.approx(min(r["bishop"], r["janbu_corrected"]))
assert 1.45 < r["janbu_corrected"] < 1.80 # 문헌 폭 1.53~1.67 둘레
def test_pore_pressure_and_seismic():
st, c = _gens(0.04)
dry = evaluate_surface(st, c, 1.0)
# φ=0 이면 간극수압은 저항에 안 들어감
assert evaluate_surface(st, c, 1.0, groundwater={"mode": "ru", "ru": 0.3})[
"bishop"
] == pytest.approx(dry["bishop"])
# c−φ 흙: r_u 가 F 를 낮춤 · 깊은 지하수위는 영향 없음 · kh 는 낮춤
st2 = Strata(st.x, st.y, st.z_top, st.bottoms, [_mat(1.0, 0.05, 25.0)], z_water=st.z_top - 5.0)
base = evaluate_surface(st2, c, 1.0)["bishop"]
assert evaluate_surface(st2, c, 1.0, groundwater={"mode": "ru", "ru": 0.3})["bishop"] < base
assert evaluate_surface(st2, c, 1.0, groundwater={"mode": "line"})["bishop"] == pytest.approx(
base
)
st2.z_water = st2.z_top + 0.0
assert evaluate_surface(st2, c, 1.0, groundwater={"mode": "line"})["bishop"] < base
assert evaluate_surface(st2, c, 1.0, seismic_kh=0.1)["bishop"] < base
def test_governing_picks_bishop_when_not_truncated():
res = {
"bishop": np.array([1.5, 1.5]),
"janbu_corrected": np.array([1.4, 1.4]),
"truncated_ratio": np.array([0.0, 0.5]),
}
f, meth = governing(res)
assert f.tolist() == [1.5, 1.4] and meth.tolist() == [0, 1]