Merge remote-tracking branches 'origin/sub_laptop_4' and 'origin/sub_laptop_8' into main_laptop_1

This commit is contained in:
2026-10-26 04:17:34 +09:00
9 changed files with 235 additions and 9 deletions
+2
View File
@@ -28,6 +28,7 @@
| 전도 측방 한계 (°) | 절리가 사면 반대로 기운 방향 차이가 이 각 안이면 전도 후보 | 5 ~ 45 | 20 |
| 암 단위중량 (kN/m³ · 비우면 E02) | 덩이 무게 계산 값 · 비우면 지반 조건(E02)의 그 측점 암 물성 γt · 그것도 없으면 25 | 15 ~ 35 | 빈 칸 |
| 우기 수위 비 (0~1) | 우기 조건 물 차는 정도 · 0 = 마름 · 1 = 가득 참 | 0 ~ 1 | 0.5 |
| 최소 블록 크기 (m³) | 이보다 작은 블록은 판정(N.G · O.K)과 최소 Fs 에서 빼고 「소규모 · 낙석 관리」로 표시 · 평면은 폭 1 m 당 부피 · 0 = 거르지 않음 · [기본값] 으로 되돌림 | 0 ~ 1,000 | 0.1 |
| 인장균열 | 사면 윗면에서 아래로 갈라진 틈을 볼지 · 없음 · 임계(최소 안전율 자리) · 깊이 지정 | - | 없음 |
| 균열 깊이 (m) | 「깊이 지정」 때만 보임 · 윗면에서 잰 균열 깊이 | 0.1 ~ 100 | 1 |
| 볼트 힘 (평면 kN/m · 쐐기 kN) | 록볼트 · 앵커가 잡아 주는 힘 · 평면은 폭 1 m 당 · 쐐기는 덩이 하나당 | 0 ~ 5,000 | 0 |
@@ -35,6 +36,7 @@
- 측방 한계 기본 20° = 상용 Dips 기본 · 지식DB 03 은 전도에 30° 를 씀 — 화면에서 바꿀 수 있음.
- 우기 수위 비 기본 0.5 = 비탈 높이 ½ 수위(KDS 11 70 05 암반).
- 최소 블록 크기 기본 0.1 m³ = 상용 쐐기 해석(SWedge)의 최소 쐐기 크기 옵션과 같은 뜻(사용자 확정 전). 아주 얇은 쐐기가 들림으로 N.G 를 내는 것을 막음. 거른 블록 수는 비탈 상세와 보고서 요약에 나옴.
- 인장균열 「임계」 = 균열 자리를 마루 뒤로 옮겨 가며 안전율이 가장 낮은 자리를 찾음. 균열 없는 쪽이 더 낮으면 균열 없음으로 셈. 평면 무너짐에만 씀.
- 볼트 = 수동 지지력(덩이가 움직이면 버팀). 0 이면 보강 없음.
+132
View File
@@ -497,3 +497,135 @@ def test_e05_rock_sheet(monkeypatch):
rock.fill_rock(sheet, old, {})
assert sheet["칸"]["A13"]["값"] == doc["sets"][0]["name"]
assert sheet["칸"]["G13"]["값"] == "-" # 구간 모름
# ---- 최소 블록 크기 (요구 351 · 536-1 덧) --------------------------------------------
def _cases_with_volume(monkeypatch, volume: float, min_block: float):
"""엔진을 가짜 부피로 바꿔 경계(< 최소 블록)만 본다 — 평면(W = γ·면적) · 쐐기 둘."""
gamma = 25.0
monkeypatch.setattr(
model.engine,
"plane_fs",
lambda **_k: {"F": 0.5, "W": volume * gamma, "A": 5.0, "z": 0.0},
)
monkeypatch.setattr(
model.engine,
"wedge_fs",
lambda **_k: {"F": 0.0, "volume": volume, "line_length": 2.0, "mode": "lift", "W": 1.0},
)
joints = [
{"id": "J1", "dip_direction": 90, "dip": 40, "phi": 30, "c": 0},
{"id": "J2", "dip_direction": 200, "dip": 50, "phi": 30, "c": 0},
]
slope = {"dip_direction": 90, "dip": 68, "upper_dip": 0, "height_m": 5}
kin = {"planar": ["J1"], "wedge": [{"ids": ["J1", "J2"]}], "toppling": []}
settings = dict(model.DEFAULT_SETTINGS, min_block_m3=min_block)
return model._cases_for(slope, joints, kin, settings, gamma, [("dry", 0.0, 0.0)])
def test_min_block_default():
assert model.DEFAULT_SETTINGS["min_block_m3"] == 0.1
assert model.upgrade({"sets": [], "settings": {}})["settings"]["min_block_m3"] == 0.1
@pytest.mark.parametrize(
"volume,small", [(0.0999, True), (0.1, False), (0.3, False), (0.0003, True)]
)
def test_min_block_boundary(monkeypatch, volume, small):
"""최소 블록 0.1 m³ — 미만만 소규모(경계 = 거르지 않음) · 평면 · 쐐기 같은 규칙."""
cases = _cases_with_volume(monkeypatch, volume, 0.1)
assert [c["small"] for c in cases] == [small, small]
def test_min_block_zero_keeps_all(monkeypatch):
cases = _cases_with_volume(monkeypatch, 0.0003, 0.0)
assert not any(c["small"] for c in cases)
def test_min_block_verdict_and_counts(monkeypatch):
"""얇은 쐐기(들림 Fs 0)가 N.G 를 내던 자리 — 거르면 판정 · 최소 Fs 에서 빠지고 거른 블록 수가 남음."""
kin = {"planar": ["J1"], "wedge": [{"ids": ["J1", "J2"]}], "toppling": []}
for min_block, verdict, n_small in ((0.0, "NG", 0), (0.1, "none", 2)):
cases = _cases_with_volume(monkeypatch, 0.0003, min_block)
for c in cases:
c["required"] = 1.2
c["ok"] = None if c["small"] else c["F"] >= 1.2
out = model._verdict(kin, cases)
assert (out["verdict"], out["small_blocks"]) == (verdict, n_small)
assert out["min_F"] == (0.0 if not n_small else None)
# 큰 블록 + 작은 블록 섞임 — 작은 것만 빠지고 큰 것으로 판정
big = dict(_cases_with_volume(monkeypatch, 0.5, 0.1)[0], required=1.2, ok=False)
tiny = dict(_cases_with_volume(monkeypatch, 0.0003, 0.1)[1], required=1.2, ok=None)
tiny["F"] = 0.0
out = model._verdict(kin, [big, tiny])
assert (out["verdict"], out["min_F"], out["small_blocks"]) == ("NG", 0.5, 1)
def test_min_block_check_range():
doc = _doc()
doc["settings"]["min_block_m3"] = -1
assert {"path": "settings.min_block_m3", "code": "range"} in model.check_joints(doc)
doc["settings"]["min_block_m3"] = 2.5
assert model.check_joints(doc) == []
assert model.clean(doc)["settings"]["min_block_m3"] == 2.5
def test_analyze_min_block_filter(monkeypatch):
"""측점 해석 전체 길 — 최소 블록을 크게 주면 모든 경우 소규모 · ok 없음 · 판정 none."""
cross, design = _cross("left")
monkeypatch.setattr(
model,
"rock_stations",
lambda _s: [{"chainage_m": 20.0, "label": "STA", "ground_type": "ripping_rock"}],
)
monkeypatch.setattr(model.src, "cross_section", lambda _s, _c: {**cross, "design": design})
ground = {
"materials": [],
"stations": [],
"safety_factors": {"dry": {"cut": 1.5}, "wet": {"cut": 1.2}},
"seismic": {"enabled": False},
}
base = model.analyze(None, _doc(), ground)[0]
assert not any(c["small"] for c in base["cases"]) and base["small_blocks"] == 0
doc = _doc()
doc["settings"]["min_block_m3"] = 1000.0
e = model.analyze(None, doc, ground)[0]
assert all(c["small"] and c["ok"] is None for c in e["cases"])
assert (e["verdict"], e["min_F"], e["small_blocks"]) == ("none", None, 1)
def test_e05_rock_sheet_small(monkeypatch):
"""E05 s11 — 최소 블록 글 · 소규모 요약 · 줄 비고."""
from E05_StabReport import E05_StabReport_Build as build
from E05_StabReport import E05_StabReport_Rock as rock
from E06_StabRock import E06_StabRock_Router as router
cross, design = _cross("left")
monkeypatch.setattr(
model,
"rock_stations",
lambda _s: [{"chainage_m": 20.0, "label": "STA", "ground_type": "ripping_rock"}],
)
monkeypatch.setattr(model.src, "cross_section", lambda _s, _c: {**cross, "design": design})
ground = {
"materials": [],
"stations": [],
"safety_factors": {"dry": {"cut": 1.5}, "wet": {"cut": 1.2}},
"seismic": {"enabled": False},
}
doc = _doc()
doc["settings"]["min_block_m3"] = 1000.0
stations = model.analyze(None, doc, ground)
value = {
"settings": doc["settings"],
"sets": doc["sets"],
"summary": router._summary(stations),
"stations": stations,
"stale": False,
}
sheet = next(s for s in build.form()["시트"] if s["id"] == "s11")
rock.fill_rock(sheet, value, {})
cells = sheet["칸"]
assert "최소 블록 1000 m³" in cells["B8"]["값"] and "사용자 입력" in cells["B8"]["값"]
assert "소규모 블록 1" in cells["B9"]["값"]
assert any("소규모 · 낙석 관리" in str(c.get("값")) for c in cells.values())