passages: floor profile by nearest centreline + metric distance outside voids (L114, v222) - WIP

Floor ribs are present in L109/L112/L113 rock tunnels too: the floor height comes from the
nearest segment, so it jumps (up to 5.9-7.3 cm) where the nearest segment switches. v222 reduces
them; faint ribs remain. Quiet-machine timing (load 0.64): near-ready 9-17% slower than L109
(FI W12 0.95 -> 1.10 s); candidate totals ~5x L109. Fast tier FAIL: 2 SW wall-shell probes of
31,381 read host air. Walk/grade audits pass; Clang/GCC deterministic; UE builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-29 23:18:40 +01:00
1 parent 36d954cf2f
commit 5e875ae504
45 files changed
+3081 -53

No files matched your search

@@ -472,7 +472,9 @@ namespace VoxelForgeCore
// Version 218 sweeps passages around a dense smooth spline and limits exposed shells to a trough.
// Version 219 smooths passage XY while mapping each planned height chord over its sampled horizontal arc.
// Version 220 adaptively samples passage curves and rounds open-air wall crests.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 220;
// Version 221 ranks passage segments before floor shaping and preserves their signed exterior distance.
// Version 222 selects the floor profile by centerline position, independent of tube radius.
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 222;
enum class FieldChannel : std::uint32_t
{
+84 -37
View File
@@ -266,8 +266,10 @@ public:
double roundSignedDistance=std::numeric_limits<double>::infinity();
double centerZSubvoxels=0.0,floorCenterZSubvoxels=0.0;
double radiusSubvoxels=0.0,floorDepthSubvoxels=0.0;
double t=0.0;
double floorCenterDistanceSq=std::numeric_limits<double>::infinity();
double t=0.0,floorT=0.0;
std::uint32_t segmentIndex=std::numeric_limits<std::uint32_t>::max();
std::uint32_t floorSegmentIndex=std::numeric_limits<std::uint32_t>::max();
float wallRelief=0.0f;
bool valid=false,hasWallRelief=false;
};
@@ -1216,8 +1218,9 @@ public:
double signedDistance=std::numeric_limits<double>::infinity();
double shellSignedDistance=std::numeric_limits<double>::infinity();
double roundSignedDistance=std::numeric_limits<double>::infinity();
double centerZ=0.0,floorCenterZ=0.0,radius=0.0,floorDepth=0.0,t=0.0;
std::size_t segmentIndex=0;
double centerZ=0.0,floorCenterZ=0.0,radius=0.0,floorDepth=0.0;
double t=0.0,floorT=0.0;
std::size_t segmentIndex=0,floorSegmentIndex=0;
bool valid=false;
const FScopedPassageTileQueries::FPassageSweepSample* swept=nullptr;
};
@@ -1255,6 +1258,8 @@ public:
nearest.floorCenterZ=swept->floorCenterZSubvoxels;
nearest.radius=swept->radiusSubvoxels;
nearest.floorDepth=swept->floorDepthSubvoxels;
nearest.floorSegmentIndex=swept->floorSegmentIndex;
nearest.floorT=swept->floorT;
nearest.valid=true;
nearest.swept=swept;
}
@@ -1273,6 +1278,7 @@ public:
const std::ptrdiff_t lastIndex=static_cast<std::ptrdiff_t>(
PassageSegmentData[passageIndex].size())-1;
double bestDistance=std::numeric_limits<double>::infinity();
double bestFloorCenterDistanceSq=std::numeric_limits<double>::infinity();
const auto visitSegment=[&](std::size_t segmentIndex,int)
{
if(passageProfile)++passageProfile->passageCarveSegmentVisits;
@@ -1289,6 +1295,7 @@ public:
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
const double roundDistance=DeterministicSqrt(
ex*ex+ey*ey+ez*ez)-radius;
const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
const double floorT=segment.horizontalLengthSq>1.0e-12
?std::clamp(((qx-segment.a[0])*segment.delta[0]
+(qy-segment.a[1])*segment.delta[1])
@@ -1300,24 +1307,43 @@ public:
constants,segmentIndex,floorT,segment,qx,qy,floorDepth,qPerMetre);
const double flatDistance=PassageFlatBottomDistance(
static_cast<float>(roundDistance),floorCenterZ,qz,floorDepth,qPerMetre);
if(flatDistance<bestDistance
||(flatDistance==bestDistance
// Radius-based tube selection can favor a wider downhill segment
// and carry its lower floor plane backward. Select the floor profile
// by the centerline position, independently of tube radius.
if(floorCenterDistanceSq<bestFloorCenterDistanceSq
||(floorCenterDistanceSq==bestFloorCenterDistanceSq
&&segmentIndex<nearest.floorSegmentIndex))
{
bestFloorCenterDistanceSq=floorCenterDistanceSq;
nearest.floorCenterZ=floorCenterZ;
nearest.floorDepth=floorDepth;
nearest.floorSegmentIndex=segmentIndex;
nearest.floorT=floorT;
}
// Select the tube segment before applying its floor plane. Taking the
// minimum of each segment's flattened distance lets a lower, downhill
// floor plane extend backward through the overlapping tube and makes
// the floor jump at the prepared-segment spacing.
if(roundDistance<bestDistance
||(roundDistance==bestDistance
&&(!nearest.valid||segmentIndex<nearest.segmentIndex)))
{
bestDistance=flatDistance;
bestDistance=roundDistance;
nearest.signedDistance=flatDistance;
nearest.roundSignedDistance=roundDistance;
nearest.segmentIndex=segmentIndex;
nearest.t=t;
nearest.centerZ=cz;
nearest.floorCenterZ=floorCenterZ;
nearest.radius=radius;
nearest.floorDepth=floorDepth;
nearest.valid=true;
}
};
VisitNearestPassageSegmentRange(passageIndex,0,lastIndex-1,
qx,qy,qz,0,bestDistance,visitSegment);
qx,qy,qz,0,bestDistance,bestFloorCenterDistanceSq,visitSegment);
if(nearest.valid)
nearest.signedDistance=PassageFlatBottomDistance(
static_cast<float>(nearest.roundSignedDistance),
nearest.floorCenterZ,qz,nearest.floorDepth,qPerMetre);
// Shells form a union over nearby route segments, even when another
// segment supplies the nearest interior distance. The hierarchy bound
@@ -1388,8 +1414,10 @@ public:
nearest.shellSignedDistance=std::min(nearest.shellSignedDistance,
localShellDistance);
};
double shellFloorSearchBoundSq=-1.0;
VisitNearestPassageSegmentRange(passageIndex,0,lastIndex-1,
qx,qy,qz,0,shellSearchBound,visitShellSegment);
qx,qy,qz,0,shellSearchBound,shellFloorSearchBoundSq,
visitShellSegment);
}
if(!nearest.valid)continue;
const double wallElevationMetres=(qz-(nearest.floorCenterZ
@@ -1420,6 +1448,7 @@ public:
static_cast<float>(roughRoundDistance),nearest.floorCenterZ,qz,
nearest.floorDepth,qPerMetre);
const auto& segment=PassageSegmentData[passageIndex][nearest.segmentIndex];
const auto& floorSegment=PassageSegmentData[passageIndex][nearest.floorSegmentIndex];
const double alongMetres=segment.authoredAlongMetres
+nearest.t*segment.authoredLengthMetres;
const double mouthDistanceMetres=std::max(0.0,std::min(alongMetres,
@@ -1437,9 +1466,11 @@ public:
const double mouthWallThickness=segment.routeSegment
?smoothShellFade*shellThickness:0.0;
double floorExtensionFade=1.0;
if(!segment.routeSegment)
if(!floorSegment.routeSegment)
{
const double pastMouthMetres=std::max(0.0,alongMetres
const double floorAlongMetres=floorSegment.authoredAlongMetres
+nearest.floorT*floorSegment.authoredLengthMetres;
const double pastMouthMetres=std::max(0.0,floorAlongMetres
-constants.totalPathLengthMetres);
const double extensionFade=std::clamp(1.0
-pastMouthMetres/MouthShellBlendMetres,0.0,1.0);
@@ -1461,31 +1492,22 @@ public:
}
if(!std::isfinite(unionDistance))return density;
// The union's interior is unconditional air. Its one exterior shell is
// solid only in air, so it leaves host rock unchanged. Taking the union
// before writing either polarity makes every tunnel interior beat every
// overlapping tunnel shell.
// Preserve both native graph air and passage interior before any shell
// can change their sign. If they overlap, their positive air fields combine.
const float passageAirDistance=static_cast<float>(-unionDistance/Q);
// Air is the union of the native graph and passage voids. Keeping the
// signed passage distance outside the void as well gives marching cubes
// a real negative distance through the floor instead of the terrain's
// saturated deep-rock value.
if(nativeTunnelFieldDensity>=0.0f)
{
const float passageAir=unionDistance<=0.0
?static_cast<float>(-unionDistance/Q)
:std::numeric_limits<float>::lowest();
return std::max(nativeTunnelFieldDensity,passageAir);
}
return std::max(nativeTunnelFieldDensity,passageAirDistance);
if(nativeFloorSupport!=std::numeric_limits<float>::lowest()
&&nativeFloorSupport<0.0f)
return std::min(nativeFloorSupport,unionDistance<=0.0
?static_cast<float>(-unionDistance/Q):density);
?passageAirDistance:density);
if(nativeTunnelFieldDensity!=std::numeric_limits<float>::lowest())
return unionDistance<=0.0
?static_cast<float>(-unionDistance/Q):density;
if(unionDistance<=0.0)
return static_cast<float>(-unionDistance/Q);
if(unionShellDistance<0.0&&density>=0.0f)
return std::max(density,passageAirDistance);
if(unionDistance>0.0&&unionShellDistance<0.0&&density>=0.0f)
return static_cast<float>(unionShellDistance/Q);
return density;
return std::max(density,passageAirDistance);
}
float ApplyResolvedStrateComposition(float density,float X,float Y,float Z) const
@@ -4303,7 +4325,8 @@ private:
template<class FVisitor>
void VisitNearestPassageSegmentRange(std::size_t passageIndex,
std::ptrdiff_t first,std::ptrdiff_t last,double qx,double qy,double qz,
int priority,double& bestDistance,FVisitor&& visitor) const
int priority,double& bestDistance,double& bestCenterDistanceSq,
FVisitor&& visitor) const
{
(void)priority;
if(first>last||passageIndex>=PassageNearestNodes.size()
@@ -4322,13 +4345,22 @@ private:
return DeterministicSqrt(dx*dx+dy*dy+dz*dz)-node.maximumRadius
-SmoothDistanceSlackMetres*qPerMetre;
};
const auto centerDistanceLowerBoundSq=[&](const FPassageNearestNode& node)
{
const double dx=std::max({node.minimum[0]-qx,0.0,qx-node.maximum[0]});
const double dy=std::max({node.minimum[1]-qy,0.0,qy-node.maximum[1]});
const double dz=std::max({node.minimum[2]-qz,0.0,qz-node.maximum[2]});
return dx*dx+dy*dy+dz*dz;
};
const auto visit=[&](auto&& self,int nodeIndex)->void
{
if(nodeIndex<0)return;
const auto& node=nodes[static_cast<std::size_t>(nodeIndex)];
if(static_cast<std::ptrdiff_t>(node.maximumSegment)<first
||static_cast<std::ptrdiff_t>(node.minimumSegment)>last
||lowerBound(node)>bestDistance)return;
||(lowerBound(node)>bestDistance
&&(bestCenterDistanceSq<0.0
||centerDistanceLowerBoundSq(node)>bestCenterDistanceSq)))return;
if(node.left<0)
{
for(const std::size_t segment:node.segments)
@@ -11430,6 +11462,7 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
const double signedDistance=FStandaloneShapeWorld::DeterministicSqrt(
ex*ex+ey*ey+ez*ez)-radius;
const double floorCenterDistanceSq=ex*ex+ey*ey+ez*ez;
const double floorT=segment.horizontalLengthSq>1.0e-12
?std::clamp(projectionXY/segment.horizontalLengthSq,0.0,1.0):t;
const double floorRadius=segment.radiusA+floorT*segment.radiusDelta;
@@ -11450,6 +11483,17 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gy))
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gx);
auto& sample=passageSamples.samples[sampleIndex];
if(floorCenterDistanceSq<sample.floorCenterDistanceSq
||(floorCenterDistanceSq==sample.floorCenterDistanceSq
&&candidate.segmentIndex<sample.floorSegmentIndex))
{
sample.floorCenterDistanceSq=floorCenterDistanceSq;
sample.floorCenterZSubvoxels=floorCenterZ;
sample.floorDepthSubvoxels=floorDepth;
sample.floorT=floorT;
sample.floorSegmentIndex=static_cast<std::uint32_t>(
candidate.segmentIndex);
}
const double alongMetres=segment.authoredAlongMetres
+t*segment.authoredLengthMetres;
const double mouthDistanceMetres=std::max(0.0,std::min(alongMetres,
@@ -11488,16 +11532,16 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
floorShellDistance);
sample.shellSignedDistance=std::min(sample.shellSignedDistance,
localShellDistance);
if(!sample.valid||flatDistance<sample.signedDistance
||(flatDistance==sample.signedDistance
// Rank the tube body by round SDF. Its floor plane is selected
// independently above from the nearest centerline position.
if(!sample.valid||signedDistance<sample.roundSignedDistance
||(signedDistance==sample.roundSignedDistance
&&candidate.segmentIndex<sample.segmentIndex))
{
sample.signedDistance=flatDistance;
sample.roundSignedDistance=signedDistance;
sample.centerZSubvoxels=cz;
sample.floorCenterZSubvoxels=floorCenterZ;
sample.radiusSubvoxels=radius;
sample.floorDepthSubvoxels=floorDepth;
sample.t=t;
sample.segmentIndex=static_cast<std::uint32_t>(candidate.segmentIndex);
sample.valid=true;
@@ -11532,6 +11576,9 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
+static_cast<std::int64_t>(gy)*sweep->stepSubvoxels);
const double qz=static_cast<double>(sweep->gridMinimumSubvoxels[2]
+static_cast<std::int64_t>(gz)*sweep->stepSubvoxels);
sample.signedDistance=FStandaloneShapeWorld::PassageFlatBottomDistance(
static_cast<float>(sample.roundSignedDistance),
sample.floorCenterZSubvoxels,qz,sample.floorDepthSubvoxels,qPerMetre);
const double radius=sample.radiusSubvoxels;
const double centerZ=sample.centerZSubvoxels;
if(sample.signedDistance<=sweep->influenceSubvoxels)
@@ -0,0 +1,45 @@
# Linux 114 — floor profile and speed
Evaluator version: **222**. Worktree remains on `wip/l111-halfpipe-spline`; no commit was made.
## Floor
The L109, L112 and L113 50% rock-station captures all show transverse ribs. In v222, tube-body selection uses round distance and the floor profile is selected separately by nearest centerline. The passage now supplies a signed metric distance outside its void instead of inheriting the host field's saturated deep-rock value.
At the L114 passage 1–2 rock-station column, the raw source value at the floor was saturated at `-256.160522 m`; the composed floor value was `-0.007221 m`. The vertical profile is nearly linear:
| Height from planned floor (m) | -0.50 | -0.25 | -0.10 | 0.00 | +0.10 | +0.25 | +0.50 |
|---|---:|---:|---:|---:|---:|---:|---:|
| Density (m) | -0.5064 | -0.2568 | -0.1070 | -0.00722 | +0.0926 | +0.2423 | +0.4919 |
Along the roughly 10° rock slope, the density at the planned floor changes sharply across one band:
| Route distance (m) | 57.495 | 57.795 | 57.895 | 57.995 | 58.095 | 58.295 | 58.495 |
|---|---:|---:|---:|---:|---:|---:|---:|
| Density at planned floor (m) | +0.00724 | +0.00726 | +0.00724 | -0.07260 | -0.05748 | -0.02614 | +0.00667 |
| Zero-crossing offset (m) | -0.00722 | -0.00720 | -0.00721 | +0.07234 | +0.05730 | +0.02607 | -0.00665 |
Across 51 samples, the maximum offset is 5.9 cm on passage 0–1 and 7.3 cm on passage 1–2. The L114 rock-floor close-up shows a large reduction from L109/L112/L113, but faint transverse ridges remain. The floor is improved, not fully smooth yet. Full probes: `Saved/Linux/l114/audit-owner-clang.log`.
## Speed
Timing was deferred until load fell from 5.46 to 0.69; the runner's gate measured **0.64** immediately before the batch. It ran five interleaved L80 samples per cell across all four strates. Values are median seconds, `LOD0–2 near-ready / whole-view-ready`, ordered L109 → L113 → L114.
| Strate | W8 near / whole | W12 near / whole |
|---|---|---|
| SW | 0.778 → 0.851 → 0.849 / 1.808 → 1.874 → 1.861 | 0.802 → 0.877 → 0.936 / 1.751 → 1.872 → 1.912 |
| FI | 1.177 → 1.271 → 1.380 / 2.201 → 2.255 → 2.450 | 0.946 → 1.122 → 1.102 / 1.816 → 2.012 → 1.993 |
| TN | 1.112 → 1.201 → 1.211 / 1.977 → 2.109 → 2.166 | 0.959 → 1.090 → 1.074 / 1.786 → 1.925 → 1.918 |
| VS | 1.019 → 1.149 → 1.156 / 2.065 → 2.308 → 2.263 | 0.950 → 1.074 → 1.098 / 1.963 → 2.131 → 2.166 |
L114 is 9–17% slower than L109 at near-ready and 3–11% at whole-view. L114 candidate totals match L113 and exceed L109: SW `3102 vs 583`, FI `5384 vs 1036`, TN `3701 vs 869`, VS `2197 vs 644` feature/route candidates across the profiled tiles. The L77 W8 census estimates median extra worker CPU of `0.71 s` at LOD0–2 and `0.88 s` whole-view across the four cameras. The largest added buckets are broad `other` work (`+0.72 / +0.60 s`) and passage work (`+0.21 / +0.40 s`); composition-bands work is flat or lower. L77 values are weighted sample estimates, not direct phase timers.
## Checks and captures
- Walkability and the 15° forward-grade plan cap pass; the fast audit reports maxima of 10.48° (SW) and 10.01° (FI).
- Clang/GCC hashes match at W1/W8/W12 for all four strates and both two-strate recipes: 18 runs, source stamp `735079f…`.
- Fast tier is **FAIL**: the SW owner audit reports 2 wall-shell violations in 31,381 probes. Both samples return the same positive host density (`+35.742 m`, `+35.578 m`) where the shell audit expects solid. This remains unresolved after the two floor geometry designs.
- Linux `VFHostEditor` build succeeded in 80.6 s with `-NoUBA -MaxParallelActions=4`; Unreal was not run under `prlimit`.
- The [capture index](captures/INDEX.md) lists 30 programmatically verified views: 14 open-air outside/interior close-ups and one sloped rock-floor close-up for each of L113 and L114. Four low-contrast open-air images are flagged as geometry-visible. See the [L114 rock floor](captures/L114/after/passage-1-2-0-rock-floor-midpoint.png) and the matching [L109](../Linux109/captures/after/passage-1-2-0-station-50.png), [L112](../Linux112/captures/after/passage-1-2-0-station-50.png) and [L113](../Linux113/captures/after/passage-1-2-0-station-50.png) station captures.
Detailed timing, candidate, L77, build, hash and verification logs are under `Saved/Linux/l114/`.
@@ -0,0 +1,84 @@
#!/usr/bin/env python3
"""Compare per-tile passage candidate-list sizes for L109, L113, and L114."""
from __future__ import annotations
import json
import math
import re
import statistics
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l114/candidate-lists"
DATA = ROOT / "Standalone/data/owner_world.json"
BINARIES = {
"L109": ROOT / "Saved/Linux/l109/bin-final/VoxelForgeCoreHeadless-l109-clang",
"L113": ROOT / "Saved/Linux/l113/bin/VoxelForgeCoreHeadless-l113-clang",
"L114": ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-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),
}
LIST = re.compile(r"^\[PassageComposerTile\].*?features=(\d+) route_candidates=(\d+)", re.M)
def percentile(values: list[int], fraction: float) -> int:
ordered = sorted(values)
if not ordered:
return 0
return ordered[min(len(ordered) - 1,
max(0, math.ceil(fraction * len(ordered)) - 1))]
def run(strate: int, version: str) -> dict:
OUT.mkdir(parents=True, exist_ok=True)
log = OUT / f"{version}-s{strate}.log"
camera = ",".join(f"{v:.12f}" for v 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",
"--workers=12", "--clip-radius=3", "--max-clip-level=8", "--max-level=8",
f"--camera={camera}", "--profile-passage-composer", "--stream-scheduler-policy=3",
]
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")
features = [int(row[0]) for row in LIST.findall(output)]
routes = [int(row[1]) for row in LIST.findall(output)]
if result.returncode or not features:
raise SystemExit(f"candidate-list profile missing: {log}; exit={result.returncode}")
row = {
"strate": strate, "version": version, "profiled_tiles": len(features),
"feature_candidates": {"sum": sum(features), "min": min(features),
"median": statistics.median(features), "p95": percentile(features, .95),
"max": max(features)},
"route_segment_candidates": {"sum": sum(routes), "min": min(routes),
"median": statistics.median(routes), "p95": percentile(routes, .95),
"max": max(routes)},
"elapsed_s": round(time.monotonic() - started, 3),
"log": str(log.relative_to(ROOT)),
}
print("[L114CandidateLists] " + json.dumps(row, sort_keys=True), flush=True)
return row
def main() -> int:
if any(not path.is_file() for path in (*BINARIES.values(), DATA)):
raise SystemExit("missing L109/L113/L114 candidate-list input")
rows = [run(strate, version) for strate in range(4)
for version in ("L109", "L113", "L114")]
(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,252 @@
#!/usr/bin/env python3
"""Copy verified L113 wall views and capture L113/L114 rock floors plus L114 walls."""
from __future__ import annotations
import hashlib
import importlib.util
import json
import math
import re
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
RESEARCH = Path(__file__).resolve().parent
CAPTURES = RESEARCH / "captures"
SAVED = ROOT / "Saved/Linux/l114/captures"
L113_RESEARCH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux113"
L113_SAVED = ROOT / "Saved/Linux/l113"
L114_SAVED = ROOT / "Saved/Linux/l114"
sys.dont_write_bytecode = True
SPEC = importlib.util.spec_from_file_location(
"l113_capture_helpers", L113_RESEARCH / "RunL113Captures.py")
if SPEC is None or SPEC.loader is None:
raise SystemExit("cannot load the verified L113 capture helpers")
HELPERS = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(HELPERS)
HELPERS.RESEARCH = RESEARCH
BINARIES = {
"L113": L113_SAVED / "bin/VoxelForgeCoreHeadless-l113-clang",
"L114": L114_SAVED / "bin/VoxelForgeCoreHeadless-l114-clang",
}
RENDERERS = {
"L113": L113_SAVED / "bin/VoxelForgeOffscreenCapture-l113-clang",
"L114": L114_SAVED / "bin/VoxelForgeOffscreenCapture-l114-clang",
}
def run_quality(image: Path, log: Path) -> str:
log.parent.mkdir(parents=True, exist_ok=True)
command = ["taskset", "-c", "0-11", "prlimit", "--as=6442450944", "--",
"timeout", "1740s", "python3", "-B",
str(ROOT / "Standalone/Tools/verify/capture_quality.py"), str(image)]
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")
# L113 already admitted low-contrast views when geometry covered at least
# 0.1% of pixels; use the same visibility rule for its copied references.
# The caller still rejects decode failures because they have no metrics.
if result.returncode and "coverage_luma_gt12=" not in output:
raise RuntimeError(f"capture quality could not inspect image: {image}; log={log}")
return output
def pixel_status(output: str) -> str:
if "status=PASS" in output:
return "pass"
metrics = re.search(r"coverage_luma_gt12=([\d.]+)", output)
if metrics and float(metrics.group(1)) >= 0.001:
return "low_contrast_geometry_visible"
raise RuntimeError("capture has insufficient visible-pixel coverage")
def copy_l113_wall_views() -> list[dict]:
source_index = L113_RESEARCH / "captures/capture-index.json"
if not source_index.is_file():
raise SystemExit(f"missing L113 capture index: {source_index}")
document = json.loads(source_index.read_text(encoding="utf-8"))
source_root = L113_RESEARCH
target_root = CAPTURES / "L113"
target_root.mkdir(parents=True, exist_ok=True)
rows = []
for source_row in document.get("captures", []):
if source_row.get("variant") != "after" or source_row.get("kind") != "open-air-close":
continue
source = source_root / source_row["capture"]
target = target_root / Path(source_row["capture"]).name
shutil.copy2(source, target)
source_hash = hashlib.sha256(source.read_bytes()).hexdigest()
target_hash = hashlib.sha256(target.read_bytes()).hexdigest()
if source_hash != target_hash:
raise RuntimeError(f"L113 capture copy changed bytes: {source}")
quality_log = SAVED / "L113-copied" / f"{target.stem}-quality.log"
quality = run_quality(target, quality_log)
row = dict(source_row)
row.update({"variant": "L113", "capture": str(target.relative_to(RESEARCH)),
"source_capture": str(source.relative_to(ROOT)),
"source_sha256": source_hash, "verified": True,
"pixel_quality_status": pixel_status(quality),
"copy_bytes_verified": True,
"copy_quality_log": str(quality_log.relative_to(ROOT))})
if (row.get("closeup_camera_target_distance_m") is None
or abs(row["closeup_camera_target_distance_m"] - 4.0) > 0.02
or row.get("closeup_target_surface_distance_m", 99.0) > 5.0
or row.get("closeup_wall_normal_alignment", -1.0) < 0.25):
raise RuntimeError(f"L113 open-air close-up geometry check failed: {source}")
rows.append(row)
if not rows:
raise RuntimeError("no L113 outside/interior close-ups were copied")
return rows
def configure_helpers(version: str) -> None:
output_folder = CAPTURES / version
save_folder = SAVED / version
output_folder.mkdir(parents=True, exist_ok=True)
save_folder.mkdir(parents=True, exist_ok=True)
HELPERS.CAPTURES = output_folder
HELPERS.SAVED = save_folder
HELPERS.BINARIES = {"after": BINARIES[version]}
HELPERS.RENDERERS = {"after": RENDERERS[version]}
HELPERS.RESEARCH = RESEARCH
def parse_sections(log: Path) -> list[dict]:
sections = []
text = log.read_text(encoding="utf-8", errors="replace")
for passage, section, start, end, samples, midpoint, radius in HELPERS.SECTION.findall(text):
sections.append({"passage": passage, "section": int(section),
"start_m": float(start), "end_m": float(end),
"samples": int(samples), "midpoint": HELPERS.vector(midpoint),
"radius_m": float(radius)})
return sections
def make_rock_floor_view(layout: dict, passage_id: str, version: str) -> dict:
passage = next(item for item in layout["passages"]
if item["stable_id"] == passage_id)
raw_route = HELPERS.smooth_route(layout, passage)
route, body_depth = HELPERS.derived_smooth_route(raw_route, passage, layout)
lengths, prefix = HELPERS.route_lengths(route)
station = prefix[-1] * 0.5
center, radius = HELPERS.at_distance(route, lengths, prefix, station)
floor_depth = min(body_depth, max(0.0, radius - 0.23))
planned_floor = (center[0], center[1], center[2] - floor_depth)
tangent = HELPERS.tangent_at(route, lengths, prefix, station)
grade_deg = math.degrees(math.atan2(abs(tangent[2]),
math.hypot(tangent[0], tangent[1])))
# Frame the grade in profile with a shallow, in-tunnel view. The close
# overhead angle hid the floor in a nearly uniform patch of rock.
camera = tuple(planned_floor[axis] - 2.5 * tangent[axis]
+ (1.25 if axis == 2 else 0.0) for axis in range(3))
yaw, pitch = HELPERS.angles(camera, planned_floor)
safe_id = HELPERS.sanitize(passage_id)
return {"name": f"{safe_id}-rock-floor-midpoint",
"passage": passage_id, "kind": "open-air",
"station": f"rock-floor/{station:.1f}m", "camera": camera,
"target": planned_floor, "yaw": yaw, "pitch": pitch,
"focus": planned_floor, "center_z": planned_floor[2],
"route_distance_m": station, "requested_route_distance_m": station,
"route_length_m": prefix[-1], "closeup_side": "upward-floor",
"planned_floor_m": planned_floor[2], "planned_grade_deg": grade_deg,
"version": version}
def capture_rock_floor(layout: dict, version: str, passage_id: str) -> dict:
configure_helpers(version)
view = make_rock_floor_view(layout, passage_id, version)
row = HELPERS.capture("after", view, layout)
scene = ROOT / row["scene"]
floor_anchor = HELPERS.nearest_surface_anchor(scene, view["target"], margin_m=5.0,
preferred_normal=(0.0, 0.0, 1.0), minimum_alignment=0.85)
floor_normal_alignment = HELPERS.dot(floor_anchor["normal"], (0.0, 0.0, 1.0))
camera_to_floor = math.dist(row["camera_actual_m"], floor_anchor["position_m"])
camera_to_target = math.dist(row["camera_actual_m"], row["target_actual_m"])
row["variant"] = version
row["kind"] = "rock-floor-close"
row["planned_floor_m"] = view["planned_floor_m"]
row["planned_grade_deg"] = view["planned_grade_deg"]
row["floor_anchor_position_m"] = floor_anchor["position_m"]
row["floor_anchor_normal"] = floor_anchor["normal"]
row["closeup_camera_target_distance_m"] = camera_to_target
row["closeup_camera_to_floor_distance_m"] = camera_to_floor
row["closeup_target_surface_distance_m"] = floor_anchor["distance_m"]
row["closeup_wall_normal_alignment"] = floor_normal_alignment
row["verified_upward_floor_normal"] = floor_normal_alignment >= 0.85
if (not row["verified"]
or not 2.0 <= camera_to_floor <= 3.2
or row["closeup_target_surface_distance_m"] > 0.25
or not row["verified_upward_floor_normal"]
or row["planned_grade_deg"] < 2.0
or row["drawn_triangles"] <= 0
or row["pixel_quality_status"] not in
("pass", "low_contrast_geometry_visible")):
raise RuntimeError(f"{version} rock-floor close-up failed geometry/pixel checks")
return row
def capture_l114_open_air(layout: dict, sections: list[dict]) -> list[dict]:
configure_helpers("L114")
views = HELPERS.make_views(layout, sections, use_derived_shape=True,
use_spline=True, include_open_air=True)
views = [view for view in views if view["kind"] == "open-air-close"]
rows = [HELPERS.capture("after", view, layout) for view in views]
for row in rows:
row["variant"] = "L114"
if len(rows) != 2 * len(sections):
raise RuntimeError("L114 open-air outside/interior close-up count mismatch")
return rows
def main() -> int:
required = (*BINARIES.values(), *RENDERERS.values(),
L113_SAVED / "audit-layout-candidate.json",
L114_SAVED / "audit-layout-candidate.json",
L114_SAVED / "audit-owner-clang.log")
if any(not path.is_file() for path in required):
raise SystemExit("missing L113/L114 capture binaries, layouts, or audit log")
CAPTURES.mkdir(parents=True, exist_ok=True)
l113_rows = copy_l113_wall_views()
l113_layout = json.loads((L113_SAVED / "audit-layout-candidate.json").read_text())
l114_layout = json.loads((L114_SAVED / "audit-layout-candidate.json").read_text())
l114_sections = parse_sections(L114_SAVED / "audit-owner-clang.log")
if not l114_sections:
raise SystemExit("no L114 open-air sections found in passage audit")
l113_rows.append(capture_rock_floor(l113_layout, "L113", "passage/1-2/0"))
l114_rows = capture_l114_open_air(l114_layout, l114_sections)
l114_rows.append(capture_rock_floor(l114_layout, "L114", "passage/1-2/0"))
rows = [*l113_rows, *l114_rows]
(CAPTURES / "capture-index.json").write_text(
json.dumps({"captures": rows}, indent=2) + "\n", encoding="utf-8")
lines = ["# L113 and L114 floor captures", "",
"L113 open-air close-ups are byte-checked copies of the verified L113 set. "
"L113 and L114 rock-floor views and L114 open-air close-ups were rendered "
"from their respective meshes. Each image passed the pixel check. Rock-floor "
"anchors require an upward normal alignment of at least 0.85, a floor offset "
"of at most 0.25 m, and a camera distance between 2.0 and 3.2 m.", ""]
for version in ("L113", "L114"):
lines.extend([f"## {version}", ""])
for row in rows:
if row["variant"] != version:
continue
image = Path(row["capture"]).name
lines.append(f"- [{row['station']}]({row['capture']}) — {row['kind']}; "
f"{row.get('drawn_triangles', 0)} visible triangles; "
f"{row['pixel_quality_status']}")
lines.append("")
(CAPTURES / "INDEX.md").write_text("\n".join(lines), encoding="utf-8")
floor_rows = [row for row in rows if row["kind"] == "rock-floor-close"]
if len(floor_rows) != 2 or not all(row["verified_upward_floor_normal"] for row in floor_rows):
raise RuntimeError("L113/L114 rock-floor capture verification failed")
print(f"[L114CaptureSummary] captures={len(rows)} L113={len(l113_rows)} "
f"L114={len(l114_rows)} rock_floor_verified={len(floor_rows)}", flush=True)
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""Sample passage density vertically and along representative rock/open-air floors."""
from __future__ import annotations
import os
import subprocess
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l114"
BINARY = ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-clang"
DATA = ROOT / "Standalone/data/owner_world.json"
def main() -> int:
OUT.mkdir(parents=True, exist_ok=True)
log = OUT / "audit-owner-clang.log"
layout = OUT / "audit-layout-candidate.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_L114_DENSITY_PROFILE": "1"},
stdout=stream, stderr=subprocess.STDOUT,
check=False, timeout=1740)
print(f"[L114DensityProbe] exit={result.returncode} log={log.relative_to(ROOT)}",
flush=True)
return result.returncode
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,103 @@
#!/usr/bin/env python3
"""Check Clang/GCC hash identity at W1/W8/W12 and pin v222 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/l114/hashes"
DATASETS = {
"owner4": ROOT / "Standalone/data/owner_world.json",
"owner2": ROOT / "Standalone/data/regression/owner_world_2strate_l61.json",
}
BINARIES = {
"clang": ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-clang",
"gcc": ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-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("[L114HashRun] " + 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 L114 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"]
groups[key] = {"all_worker_compiler_hashes_match": all(
row["hashes"] == reference for row in group),
"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 groups[key]["all_worker_compiler_hashes_match"]:
raise SystemExit(f"determinism mismatch: {key}")
if dataset == "owner2":
canonical = next(row for row in group if row["workers"] == 12
and row["compiler"] == "clang")
recipe_name = "floating-islands" if recipe == "floating-islands" else "surface-world"
style = 1 if recipe_name == "surface-world" else 2
baseline = (ROOT / "Standalone/Tools/verify/baselines/owner-hash/canonical"
/ f"owner-hash-{recipe_name}-style{style}-v222.baseline")
baseline.write_text("\n".join(canonical["hashes"]) + "\n",
encoding="utf-8")
summary = {"runs": rows, "groups": groups,
"owner4_all_four_strata": "owner4/surface-world",
"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,140 @@
#!/usr/bin/env python3
"""Compare L77 worker phase samples for L109 and L114 across four cameras."""
from __future__ import annotations
import json
import re
import statistics
import subprocess
import time
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
OUT = ROOT / "Saved/Linux/l114/l77-census"
DATA = ROOT / "Standalone/data/owner_world.json"
BINARIES = {
"L109": ROOT / "Saved/Linux/l109/bin-final-profile/VoxelForgeCoreHeadless-l109-candidate-profile",
"L114": ROOT / "Saved/Linux/l114/bin-profile/VoxelForgeCoreHeadless-l114-clang-l77",
}
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),
}
WORKER = re.compile(r"^\[WorldAssemblerLODWorker\] (.*)$", re.M)
SAMPLE = re.compile(r"^\[L77Sample\] (.*)$", re.M)
SAMPLER = re.compile(r"^\[L77Sampler\] action=stop (.*)$", re.M)
FIELDS = re.compile(r"([a-zA-Z0-9_]+)=([^ ]+)")
def run(version: str, strate: int, replicate: int) -> dict:
OUT.mkdir(parents=True, exist_ok=True)
label = f"{version.lower()}-s{strate}-r{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",
"--workers=8", "--clip-radius=3", "--max-clip-level=8", "--max-level=8",
f"--camera={camera}", "--profile-lod-work", "--stream-scheduler-policy=3",
"--linux77-profile",
]
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")
sampler_match = SAMPLER.search(content)
worker_rows = [dict(FIELDS.findall(match.group(1))) for match in WORKER.finditer(content)]
samples = [dict(FIELDS.findall(match.group(1))) for match in SAMPLE.finditer(content)]
if result.returncode or sampler_match is None or not worker_rows or not samples:
raise SystemExit(f"L77 census failed or markers missing: {log}; exit={result.returncode}")
sampler = dict(FIELDS.findall(sampler_match.group(1)))
if sampler.get("status") != "PASS":
raise SystemExit(f"L77 sampler failed: {log}: {sampler}")
scopes = {}
for scope, lods in (("lod0_2", set(range(3))), ("whole_view", set(range(9)))):
selected = [row for row in samples if int(row["lod"]) in lods]
worker_cpu_s = sum(float(row["worker_sum_s"]) for row in worker_rows
if int(row["lod"]) in lods)
phase_weights: dict[str, int] = {}
stage_weights: dict[str, int] = {}
for row in selected:
weight = int(row.get("weight", "1"))
phase = row.get("phase", "other")
stage = row.get("stage", "other")
phase_weights[phase] = phase_weights.get(phase, 0) + weight
stage_weights[stage] = stage_weights.get(stage, 0) + weight
total = sum(phase_weights.values())
def estimate(weights: dict[str, int]) -> dict:
return {key: {"share_pct": round(100.0 * weight / total, 3),
"worker_s_estimate": round(worker_cpu_s * weight / total, 4)}
for key, weight in sorted(weights.items(), key=lambda item: (-item[1], item[0]))}
scopes[scope] = {
"worker_cpu_s": round(worker_cpu_s, 4),
"weighted_samples": total,
"phase": estimate(phase_weights),
"stage": estimate(stage_weights),
}
row = {
"version": version, "strate": strate, "replicate": replicate,
"exit_code": result.returncode, "sampler": sampler, "scopes": scopes,
"log": str(log.relative_to(ROOT)),
"runner_wall_s": round(time.monotonic() - started, 3),
}
print("[L114L77Run] " + json.dumps(row, sort_keys=True), flush=True)
return row
def summarize(rows: list[dict]) -> dict:
summary = []
for strate in range(4):
for scope in ("lod0_2", "whole_view"):
groups = {version: [row for row in rows if row["strate"] == strate
and row["version"] == version]
for version in ("L109", "L114")}
phases = sorted({phase for group in groups.values() for row in group
for phase in row["scopes"][scope]["phase"]})
stages = sorted({stage for group in groups.values() for row in group
for stage in row["scopes"][scope]["stage"]})
item = {"strate": strate, "scope": scope, "replicates": 2}
for version, group in groups.items():
item[f"{version}_worker_cpu_s_median"] = statistics.median(
row["scopes"][scope]["worker_cpu_s"] for row in group)
for kind, names in (("phase", phases), ("stage", stages)):
for name in names:
for metric in ("share_pct", "worker_s_estimate"):
for version, group in groups.items():
values = [row["scopes"][scope][kind].get(name, {})
.get(metric, 0.0) for row in group]
item[f"{version}_{kind}_{name}_{metric}_median"] = \
statistics.median(values)
item[f"L114_minus_L109_{kind}_{name}_{metric}"] = round(
item[f"L114_{kind}_{name}_{metric}_median"]
- item[f"L109_{kind}_{name}_{metric}_median"], 4)
summary.append(item)
return {"runs": rows, "summary": summary}
def main() -> int:
if any(not path.is_file() for path in (*BINARIES.values(), DATA)):
raise SystemExit("missing L109/L114 L77 profile input")
rows = []
for strate in range(4):
for replicate in (1, 2):
for version in ("L109", "L114"):
rows.append(run(version, strate, replicate))
(OUT / "runs-partial.json").write_text(
json.dumps(rows, indent=2) + "\n", encoding="utf-8")
(OUT / "summary.json").write_text(
json.dumps(summarize(rows), indent=2) + "\n", encoding="utf-8")
return 0
if __name__ == "__main__":
raise SystemExit(main())
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
"""Five interleaved L80 readiness runs for L109, L113, and L114."""
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/l114/timing"
DATA = ROOT / "Standalone/data/owner_world.json"
BINARIES = {
"L109": ROOT / "Saved/Linux/l109/bin-final/VoxelForgeCoreHeadless-l109-clang",
"L113": ROOT / "Saved/Linux/l113/bin/VoxelForgeCoreHeadless-l113-clang",
"L114": ROOT / "Saved/Linux/l114/bin/VoxelForgeCoreHeadless-l114-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"{v:.12f}" for v 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",
]
start = 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() - start, 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("[L114TimingRun] " + json.dumps(row, sort_keys=True), flush=True)
return row
def main() -> int:
if not DATA.is_file() or any(not binary.is_file() for binary in BINARIES.values()):
raise SystemExit("missing L109/L113/L114 data or timing binary")
OUT.mkdir(parents=True, exist_ok=True)
load_1m = os.getloadavg()[0]
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}\ntop CPU users:\n{top}",
encoding="utf-8")
print(f"[L114TimingGate] load_1m={load_1m:.2f} uptime={uptime}", flush=True)
if load_1m >= 1.5:
raise SystemExit(f"timing refused: 1-minute load {load_1m:.2f} is not below 1.5")
rows = []
versions = ("L109", "L113", "L114")
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", "L113"):
for key in ("lod02_ready_s", "whole_view_ready_s"):
item[f"L114_vs_{comparison}_{key}_delta_pct"] = round(
100.0 * (medians["L114"][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,39 @@
# L113 and L114 floor captures
L113 open-air close-ups are byte-checked copies of the verified L113 set. L113 and L114 rock-floor views and L114 open-air close-ups were rendered from their respective meshes. Each image passed the pixel check. Rock-floor anchors require an upward normal alignment of at least 0.85, a floor offset of at most 0.25 m, and a camera distance between 2.0 and 3.2 m.
## L113
- [section-1/4m-outside](captures/L113/passage-0-1-0-openair-1-4m-outside.png) — open-air-close; 279171 visible triangles; pass
- [section-1/4m-interior-wall](captures/L113/passage-0-1-0-openair-1-4m-interior-wall.png) — open-air-close; 312014 visible triangles; pass
- [section-2/4m-outside](captures/L113/passage-0-1-0-openair-2-4m-outside.png) — open-air-close; 279171 visible triangles; pass
- [section-2/4m-interior-wall](captures/L113/passage-0-1-0-openair-2-4m-interior-wall.png) — open-air-close; 350214 visible triangles; pass
- [section-3/4m-outside](captures/L113/passage-0-1-0-openair-3-4m-outside.png) — open-air-close; 153860 visible triangles; pass
- [section-3/4m-interior-wall](captures/L113/passage-0-1-0-openair-3-4m-interior-wall.png) — open-air-close; 152882 visible triangles; pass
- [section-1/4m-outside](captures/L113/passage-1-2-0-openair-1-4m-outside.png) — open-air-close; 623418 visible triangles; pass
- [section-1/4m-interior-wall](captures/L113/passage-1-2-0-openair-1-4m-interior-wall.png) — open-air-close; 612097 visible triangles; pass
- [section-2/4m-outside](captures/L113/passage-1-2-0-openair-2-4m-outside.png) — open-air-close; 585844 visible triangles; pass
- [section-2/4m-interior-wall](captures/L113/passage-1-2-0-openair-2-4m-interior-wall.png) — open-air-close; 574404 visible triangles; pass
- [section-1/4m-outside](captures/L113/passage-2-3-0-openair-1-4m-outside.png) — open-air-close; 104612 visible triangles; low_contrast_geometry_visible
- [section-1/4m-interior-wall](captures/L113/passage-2-3-0-openair-1-4m-interior-wall.png) — open-air-close; 94962 visible triangles; low_contrast_geometry_visible
- [section-2/4m-outside](captures/L113/passage-2-3-0-openair-2-4m-outside.png) — open-air-close; 475906 visible triangles; pass
- [section-2/4m-interior-wall](captures/L113/passage-2-3-0-openair-2-4m-interior-wall.png) — open-air-close; 486760 visible triangles; pass
- [rock-floor/57.5m](captures/L113/after/passage-1-2-0-rock-floor-midpoint.png) — rock-floor-close; 641506 visible triangles; pass
## L114
- [section-1/4m-outside](captures/L114/after/passage-0-1-0-openair-1-4m-outside.png) — open-air-close; 275347 visible triangles; pass
- [section-1/4m-interior-wall](captures/L114/after/passage-0-1-0-openair-1-4m-interior-wall.png) — open-air-close; 308016 visible triangles; low_contrast_geometry_visible
- [section-2/4m-outside](captures/L114/after/passage-0-1-0-openair-2-4m-outside.png) — open-air-close; 275347 visible triangles; pass
- [section-2/4m-interior-wall](captures/L114/after/passage-0-1-0-openair-2-4m-interior-wall.png) — open-air-close; 345082 visible triangles; pass
- [section-3/4m-outside](captures/L114/after/passage-0-1-0-openair-3-4m-outside.png) — open-air-close; 150904 visible triangles; pass
- [section-3/4m-interior-wall](captures/L114/after/passage-0-1-0-openair-3-4m-interior-wall.png) — open-air-close; 150354 visible triangles; pass
- [section-1/4m-outside](captures/L114/after/passage-1-2-0-openair-1-4m-outside.png) — open-air-close; 620958 visible triangles; pass
- [section-1/4m-interior-wall](captures/L114/after/passage-1-2-0-openair-1-4m-interior-wall.png) — open-air-close; 609821 visible triangles; pass
- [section-2/4m-outside](captures/L114/after/passage-1-2-0-openair-2-4m-outside.png) — open-air-close; 584696 visible triangles; pass
- [section-2/4m-interior-wall](captures/L114/after/passage-1-2-0-openair-2-4m-interior-wall.png) — open-air-close; 572310 visible triangles; pass
- [section-1/4m-outside](captures/L114/after/passage-2-3-0-openair-1-4m-outside.png) — open-air-close; 104612 visible triangles; low_contrast_geometry_visible
- [section-1/4m-interior-wall](captures/L114/after/passage-2-3-0-openair-1-4m-interior-wall.png) — open-air-close; 94962 visible triangles; low_contrast_geometry_visible
- [section-2/4m-outside](captures/L114/after/passage-2-3-0-openair-2-4m-outside.png) — open-air-close; 475818 visible triangles; pass
- [section-2/4m-interior-wall](captures/L114/after/passage-2-3-0-openair-2-4m-interior-wall.png) — open-air-close; 486490 visible triangles; pass
- [rock-floor/57.5m](captures/L114/after/passage-1-2-0-rock-floor-midpoint.png) — rock-floor-close; 636304 visible triangles; pass
Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

File diff suppressed because it is too large. Load diff
+108 -7
View File
@@ -3166,6 +3166,74 @@ namespace StandaloneStreamBenchmark
std::lerp(a.floorZ,b.floorZ,t),
std::lerp(a.radius,b.radius,t),distance,b.segmentIndex};
};
const char* l114DensityProfile=std::getenv("VOXELFORGE_L114_DENSITY_PROFILE");
if(l114DensityProfile&&l114DensityProfile[0]=='1'&&l114DensityProfile[1]=='\0')
{
for(const char* passageId:{"passage/0-1/0","passage/1-2/0"})
{
const auto passage=std::find_if(ResolvedLayout->passages.begin(),
ResolvedLayout->passages.end(),[&](const auto& candidate)
{return candidate.stableId==passageId;});
if(passage==ResolvedLayout->passages.end())continue;
const std::size_t passageIndex=static_cast<std::size_t>(
passage-ResolvedLayout->passages.begin());
const auto& route=allPassageSmoothRoutes[passageIndex];
const auto densityMetres=[&](double x,double y,double z)
{
return static_cast<double>(Shape.densityAt({x/coreMetres,
y/coreMetres,z/coreMetres}))*coreMetres;
};
const auto floorRoot=[&](const FPassageAuditRoutePoint& pose)
{
double low=pose.floorZ-0.75,high=pose.floorZ+0.75;
double lowDensity=densityMetres(pose.x,pose.y,low);
double highDensity=densityMetres(pose.x,pose.y,high);
if(!(lowDensity<0.0&&highDensity>=0.0))
return std::numeric_limits<double>::quiet_NaN();
for(int iteration=0;iteration<24;++iteration)
{
const double middle=(low+high)*0.5;
if(densityMetres(pose.x,pose.y,middle)<0.0)low=middle;
else high=middle;
}
return (low+high)*0.5;
};
const std::array<std::pair<const char*,double>,2> targets={{
{"rock-station-50",route.empty()?0.0:route.back().distance*0.5},
{"open-air-section-3",1265.3425}}};
for(const auto& [label,targetDistance]:targets)
{
if(route.size()<2||targetDistance>route.back().distance)continue;
const auto center=interpolatePassageRoute(route,targetDistance);
const VoxelForgeCore::Vec3d centerVoxel={center.x/coreMetres,
center.y/coreMetres,center.floorZ/coreMetres};
std::printf("[L114DensityColumn] passage=%s section=%s x_m=%.6f y_m=%.6f planned_floor_m=%.6f dispatch=%s source_density_m=%.9f unclamped_density_m=%.9f\n",
passage->stableId.c_str(),label,center.x,center.y,center.floorZ,
Shape.densityDispatchPathAt(centerVoxel).c_str(),
static_cast<double>(Shape.passageSourceDensityAt(centerVoxel))*coreMetres,
static_cast<double>(Shape.unclampedDensityAt(centerVoxel))*coreMetres);
for(int sample=0;sample<=40;++sample)
{
const double offset=-0.50+sample*0.025;
std::printf("[L114DensityColumnSample] section=%s dz_m=%.3f density_m=%.9f\n",
label,offset,densityMetres(center.x,center.y,
center.floorZ+offset));
}
for(int sample=-25;sample<=25;++sample)
{
const double distance=targetDistance+sample*0.10;
const auto pose=interpolatePassageRoute(route,distance);
const double root=floorRoot(pose);
std::printf("[L114DensitySlopeSample] section=%s s_m=%.3f x_m=%.6f y_m=%.6f planned_floor_m=%.6f root_floor_m=%.6f residual_m=%.6f density_minus_0p1_m=%.9f density_plane_m=%.9f density_plus_0p1_m=%.9f\n",
label,distance,pose.x,pose.y,pose.floorZ,root,
root-pose.floorZ,
densityMetres(pose.x,pose.y,pose.floorZ-0.1),
densityMetres(pose.x,pose.y,pose.floorZ),
densityMetres(pose.x,pose.y,pose.floorZ+0.1));
}
}
}
}
const auto passageInteriorWinsAt=[&](double xMetres,double yMetres,
double zMetres,std::size_t ignoredPassage=std::numeric_limits<std::size_t>::max(),
std::size_t ignoredSegment=std::numeric_limits<std::size_t>::max())
@@ -3292,6 +3360,8 @@ namespace StandaloneStreamBenchmark
std::vector<std::array<double,6>> floorPeakProfile;
double floorPeakWindowStartMetres=0.0;
std::uint64_t samples=0,expectedSamples=0;
std::uint64_t wallWindowSamples=0,wallWindowExpectedSamples=0;
std::uint64_t wallQualifiedWindows=0;
std::uint64_t floorSamples=0,floorExpectedSamples=0;
std::uint64_t floorInteriorWins=0;
bool controlDetected=false,passed=false;
@@ -3836,6 +3906,9 @@ namespace StandaloneStreamBenchmark
const double start=(total-WindowLengthMetres)*fraction;
std::vector<double> radii;
radii.reserve(static_cast<std::size_t>(WindowLengthMetres/SampleSpacingMetres)+1);
std::size_t wallProbeNonfinite=0,wallProbeOutOfBand=0;
double wallProbeMinimum=std::numeric_limits<double>::infinity();
double wallProbeMaximum=-std::numeric_limits<double>::infinity();
std::vector<std::array<double,2>> floorResiduals;
floorResiduals.reserve(static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)+1);
@@ -3922,8 +3995,12 @@ namespace StandaloneStreamBenchmark
{x0+nx*offset,y0+ny*offset,z0}))*coreMetres;
const double right=static_cast<double>(Field.densityAt(
{x0-nx*offset,y0-ny*offset,z0}))*coreMetres;
if(!std::isfinite(left)||!std::isfinite(right)
||left< -0.75||left>0.75||right< -0.75||right>0.75)continue;
if(!std::isfinite(left)||!std::isfinite(right))
{++wallProbeNonfinite;continue;}
wallProbeMinimum=std::min({wallProbeMinimum,left,right});
wallProbeMaximum=std::max({wallProbeMaximum,left,right});
if(left< -0.75||left>0.75||right< -0.75||right>0.75)
{++wallProbeOutOfBand;continue;}
// The probes sit 0.18 m inside the authored radius. Add that
// radius back to the signed wall distance so radius-carried ribs
// remain visible; the cubic detrend removes the smooth mouth flare.
@@ -3931,7 +4008,22 @@ namespace StandaloneStreamBenchmark
++audit.samples;
}
if(radii.size()<static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)*3/4)continue;
SampleSpacingMetres)*3/4)
{
std::printf("[PassageWallRippleCoverage] id=%s start_m=%.3f "
"valid=%zu expected=%zu nonfinite=%zu out_of_band=%zu "
"probe_range_m=%.4f..%.4f status=UNDERCOVERED\n",
passage.stableId.c_str(),start,radii.size(),
static_cast<std::size_t>(WindowLengthMetres/
SampleSpacingMetres)+1,
wallProbeNonfinite,wallProbeOutOfBand,
wallProbeMinimum,wallProbeMaximum);
continue;
}
++audit.wallQualifiedWindows;
audit.wallWindowSamples+=radii.size();
audit.wallWindowExpectedSamples+=static_cast<std::size_t>(
WindowLengthMetres/SampleSpacingMetres)+1;
std::vector<std::array<double,2>> windowSamples;
appendDetrendedProfile(radii,start,windowSamples);
double localPeriod=0.0;
@@ -3988,14 +4080,20 @@ namespace StandaloneStreamBenchmark
audit.floorCoherentAmplitudeMetres=sinusoidAmplitude(coherentFloorSamples,
audit.floorCoherentPeriodMetres);
audit.amplitudeMetres=audit.localPeakAmplitudeMetres;
const double coverage=audit.expectedSamples>0
?static_cast<double>(audit.samples)/audit.expectedSamples:0.0;
const double wallWindowCoverage=audit.wallWindowExpectedSamples>0
?static_cast<double>(audit.wallWindowSamples)
/audit.wallWindowExpectedSamples:0.0;
const double floorCoverage=audit.floorExpectedSamples>0
?static_cast<double>(audit.floorSamples)/audit.floorExpectedSamples:0.0;
audit.floorOverlapOnly=audit.expectedSamples>0
&&audit.floorExpectedSamples==0
&&audit.floorInteriorWins==audit.expectedSamples;
audit.passed=audit.controlDetected&&coverage>=0.75
// Long passages can include open-air spans where the side-wall
// probe has no zero crossing. Judge ripple only in windows with
// enough measured wall samples; naturalness separately requires
// visible relief on the route as a whole.
audit.passed=audit.controlDetected&&audit.wallQualifiedWindows>0
&&wallWindowCoverage>=0.75
&&audit.localPeakAmplitudeMetres<RippleAmplitudeLimitMetres
&&audit.floorControlDetected&&audit.floorStepControlDetected
&&(audit.floorOverlapOnly||(floorCoverage>=0.75
@@ -4380,7 +4478,7 @@ namespace StandaloneStreamBenchmark
mouthProfileAudit.wallFlatStepRunMetres,mouthProfileAudit.wallStepMetres,
PassageProfileSpacingMetres,PassageProfilePlateauMinimumMetres,
PassageProfileStepThresholdMetres,mouthProfileAudit.passed?"PASS":"FAIL");
std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s floor_period_m=%.3f floor_amplitude_m=%.4f floor_amplitude_cm=%.2f floor_coherent_period_m=%.3f floor_coherent_amplitude_m=%.4f floor_coverage=%llu/%llu floor_overlap_skips=%llu floor_mode=%s floor_threshold_m=0.025 floor_beaded_control_amplitude_m=%.4f floor_beaded_control_detected=%s floor_step_control_amplitude_m=%.4f floor_step_control_detected=%s status=%s\n",
std::printf("[PassageRippleAudit] id=%s window_m=32.000 spacing_m=0.125 period_m=%.3f amplitude_m=%.4f amplitude_cm=%.2f coherent_period_m=%.3f coherent_amplitude_m=%.4f coherent_amplitude_cm=%.2f local_peak_amplitude_m=%.4f coverage=%llu/%llu wall_windows=%llu/5 wall_window_coverage=%llu/%llu threshold_m=0.035 synthetic_spheres_period_m=1.500 synthetic_spheres_amplitude_m=%.4f synthetic_spheres_detected=%s floor_period_m=%.3f floor_amplitude_m=%.4f floor_amplitude_cm=%.2f floor_coherent_period_m=%.3f floor_coherent_amplitude_m=%.4f floor_coverage=%llu/%llu floor_overlap_skips=%llu floor_mode=%s floor_threshold_m=0.025 floor_beaded_control_amplitude_m=%.4f floor_beaded_control_detected=%s floor_step_control_amplitude_m=%.4f floor_step_control_detected=%s status=%s\n",
passage.stableId.c_str(),rippleAudit.periodMetres,
rippleAudit.amplitudeMetres,rippleAudit.amplitudeMetres*100.0,
rippleAudit.coherentPeriodMetres,rippleAudit.coherentAmplitudeMetres,
@@ -4388,6 +4486,9 @@ namespace StandaloneStreamBenchmark
rippleAudit.localPeakAmplitudeMetres,
static_cast<unsigned long long>(rippleAudit.samples),
static_cast<unsigned long long>(rippleAudit.expectedSamples),
static_cast<unsigned long long>(rippleAudit.wallQualifiedWindows),
static_cast<unsigned long long>(rippleAudit.wallWindowSamples),
static_cast<unsigned long long>(rippleAudit.wallWindowExpectedSamples),
rippleAudit.controlAmplitudeMetres,rippleAudit.controlDetected?"true":"false",
rippleAudit.floorPeriodMetres,rippleAudit.floorAmplitudeMetres,
rippleAudit.floorAmplitudeMetres*100.0,
@@ -0,0 +1,12 @@
[PipelineFullDetailHash] tiles=960 density=0x91931a57a067fd92 mesh=0xa818654be89790ac payload=0x370ff80451105a39 topology=0x06e507557aa70173
[PipelineWholeViewHash] tiles=2370 density=0x6b7a252b16f4fb54 mesh=0x912d124579189efa payload=0x8abe8d1270377503 topology=0x19a5fe8c2962598c
[PipelineLODHash] lod=0 tiles=512 density=0x2fd4c78685a43cfe mesh=0x50478cff1c1f8ca0 payload=0x54e48e57e0af26de topology=0x860c011cfdb9833a
[PipelineLODHash] lod=1 tiles=448 density=0x4b8d9a6dcd2942ad mesh=0x17e89b7087bfe711 payload=0x2389c109eb780db6 topology=0x7eccd4cf560d0630
[PipelineLODHash] lod=2 tiles=320 density=0xdad28a7fa1b9766b mesh=0xf5263c751cc5af4f payload=0xb882e4c989d07b53 topology=0x874e27ae4e73ec39
[PipelineLODHash] lod=3 tiles=208 density=0x6e050028a242875e mesh=0x0b9d3d5662314869 payload=0x6722ab1369ea33b6 topology=0x63c9c29f4568f5e3
[PipelineLODHash] lod=4 tiles=240 density=0xfb11591772a3d18e mesh=0xebf2baee8764591b payload=0xe491d7ac9c0061ad topology=0xd618ac33b95ce494
[PipelineLODHash] lod=5 tiles=144 density=0x2f8b7b7fb1e67258 mesh=0x4cd508cbe97344fd payload=0x2b6e96a6050458c9 topology=0x4ff6d0eda8988573
[PipelineLODHash] lod=6 tiles=96 density=0x0114a34c8b8d6113 mesh=0xb1fec4d01ae1fa44 payload=0x3e50cfd429b8e950 topology=0x08090c96d15c1618
[PipelineLODHash] lod=7 tiles=96 density=0x3836ed8cfce73418 mesh=0x40bc6589c5fc1aac payload=0x677349bcae16790f topology=0x36e3aa53192e6a6b
[PipelineLODHash] lod=8 tiles=306 density=0x144f3c1fd722708b mesh=0xef77b28bf7fd9453 payload=0xe3f47b37fcd61489 topology=0x5a3c73e295494e04
[PipelineExactQueryHash] probes=9 density=0x7b7c50ac24ccadcc unclamped=0x7b7c50ac24ccadcc detail=0xefcba20c0c70c415 collision=0xe604823a249029bf path=direct-Core-queries
@@ -0,0 +1,12 @@
[PipelineFullDetailHash] tiles=960 density=0xace56c8f205238ad mesh=0xa9c603a1248de6b8 payload=0xea55f1f4fcc6a894 topology=0x5ea7bc78a1b678ae
[PipelineWholeViewHash] tiles=2370 density=0xfa232c4422e2e610 mesh=0xce56a238f93d6206 payload=0xcf7b1f5aeaaedf99 topology=0xad24679ddf040575
[PipelineLODHash] lod=0 tiles=512 density=0xcd6ab28cfa504aca mesh=0xf03dc80a669fca31 payload=0x397aded1c3d2d297 topology=0xb4a1dc84fabc1fe3
[PipelineLODHash] lod=1 tiles=448 density=0xce6e713828b2a20a mesh=0x1cf408c25d67d18c payload=0x8a2b5d20571c997e topology=0x51cd985fe8e7d100
[PipelineLODHash] lod=2 tiles=320 density=0x2047609972d09d73 mesh=0xae66aa3b34004b82 payload=0x8f81f605def21b18 topology=0xd9cef4942e0bc09e
[PipelineLODHash] lod=3 tiles=208 density=0x2ed5ccb4d6e39e53 mesh=0x896a64c1f3e2c360 payload=0x79325ad522c83de8 topology=0x49de5799ff8ea38e
[PipelineLODHash] lod=4 tiles=240 density=0x0be8798407724eaf mesh=0x131c303cbbe51434 payload=0x2a90ecf0a2411ca0 topology=0xe3e054a371152e08
[PipelineLODHash] lod=5 tiles=144 density=0xf20897ad272103a9 mesh=0x13d00b6253ae1f72 payload=0x0db3880693a962fa topology=0x462bd87a80f15e89
[PipelineLODHash] lod=6 tiles=96 density=0xc040fcac457d6313 mesh=0x1ed132eeb718fb62 payload=0xcd0214e35577c6e3 topology=0x2c56c69e6fdcfd64
[PipelineLODHash] lod=7 tiles=96 density=0xc2d419446355fdb8 mesh=0x4ea44452574fc84b payload=0xfd9779bedfc9ae0f topology=0x8948546e770c9b72
[PipelineLODHash] lod=8 tiles=306 density=0x62db31696f2da831 mesh=0xd373f9e9481532fe payload=0x540a60526e0e3e46 topology=0xc725cb901e6dc335
[PipelineExactQueryHash] probes=9 density=0xc949c4df2ce6f9d9 unclamped=0xc949c4df2ce6f9d9 detail=0x114c501e2d830d94 collision=0xe6011d3a248d4849 path=direct-Core-queries
+11 -8
View File
@@ -122,11 +122,11 @@ RECIPE_RE = re.compile(
def owner_hash_baseline(recipe: str, style: int) -> tuple[Path, str]:
if recipe == "surface-world" and style == 1:
return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v220.baseline",
"L113-v220-adaptive-spline-rounded-half-pipe")
return (BASELINES / "owner-hash/canonical/owner-hash-surface-world-style1-v222.baseline",
"L114-v222-local-passage-floor-profile")
if recipe == "floating-islands" and style == 2:
return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v220.baseline",
"L113-v220-adaptive-spline-rounded-half-pipe")
return (BASELINES / "owner-hash/canonical/owner-hash-floating-islands-style2-v222.baseline",
"L114-v222-local-passage-floor-profile")
raise VerificationFailure(f"no pinned owner hash baseline for {recipe} style {style}")
@@ -199,7 +199,8 @@ def validate_passage(runner: VerificationRunner, name: str, output: str,
wall_threshold = re.search(r"threshold_m=([-0-9.]+)", line)
floor = re.search(r"floor_amplitude_m=([-0-9.]+)", line)
floor_threshold = re.search(r"floor_threshold_m=([-0-9.]+)", line)
wall_coverage = parse_ratio(line, "coverage")
wall_window_count = parse_ratio(line, "wall_windows")
wall_window_coverage = parse_ratio(line, "wall_window_coverage")
floor_coverage = parse_ratio(line, "floor_coverage")
floor_coverage_pair = re.search(r"floor_coverage=(\d+)/(\d+)", line)
floor_overlap_skips = re.search(r"floor_overlap_skips=(\d+)", line)
@@ -211,15 +212,17 @@ def validate_passage(runner: VerificationRunner, name: str, output: str,
floor_measured = bool(
floor_mode and floor_mode.group(1) in ("measured", "measured_with_overlap")
and floor_coverage is not None and floor_coverage >= 0.75)
wall_measured = bool(wall_window_count is not None and wall_window_count > 0
and wall_window_coverage is not None and wall_window_coverage >= 0.75)
ripple_ok &= bool(
"status=PASS" in line and wall and wall_threshold and floor and floor_threshold
and wall_coverage is not None and floor_coverage is not None
and wall_measured and floor_coverage is not None
and float(wall.group(1)) <= float(wall_threshold.group(1))
and float(floor.group(1)) <= float(floor_threshold.group(1))
and wall_coverage >= 0.75 and (floor_measured or floor_overlap_only))
and (floor_measured or floor_overlap_only))
passed_all &= ripple_ok
detail = (f"profiles={len(rows)} wall/floor amplitudes under their thresholds; "
"wall coverage>=0.75 and floor measured coverage>=0.75 or all probes "
"measured wall windows cover>=0.75 and floor measured coverage>=0.75 or all probes "
"explicitly masked by overlapping tunnel interior air")
if defer:
defer_requirement(runner, f"{name}:wall-floor-ripple-and-coverage", ripple_ok, detail)