feat(567-2): E04 임계 활동체 기둥 수 · 100 미만 경고 · 기본 설정 Scoops3D 재현 시험 · E07 집수면적 D∞
- E04 best · stats 에 columns · few_columns(< 100 · Scoops3D limcol) - 시험 533_3: 기본 설정 그대로 · 상자 없이 제방 30° 1.3203 · D&G 1a 1.0385 · 제방 60° 0.7488(±2 %) · 기둥 경고 - E07 집수면적 = D∞(Tarboton 1997 · SINMAP 원본) · 내리막 없는 채운 평지만 D8 - 시험 536_2: D∞ 면 몫(22.5° = 반씩) · 30° 돌린 평면 줄무늬 표준편차 0.05(D8 0.16) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -217,3 +217,38 @@ def test_ground_order_and_label_map(tmp_path):
|
||||
assert ids == ["fill", "weathered_soil", "weathered_rock", "soft_rock"]
|
||||
mapped = grid_engine.strata_from_grid(grid, label_map={"soil": "colluvium", "fill": "fill"})
|
||||
assert [m["id"] for m in mapped.materials][:2] == ["fill", "colluvium"]
|
||||
|
||||
|
||||
def _embankment(run_m, gamma, phi, c, half=20.0):
|
||||
"""Scoops3D 검증 제방(H 10 m) — 탐색 상자 없이 격자 전체 · y ±20 m."""
|
||||
x = np.arange(-25, run_m + 35 + 1e-9, 1.0)
|
||||
y = np.arange(-half, half + 1e-9, 1.0)
|
||||
xx, _ = np.meshgrid(x, y)
|
||||
z = np.clip(xx / run_m * 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])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("run_m", "gamma", "phi", "c", "expected"),
|
||||
[
|
||||
(10 / math.tan(math.radians(30)), 19, 20, 8.64, 1.32), # 표 6.8 제방 30°
|
||||
(20.0, 20, 19.6, 3.0, 1.04), # Donald & Giam 1a
|
||||
(10 / math.tan(math.radians(60)), 19, 20, 8.64, 0.75), # 표 6.11 제방 60°
|
||||
],
|
||||
)
|
||||
def test_default_settings_reproduce_scoops3d(run_m, gamma, phi, c, expected):
|
||||
"""567-2 — 실사용 기본 설정 그대로(노드 2 m · 거친 4 배 · 높이 2~30 m · dr 1 m · 부피 10~10,000 m³ ·
|
||||
구 + 타원체) · 좁힌 상자 없이 → 문헌값 ±2 %(실측 +0.0 · −0.1 · −0.2 %)."""
|
||||
best = search(_embankment(run_m, gamma, phi, c), SearchParams(workers=8)).best
|
||||
assert best["governing"] == pytest.approx(expected, rel=0.02)
|
||||
assert best["columns"] == len(best["cells"]) >= 100 and best["few_columns"] is False
|
||||
|
||||
|
||||
def test_few_columns_warning():
|
||||
"""567-2 — 임계 활동체 기둥 < 100(Scoops3D limcol) → few_columns 경고."""
|
||||
st = _embankment(10 / math.tan(math.radians(60)), 19, 20, 8.64, half=8.0)
|
||||
p = SearchParams(box=(-9, -3, -1, 1), h_min=4, h_max=10, v_min=10, v_max=60, ratios=(1.0,))
|
||||
r = search(st, p)
|
||||
assert r.best["columns"] < 100 and r.best["few_columns"] is True
|
||||
assert r.stats["columns"] == r.best["columns"] and r.stats["few_columns"] is True
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""536-2 — E07 광역 자연사면 위험 `E07_StabArea_Engine` · `_Router`.
|
||||
|
||||
무한사면 해석해(건조 · 포화 · 점착) · SINMAP 안정 지수(닫힌 꼴 = 표본 · 등급 경계) ·
|
||||
D8 집수면적 견본(기운 평면 · V 골짜기) · 습윤지수 · SI 하한 / 상한 해석해 · 시나리오 둘(표준 · 최악) ·
|
||||
D∞ 집수면적 견본(기운 평면 · V 골짜기 · 면 몫 · 돌린 평면) · 습윤지수 · SI 하한 / 상한 해석해 · 시나리오 둘(표준 · 최악) ·
|
||||
가짜 복사본으로 띠 · 측점표 · 저장본 · 지문.
|
||||
"""
|
||||
|
||||
@@ -84,6 +84,22 @@ def test_D8_집수면적_기운평면_V골짜기():
|
||||
assert np.all(a[4, :-1] < a[4, 1:]) # 골 따라 늘어남
|
||||
|
||||
|
||||
def test_Dinf_면_몫_돌린평면():
|
||||
"""567-2 D∞(Tarboton 1997 · SINMAP 원본) — 면 안 22.5° 흐름 = 곁 · 대각 반씩 · 30° 돌린 평면
|
||||
집수면적 = 흐름길 길이(D8 줄무늬 표준편차 0.16 → D∞ 0.05)."""
|
||||
cell = 2.0
|
||||
ii, jj = np.indices((5, 5))
|
||||
r1, r2, f1 = engine.dinf_receivers(-(jj - math.tan(math.pi / 8) * ii) * cell, cell)
|
||||
assert (r1[2, 2], r2[2, 2]) == (2 * 5 + 3, 1 * 5 + 3) and f1[2, 2] == pytest.approx(0.5)
|
||||
n, th = 60, math.radians(30)
|
||||
i, j = np.indices((n, n))
|
||||
z = 500 - (j * math.cos(th) + i * math.sin(th)) * cell * 0.5
|
||||
length = np.minimum((j + 0.5) / math.cos(th), (i + 0.5) / math.sin(th)) * cell
|
||||
inner = (i > 5) & (j > 5) & (i < n - 5) & (j < n - 5)
|
||||
ratio = engine.catchment_area(z, cell)[inner] / length[inner]
|
||||
assert np.std(ratio) < 0.08 and np.median(np.abs(ratio - 1)) < 0.2
|
||||
|
||||
|
||||
def test_습윤지수():
|
||||
beta = np.radians(np.array([30.0, 30.0, 0.0]))
|
||||
a = np.array([100.0, 1e6, 50.0])
|
||||
|
||||
Reference in New Issue
Block a user