Files
Aislo/resources/tester/test_b06_sample_extend.py
eomsangdonandClaude Opus 5 8bf24c268f fix(b06): 미교차 측점 지반 샘플을 지표면 끝까지 넓힘(㉳ (가) · 브레인 판정 「+5m 씩 · 상한 = 지표면 끝」 · 716 「+5m 한 번」 갈음)
- 서버 재계산([저장]·[확정]·자동설계 체인) 맨 앞에서 미교차 측점만 열린 쪽을 +5m 씩 확정 지표면에서 다시 떠 계산 · 닫히면 멈춤 · 지표면 밖 샘플이 섞이면 그 걸음은 안 붙이고 미교차로 남김
- 넓힌 샘플은 횡단 파일에 남겨 화면·Node·B08 이 같은 지반을 봄 · 계산식은 안 바뀜(입력만 넓어짐) · 뒤 보정(포장·세월교·사토장)은 넓힌 지반 위에서
- 종전엔 반폭 20m 끝에서 잘려 성토가 작게 섰음
- 936be972 서버 재계산 전→후: 미교차 12 → 1(840 지표면 끝) · 성토 단면 460 19.87→35.11 · 480 48.04→84.35 · 500 37.15→52.47 · 700 24.74→54.84 · 1000 56.30→80.40 · 840 41.60→110.35 · 258.12 25.11→31.44 · 유토곡선 성토 13,350.64 → 17,248.52㎥ · 토취 7,259.84 → 11,100.86㎥ · 내역 본체 129,498,518 → 154,857,626원

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
2026-09-14 22:43:10 +09:00

84 lines
3.4 KiB
Python

"""㉳ (가) 미교차 측점 지반 샘플을 지표면 끝까지 넓힘 — 2026-09-14 브레인 판정.
반폭 20m 끝에서 성토 비탈이 원지반과 안 만나면 면적이 잘려 성토가 작게 섰음(936be972 12곳 중 11곳).
⇒ 열린 쪽만 +5m 씩 확정 지표면에서 다시 떠 계산 · 닫히면 멈춤 · 지표면 밖(무효 샘플)이면 멈추고 미교차 그대로.
상한 숫자 없음(지표면이 실제로 있는 끝) · 716 「미교차만 +5m 한 번」 갈음.
"""
from __future__ import annotations
import sys
from pathlib import Path
import numpy as np
import pytest
ROOT = Path(__file__).resolve().parents[2]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
from B06_Section.B06_Section_Engine_Design import compute_cross_design # noqa: E402
from B06_Section.B06_Section_Engine_SampleExtend import extend_unclosed # noqa: E402
from common_util.common_util_surface_sampler import CallableSurfaceSampler # noqa: E402
FRAME = {"origin": {"x": 0.0, "y": 0.0}, "left_xy": [1.0, 0.0]}
def _ground(x: np.ndarray) -> np.ndarray:
"""좌(+)는 30m 까지 1:1 로 떨어지다 완만 · 우(−)는 오르막(절토가 금방 닫힘)."""
x = np.asarray(x, dtype=float)
left = np.where(x < 30.0, 100.0 - x, 70.0 - 0.1 * (x - 30.0))
return np.where(x >= 0, left, 100.0 - 0.8 * x)
def _samples(half: float = 20.0) -> list[dict]:
offsets = np.arange(-half, half + 0.25, 0.5)
return [
{"offset_m": float(o), "elevation_m": float(z), "valid": True}
for o, z in zip(offsets, _ground(offsets))
]
def _compute(samples: list[dict]) -> dict:
return compute_cross_design(samples, 100.0, ground_type="soil", section_mode="right_cut")
def _sampler(limit: float | None = None) -> CallableSurfaceSampler:
def function(xy: np.ndarray) -> np.ndarray:
values = _ground(xy[:, 0])
if limit is not None:
values = np.where(xy[:, 0] > limit, np.nan, values)
return values
return CallableSurfaceSampler(function)
def test_열린_쪽만_5m_씩_넓혀_닫히면_멈춤() -> None:
before = _compute(_samples())
assert before["slope_unclosed"], "기준 단면이 20m 에서 안 닫혀야 시험이 뜻이 있음"
samples, info = extend_unclosed(_samples(), FRAME, _compute, _sampler())
after = _compute(samples)
assert not after["slope_unclosed"]
assert info["left_m"] > 0 and info["left_m"] % 5 == 0 and info["right_m"] == 0
assert info["surface_end"] is False
assert max(s["offset_m"] for s in samples) == pytest.approx(20.0 + info["left_m"])
assert min(s["offset_m"] for s in samples) == pytest.approx(-20.0) # 닫힌 쪽은 안 넓힘
assert after["fill_area_m2"] > before["fill_area_m2"] # 잘린 성토가 제 크기로
def test_지표면_끝이면_멈추고_미교차_그대로() -> None:
samples, info = extend_unclosed(_samples(), FRAME, _compute, _sampler(limit=32.0))
assert info["surface_end"] is True
assert max(s["offset_m"] for s in samples) == pytest.approx(30.0) # 무효가 섞인 걸음은 안 붙임
assert _compute(samples)["slope_unclosed"]
def test_닫힌_측점은_그대로() -> None:
closed = _samples(60.0)
assert extend_unclosed(closed, FRAME, _compute, _sampler()) is None
def test_서버_재계산이_부름() -> None:
source = (ROOT / "B06_Section" / "B06_Section_Server_Calc_Prebuild.py").read_text("utf-8")
assert "extend_unclosed_sections(" in source