- 운반표를 만든 한 곳(Router_Earthwork)에서 암 줄을 흙깎기와 같은 구성비(_split_by_rock)·갈래별 시공법으로 가름 → 운반거리·토공집계 운반 줄·인계·사토가 한 값 - 구성비가 비면 「암」 한 줄로 막음(깎기와 같은 사유) · 시공법 안 고른 갈래만 막음 · 무대(내역 밖) 줄은 안 막음 - 유토곡선 거리·다짐 부피는 그대로(몫대로 나눔 · 검산 차이 0) — C 까지 구성비로 맞추는 것은 (나) 차례 - 936be972: 구성비 없음 → 운반·적재·사토 암 전부 입력 사유(종전 리핑암 금액 섬) · 연암 60 리핑/보통암 40 발파 → 흙깎기 2,060.043/1,373.362 · 도자 38.123/25.416 · 덤프 112.195/74.797 · 사토 28.858/19.238 같은 몫 · 되돌림 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
107 lines
4.7 KiB
Python
107 lines
4.7 KiB
Python
"""㉱ (가) 암 운반량을 구성비로 가르기 — 2026-09-14 브레인 판정(구성비가 정본 · 8-1 사용자 확정).
|
|
|
|
B06 토사 토글 끔 = 저장값 `ripping_rock` 은 **자리표시**(「갈라 넣는 것은 설계내역 몫」)인데
|
|
운반·사토가 그 이름을 값처럼 써서 「깎기 암은 구성비가 비어 막히는데 운반 암은 리핑암으로 금액이 섬」.
|
|
⇒ 운반표 한 곳에서 암 줄을 구성비·시공법으로 가름 · 비면 「암」 한 줄로 막음(깎기와 같은 사유).
|
|
유토곡선 거리·다짐 부피는 그대로 — 검산이 안 흔들림((나)는 뒤 차례).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
if str(ROOT) not in sys.path:
|
|
sys.path.insert(0, str(ROOT))
|
|
|
|
from B08_Quantity.B08_Quantity_Engine_EarthworkSummary import SummaryInput # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_EarthworkSummary import build_table as summary # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_Handoff import build_handoff # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_Handoff_Mapping import ( # noqa: E402
|
|
NOTE_METHOD_MISSING,
|
|
NOTE_ROCK_RATIO_MISSING,
|
|
)
|
|
from B08_Quantity.B08_Quantity_Engine_HaulSummary import build_table, check_against_plan # noqa: E402
|
|
from B08_Quantity.B08_Quantity_Engine_RockSplit import apply_rock_split # noqa: E402
|
|
|
|
CLASSES = ["토사", "풍화암", "연암", "보통암", "경암"]
|
|
PLAN = {
|
|
"blocks": [
|
|
{
|
|
"bands": [
|
|
{"equipment": "dozer", "haul_distance_m": 40.0, "haul_from_m": 0.0,
|
|
"haul_to_m": 40.0, "ea_m3": 90.0, "rr_m3": 115.0, "br_m3": 0.0},
|
|
]
|
|
}
|
|
],
|
|
"transfers": [],
|
|
"hauled_m3": 205.0,
|
|
"transferred_m3": 0.0,
|
|
} # fmt: skip
|
|
SPOIL = {"volume_m3": 23.0, "distance_m": 300.0, "by_ground_m3": {"rr_m3": 23.0},
|
|
"natural_m3_by_ground": {"rr_m3": 20.0}} # fmt: skip
|
|
|
|
|
|
def _haul(ratios: dict, methods: dict) -> dict:
|
|
haul = build_table(PLAN)
|
|
haul["spoil"] = dict(SPOIL)
|
|
apply_rock_split(haul, CLASSES, ratios, methods)
|
|
return haul
|
|
|
|
|
|
def _rock(haul: dict) -> list[dict]:
|
|
return [r for r in haul["rows"] if r["ground"] != "토사"]
|
|
|
|
|
|
def test_구성비가_비면_운반_암도_한_줄_암으로_막힘() -> None:
|
|
haul = _haul({}, {})
|
|
(rock,) = _rock(haul)
|
|
assert rock["ground"] == "암" and rock["natural_m3"] == pytest.approx(100.0)
|
|
assert rock["blocked_reason"] == NOTE_ROCK_RATIO_MISSING
|
|
items = build_handoff(haul_table=haul)["work_items"]
|
|
dozer = next(r for r in items if r["name"].endswith("운반") and r["ground_class"] == "암")
|
|
assert (
|
|
dozer["blocked_kind"] == "input_missing"
|
|
and dozer["blocked_reason"] == NOTE_ROCK_RATIO_MISSING
|
|
)
|
|
spoil = next(r for r in items if r["name"] == "사토 운반")
|
|
assert (
|
|
spoil["blocked_kind"] == "input_missing"
|
|
and NOTE_ROCK_RATIO_MISSING in spoil["blocked_reason"]
|
|
)
|
|
|
|
|
|
def test_구성비와_시공법대로_갈리고_검산은_그대로() -> None:
|
|
ratios = {"연암": 60.0, "보통암": 40.0}
|
|
methods = {"연암": "ripping", "보통암": "blasting"}
|
|
haul = _haul(ratios, methods)
|
|
got = [(r["rock_class"], r["ground"], round(r["natural_m3"], 6)) for r in _rock(haul)]
|
|
assert got == [("연암", "리핑암", 60.0), ("보통암", "발파암", 40.0)]
|
|
assert check_against_plan(haul, PLAN).difference_m3 == pytest.approx(0.0)
|
|
items = build_handoff(haul_table=haul)["work_items"]
|
|
dozer = [r for r in items if r["haul_equipment"] == "dozer" and r["ground_class"] != "토사"]
|
|
assert [(r["spec"], r["variant_value"], r["blocked_kind"]) for r in dozer] == [
|
|
("연암 · 리핑암", "리핑암", None),
|
|
("보통암 · 발파암", "발파암", None),
|
|
]
|
|
spoil = [r for r in items if r["name"] == "사토 운반"]
|
|
assert [(r["variant_value"], round(r["quantity"], 3)) for r in spoil] == [
|
|
("리핑암", 12.0),
|
|
("발파암", 8.0),
|
|
]
|
|
# 깎기와 같은 몫 — 흙깎기 암 1000 이 같은 구성비로 600 · 400
|
|
rows = summary(SummaryInput(earthwork_totals={"cut_rock_volume_m3": 1000.0},
|
|
rock_classes=CLASSES, rock_ratios_pct=ratios))["rows"] # fmt: skip
|
|
cut = {r["item"]: r["amount"] for r in rows if r["group"] == "흙깎기" and r["item"] != "토사"}
|
|
assert cut == {"연암": 600.0, "보통암": 400.0}
|
|
|
|
|
|
def test_시공법을_안_고른_갈래만_막힘() -> None:
|
|
haul = _haul({"연암": 50.0, "경암": 50.0}, {"연암": "ripping"})
|
|
rows = {r["rock_class"]: r for r in _rock(haul)}
|
|
assert not rows["연암"]["blocked_reason"]
|
|
assert rows["경암"]["blocked_reason"] == NOTE_METHOD_MISSING
|