#!/usr/bin/env python3 """Bounded 320x180 adaptive-mesh candidates (8 cases; no 4K, no references). Usage: run_mesh.py [OUT_DIR] OUT_DIR defaults to /local/adaptive_bounds_mesh. The renderer binary is expected to already exist at build/Release/schwarzschild_sky; build it with (make command is also in README.md): make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend No survey catalog is used: the script writes a one-point synthetic dim catalog with the required column header (longitude_deg,latitude_deg,temperature_K, amplitude) and a 1e-30 amplitude star. No external CSV is read. """ import json import os from pathlib import Path import shlex import subprocess import sys import time from mesh_maps import load, compare # tracked sibling module (no local/ import) ROOT = Path(__file__).resolve().parents[2] OUT = Path(sys.argv[1]).resolve() if len(sys.argv) > 1 else \ ROOT / 'local/adaptive_bounds_mesh' BIN = ROOT / 'build/Release/schwarzschild_sky' BUILD_CMD = 'make -j4 BUILD_TYPE=Release SPACETIME=schwarzschild backend' ENV = dict(os.environ, OMP_NUM_THREADS='8', OMP_DYNAMIC='FALSE') def scene_args(scene): if scene == 'r100': return ['--observer-radius', '100', '--look-ra-deg', '262.5', '--look-dec-deg', '-30', '--fov-deg', '45', '--refine-jacobian-min', '.2'] return ['--observer-position', '2.1', '0', '0', '--observer-velocity', '0', '0', '0', '--look-ra-deg', '0', '--look-dec-deg', '0', '--fov-deg', '90'] def main(): if not BIN.exists(): raise SystemExit(f'missing {BIN}; build it first:\n {BUILD_CMD}') OUT.mkdir(parents=True, exist_ok=True) catalog = OUT / 'single_dim_star.csv' catalog.write_text('longitude_deg,latitude_deg,temperature_K,amplitude\n' '262.5,-30,6000,1e-30\n') results = {} for scene in ('r100', 'r2p1'): meshes = {} for upper in (.5, 2, 8, 32): name = f'{scene}_hmax{upper:g}' cmd = [str(BIN), '--integrator', 'dp54', '--width', '320', '--height', '180', '--coarse-cell-pixels', '8', '--refine-max-level', '3', '--catalog', str(catalog), '--exposure', '1', '--psf-min-y', '1e-20', '--psf-relative-tail', '1e-4', '--ode-min-step', '1e-12', '--ode-max-step', str(upper), '--verbose', '--lens-map-output', str(OUT / (name + '.grlens')), '--output', str(OUT / (name + '.png')), *scene_args(scene)] start = time.perf_counter() with (OUT / (name + '.log')).open('w') as log: log.write('OMP_NUM_THREADS=8 OMP_DYNAMIC=FALSE ' + shlex.join(cmd) + '\n') log.flush() subprocess.run(cmd, cwd=ROOT, env=ENV, stdout=log, stderr=subprocess.STDOUT, check=True, timeout=180) info, meshes[upper] = load(OUT / (name + '.grlens')) info['wall_seconds'] = time.perf_counter() - start results[name] = info print(name, json.dumps(info), flush=True) for upper in (.5, 8, 32): comparison = compare(meshes[2], meshes[upper]) results[f'{scene}_2_vs_{upper:g}'] = comparison print(f'{scene} 2 vs {upper:g}', json.dumps(comparison), flush=True) (OUT / 'summary.json').write_text(json.dumps(results, indent=2) + '\n') if __name__ == '__main__': main()