Add error-controlled DP5(4) integration and trusted first-crossing localization, including non-monotonic energy thresholds and representable-time stepping. Preserve adaptive state and independent step/time retry grants across RayPool, refinement and movie scheduling. Expose numerical controls, record actual persistent-sample costs, and add v3 lens-map provenance with legacy v2 RK4 import. Use DP54 by default and select an 8M Schwarzschild maximum step from bounded scans and a two-run 4K comparison. Retain the conservative minimum-step guard and document critical-ray and backend capability limits. Archive self-contained benchmark inputs and raw output; keep fixed RK4 HDR references explicit. Validation: make -B -j4 BUILD_TYPE=Debug test passed; explicit RK4 HDR references have zero differences. Bounded convergence checks, benchmark reproduction, Release build and focused reviews passed. No numerical-relativity backend is added.
68 lines
2.7 KiB
Python
Executable File
68 lines
2.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Postprocess existing 4K/limited maps only; never invokes a renderer.
|
|
|
|
Usage:
|
|
summarize_4k.py [OUT_DIR]
|
|
|
|
OUT_DIR defaults to <repo>/local/adaptive_bounds_4k and must contain
|
|
``r100_4k_hmax2.grlens``, ``r100_4k_hmax8.grlens`` and ``attempts.json``.
|
|
Writes summary.json in OUT_DIR.
|
|
|
|
Cost scope note: accepted/rejected/RHS sums cover the final persistent map
|
|
vertices only. Nonpersistent discarded refinement probes are not stored in the
|
|
v3 map, so these sums are not full-render executed RHS totals.
|
|
"""
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
import sys
|
|
|
|
from mesh_maps import load, compare
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
OUT = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else \
|
|
ROOT / 'local/adaptive_bounds_4k'
|
|
|
|
|
|
def main():
|
|
summaries = {}
|
|
meshes = {}
|
|
for upper in (2, 8):
|
|
name = f'r100_4k_hmax{upper}'
|
|
summaries[name], meshes[upper] = load(OUT / (name + '.grlens'))
|
|
text = (OUT / (name + '.log')).read_text()
|
|
initial = int(re.search(r'tracing (\d+) initial rays', text).group(1))
|
|
generations = [int(n) for n in re.findall(
|
|
r'refinement generation \d+ tracing (\d+) samples', text)]
|
|
summaries[name]['requested_samples_including_nonpersistent_probes'] = \
|
|
initial + sum(generations)
|
|
summaries[name]['initial_samples'] = initial
|
|
summaries[name]['refinement_samples_per_generation'] = generations
|
|
summaries[name]['trace_wall_seconds'] = sum(
|
|
float(x) for x in re.findall(
|
|
r'(?:initial ray trace|adaptive ray-trace refinement) '
|
|
r'finished in ([\d.]+) s', text))
|
|
ledger = OUT / 'attempts.json'
|
|
if ledger.exists():
|
|
for entry in json.loads(ledger.read_text()):
|
|
if entry.get('state') == 'completed':
|
|
summaries[f'r100_4k_hmax{entry["upper"]}']['wall_seconds'] = \
|
|
entry['wall_seconds']
|
|
summaries['comparison'] = compare(meshes[2], meshes[8])
|
|
a, b = (summaries[f'r100_4k_hmax{upper}'] for upper in (2, 8))
|
|
summaries['relative_reduction'] = {
|
|
key: 1 - b[key] / a[key]
|
|
for key in ('accepted', 'rhs', 'wall_seconds', 'trace_wall_seconds')}
|
|
summaries['comparison']['triangle_payload_identical'] = \
|
|
a['triangle_sha256'] == b['triangle_sha256']
|
|
summaries['cost_scope'] = (
|
|
'accepted/rejected/RHS sums cover final persistent vertices only; '
|
|
'nonpersistent discarded refinement probes are not in the v3 map. '
|
|
'Do not interpret them as full-render executed RHS totals.')
|
|
(OUT / 'summary.json').write_text(json.dumps(summaries, indent=2) + '\n')
|
|
print(json.dumps(summaries, indent=2))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|