fix(534-4): E05 3D요약 — 2D 최소 = 3D 와 같은 조건(우기 3D 를 건기 · 전 조건 최소와 견주던 것) · 판정 = E04 엔진 판정(기준안전율 건기 고정이던 것) · 시험 3D 저장본에 condition · verdict

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 23:00:57 +09:00
co-authored by Claude Opus 5.5
parent 770d5b27c7
commit 52858c5078
2 changed files with 20 additions and 7 deletions
+9 -4
View File
@@ -136,6 +136,7 @@ def _row2d(row: dict[str, Any], method: str) -> dict[str, Any]:
cond: sides[side]["fs"] for cond, sides in cases.items() if side in sides
},
"fs_min": min(values) if values else None,
"min_by_condition": row.get("min") or {},
"method": method,
"verdict": "ng" if "ng" in verdicts else "ok" if verdicts == {"ok"} else None,
"representative": row.get("representative") or {},
@@ -553,19 +554,23 @@ def fill_3d(sheet: dict[str, Any], inputs: dict[str, Any]) -> tuple[str, str]:
ground = inputs["ground"]
labels = _labels(inputs["stations"])
rows2d = inputs["result2d"]["stations"]
crit = _criterion(ground, "dry")
sections = []
for i, sec in enumerate(inputs["sections3d"]):
r = 20 + i
_copy_row(sheet, 20, r, "ABCDEGH")
start, end = float(sec["start_m"]), float(sec["end_m"])
cond = sec.get("condition") or "dry" # 2D 는 3D 와 같은 조건끼리 견줌
inside = [
float(s["fs_min"])
float(s["min_by_condition"][cond])
for s in rows2d
if s.get("fs_min") is not None and start - 1e-6 <= float(s["chainage_m"]) <= end + 1e-6
if s["min_by_condition"].get(cond) is not None
and start - 1e-6 <= float(s["chainage_m"]) <= end + 1e-6
]
f3 = float(sec["f_min"])
ok = f3 >= crit - 1e-9
if sec.get("verdict") in ("ok", "ng"): # 판정 = E04 엔진 값(기준안전율도 E04)
ok = sec["verdict"] == "ok"
else:
ok = f3 >= _criterion(ground, cond) - 1e-9
_set(sheet, f"A{r}", f"{i + 1}구간" + (" (미리보기)" if sec.get("preview") else ""))
_set(sheet, f"B{r}", _label_at(labels, start))
_set(sheet, f"C{r}", _label_at(labels, end))
+11 -3
View File
@@ -157,7 +157,15 @@ def project(tmp_path, monkeypatch) -> Path:
{
"fingerprint": "3d-1",
"settings": {},
"summary": {"start_m": 0.0, "end_m": 200.0, "f_min": 1.42, "volume": 830.0},
"summary": {
"start_m": 0.0,
"end_m": 200.0,
"f_min": 1.42,
"volume": 830.0,
"condition": "wet",
"reference_fs": 1.3,
"verdict": "ok",
},
}
),
encoding="utf-8",
@@ -215,8 +223,8 @@ def test_처음_만듦_측점수_NG_그림(project):
assert s3["A26"]["값"] == "풍화토" and s3["B32"]["값"].startswith("0 ~ 100 m 위 지층")
assert s3["A32"]["값"] == "붕적토" and s3["B13"]["값"] == 1.3
s6 = by["3D요약"]["칸"]
assert s6["D20"]["값"] == 1.42 and s6["H20"] == {"값": "N.G", "서식": build.ST_NG}
assert s6["E20"]["값"] == pytest.approx(1.11) # 0~200 m 안 2D 최소
assert s6["D20"]["값"] == 1.42 and s6["H20"] == {"값": "O.K", "서식": build.ST_OK} # E04 판정
assert s6["E20"]["값"] == pytest.approx(1.11) # 0~200 m 안 2D 우기 최소(3D 와 같은 조건)
assert (build.initial_dir(project) / build.REPORT).is_file()
assert saved["fingerprint"] == build.analysis_fingerprint(project)