Files
Aislo/resources/tester/test_533_2_stab3d_column.py
T
eomsangdonandClaude Opus 5.5 e966a37b5f fix(533-2 2차): E04 급경사 전역 최소 — 점 단위 덩이 나눔 · 전역 최소 다듬기 · Zhang 경우 3 시험
- Search: 활동면이 지표를 자른 점을 셀 안 점 단위로 덩이 나눔 — 발끝을 살짝 비켜 지나는 구의 사면 몸통 · 발끝 앞 접시가 따로(셀 중심 줄 꺾임만 검사 · 지표 쌍선형 + 활동면 볼록)
- Search: 전역 최소 면을 찾은 노드 · 반지름 한 눈금 안에서 Nelder-Mead 로 다듬음(box · node_mask 안) — 셀 지도도 그 면으로 고침
- Scoops3D 60° 0.771~0.776 → 0.754(0.75 · +0.5 %) · 30° 1.325 → 1.3197(1.32)
- 검증_sub5 1 km 띠: 전역 최소 1.185 → 1.174(−0.9 %) · p1/p5/p50 같음 · 셀 9.7만 중 168 이 1 % 넘게 바뀜 · 12 프로세스 28 s → 45 s
- 시험: 60° 제방 ±1 % · Zhang 경우 3(약층 + 수위선 · FK 1977 그림 8) Bishop 1.524 = Lam & Fredlund 1.481~1.54 · Gharti 1.49 ±3 % · 경우3/2 비 0.943

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 04:22:26 +09:00

122 lines
5.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.
"""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.
- 경우 3 = 경우 2 + 수위선(Fredlund & Krahn 1977 그림 8 · Slide3 2D Extruded #16 그림 16:
뒤 경계 42.7 m 에서 발끝 위 6.1 m → 발끝 → 발끝 앞 지표) → Lam & Fredlund 1993 1.481~1.54
· Gharti 2011 1.49 · Zhang 1.441(경우 2 처럼 Zhang 은 다른 풀이보다 4~6 % 낮음).
"""
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_zhang_case3_weak_layer_piezometric_line():
st = _zhang(True)
xx, _ = np.meshgrid(st.x, st.y)
st.z_water = np.clip(xx * 6.1 / 42.67, 0.0, None)
args = ([6.1, 0.0, 21.3], 24.4, 78.2 / 24.4, [-1.0, 0.0])
r = evaluate_surface(st, *args, groundwater={"mode": "line"})
assert 1.481 * 0.99 < r["bishop"] < 1.54 * 1.01 # Lam & Fredlund 1993 네 값 폭
assert r["bishop"] == pytest.approx(1.49, rel=0.03) # Gharti 2011
# 수위선이 낮추는 비 = Lam & Fredlund 경우 3/경우 2(0.940~0.951)
dry = evaluate_surface(_zhang(True), *args)["bishop"]
assert 0.93 < r["bishop"] / dry < 0.96
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]