Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BW6Jdsh18WPtYUR6THZJqn
69 lines
2.8 KiB
Python
69 lines
2.8 KiB
Python
"""B09 — 기계 작업량 **밑값**을 마스터에서 읽는다(2026-09-16 사용자 원칙 · 브레인 지시).
|
|
|
|
마스터 = 관리자가 제어할 값 · **코드 안에 있으면 안 됨.**
|
|
|
|
그동안 불도저 속도·삽날 용량(건설품셈 8-2-1)과 덤프 운반·적재 식 계수(산림품셈 10-12)가
|
|
코드 상수로 박혀 있었다. 값은 그대로 두고 자리만 옮긴다 —
|
|
`resources/data_machine_productivity/machine_productivity_<판>.json`.
|
|
⚠ **식은 여기 없다.** `Q = n·q·f·E` 같은 식은 값이 아니라 로직이라 계산 모듈에 남는다.
|
|
⚠ 옮기면서 값을 하나도 안 바꿨다 — 원문(pum_const C0426·C0427)과의 대조는 시험이 지킨다.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from decimal import Decimal
|
|
from functools import lru_cache
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
DATA_DIR = Path(__file__).resolve().parent.parent / "resources" / "data_machine_productivity"
|
|
PREFIX = "machine_productivity_"
|
|
|
|
|
|
class MachineProductivityDataError(FileNotFoundError):
|
|
"""밑값 판이 없다 — 지어내지 않고 멈춘다."""
|
|
|
|
|
|
@lru_cache(maxsize=2)
|
|
def _read(path: str, _mtime_ns: int) -> dict[str, Any]:
|
|
return json.loads(Path(path).read_text(encoding="utf-8"))
|
|
|
|
|
|
def load() -> dict[str, Any]:
|
|
"""끝 판 한 벌(이름 차례)."""
|
|
found = sorted(DATA_DIR.glob(PREFIX + "*.json")) if DATA_DIR.is_dir() else []
|
|
if not found:
|
|
raise MachineProductivityDataError(f"기계 작업량 밑값 판이 없습니다: {DATA_DIR}")
|
|
return _read(str(found[-1]), found[-1].stat().st_mtime_ns)
|
|
|
|
|
|
def records(variable: str) -> list[dict[str, Any]]:
|
|
return load()["variables"][variable]["records"]
|
|
|
|
|
|
def dozer_speeds() -> dict[str, dict[Decimal, dict[int, tuple[Decimal, Decimal]]]]:
|
|
"""{무한궤도·타이어: {규격(ton): {단: (전진, 후진)}}} — 후진이 원문에 없는 단은 담기지 않는다."""
|
|
out: dict[str, dict[Decimal, dict[int, tuple[Decimal, Decimal]]]] = {}
|
|
for row in records("dozer_speed"):
|
|
track = out.setdefault(row["track"], {})
|
|
gears = track.setdefault(Decimal(row["tonnage_ton"]), {})
|
|
gears[int(row["gear"])] = (
|
|
Decimal(row["forward_m_per_min"]),
|
|
Decimal(row["reverse_m_per_min"]),
|
|
)
|
|
return out
|
|
|
|
|
|
def dozer_blades() -> dict[tuple[str, Decimal], Decimal]:
|
|
"""{(무한궤도·타이어, 규격(ton)): 삽날 용량 q˚(㎥)}."""
|
|
return {
|
|
(row["track"], Decimal(row["tonnage_ton"])): Decimal(row["blade_m3"])
|
|
for row in records("dozer_blade")
|
|
}
|
|
|
|
|
|
def haul_params() -> dict[str, Decimal]:
|
|
"""덤프 운반·적재 식이 쓰는 밑값(적재 규격 T · 버켓 q · 싸이클 · 주행속도 · 적하·대기·덮개)."""
|
|
return {row["key"]: Decimal(row["value"]) for row in records("dump_haul")}
|