Files
Aislo/resources/tester/test_533_2_stab3d_search.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

121 lines
4.1 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 활동면 탐색 — Scoops3D 검증 표 전역 최소 ±3 %.
Reid 외(2015) Scoops3D 표 6.8 · 6.11(CLARA-W 와 같은 구): H 10 m 제방
- 30° · λ 0.125(γ 19 · φ 20° · c 8.64 kPa) → Bishop 1.32 · 부피 1,124 m³
- 60° · λ 0.125 → 0.75 — 발끝에 거의 닿는 면(발끝 앞 접시는 따로 덩이 · 마지막 다듬기) ±1 %
- Donald & Giam 1a 2:1 · γ 20 · φ 19.6° · c 3 kPa → 1.04
- 표 6.7 원뿔 30° · r_u 0.4 → 1.626
탐색 격자는 시험 시간 때문에 문헌 임계 중심 둘레로 좁힘.
"""
import numpy as np
import pytest
from E04_Stab3D.E04_Stab3D_Engine_Column import Strata
from E04_Stab3D.E04_Stab3D_Engine_Search import SearchParams, search
def _embankment(run, gamma, phi, c, dx=1.0):
x = np.arange(-25, run + 35 + 1e-9, dx)
y = np.arange(-40, 40 + 1e-9, dx)
xx, _ = np.meshgrid(x, y)
z = np.clip(xx / run * 10.0, 0, 10.0)
mat = {"id": "m", "name": "m", "gamma_t": gamma, "gamma_sat": gamma, "c": c, "phi": phi}
return Strata(x, y, z, np.zeros((0,) + z.shape), [mat])
def test_embankment_30deg_global_minimum():
st = _embankment(10 / np.tan(np.radians(30)), 19, 20, 8.64)
p = SearchParams(
box=(-2, 10, -1, 1),
h_min=4,
h_max=24,
spacing=1.0,
coarse=2,
max_depth=20,
v_min=50,
v_max=2e4,
ratios=(1.0,),
)
r = search(st, p)
assert r.best["governing"] == pytest.approx(1.32, rel=0.03)
assert r.best["volume"] == pytest.approx(1124, rel=0.15)
f = r.f_min
assert np.nanmin(f) == pytest.approx(r.best["governing"])
# 셀별 최소 지도: 임계 활동체 안 셀은 전역 최소 · 부피 래스터가 같이 채워짐
assert np.isfinite(r.volume[np.isfinite(f)]).all()
def test_embankment_60deg_toe_minimum():
st = _embankment(10 / np.tan(np.radians(60)), 19, 20, 8.64)
p = SearchParams(
box=(-9, -5, -1, 1),
h_min=13,
h_max=17,
h_step=1,
spacing=1.0,
coarse=2,
dr=0.5,
max_depth=20,
v_min=50,
v_max=2e4,
ratios=(1.0,),
)
r = search(st, p)
assert r.best["governing"] == pytest.approx(0.75, rel=0.01)
assert np.nanmin(r.f_min) == pytest.approx(r.best["governing"])
def test_donald_giam_1a():
st = _embankment(20, 20, 19.6, 3.0)
p = SearchParams(
box=(-4, 6, -1, 1),
h_min=16,
h_max=30,
spacing=1.0,
coarse=2,
max_depth=20,
v_min=50,
v_max=3e4,
ratios=(1.0,),
)
assert search(st, p).best["governing"] == pytest.approx(1.04, rel=0.03)
def test_wet_cone_pore_pressure_ratio():
"""Scoops3D 표 6.7 · 원뿔 30° · λ 0.125(γ 20 · φ 30°) · r_u 0.4 → Bishop 1.626(도표 1.644)."""
h = 10.0
r0 = h / np.tan(np.radians(30))
x = np.arange(-r0 - 15, r0 + 15 + 1e-9, 0.5)
xx, yy = np.meshgrid(x, x)
z = np.clip(h - np.hypot(xx, yy) * np.tan(np.radians(30)), 0, h)
c = 0.125 * 20 * h * np.tan(np.radians(30))
mat = {"id": "m", "name": "m", "gamma_t": 20, "gamma_sat": 20, "c": c, "phi": 30}
st = Strata(x, x, z, np.zeros((0,) + z.shape), [mat])
p = SearchParams(
box=(8, r0 + 4, -1, 1),
spacing=1.0,
h_min=1,
h_max=21,
h_step=2,
coarse=4,
max_depth=15,
v_min=20,
v_max=3e4,
ratios=(1.0,),
groundwater={"mode": "ru", "ru": 0.4},
)
assert search(st, p).best["governing"] == pytest.approx(1.626, rel=0.03)
def test_workers_same_result():
"""프로세스 나눔 — 일꾼 수와 무관하게 셀별 최소 F · 전역 최소가 같음."""
st = _embankment(10 / np.tan(np.radians(30)), 19, 20, 8.64)
kw = dict(box=(-2, 10, -4, 4), h_min=4, h_max=20, spacing=2.0, coarse=2, max_depth=16)
kw.update(v_min=50, v_max=2e4, ratios=(1.0, 2.0))
one = search(st, SearchParams(workers=1, **kw))
two = search(st, SearchParams(workers=2, **kw))
np.testing.assert_array_equal(one.f_min, two.f_min)
assert one.best["governing"] == two.best["governing"]
assert one.evaluated == two.evaluated