- Search: 후보 덩이를 프로세스로 나눠 셈(workers · 0 = 자동 · 격자 5만 칸 이상이면 CPU − 2 · 12 까지) · 낸 차례대로 합침 — 일꾼 수와 무관하게 같은 값 - Search: 지층은 임시 파일로 일꾼에 넘김(spawn 관이면 일꾼이 차례로 떠 12 개 6 s) · 돌려받는 칸은 iy · ix · group(int32)만 - Search: 고친 노드 판정 = 반지름 시작 때 셀 최소(덩이 나눔과 무관) · 1차 SearchParams 칸 · SearchResult 꼴 그대로 - Search: 1단계 거르기 = 활동면 높이를 창 전체가 아니라 걸친 칸에서만 · 큰 창 배열 펴지 않음 - Column: Bishop · Janbu 고정점 — 기둥별 상수 미리 · 수렴한 활동체 기둥은 빼며 셈(값 같음) - 측정(검증_sub5 57 측점 · 노드 2 m · 구 + 타원체 2): 1차 287 s → 한 프로세스 217 s → 12 프로세스 32.1 s · 셀 9.7만 F 전후 최대 차 6e-15 · 전역 최소 1.099 그대로 - 시험: 일꾼 1 · 2 같은 값 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
100 lines
3.4 KiB
Python
100 lines
3.4 KiB
Python
"""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³
|
||
- 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_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
|