- 좁은 λ 에 해 없으면 넓은 λ(Spencer −2 ~ 2 · M-P ±π · 41 점 거친 훑기 → 뉴턴) 다시 찾음 - Bishop 임계 원에서도 해 없음 + 찾은 최소 > Bishop = 그 방법 원호 「해 없음」(F None · status · reason) · 최소 F 후보에서 빠짐 - 수렴 정보 칸 residual · lambda_range · status(converged · no_solution · rejected) 덧붙임 · 해 없음 때도 F_m · F_f–λ 곡선(넓은 범위) - E03 방법 표 빈 값 = 「수렴 안 됨」(View no_solution 칸 · 옛 저장본은 없음) - 시험 test_532_2_stab_nosolution 새로 · 검증_sub4 59 측점 Bishop · Fellenius · Janbu 값 차 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
123 lines
5.1 KiB
Python
123 lines
5.1 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""532-2 덧 3 엄밀해(Spencer · M-P) 해 없음 — 넓은 λ 다시 찾기 · 「수렴 안 됨」 · 수렴 정보 칸.
|
|
|
|
- 해 없는 견본 = 검증_sub4 STA.0+340 우기 깎기 비탈을 줄인 꼴(풍화토 위 · 풍화암 · 지표 수위 · 노면 하중):
|
|
Bishop 임계 원에서 F_m · F_f 가 λ −2 ~ 2(M-P ±π)에서 안 만남 → 옛 엔진은 먼 원(F 1.82 · Bishop 1.34 의
|
|
136 %)을 Spencer 값으로 냈음 → 이제 Spencer · M-P 원호 = F None · status no_solution · 까닭 · 넓은 곡선.
|
|
- 해 있는 면 = 상태 converged · 잔차 < 1e-4 · λ 좁은 범위 안 · 곡선 21 점(옛 꼴 그대로).
|
|
|
|
./venv/Scripts/python.exe -m pytest resources/tester/test_532_2_stab_nosolution.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 test_532_2_stab_lem_benchmarks import ACADS_EXT, mats # noqa: E402
|
|
|
|
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,
|
|
)
|
|
|
|
MP = "morgenstern_price"
|
|
SURFACE = [
|
|
[-25.0, 876.6], [-17.0, 871.7], [-13.0, 867.7], [-11.5, 867.1],
|
|
[-3.9, 859.7], [-2.5, 856.6], [2.0, 857.0], [10.0, 850.3],
|
|
] # fmt: skip
|
|
NO_SOLUTION_MODEL = {
|
|
"materials": [
|
|
{"id": "ws", "gamma_t": 18.0, "gamma_sat": 19.0, "c": 15.0, "phi": 30.0},
|
|
{"id": "wr", "gamma_t": 20.0, "gamma_sat": 21.0, "c": 30.0, "phi": 33.0},
|
|
],
|
|
"regions": [
|
|
{"material_id": "ws", "polygon": [
|
|
[-24.5, 876.5], [-16.5, 871.4], [-13.0, 867.7], [-11.5, 867.1], [-8.0, 863.0],
|
|
[-5.5, 861.4], [-3.5, 858.9], [-8.0, 862.5], [-11.5, 866.6], [-14.5, 868.5],
|
|
[-16.5, 870.9], [-25.0, 876.1],
|
|
]},
|
|
{"material_id": "ws", "polygon": [
|
|
[-0.2, 856.9], [3.5, 855.3], [10.0, 849.2], [3.5, 854.8], [1.0, 855.4], [-0.8, 856.9],
|
|
]},
|
|
{"material_id": "wr", "polygon": [
|
|
[-3.0, 857.6], [-2.5, 856.6], [-0.8, 856.9], [1.0, 855.4], [3.5, 854.8],
|
|
[10.0, 849.2], [10.0, 801.5], [-25.0, 801.5], [-25.0, 876.1], [-16.5, 870.9],
|
|
[-5.0, 860.5],
|
|
]},
|
|
],
|
|
"surface": SURFACE,
|
|
"groundwater": {"mode": "line", "line": SURFACE},
|
|
"surcharge": [{"x0": -2.0162, "x1": 2.0, "q": 10.0}],
|
|
"bottom_z": 801.5,
|
|
} # fmt: skip
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def unsolved():
|
|
return analyze(
|
|
NO_SOLUTION_MODEL, direction=1, limits=[-9.561, 2.0], min_depth=0.3, noncircular=False
|
|
)
|
|
|
|
|
|
def test_no_solution_reported_not_a_far_circle(unsolved):
|
|
ms = unsolved["methods"]
|
|
bishop = ms["bishop"]["circular"]
|
|
assert 1.30 < bishop["F"] < 1.40
|
|
for key, rng in (("spencer", lem.LAMBDA_WIDE), (MP, gle.LAMBDA_WIDE)):
|
|
c = ms[key]["circular"]
|
|
assert c["F"] is None and c["status"] == "no_solution" and c["converged"] is False
|
|
assert c["lambda"] is None and "해 없음" in c["reason"]
|
|
assert c["lambda_range"] == pytest.approx(list(rng))
|
|
# 「해 없음」 면 = Bishop 임계 원 · 최소 F 후보에서 빠짐
|
|
assert c["radius"] == pytest.approx(bishop["radius"]) and c["center"] == bishop["center"]
|
|
assert ms[key]["min"] is None
|
|
assert isinstance(c["iterations"], int)
|
|
assert c["residual"] is None or c["residual"] > 1e-4
|
|
# F_m · F_f – λ 곡선은 넓은 범위 그대로(화면 그래프로 해 없음이 보이게)
|
|
curve = c["lambda_curve"]
|
|
assert len(curve["lambda"]) == lem.WIDE_POINTS
|
|
assert curve["lambda"][0] == pytest.approx(rng[0]) and curve["lambda"][-1] == pytest.approx(
|
|
rng[1]
|
|
)
|
|
assert sum(v is not None for v in curve["Fm"]) > 10
|
|
# 판정 쪽(Bishop · Fellenius · Janbu)은 그대로
|
|
assert all(ms[k]["min"]["F"] is not None for k in ("ordinary", "bishop", "janbu"))
|
|
|
|
|
|
def test_spencer_curve_has_no_crossing_in_wide_range(unsolved):
|
|
curve = unsolved["methods"]["spencer"]["circular"]["lambda_curve"]
|
|
lam = np.array(curve["lambda"], float)
|
|
d = np.array(curve["Fm"], float) - np.array(curve["Ff"], float)
|
|
near0 = np.isfinite(d) & (lam <= 0.25)
|
|
assert near0.sum() > 20 and np.all(d[near0] < 0)
|
|
|
|
|
|
def test_solved_surface_status_and_shape_unchanged():
|
|
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, rng in (("spencer", lem.LAMBDA_RANGE), (MP, gle.LAMBDA_RANGE)):
|
|
out = r[key]
|
|
assert out["status"] == "converged" and out["reason"] is None and out["converged"] is True
|
|
assert out["residual"] < 1e-4 and rng[0] <= out["lambda"] <= rng[1]
|
|
assert out["lambda_range"] == pytest.approx(list(rng))
|
|
assert len(out["lambda_curve"]["lambda"]) == gle.CURVE_POINTS
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(pytest.main([__file__, "-q"]))
|