Files
Aislo/resources/tester/test_532_2_stab_mp_outputs.py
T

142 lines
6.2 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.
# -*- coding: utf-8 -*-
"""532-2 2차 E03 2D — Morgenstern-Price(반정현) 대조 · 결과 자료(자유물체도 · F–λ 곡선 · Safety Map).
기대값 = Rocscience Slide2 Slope Stability Verification Manual(지식DB 참고문헌) 원문 GLE · M-P 값.
- #1 ACADS 1a GLE 0.986 · #3 ACADS 1c GLE 1.374 · #8 ACADS 3b 지정 비원호 GLE 1.262 ·
#9 ACADS 4 블록 + 최적화 GLE 0.683 · #21 F&K 지정 원 M-P 건기 2.075 · r_u 1.760(Slide 열).
- 뺀 것: #7 · #15 — 원문 GLE(1.275 · 0.437)가 같은 표 Spencer(1.246 · 0.409)보다 높음(Slide 탐색이 GLE
임계면을 놓친 값 · 같은 문제 #8 지정면 GLE 는 Spencer 보다 낮음) → 대조 기준으로 못 씀.
./venv/Scripts/python.exe -m pytest resources/tester/test_532_2_stab_mp_outputs.py -q
"""
from __future__ import annotations
import sys
from pathlib import Path
import numpy as np
import pytest
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(Path(__file__).resolve().parent))
from E03_StabSection import E03_StabSection_Engine_GLE as gle # noqa: E402
from E03_StabSection import E03_StabSection_Engine_LEM as lem # noqa: E402
from E03_StabSection.E03_StabSection_Engine_Search import ( # noqa: E402
analyze,
evaluate_specified,
)
from E03_StabSection.E03_StabSection_Engine_Surface import ( # noqa: E402
poly_slices,
three_point_center,
)
from test_532_2_stab_lem_benchmarks import ( # noqa: E402
ACADS1C_MATS,
ACADS1C_REGIONS,
ACADS_EXT,
FK_EXT,
_acads3_model,
_acads4_model,
circ,
mats,
near,
nonc,
)
MP = "morgenstern_price"
SEAM_3B = [[41.85, 27.75], [44.0, 26.5], [63.5, 27.0], [73.31, 40.0]]
def test_mp_constant_function_equals_spencer():
# f(x) ≡ 1 이면 M-P 식 = Spencer 식 — 같은 F · λ
prep = lem.Prepared(_acads3_model(), -1)
pts = sorted((-x, z) for x, z in SEAM_3B)
vx, vz = np.array([[p[0] for p in pts]]), np.array([[p[1] for p in pts]])
sl = poly_slices(prep, vx, vz, 50)
center = three_point_center(vx, vz)
sp = lem.spencer(sl, center, np.array([1.3]))
mp = gle.morgenstern_price(sl, center, "constant", F0=np.array([1.3]))
assert abs(mp["F"][0] - sp["F"][0]) < 1e-6
assert abs(mp["lambda"][0] - sp["lambda"][0]) < 1e-5
def test_mp_specified_surfaces_slide2():
# #8 지정 비원호 GLE 1.262 · #21 지정 원 M-P 건기 2.075 · r_u 0.25 1.760
r = evaluate_specified(_acads3_model(), polyline=SEAM_3B, direction=-1, methods=(MP,))
near(r[MP]["F"], 1.262, 0.01)
m = {"materials": mats(("s", 120, 600, 20)), "regions": [{"material_id": "s", "polygon": FK_EXT}]}
near(evaluate_specified(m, circle=[120, 90, 80], direction=1, methods=(MP,))[MP]["F"], 2.075, 0.01)
m["groundwater"] = {"mode": "ru", "ru": 0.25}
near(evaluate_specified(m, circle=[120, 90, 80], direction=1, methods=(MP,))[MP]["F"], 1.760, 0.01)
def test_mp_search_slide2():
# #1 원호 GLE 0.986 · #3 원호 GLE 1.374
m = {"materials": mats(("s", 20, 3, 19.6)), "regions": [{"material_id": "s", "polygon": ACADS_EXT}]}
near(circ(analyze(m, direction=-1, noncircular=False), MP), 0.986, 0.01)
r = analyze({"materials": ACADS1C_MATS, "regions": ACADS1C_REGIONS}, direction=-1, noncircular=False)
near(circ(r, MP), 1.374, 0.01)
def test_mp_acads4_noncircular():
# #9 블록 + 최적화 GLE 0.683 (약층 좌표 = 그림 판독 → ±2 %)
r = analyze(_acads4_model(), direction=-1, methods=("janbu", "spencer", MP))
near(nonc(r, MP), 0.683, 0.02)
def _closure(rows, lam, f_last=1.0):
weight = sum(r["weight"] for r in rows)
for a, b in zip(rows, rows[1:]):
assert abs(a["E_right"] - b["E_left"]) < 1e-9 and abs(a["X_right"] - b["X_left"]) < 1e-9
assert abs(rows[-1]["E_right"]) < 1e-3 * weight # 끝 절편에서 힘 평형이 닫힘
assert abs(rows[0]["X_left"]) < 1e-12
for r in rows:
# 연직 평형 — N·cosα + S·sinα = W + (X_right − X_left) (지진 · 균열 없음)
a = np.radians(r["alpha_deg"])
lhs = r["normal_total"] * np.cos(a) + r["shear_mobilized"] * np.sin(a)
assert abs(lhs - (r["weight"] + r["X_right"] - r["X_left"])) < 1e-6 * weight
def test_free_body_and_lambda_curve_outputs():
m = {"materials": mats(("s", 20, 3, 19.6)), "regions": [{"material_id": "s", "polygon": ACADS_EXT}]}
r = evaluate_specified(m, circle=[29.104, 55.527, 30.527], direction=-1, methods=("spencer", MP))
for key in ("spencer", MP):
out = r[key]
rows = out["slices"]
assert {"normal_total", "pore_force", "shear_strength", "E_right", "X_right", "x_mid"} <= rows[0].keys()
_closure(rows, out["lambda"])
curve = out["lambda_curve"]
lam, fm, ff = (np.array(curve[k], float) for k in ("lambda", "Fm", "Ff"))
assert len(lam) == gle.CURVE_POINTS and np.isfinite(fm).sum() > 10
# 곡선 교점 = 해 (F · λ)
d = fm - ff
k = np.where(np.isfinite(d[:-1]) & np.isfinite(d[1:]) & (np.sign(d[:-1]) != np.sign(d[1:])))[0]
assert len(k)
j = k[np.argmin(np.abs(lam[k] - out["lambda"]))]
t = d[j] / (d[j] - d[j + 1])
assert abs(lam[j] + t * (lam[j + 1] - lam[j]) - out["lambda"]) < 0.02
assert abs(fm[j] + t * (fm[j + 1] - fm[j]) - out["F"]) < 0.01 * out["F"]
assert abs(r[MP]["slices"][-1]["X_right"]) < 1e-9 # 반정현 f = 0 (끝)
def test_safety_map_and_reference_only():
m = {"materials": mats(("s", 17.64, 9.8, 10)), "regions": [{"material_id": "s", "polygon": [[0, 0], [25, 0], [25, 10], [15, 10], [5, 5], [0, 5]]}]}
r = analyze(m, direction=-1)
smap = r["safety_map"]["surfaces"]
assert 0 < len(smap) <= 50
F = [s["F"] for s in smap]
assert F == sorted(F) and F[0] >= 0.97 * circ(r, "bishop")
assert all(len(s["points"]) == 25 and s["points"][0][0] < s["points"][-1][0] for s in smap)
# 비원호 Fellenius · Bishop = 참고 칸 · 최소 F 는 원호에서만
for k in ("ordinary", "bishop"):
res = r["methods"][k]
assert res["noncircular"]["reference_only"] is True
assert res["min"]["kind"] == "circle"
assert r["methods"]["spencer"]["min"]["F"] <= circ(r, "spencer") + 1e-12
if __name__ == "__main__":
sys.exit(pytest.main([__file__, "-q"]))