core: coarser smooth-route tolerance + shell support bound (L119, evaluator v224)
Chord error 2.5 -> 10 cm, shell work skipped outside the 0-0.75 m band. Sweep pairs -39%, prepare -60%, near-ready 3-8% faster than L115 but still +13..+22% vs L109. Floor offset 7.88 mm; captures match L115 by eye; fast tier, walk audits, Clang/GCC W1/W8/W12 determinism green. Not for merge yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
No files matched your search
@@ -0,0 +1,43 @@
|
||||
# Linux119 — smooth half-pipe speed
|
||||
|
||||
## Result
|
||||
|
||||
The route now uses a 10 cm chord-error tolerance (was 2.5 cm); the 8 m spacing cap is unchanged. The evaluator is version 224. Output changed, but Clang/GCC and W1/W8/W12 hashes match.
|
||||
|
||||
L119 improves on L115, but misses the L109 near-ready target in all eight stratum/worker cells: **13.3–22.0% slower than L109**. It is 2.8–7.7% faster than L115 at near-ready. Whole-view readiness remains 6.5–12.3% slower than L109.
|
||||
|
||||
Five interleaved L80 measurements per cell followed one warmup per version. The timing gate recorded 1-minute load 0.82 and 98.7% CPU idle. Headless runs used CPUs 0–11, the 6 GiB address-space limit, and a 1,740 s timeout.
|
||||
|
||||
| Stratum | Workers | Near L109 / L115 / L119 (s; Δ vs L109) | Whole view L109 / L115 / L119 (s; Δ vs L109) |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| S0 | 8 | 0.761 / 0.929 / 0.880 (+15.6%) | 1.742 / 1.927 / 1.860 (+6.8%) |
|
||||
| S0 | 12 | 0.785 / 0.926 / 0.890 (+13.5%) | 1.717 / 1.873 / 1.829 (+6.5%) |
|
||||
| S1 | 8 | 0.951 / 1.250 / 1.158 (+21.9%) | 1.863 / 2.112 / 2.073 (+11.3%) |
|
||||
| S1 | 12 | 0.899 / 1.152 / 1.097 (+22.0%) | 1.731 / 2.000 / 1.943 (+12.3%) |
|
||||
| S2 | 8 | 0.994 / 1.252 / 1.177 (+18.4%) | 1.844 / 2.079 / 2.030 (+10.1%) |
|
||||
| S2 | 12 | 0.914 / 1.169 / 1.079 (+18.1%) | 1.710 / 1.989 / 1.885 (+10.2%) |
|
||||
| S3 | 8 | 0.812 / 0.988 / 0.960 (+18.3%) | 1.728 / 1.870 / 1.891 (+9.4%) |
|
||||
| S3 | 12 | 0.772 / 0.928 / 0.874 (+13.3%) | 1.617 / 1.783 / 1.723 (+6.6%) |
|
||||
|
||||
## Designs and work
|
||||
|
||||
Two designs were built together. Before building, the fourfold chord tolerance increase predicted about half as many curvature-limited route segments (segment count scales roughly with the inverse square root of the error tolerance). The shell support bound was expected to skip most shell calculations: only flattened distances in the 0–0.75 m shell band can contribute, with a 1-subvoxel guard. L118 had 48.93M W8 sweep pairs and 39.3M sampled smooth-min calls.
|
||||
|
||||
| Stratum | W8 LOD0–2 pairs L109 / L115=L118 / L119 (M) | Exact fallbacks L109 / L115=L118 / L119 (M) | Segment visits L109 / L115=L118 / L119 (M) | Prepare ms L118 → L119 | L119 shell-support skips |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: |
|
||||
| S0 | 3.36 / 7.56 / 4.55 | 0.241 / 0.413 / 0.652 | 1.19 / 3.41 / 4.68 | 467 → 185 | 3.73M (81.9%) |
|
||||
| S1 | 6.19 / 16.22 / 9.69 | 0.369 / 0.719 / 1.114 | 1.91 / 7.60 / 9.25 | 919 → 361 | 8.05M (83.1%) |
|
||||
| S2 | 6.15 / 15.52 / 9.28 | 0.315 / 0.634 / 0.986 | 1.66 / 6.88 / 8.34 | 848 → 345 | 7.69M (82.8%) |
|
||||
| S3 | 4.09 / 9.63 / 5.88 | 0.074 / 0.131 / 0.203 | 0.48 / 1.41 / 2.19 | 567 → 235 | 4.76M (80.8%) |
|
||||
|
||||
L119 reduced pairs 39–40% versus L115/L118, and summed W1 prepare time fell 59.8% (2.801 s to 1.125 s). Exact fallbacks are 55–58% higher than L115/L118 and visits are 21–56% higher. Those extra fallback scans are the likely remaining readiness cost. L119 prepare time is timed directly; L109/L115 prepare time was not separately instrumented.
|
||||
|
||||
## Quality and verification
|
||||
|
||||
- Floor root offsets: 51 samples at each of 9 stations; maximum 7.884 mm versus L115’s 7.849 mm.
|
||||
- Fast tier: PASS in 277.9 s. Walkability, floor/mouth profiles, open-air shell, ripple, naturalness, and grade audits passed; no geometry threshold was relaxed.
|
||||
- Determinism: all 18 Clang/GCC W1/W8/W12 hash runs matched for owner4 surface world and both owner2 canonical recipes. Owner2 v224 baselines were added. Source stamp: `9a592cb548c6768c8c25723f4168f65da9645068cb67dcb317e91f707e7d41df`.
|
||||
- Captures: 23/23 L115 view names and camera poses rendered with the L119 binary; 19 pass and 4 low-contrast-visible. L115 had 18 pass and 5 low-contrast-visible. [Compare all views side by side](captures/COMPARE.html); [L119 capture index](captures/L119/INDEX.md).
|
||||
- Linux VFHostEditor: PASS, 27/27 actions in 70.98 s with `-NoUBA -MaxParallelActions=4`. Unreal ran without `prlimit`; three existing RealtimeMesh deprecation warnings remain.
|
||||
|
||||
Logs and timing summaries are in `Saved/Linux/l119/`.
|
||||
@@ -0,0 +1,54 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Render the L115 view set with the L119 candidate binaries."""
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
RESEARCH = Path(__file__).resolve().parent
|
||||
SPEC = importlib.util.spec_from_file_location(
|
||||
"l115_capture_runner", ROOT / "Standalone/Research/WorldAssemblerM3/Linux115/RunL115Captures.py")
|
||||
if SPEC is None or SPEC.loader is None:
|
||||
raise SystemExit("cannot load the L115 capture view definitions")
|
||||
RUNNER = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(RUNNER)
|
||||
|
||||
# Reuse L115's exact camera and station definitions, while rendering through L119.
|
||||
RUNNER.CAPTURES = RESEARCH / "captures/L119"
|
||||
RUNNER.SAVED = ROOT / "Saved/Linux/l119/captures"
|
||||
RUNNER.HELPERS.RESEARCH = RESEARCH
|
||||
RUNNER.BINARIES = {
|
||||
"L115": ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-clang"}
|
||||
RUNNER.RENDERERS = {
|
||||
"L115": ROOT / "Saved/Linux/l119/bin/VoxelForgeOffscreenCapture-l119-clang"}
|
||||
RUNNER.HELPERS.BINARIES = RUNNER.BINARIES
|
||||
RUNNER.HELPERS.RENDERERS = RUNNER.RENDERERS
|
||||
|
||||
|
||||
def main() -> int:
|
||||
result = RUNNER.main()
|
||||
if result != 0:
|
||||
return result
|
||||
index = RUNNER.CAPTURES / "capture-index.json"
|
||||
document = json.loads(index.read_text(encoding="utf-8"))
|
||||
for row in document["captures"]:
|
||||
row["variant"] = "L119"
|
||||
index.write_text(json.dumps(document, indent=2) + "\n", encoding="utf-8")
|
||||
markdown = RUNNER.CAPTURES / "INDEX.md"
|
||||
lines = ["# L119 captures (L115 view set)", "",
|
||||
"The 23 L115 camera poses were rendered with the L119 binary. Floor anchors "
|
||||
"require an upward normal alignment of at least 0.85, target-to-floor distance "
|
||||
"at most 0.25 m, and camera-to-floor distance between 2.0 and 3.2 m. Open-air "
|
||||
"sections have outside and interior wall close-ups at 4 m.", ""]
|
||||
for row in document["captures"]:
|
||||
image = row["capture"].removeprefix("captures/L119/")
|
||||
lines.append(f"- [{row['passage']} {row['station']}]({image}) — "
|
||||
f"{row['kind']}; {row.get('drawn_triangles', 0)} triangles; "
|
||||
f"{row['pixel_quality_status']}")
|
||||
markdown.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/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())
|
||||
@@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Check owner hash identity at W1/W8/W12 and pin the v224 owner hashes."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l119/hashes"
|
||||
DATASETS = {
|
||||
"owner4": ROOT / "Standalone/data/owner_world.json",
|
||||
"owner2": ROOT / "Standalone/data/regression/owner_world_2strate_l61.json",
|
||||
}
|
||||
BINARIES = {
|
||||
"clang": ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-clang",
|
||||
"gcc": ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-gcc",
|
||||
}
|
||||
HASH = re.compile(r"^\[Pipeline(?:FullDetailHash|WholeViewHash|LODHash|ExactQueryHash)\].*$", re.M)
|
||||
STAMP = re.compile(r"^\[VoxelForgeSourceStamp\] sha256=(\S+)$", re.M)
|
||||
|
||||
|
||||
def run(dataset: str, recipe: str, workers: int, compiler: str) -> dict:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
label = f"{dataset}-{recipe}-w{workers}-{compiler}"
|
||||
log = OUT / f"{label}.log"
|
||||
layout = OUT / f"{label}.layout.json"
|
||||
command = [
|
||||
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(BINARIES[compiler]), str(DATASETS[dataset]),
|
||||
f"--workers={workers}", "--world-assembler-prototype", "--stream-benchmark",
|
||||
"--stream-pipeline", "--force-generate", "--clip-radius=3",
|
||||
"--max-clip-level=8", "--max-level=8", f"--recipe={recipe}",
|
||||
"--stream-hash", f"--resolved-layout-output={layout}",
|
||||
]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
output = log.read_text(encoding="utf-8", errors="replace")
|
||||
hashes = HASH.findall(output)
|
||||
if result.returncode or len(hashes) != 12:
|
||||
raise SystemExit(f"hash run failed or incomplete: {label}; exit={result.returncode} "
|
||||
f"hashes={len(hashes)} log={log}")
|
||||
row = {"dataset": dataset, "recipe": recipe, "workers": workers,
|
||||
"compiler": compiler, "exit_code": result.returncode, "hashes": hashes,
|
||||
"source_stamp": (STAMP.search(output).group(1)
|
||||
if STAMP.search(output) else None),
|
||||
"elapsed_s": round(time.monotonic() - started, 3),
|
||||
"log": str(log.relative_to(ROOT))}
|
||||
print("[L119HashRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
return row
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if any(not path.is_file() for path in (*DATASETS.values(), *BINARIES.values())):
|
||||
raise SystemExit("missing L119 hash input")
|
||||
rows = []
|
||||
recipes = {"owner4": ("surface-world",),
|
||||
"owner2": ("surface-world", "floating-islands")}
|
||||
for dataset, dataset_recipes in recipes.items():
|
||||
for recipe in dataset_recipes:
|
||||
for workers in (1, 8, 12):
|
||||
for compiler in ("clang", "gcc"):
|
||||
rows.append(run(dataset, recipe, workers, compiler))
|
||||
(OUT / "runs-partial.json").write_text(
|
||||
json.dumps(rows, indent=2) + "\n", encoding="utf-8")
|
||||
groups = {}
|
||||
for dataset, dataset_recipes in recipes.items():
|
||||
for recipe in dataset_recipes:
|
||||
key = f"{dataset}/{recipe}"
|
||||
group = [row for row in rows if row["dataset"] == dataset
|
||||
and row["recipe"] == recipe]
|
||||
reference = group[0]["hashes"]
|
||||
matches = all(row["hashes"] == reference for row in group)
|
||||
groups[key] = {"all_worker_compiler_hashes_match": matches,
|
||||
"source_stamps": sorted({row["source_stamp"] for row in group}),
|
||||
"runs": [{"workers": row["workers"], "compiler": row["compiler"],
|
||||
"log": row["log"]} for row in group]}
|
||||
if not matches:
|
||||
raise SystemExit(f"determinism mismatch: {key}")
|
||||
if dataset == "owner2":
|
||||
canonical = next(row for row in group if row["workers"] == 12
|
||||
and row["compiler"] == "clang")
|
||||
style = 1 if recipe == "surface-world" else 2
|
||||
baseline = (ROOT / "Standalone/Tools/verify/baselines/owner-hash/canonical"
|
||||
/ f"owner-hash-{recipe}-style{style}-v224.baseline")
|
||||
baseline.write_text("\n".join(canonical["hashes"]) + "\n",
|
||||
encoding="utf-8")
|
||||
summary = {"runs": rows, "groups": groups,
|
||||
"owner2_canonical_pins": ["owner2/surface-world",
|
||||
"owner2/floating-islands"]}
|
||||
(OUT / "summary.json").write_text(json.dumps(summary, indent=2) + "\n",
|
||||
encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Collect two W8 passage-counter profiles per owner stratum."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l119/passage-counters"
|
||||
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||
BINARY = ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-clang"
|
||||
CAMERAS = {
|
||||
0: (8.0, 16.0, -372.2626953125),
|
||||
1: (25.8369140625, 3.19921875, -737.0),
|
||||
2: (19.166015625, -14.2001953125, -753.3740234375),
|
||||
3: (-20.0625, -5.068359375, -900.353515625),
|
||||
}
|
||||
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||
|
||||
|
||||
def rows(path: Path, tag: str) -> dict[str, dict[str, str]]:
|
||||
result = {}
|
||||
for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
|
||||
if line.startswith(tag + " "):
|
||||
field = dict(FIELDS.findall(line))
|
||||
result[field["key"]] = field
|
||||
return result
|
||||
|
||||
|
||||
def run(strate: int, replicate: int) -> dict:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
label = f"s{strate}-w8-profile{replicate}"
|
||||
log = OUT / f"{label}.log"
|
||||
camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
|
||||
command = [
|
||||
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(BINARY), str(DATA),
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--workers=8", "--clip-radius=3", "--max-clip-level=8", "--max-level=8",
|
||||
f"--camera={camera}", "--profile-lod-work", "--profile-passage-composer",
|
||||
]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
if result.returncode:
|
||||
raise SystemExit(f"passage-counter profile failed: {log}; exit={result.returncode}")
|
||||
composer, stages = rows(log, "[PassageComposerTile]"), rows(log, "[CpuTileStages]")
|
||||
selected = []
|
||||
for key, comp in composer.items():
|
||||
lod = int(key.rsplit("lod", 1)[1].rstrip(")"))
|
||||
if lod > 2 or int(comp["features"]) == 0:
|
||||
continue
|
||||
stage = stages.get(key)
|
||||
if stage is None:
|
||||
raise SystemExit(f"missing CpuTileStages record for {label} {key}")
|
||||
fallbacks = [int(value) for value in stage["sweep_exact_fallback_by_caller"].split(",")]
|
||||
selected.append({
|
||||
"features": int(comp["features"]),
|
||||
"sweep_pairs": int(comp["sweep_pairs"]),
|
||||
"shell_support_skips": int(comp.get("sweep_shell_support_skips", "0")),
|
||||
"exact_fallbacks": sum(fallbacks),
|
||||
"segment_visits": int(comp["carve_segment_visits"]),
|
||||
})
|
||||
names = ("sweep_pairs", "shell_support_skips", "exact_fallbacks", "segment_visits")
|
||||
totals = {name: sum(item[name] for item in selected) for name in names}
|
||||
row = {"strate": strate, "workers": 8, "replicate": replicate,
|
||||
"passage_tiles_lod02": len(selected), "totals": totals,
|
||||
"elapsed_s": round(time.monotonic() - started, 3),
|
||||
"log": str(log.relative_to(ROOT))}
|
||||
print("[L119PassageCounters] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
return row
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not DATA.is_file() or not BINARY.is_file():
|
||||
raise SystemExit("missing L119 passage-counter input")
|
||||
result = [run(strate, replicate) for strate in range(4) for replicate in (1, 2)]
|
||||
summary = []
|
||||
for strate in range(4):
|
||||
group = [item for item in result if item["strate"] == strate]
|
||||
summary.append({"strate": strate, "workers": 8, "replicates": len(group),
|
||||
"totals_mean": {
|
||||
name: sum(row["totals"][name] for row in group) / len(group)
|
||||
for name in group[0]["totals"]}})
|
||||
(OUT / "summary.json").write_text(
|
||||
json.dumps({"runs": result, "summary": summary}, indent=2) + "\n",
|
||||
encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Collect W1 per-tile swept-tube preparation timings for each owner stratum."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l119/tag-probe"
|
||||
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||
BINARY = ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-clang"
|
||||
CAMERAS = {
|
||||
0: (8.0, 16.0, -372.2626953125),
|
||||
1: (25.8369140625, 3.19921875, -737.0),
|
||||
2: (19.166015625, -14.2001953125, -753.3740234375),
|
||||
3: (-20.0625, -5.068359375, -900.353515625),
|
||||
}
|
||||
PASSAGE = re.compile(r"^\[PassageComposerTile\] (.*)$", re.M)
|
||||
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||
|
||||
|
||||
def run(strate: int) -> dict:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
label = f"s{strate}-w1-tags"
|
||||
log = OUT / f"{label}.log"
|
||||
camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
|
||||
command = [
|
||||
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(BINARY), str(DATA),
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
"--workers=1", "--clip-radius=3", "--max-clip-level=8", "--max-level=8",
|
||||
f"--camera={camera}", "--profile-lod-work", "--profile-passage-composer",
|
||||
]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as stream:
|
||||
result = subprocess.run(command, cwd=ROOT, stdout=stream,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
content = log.read_text(encoding="utf-8", errors="replace")
|
||||
passage = [dict(FIELDS.findall(match)) for match in PASSAGE.findall(content)]
|
||||
if result.returncode or not passage:
|
||||
raise SystemExit(f"prepare probe failed or emitted no passage counters: {log}; "
|
||||
f"exit={result.returncode}")
|
||||
near = [row for row in passage
|
||||
if int(row["key"].rsplit("lod", 1)[1].rstrip(")")) <= 2
|
||||
and int(row["features"]) > 0]
|
||||
totals = {
|
||||
"passage_feature_tiles": len(near),
|
||||
"sweep_prepare_ms": sum(float(row["sweep_prepare_ms"]) for row in near),
|
||||
"sweep_pairs": sum(int(row["sweep_pairs"]) for row in near),
|
||||
"shell_support_skips": sum(
|
||||
int(row["sweep_shell_support_skips"]) for row in near),
|
||||
}
|
||||
row = {"strate": strate, "workers": 1, "elapsed_s": round(time.monotonic() - started, 3),
|
||||
"near_lod02_feature_tiles": totals,
|
||||
"log": str(log.relative_to(ROOT))}
|
||||
print("[L119TagProbe] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
return row
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not DATA.is_file() or not BINARY.is_file():
|
||||
raise SystemExit("missing owner data or L119 Clang binary")
|
||||
rows = [run(strate) for strate in range(4)]
|
||||
(OUT / "summary.json").write_text(json.dumps(rows, indent=2) + "\n",
|
||||
encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Five interleaved L80 readiness runs for L109, L115, and L119."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import statistics
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[4]
|
||||
OUT = ROOT / "Saved/Linux/l119/timing"
|
||||
DATA = ROOT / "Standalone/data/owner_world.json"
|
||||
BINARIES = {
|
||||
"L109": ROOT / "Saved/Linux/l109/bin-final/VoxelForgeCoreHeadless-l109-clang",
|
||||
"L115": ROOT / "Saved/Linux/l115/bin/VoxelForgeCoreHeadless-l115-clang",
|
||||
"L119": ROOT / "Saved/Linux/l119/bin/VoxelForgeCoreHeadless-l119-clang",
|
||||
}
|
||||
CAMERAS = {
|
||||
0: (8.0, 16.0, -372.2626953125),
|
||||
1: (25.8369140625, 3.19921875, -737.0),
|
||||
2: (19.166015625, -14.2001953125, -753.3740234375),
|
||||
3: (-20.0625, -5.068359375, -900.353515625),
|
||||
}
|
||||
PIPELINE = re.compile(r"^\[StreamPipeline\] (.*)$", re.M)
|
||||
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
|
||||
NEAR = re.compile(
|
||||
r"^\[WorldAssemblerNearLODReady\] lods=0-2 tiles=(\d+)/(\d+) cold_ready_s=([0-9.]+)$",
|
||||
re.M,
|
||||
)
|
||||
|
||||
|
||||
def run(strate: int, workers: int, version: str, phase: str, replicate: int) -> dict:
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
label = f"s{strate}-w{workers}-{version}-{phase}{replicate}"
|
||||
log = OUT / f"{label}.log"
|
||||
camera = ",".join(f"{value:.12f}" for value in CAMERAS[strate]) + ",0,0"
|
||||
command = [
|
||||
"taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
|
||||
"timeout", "1740s", str(BINARIES[version]), str(DATA),
|
||||
"--world-assembler-prototype", "--stream-benchmark", "--stream-pipeline",
|
||||
f"--workers={workers}", "--clip-radius=3", "--max-clip-level=8", "--max-level=8",
|
||||
f"--camera={camera}", "--profile-lod-work", "--stream-scheduler-policy=3",
|
||||
]
|
||||
started = time.monotonic()
|
||||
with log.open("w", encoding="utf-8") as output:
|
||||
result = subprocess.run(command, cwd=ROOT, stdout=output,
|
||||
stderr=subprocess.STDOUT, check=False, timeout=1740)
|
||||
content = log.read_text(encoding="utf-8", errors="replace")
|
||||
pipeline_match = PIPELINE.search(content)
|
||||
near_match = NEAR.search(content)
|
||||
if result.returncode or pipeline_match is None or near_match is None:
|
||||
raise SystemExit(f"readiness run failed or trace missing: {log}; exit={result.returncode}")
|
||||
pipeline = dict(FIELDS.findall(pipeline_match.group(1)))
|
||||
row = {"strate": strate, "workers": workers, "version": version,
|
||||
"phase": phase, "replicate": replicate, "exit_code": result.returncode,
|
||||
"wall_s": round(time.monotonic() - started, 3),
|
||||
"lod02_ready_s": float(near_match.group(3)),
|
||||
"whole_view_ready_s": float(pipeline["whole_view_ready"].removesuffix("s")),
|
||||
"whole_tiles": int(pipeline["whole_tiles"].split("/")[0]),
|
||||
"log": str(log.relative_to(ROOT))}
|
||||
print("[L119TimingRun] " + json.dumps(row, sort_keys=True), flush=True)
|
||||
return row
|
||||
|
||||
|
||||
def cpu_idle_percent(interval_s: float = 2.0) -> float:
|
||||
def totals() -> tuple[int, int]:
|
||||
fields = Path("/proc/stat").read_text(encoding="utf-8").splitlines()[0].split()
|
||||
values = [int(value) for value in fields[1:]]
|
||||
return sum(values), values[3] + (values[4] if len(values) > 4 else 0)
|
||||
total_before, idle_before = totals()
|
||||
time.sleep(interval_s)
|
||||
total_after, idle_after = totals()
|
||||
total_delta = max(1, total_after - total_before)
|
||||
return 100.0 * (idle_after - idle_before) / total_delta
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not DATA.is_file() or any(not binary.is_file() for binary in BINARIES.values()):
|
||||
raise SystemExit("missing L109/L115/L119 timing input")
|
||||
OUT.mkdir(parents=True, exist_ok=True)
|
||||
load_1m = os.getloadavg()[0]
|
||||
idle_pct = cpu_idle_percent()
|
||||
uptime = subprocess.run(["uptime"], cwd=ROOT, text=True,
|
||||
capture_output=True, check=True).stdout.strip()
|
||||
top = subprocess.run(["ps", "-eo", "pid,pcpu,comm", "--sort=-pcpu"], cwd=ROOT,
|
||||
text=True, capture_output=True, check=True).stdout
|
||||
(OUT / "machine-load-before.txt").write_text(
|
||||
f"uptime: {uptime}\n1-minute load: {load_1m:.2f}\n"
|
||||
f"2-second CPU idle: {idle_pct:.1f}%\ntop CPU users:\n{top}",
|
||||
encoding="utf-8")
|
||||
print(f"[L119TimingGate] load_1m={load_1m:.2f} cpu_idle_2s={idle_pct:.1f}% "
|
||||
f"uptime={uptime}", flush=True)
|
||||
if load_1m >= 0.9 or idle_pct < 97.0:
|
||||
raise SystemExit("timing refused: machine is above the quiet-load gate")
|
||||
rows = []
|
||||
versions = ("L109", "L115", "L119")
|
||||
for strate in range(4):
|
||||
for workers in (8, 12):
|
||||
for version in versions:
|
||||
run(strate, workers, version, "warmup", 0)
|
||||
for replicate in range(1, 6):
|
||||
offset = (replicate - 1) % len(versions)
|
||||
order = versions[offset:] + versions[:offset]
|
||||
for version in order:
|
||||
rows.append(run(strate, workers, version, "measured", replicate))
|
||||
(OUT / "runs-partial.json").write_text(
|
||||
json.dumps(rows, indent=2) + "\n", encoding="utf-8")
|
||||
summary = []
|
||||
for strate in range(4):
|
||||
for workers in (8, 12):
|
||||
item = {"strate": strate, "workers": workers, "replicates": 5}
|
||||
medians = {}
|
||||
for version in versions:
|
||||
group = [row for row in rows if row["strate"] == strate
|
||||
and row["workers"] == workers and row["version"] == version]
|
||||
medians[version] = {}
|
||||
for key in ("lod02_ready_s", "whole_view_ready_s"):
|
||||
values = [row[key] for row in group]
|
||||
medians[version][key] = statistics.median(values)
|
||||
item[f"{version}_{key}_values"] = values
|
||||
item[f"{version}_{key}_median"] = medians[version][key]
|
||||
for comparison in ("L109", "L115"):
|
||||
for key in ("lod02_ready_s", "whole_view_ready_s"):
|
||||
item[f"L119_vs_{comparison}_{key}_delta_pct"] = round(
|
||||
100.0 * (medians["L119"][key] / medians[comparison][key] - 1.0), 2)
|
||||
summary.append(item)
|
||||
(OUT / "summary.json").write_text(
|
||||
json.dumps({"runs": rows, "summary": summary}, indent=2) + "\n",
|
||||
encoding="utf-8")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,30 @@
|
||||
<!doctype html>
|
||||
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>L115 / L119 tunnel capture comparison</title>
|
||||
<style>body{font:16px system-ui,sans-serif;max-width:1400px;margin:2rem auto;padding:0 1rem;color:#202124}h1{margin-bottom:.25rem}article{border-top:1px solid #bbb;padding:1rem 0 1.5rem}.pair{display:grid;grid-template-columns:1fr 1fr;gap:1rem}figure{margin:0}figcaption{font-weight:650;margin:.25rem 0}img{width:100%;height:auto;display:block;background:#eee}p{margin:.25rem 0 .75rem;color:#555}@media(max-width:700px){.pair{grid-template-columns:1fr}}</style>
|
||||
<h1>L115 and L119 tunnel captures</h1>
|
||||
<p>The same 23 view names and camera poses are paired side by side. Select an image to open it full size.</p>
|
||||
<article><h2>passage/0-1/0 · rock-floor/401.7m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-1.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-1.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-rock-floor-station-1.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-rock-floor-station-1.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · rock-floor/792.8m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-2.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-2.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-rock-floor-station-2.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-rock-floor-station-2.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · rock-floor/1634.5m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-3.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-rock-floor-station-3.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-rock-floor-station-3.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-rock-floor-station-3.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · rock-floor/27.0m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-1.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-1.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-rock-floor-station-1.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-rock-floor-station-1.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · rock-floor/52.9m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-2.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-2.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-rock-floor-station-2.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-rock-floor-station-2.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · rock-floor/78.9m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-3.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-rock-floor-station-3.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-rock-floor-station-3.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-rock-floor-station-3.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · rock-floor/323.4m · rock-floor-close</h2><p>Status: low_contrast_geometry_visible</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-1.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-1.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-rock-floor-station-1.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-rock-floor-station-1.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · rock-floor/333.4m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-2.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-2.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-rock-floor-station-2.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-rock-floor-station-2.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · rock-floor/343.4m · rock-floor-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-3.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-rock-floor-station-3.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-rock-floor-station-3.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-rock-floor-station-3.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · section-1/4m-outside · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-openair-1-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-openair-1-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · section-1/4m-interior-wall · open-air-close</h2><p>Status: low_contrast_geometry_visible</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · section-2/4m-outside · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-openair-2-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-openair-2-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · section-2/4m-interior-wall · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · section-3/4m-outside · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-openair-3-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-openair-3-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/0-1/0 · section-3/4m-interior-wall · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · section-1/4m-outside · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-openair-1-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-openair-1-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · section-1/4m-interior-wall · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · section-2/4m-outside · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-openair-2-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-openair-2-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/1-2/0 · section-2/4m-interior-wall · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · section-1/4m-outside · open-air-close</h2><p>Status: low_contrast_geometry_visible</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-openair-1-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-openair-1-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · section-1/4m-interior-wall · open-air-close</h2><p>Status: low_contrast_geometry_visible</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · section-2/4m-outside · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-outside.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-openair-2-4m-outside.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-openair-2-4m-outside.png"></a></figure></div></article>
|
||||
<article><h2>passage/2-3/0 · section-2/4m-interior-wall · open-air-close</h2><p>Status: pass</p><div class="pair"><figure><figcaption>L115</figcaption><a href="../../Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png"><img loading="lazy" src="../../Linux115/captures/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png"></a></figure><figure><figcaption>L119</figcaption><a href="L119/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png"><img loading="lazy" src="L119/L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png"></a></figure></div></article>
|
||||
</html>
|
||||
@@ -0,0 +1,27 @@
|
||||
# L119 captures (L115 view set)
|
||||
|
||||
The 23 L115 camera poses were rendered with the L119 binary. Floor anchors require an upward normal alignment of at least 0.85, target-to-floor distance at most 0.25 m, and camera-to-floor distance between 2.0 and 3.2 m. Open-air sections have outside and interior wall close-ups at 4 m.
|
||||
|
||||
- [passage/0-1/0 rock-floor/401.7m](L115/L115/passage-0-1-0-rock-floor-station-1.png) — rock-floor-close; 122294 triangles; pass
|
||||
- [passage/0-1/0 rock-floor/792.8m](L115/L115/passage-0-1-0-rock-floor-station-2.png) — rock-floor-close; 586092 triangles; pass
|
||||
- [passage/0-1/0 rock-floor/1634.5m](L115/L115/passage-0-1-0-rock-floor-station-3.png) — rock-floor-close; 137288 triangles; pass
|
||||
- [passage/1-2/0 rock-floor/27.0m](L115/L115/passage-1-2-0-rock-floor-station-1.png) — rock-floor-close; 652056 triangles; pass
|
||||
- [passage/1-2/0 rock-floor/52.9m](L115/L115/passage-1-2-0-rock-floor-station-2.png) — rock-floor-close; 636162 triangles; pass
|
||||
- [passage/1-2/0 rock-floor/78.9m](L115/L115/passage-1-2-0-rock-floor-station-3.png) — rock-floor-close; 580472 triangles; pass
|
||||
- [passage/2-3/0 rock-floor/323.4m](L115/L115/passage-2-3-0-rock-floor-station-1.png) — rock-floor-close; 474964 triangles; low_contrast_geometry_visible
|
||||
- [passage/2-3/0 rock-floor/333.4m](L115/L115/passage-2-3-0-rock-floor-station-2.png) — rock-floor-close; 494504 triangles; pass
|
||||
- [passage/2-3/0 rock-floor/343.4m](L115/L115/passage-2-3-0-rock-floor-station-3.png) — rock-floor-close; 485356 triangles; pass
|
||||
- [passage/0-1/0 section-1/4m-outside](L115/L115/passage-0-1-0-openair-1-4m-outside.png) — open-air-close; 275333 triangles; pass
|
||||
- [passage/0-1/0 section-1/4m-interior-wall](L115/L115/passage-0-1-0-openair-1-4m-interior-wall.png) — open-air-close; 308012 triangles; low_contrast_geometry_visible
|
||||
- [passage/0-1/0 section-2/4m-outside](L115/L115/passage-0-1-0-openair-2-4m-outside.png) — open-air-close; 275333 triangles; pass
|
||||
- [passage/0-1/0 section-2/4m-interior-wall](L115/L115/passage-0-1-0-openair-2-4m-interior-wall.png) — open-air-close; 345026 triangles; pass
|
||||
- [passage/0-1/0 section-3/4m-outside](L115/L115/passage-0-1-0-openair-3-4m-outside.png) — open-air-close; 149234 triangles; pass
|
||||
- [passage/0-1/0 section-3/4m-interior-wall](L115/L115/passage-0-1-0-openair-3-4m-interior-wall.png) — open-air-close; 148100 triangles; pass
|
||||
- [passage/1-2/0 section-1/4m-outside](L115/L115/passage-1-2-0-openair-1-4m-outside.png) — open-air-close; 620814 triangles; pass
|
||||
- [passage/1-2/0 section-1/4m-interior-wall](L115/L115/passage-1-2-0-openair-1-4m-interior-wall.png) — open-air-close; 609757 triangles; pass
|
||||
- [passage/1-2/0 section-2/4m-outside](L115/L115/passage-1-2-0-openair-2-4m-outside.png) — open-air-close; 584542 triangles; pass
|
||||
- [passage/1-2/0 section-2/4m-interior-wall](L115/L115/passage-1-2-0-openair-2-4m-interior-wall.png) — open-air-close; 572258 triangles; pass
|
||||
- [passage/2-3/0 section-1/4m-outside](L115/L115/passage-2-3-0-openair-1-4m-outside.png) — open-air-close; 104612 triangles; low_contrast_geometry_visible
|
||||
- [passage/2-3/0 section-1/4m-interior-wall](L115/L115/passage-2-3-0-openair-1-4m-interior-wall.png) — open-air-close; 94962 triangles; low_contrast_geometry_visible
|
||||
- [passage/2-3/0 section-2/4m-outside](L115/L115/passage-2-3-0-openair-2-4m-outside.png) — open-air-close; 475860 triangles; pass
|
||||
- [passage/2-3/0 section-2/4m-interior-wall](L115/L115/passage-2-3-0-openair-2-4m-interior-wall.png) — open-air-close; 486480 triangles; pass
|
||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 98 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
After Width: | Height: | Size: 177 KiB |
|
After Width: | Height: | Size: 125 KiB |
|
After Width: | Height: | Size: 112 KiB |
|
After Width: | Height: | Size: 116 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 184 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 121 KiB |
|
After Width: | Height: | Size: 111 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 55 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 67 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 146 KiB |
|
After Width: | Height: | Size: 106 KiB |