#!/usr/bin/env python3 """Measure L119 floor zero crossings at three route stations per passage.""" from __future__ import annotations import csv import json import math import os import re import statistics import subprocess from pathlib import Path ROOT = Path(__file__).resolve().parents[4] OUT = ROOT / "Saved/Linux/l119/density-probe" BINARY = ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-clang" DATA = ROOT / "Standalone/data/owner_world.json" SLOPE = re.compile( r"^\[L115DensitySlopeSample\] passage=(\S+) station=(\S+) s_m=([\d.]+) " r".*?planned_floor_m=(-?[\d.]+) root_floor_m=(-?[\d.]+|nan) " r"residual_m=(-?[\d.]+|nan)", re.M) def main() -> int: OUT.mkdir(parents=True, exist_ok=True) log = OUT / "owner4-clang.log" layout = OUT / "layout.json" command = [ "taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--", "timeout", "1740s", str(BINARY), str(DATA), "--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline", "--workers=12", "--clip-radius=3", "--max-clip-level=8", "--max-level=8", "--camera=8,16,-372.2626953125,0,0", "--audit-resolved-layout-passages", f"--resolved-layout-output={layout}", ] with log.open("w", encoding="utf-8") as stream: result = subprocess.run(command, cwd=ROOT, env={**os.environ, "VOXELFORGE_L115_DENSITY_PROFILE": "1"}, stdout=stream, stderr=subprocess.STDOUT, check=False, timeout=1740) if result.returncode: raise SystemExit(f"L119 density probe failed: {log}") text = log.read_text(encoding="utf-8", errors="replace") groups: dict[tuple[str, str], list[dict]] = {} for passage, station, distance, planned, root, residual in SLOPE.findall(text): root_value = float(root) if root != "nan" else math.nan residual_value = float(residual) if residual != "nan" else math.nan groups.setdefault((passage, station), []).append({ "route_s_m": float(distance), "planned_floor_m": float(planned), "root_floor_m": root_value, "offset_m": residual_value}) summary = [] with (OUT / "zero-crossing-offsets.csv").open("w", newline="", encoding="utf-8") as stream: writer = csv.DictWriter(stream, fieldnames=("passage", "station", "route_s_m", "planned_floor_m", "root_floor_m", "offset_m")) writer.writeheader() for (passage, station), samples in sorted(groups.items()): for sample in samples: writer.writerow({"passage": passage, "station": station, **sample}) finite = [sample["offset_m"] for sample in samples if math.isfinite(sample["offset_m"])] summary.append({"passage": passage, "station": station, "samples": len(samples), "finite_roots": len(finite), "max_abs_offset_m": max(map(abs, finite)) if finite else None, "median_abs_offset_m": statistics.median(map(abs, finite)) if finite else None, "p95_abs_offset_m": sorted(map(abs, finite))[ min(len(finite)-1, math.ceil(0.95*len(finite))-1)] if finite else None}) if not summary or any(item["samples"] != 51 for item in summary): raise RuntimeError("L119 density profile is missing 51-sample route stations") (OUT / "zero-crossing-summary.json").write_text( json.dumps(summary, indent=2) + "\n", encoding="utf-8") print(f"[L119DensityProbe] exit={result.returncode} stations={len(summary)} " f"log={log.relative_to(ROOT)}", flush=True) return result.returncode if __name__ == "__main__": raise SystemExit(main())