Merge remote-tracking branch 'origin/sub_laptop_4' into sub_laptop_3
This commit is contained in:
@@ -180,9 +180,8 @@ def test_acads_3a_weak_seam_noncircular_search():
|
||||
near(nonc(r, "spencer"), 1.258)
|
||||
|
||||
|
||||
def test_acads_4_inclined_seam_water_surcharge():
|
||||
def _acads4_model():
|
||||
# S2VM #9 (ACADS 4) — 기운 약층 · 지하수위선 · 등분포 20 kPa + 선형 20→40 kPa
|
||||
# 최적화 비원호 Spencer 0.707 · Janbu 보정 0.699 (약층 좌표 = 저해상 그림 판독 — 출처 ±5 % 권함)
|
||||
ext = Polygon([[20, 15], [84, 15], [84, 40], [67.5, 40], [43, 27.75], [20, 27.75]])
|
||||
seam = Polygon([[20, 18.26], [84, 36.2], [84, 36.8], [20, 18.88]])
|
||||
regions = [{"material_id": "seam", "polygon": list(ext.intersection(seam).exterior.coords)}] + [
|
||||
@@ -208,7 +207,12 @@ def test_acads_4_inclined_seam_water_surcharge():
|
||||
],
|
||||
},
|
||||
}
|
||||
r = analyze(m, direction=-1, methods=("janbu", "spencer"))
|
||||
return m
|
||||
|
||||
|
||||
def test_acads_4_inclined_seam_water_surcharge():
|
||||
# S2VM #9 — 최적화 비원호 Spencer 0.707 · Janbu 보정 0.699 (약층 좌표 = 저해상 그림 판독 — 출처 ±5 % 권함)
|
||||
r = analyze(_acads4_model(), direction=-1, methods=("janbu", "spencer"))
|
||||
near(nonc(r, "spencer"), 0.707)
|
||||
near(nonc(r, "janbu"), 0.699)
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
# -*- 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"]))
|
||||
Reference in New Issue
Block a user