#!/usr/bin/env python3 """Exercise the production DP54 default, v3 lens-map provenance/replay and the adaptive retry/budget policy from the CLI. The production default is now adaptive Dormand-Prince 5(4). These checks require that a run without --integrator exports wire code 1 and is physically and bit-for-bit equal to an explicit --integrator dp54 run, so `make test` truly covers the production default rather than only the explicit path. --integrator rk4 stays available for the legacy wire code and for a fixed-step reference convergence check. Small CPU 16x8/32x16 scenes keep the runtime short; physical comparisons use stored lens-map endpoints, not only the rendered PNG. """ import math import os import re import struct import subprocess import sys import tempfile import zlib from pathlib import Path # Keep scratch data inside the pre-approved OpenCode scratch directory instead # of creating directories directly under the system temporary root. TMP_ROOT = Path('/tmp/opencode') TMP_ROOT.mkdir(parents=True, exist_ok=True) BUILD = Path(sys.argv[1] if len(sys.argv) > 1 else 'build/Release').resolve() TESTDIR = Path(sys.argv[2]).resolve() if len(sys.argv) > 2 else BUILD ENV = dict(os.environ, OMP_NUM_THREADS='4') # v3 wire offsets (see src/lens_map.c). The header is deliberately not part of # the payload CRC. VERSION_OFFSET = 8 FRAME_COUNT_OFFSET = 32 PROVENANCE_OFFSET = 40 PROVENANCE_V3_OFFSET = 100 VERTEX_COUNT_OFFSET = 200 TRIANGLE_COUNT_OFFSET = 208 VERTEX_START = 224 VERTEX_SIZE = 108 TRIANGLE_SIZE = 32 ATOL_FIELDS = ('atol_x', 'atol_Pi', 'atol_L', 'rtol', 'min_step', 'max_step', 'max_lookback_time', 'retry_lookback_increment', 'max_total_lookback_time') # Machine-roundoff floor for comparing two adaptive integrations; below this a # difference carries no convergence information. ROUNDOFF_FLOOR = 1e-12 ENDPOINT_ASSERT = 1e-6 def run(binary, *args, ok=True, env=ENV): result = subprocess.run([str(binary), *map(str, args)], env=env, capture_output=True, text=True) if (result.returncode == 0) != ok: raise AssertionError( f'{binary.name} {args}: rc={result.returncode}\n{result.stderr}') return result def image_payload(path): data = path.read_bytes() assert data[:8] == b'\x89PNG\r\n\x1a\n', f'not a PNG: {path}' offset, compressed = 8, bytearray() while offset < len(data): count, kind = struct.unpack_from('>I4s', data, offset) payload = data[offset + 8:offset + 8 + count] if kind == b'IDAT': compressed.extend(payload) offset += count + 12 return bytes(zlib.decompress(compressed)) def map_provenance(path): data = path.read_bytes() assert data[:8] == b'GRLENS\x01\x00' version = struct.unpack_from(' 0.0 and math.isfinite(denom): scaled = 5.0 * (escape / denom) if math.isfinite(scaled) and scaled > 0.0: return min(max(scaled, sys.float_info.min), upper) log_sep = math.log(sep) if sep > 0.0 else -math.inf log_budget = math.log(5.0) + math.log(escape) - max(log_sep, -dark_threshold) if not math.isfinite(log_budget): log_budget = math.log(upper) log_budget = min(log_budget, math.log(upper)) log_budget = max(log_budget, math.log(sys.float_info.min)) return min(max(math.exp(log_budget), sys.float_info.min), upper) with tempfile.TemporaryDirectory(prefix='gr-adaptive-cli-', dir=str(TMP_ROOT)) as directory: tmp = Path(directory) for backend in ('minkowski', 'schwarzschild'): binary = BUILD / f'{backend}_sky' if not binary.exists(): print(f'{backend}: binary absent, skipping', flush=True) continue help_text = run(binary, '--help').stdout for option in ('--integrator', '--ode-rtol', '--ode-atol-x', '--ode-atol-pi', '--ode-atol-l', '--ode-initial-step', '--ode-min-step', '--ode-max-step', '--ode-max-rejections', '--trace-max-steps', '--trace-lookback-time', '--retry-step-increment', '--max-total-steps', '--retry-lookback-increment', '--max-total-lookback-time'): assert option in help_text, (backend, option) ext = 'png' if '.png' in help_text else 'ppm' hdr_available = '--hdr-output' in help_text hdr_args = ['--hdr-output'] if hdr_available else [] common = ['--catalog', 'assets/sky_grid_5deg.csv', '--width', 32, '--height', 16, '--fov-deg', 80, '--exposure', 1e-3, '--coarse-cell-pixels', 8, '--refine-max-level', 0, '--psf-relative-tail', 1e-4] def single(name, *options, ok=True, env=ENV, use_common=common): out = tmp / f'{backend}_{name}.{ext}' result = run(binary, *use_common, '--output', out, *options, ok=ok, env=env) return out, result # 1) The production default (no --integrator) must be DP54 and must # match an explicit --integrator dp54 run physically and in its # PNG/HDR output. dflt_map = tmp / f'{backend}_dflt.grlens' dflt_out, dflt_run = single('dflt', *hdr_args, '--verbose', '--lens-map-output', dflt_map) version, frame_count, dflt_prov = map_provenance(dflt_map) assert version == 3 and frame_count == 1 assert dflt_prov['integrator'] == 1, dflt_prov assert dflt_prov['min_step'] == 1e-12, dflt_prov assert dflt_prov['max_step'] == {'minkowski': 16.0, 'schwarzschild': 8.0}[backend], dflt_prov assert dflt_prov['min_step'] <= dflt_prov['coordinate_time_step'] \ <= dflt_prov['max_step'] assert dflt_prov['atol_x'] > 0 and dflt_prov['rtol'] > 0 assert dflt_prov['max_lookback_time'] > 0 assert dflt_prov['max_consecutive_rejections'] > 0 expl_map = tmp / f'{backend}_expl.grlens' expl_out, _ = single('expl', *hdr_args, '--integrator', 'dp54', '--lens-map-output', expl_map) assert dflt_map.read_bytes() == expl_map.read_bytes(), \ 'default map differs from explicit dp54' assert image_payload(dflt_out) == image_payload(expl_out) if hdr_available: dflt_hdr = dflt_out.with_name(dflt_out.stem + '_HDR.fits') expl_hdr = expl_out.with_name(expl_out.stem + '_HDR.fits') assert dflt_hdr.read_bytes() == expl_hdr.read_bytes() dflt_vertices, _ = map_vertices(dflt_map) # 2) The legacy RK4 wire code must be 0 and its cost counters must be # real (nonzero RHS evaluations), not legacy zeros. rk4_map = tmp / f'{backend}_rk4.grlens' single('rk4', '--integrator', 'rk4', '--lens-map-output', rk4_map) _, _, rk4_prov = map_provenance(rk4_map) assert rk4_prov['integrator'] == 0, rk4_prov rk4_vertices, _ = map_vertices(rk4_map) assert sum_rhs(rk4_vertices) > 0, 'RK4 RHS cost counters are not real' # 3) Same-camera tolerance convergence with three levels. Outcome, # reason and end must not change between levels, and the deviation # from the tightest reference must shrink as the tolerance tightens. # These are local ODE tolerances, not a global sky-error bound. tol_maps = {} for tol in ('1e-7', '1e-9', '1e-12'): m = tmp / f'{backend}_tol_{tol}.grlens' single(f'tol_{tol}', '--integrator', 'dp54', '--ode-rtol', tol, '--ode-atol-x', tol, '--ode-atol-pi', tol, '--ode-atol-l', tol, '--lens-map-output', m) tol_maps[tol] = map_vertices(m)[0] mism7, err7 = endpoint_deviation(tol_maps['1e-7'], tol_maps['1e-12']) mism9, err9 = endpoint_deviation(tol_maps['1e-9'], tol_maps['1e-12']) assert mism7 == 0 and mism9 == 0, \ f'{backend}: tolerance levels disagree on outcome/end' assert err9 < ENDPOINT_ASSERT, (backend, 'default vs tight', err9) assert err7 + ROUNDOFF_FLOOR >= err9, \ f'{backend}: tightening tolerance did not reduce error ' \ f'({err7} -> {err9})' print(f'{backend}: default==dp54, tol errors 1e-7={err7:.3g} ' f'1e-9={err9:.3g}', flush=True) # 4) Render-only replay of the default map must be bit-identical and # its stored statistics must equal the live trace cost. replay_out = tmp / f'{backend}_replay.{ext}' replay_run = run(binary, *common, *hdr_args, '--lens-map-input', dflt_map, '--verbose', '--output', replay_out) assert image_payload(replay_out) == image_payload(dflt_out) if hdr_available: replay_hdr = replay_out.with_name(replay_out.stem + '_HDR.fits') assert dflt_out.with_name(dflt_out.stem + '_HDR.fits').read_bytes() \ == replay_hdr.read_bytes() live_cost = trace_cost(dflt_run.stdout, 'Frame 0') replay_cost = trace_cost(replay_run.stdout, 'Imported map') assert live_cost is not None and replay_cost is not None assert live_cost == replay_cost, (live_cost, replay_cost) # 5) Explicit zeros in the retry policy must survive, not be filled in # by the derived defaults. zero_step_map = tmp / f'{backend}_zero_step.grlens' single('zero_step', '--integrator', 'dp54', '--retry-step-increment', '0', '--lens-map-output', zero_step_map) _, _, zero_step = map_provenance(zero_step_map) assert zero_step['retry_step_increment'] == 0, zero_step assert zero_step['max_total_steps'] > 0, zero_step zero_time_map = tmp / f'{backend}_zero_time.grlens' single('zero_time', '--integrator', 'dp54', '--retry-lookback-increment', '0', '--lens-map-output', zero_time_map) _, _, zero_time = map_provenance(zero_time_map) assert zero_time['retry_lookback_increment'] == 0, zero_time assert zero_time['max_total_lookback_time'] >= \ zero_time['max_lookback_time'], zero_time # 6) RK4 rejects every DP-only option rather than silently ignoring it. rk4_errors = [ (['--integrator', 'rk4', '--ode-rtol', 1e-9], 'applies only'), (['--integrator', 'rk4', '--ode-min-step', 1e-9], 'applies only'), (['--integrator', 'rk4', '--ode-max-step', 1e-3], 'applies only'), (['--integrator', 'rk4', '--ode-max-rejections', 4], 'applies only'), (['--integrator', 'rk4', '--trace-lookback-time', 1], 'applies only'), (['--integrator', 'rk4', '--retry-lookback-increment', 1], 'applies only'), (['--integrator', 'rk4', '--max-total-lookback-time', 2], 'applies only'), ] # DP cross-field validation and malformed values fail immediately. invalid = [ (['--integrator', 'bogus'], None), (['--integrator'], None), (['--integrator', 'dp54', '--ode-rtol', 0], None), (['--integrator', 'dp54', '--ode-rtol', -1], None), (['--integrator', 'dp54', '--ode-atol-x', 'nan'], None), (['--integrator', 'dp54', '--ode-max-rejections', 0], None), (['--integrator', 'dp54', '--trace-max-steps', 0], None), (['--integrator', 'dp54', '--ode-initial-step', 5, '--ode-max-step', 1], 'min <= initial <= max'), (['--integrator', 'dp54', '--ode-min-step', 4, '--ode-initial-step', 2], 'min <= initial <= max'), (['--integrator', 'dp54', '--trace-lookback-time', 0], None), (['--integrator', 'dp54', '--retry-step-increment', -1], None), ] for options, message in rk4_errors + invalid: missing = tmp / 'adaptive_should_not_exist.csv' result = run(binary, '--catalog', missing, *options, ok=False) if message: assert message in result.stderr, (options, result.stderr) assert not missing.exists(), result.stderr # 7) Replay must consume the stored policy: explicit tracing options # cannot be layered on top of --lens-map-input. conflict = run(binary, *common, '--lens-map-input', dflt_map, '--integrator', 'rk4', '--output', tmp / 'conflict.png', ok=False) assert 'cannot be combined with --lens-map-input' in conflict.stderr, \ conflict.stderr conflict2 = run(binary, *common, '--lens-map-input', dflt_map, '--trace-max-steps', 100, '--output', tmp / 'conflict2.png', ok=False) assert 'cannot be combined with --lens-map-input' in conflict2.stderr, \ conflict2.stderr conflict3 = run(binary, *common, '--lens-map-input', dflt_map, '--integrator', 'dp54', '--ode-rtol', 1e-9, '--output', tmp / 'conflict3.png', ok=False) assert 'cannot be combined with --lens-map-input' in conflict3.stderr, \ conflict3.stderr # 8) Single vs movie: the same physical observer event must agree, and # threads/slabs must not change the stored adaptive endpoints. track = tmp / f'{backend}.csv' observer_test = TESTDIR / f'test_observer_{backend}' if observer_test.exists(): run(observer_test, track) moving_single = tmp / f'{backend}_moving.grlens' single('moving', '--observer-position', 3, -4, 5, '--observer-velocity', 0.2, -0.1, 0.3, '--look-ra-deg', 37, '--look-dec-deg', -23, '--camera-roll-deg', 19, '--lens-map-output', moving_single) movie_map = tmp / f'{backend}_movie.grlens' run(binary, *common, '--observer-track', track, '--frames-dir', tmp, '--frames-prefix', f'{backend}_movie', '--duration', 0, '--fps', 1, '--lens-map-output', movie_map) single_v, _ = map_vertices(moving_single) movie_v, _ = map_vertices(movie_map) mism, dev = endpoint_deviation(single_v, movie_v) assert mism == 0 and dev < ENDPOINT_ASSERT, (mism, dev) thread_maps = [] for threads in (1, 2, 4): m = tmp / f'{backend}_movie_{threads}thr.grlens' run(binary, *common, '--observer-track', track, '--frames-dir', tmp, '--frames-prefix', f'{backend}_m{threads}', '--duration', 0, '--fps', 1, '--lens-map-output', m, env=dict(ENV, OMP_NUM_THREADS=str(threads))) thread_maps.append(m) reference = thread_maps[0].read_bytes() for m in thread_maps[1:]: assert m.read_bytes() == reference, \ f'{backend}: DP movie map changed across threads' slab_maps = [] for slab in (2, 8, 64): m = tmp / f'{backend}_slab_{slab}.grlens' run(binary, *common, '--observer-track', track, '--frames-dir', tmp, '--frames-prefix', f'{backend}_s{slab}', '--slab-duration', slab, '--duration', 0, '--fps', 1, '--lens-map-output', m) slab_maps.append(m) base_v, _ = map_vertices(slab_maps[0]) for m in slab_maps[1:]: other_v, _ = map_vertices(m) mism, dev = endpoint_deviation(base_v, other_v) assert mism == 0 and dev < ENDPOINT_ASSERT, (mism, dev) print(f'{backend}: DP movie threads/slabs agree', flush=True) # 9) Budget: a tiny initial coordinate-time budget leaves UNRESOLVED # rays; with no room to grow the publication gate refuses the frame, # while retry increments that can grow resolve it. if backend == 'schwarzschild': refused = tmp / f'{backend}_refused.{ext}' small = ['--integrator', 'dp54', '--trace-lookback-time', 1e-6, '--retry-lookback-increment', 0, '--max-total-lookback-time', 1e-6] result = run(binary, *common, '--output', refused, *small, ok=False) assert 'Incomplete render refused' in result.stderr, result.stderr assert not refused.exists() allow = tmp / f'{backend}_allow.{ext}' run(binary, *common, '--output', allow, '--allow-incomplete', *small) assert allow.exists() direct = tmp / f'{backend}_direct.{ext}' direct_result = subprocess.run( [str(binary), *map(str, common), '--output', str(direct), '--integrator', 'dp54', '--trace-lookback-time', '4000'], env=ENV, capture_output=True, text=True) if direct_result.returncode == 0: retried = tmp / f'{backend}_retried.{ext}' run(binary, *common, '--output', retried, '--integrator', 'dp54', '--trace-lookback-time', 1e-6, '--retry-lookback-increment', 25, '--max-total-lookback-time', 4000) assert image_payload(retried) print('schwarzschild: retry budget resolves previously ' 'unresolved rays', flush=True) else: print('schwarzschild: direct budget scene still unresolved; ' 'retry-resolution case skipped', flush=True) # 10) Fixed-step reference convergence on a small scene. The # accepted budget is explicit and large so the finer step does # not silently shorten the traced history. Both fixed-step # levels and the DP54 default must agree below ENDPOINT_ASSERT. # If the reference itself does not converge this must FAIL and # be reported, never loosened into a false zero. ref_common = ['--catalog', 'assets/sky_grid_5deg.csv', '--width', 16, '--height', 8, '--fov-deg', 80, '--exposure', 1e-3, '--coarse-cell-pixels', 8, '--refine-max-level', 0, '--psf-relative-tail', 1e-4] def ref_map(tag, *options): m = tmp / f'{backend}_ref_{tag}.grlens' run(binary, *ref_common, '--output', tmp / f'{backend}_ref_{tag}.{ext}', '--lens-map-output', m, *options) return map_vertices(m)[0] rk4_04 = ref_map('rk4_04', '--integrator', 'rk4', '--ode-initial-step', 0.04, '--trace-max-steps', '262144') rk4_02 = ref_map('rk4_02', '--integrator', 'rk4', '--ode-initial-step', 0.02, '--trace-max-steps', '262144') dp_tight = ref_map('dp_tight', '--ode-rtol', '1e-12', '--ode-atol-x', '1e-12', '--ode-atol-pi', '1e-12', '--ode-atol-l', '1e-12') assert sum(1 for v in rk4_02 if v[10] == 0) > 0, \ 'reference scene has no escaped ray' mism, ref_dev = endpoint_deviation(rk4_04, rk4_02) assert mism == 0, 'RK4 reference levels disagree on outcome/end' assert ref_dev < ENDPOINT_ASSERT, \ f'RK4 reference not converged: {ref_dev}; report to parent' mism, dp_dev = endpoint_deviation(dp_tight, rk4_02) assert mism == 0, 'DP54 default disagrees with RK4 reference' assert dp_dev < ENDPOINT_ASSERT, (dp_dev,) print(f'schwarzschild: RK4 ref convergence {ref_dev:.3g}, ' f'DP default vs fine RK4 {dp_dev:.3g}', flush=True) print(f'{backend}: adaptive CLI checks passed', flush=True) # Alcubierre production policy: sub- and super-luminal velocities share one # finite resource allowance B = 5*escape / max(|1-|v_s||, exp(-D)); the DP54 # default must validate, actually integrate the warp feature, and reach both # the shared DARK terminal and escapes. All images are tiny 8x4/16x8. alc = BUILD / 'alcubierre_sky' if not alc.exists(): print('alcubierre: binary absent, skipping', flush=True) else: alc_help = run(alc, '--help').stdout ext = 'png' if '.png' in alc_help else 'ppm' assert '|v_s| < 1' not in alc_help, 'help still claims |v_s| < 1' escape1 = 1.0 + 20.0 / 1.0 # R = sigma = 1 def alc_camera(vs, ra_deg, dec_deg=0.0): return ['--observer-position', '0', '0', '0', '--observer-velocity', repr(vs), '0', '0', '--look-ra-deg', repr(ra_deg), '--look-dec-deg', repr(dec_deg)] def alc_map_prov(tag, vs, D=8.0, radius=1.0, extra=(), allow=True, width=8, height=4, cell=4, camera=None, catalog=True): m = tmp / f'alc_{tag}.grlens' args = ['--alcubierre-vs', repr(vs), '--alcubierre-radius', repr(radius), '--alcubierre-sigma', '1', '--dark-threshold', repr(D), '--width', str(width), '--height', str(height), '--fov-deg', 80, '--exposure', '1e-3', '--coarse-cell-pixels', str(cell), '--refine-max-level', 0, '--psf-relative-tail', 1e-4] if catalog: args += ['--catalog', 'assets/sky_grid_5deg.csv'] if camera is not None: args += camera if allow: args.append('--allow-incomplete') args += ['--output', str(tmp / f'alc_{tag}.{ext}'), '--lens-map-output', str(m), *extra] run(alc, *args) return map_provenance(m)[2], m # 1) Ordinary sub-luminal separation: B is exactly 5*escape/sep and is # independent of the step count and of the initial step. p_sub, _ = alc_map_prov('sub', 0.3, camera=alc_camera(0.3, 0.0)) assert p_sub['integrator'] == 1, p_sub assert math.isclose(p_sub['max_lookback_time'], alcubierre_budget(escape1, 0.3, 8.0), rel_tol=1e-12) assert p_sub['min_step'] <= p_sub['coordinate_time_step'] \ <= p_sub['max_step'] p_steps, _ = alc_map_prov('sub_steps', 0.3, extra=('--trace-max-steps', '8'), camera=alc_camera(0.3, 0.0)) assert p_steps['initial_max_steps'] == 8 assert math.isclose(p_steps['max_lookback_time'], alcubierre_budget(escape1, 0.3, 8.0), rel_tol=1e-12) p_step, _ = alc_map_prov('sub_step', 0.3, extra=('--ode-initial-step', '0.02'), camera=alc_camera(0.3, 0.0)) assert abs(p_step['coordinate_time_step'] - 0.02) < 1e-15 assert math.isclose(p_step['max_lookback_time'], alcubierre_budget(escape1, 0.3, 8.0), rel_tol=1e-12) # 2) Near-luminal (vs = 1, separation 0): the exp(-D) floor makes the # allowance finite, and it grows with the dark threshold D. p8, _ = alc_map_prov('near8', 1.0, D=8.0, camera=alc_camera(1.0, 0.0)) p12, _ = alc_map_prov('near12', 1.0, D=12.0, camera=alc_camera(1.0, 0.0)) assert math.isclose(p8['max_lookback_time'], alcubierre_budget(escape1, 1.0, 8.0), rel_tol=1e-12) assert math.isclose(p12['max_lookback_time'], alcubierre_budget(escape1, 1.0, 12.0), rel_tol=1e-12) assert p12['max_lookback_time'] > p8['max_lookback_time'] # 3) Both sides of the threshold-derived vcut and exactly luminal # values use either separation or the finite floor; a tiny film traces # and resolves without INCOMPLETE outcomes. vcut = 1.0 - math.exp(-8.0) for vs in (0.999, math.nextafter(vcut, 0.0), math.nextafter(vcut, 1.0), 0.9999, math.nextafter(1.0, 0.0), math.nextafter(1.0, 2.0)): pv, mv = alc_map_prov(f'vcut_{vs!r}', vs, camera=alc_camera(vs, 0.0)) assert math.isclose(pv['max_lookback_time'], alcubierre_budget(escape1, vs, 8.0), rel_tol=1e-12), (vs, pv['max_lookback_time']) vv, _ = map_vertices(mv) assert 3 not in {v[10] for v in vv}, (vs, 'INCOMPLETE ray') assert sum_rhs(vv) > 0, vs # 4) The default camera (0,0,15 for R=5) must work with a superluminal # bubble: the generic radius-15 camera lies inside escape radius 25. pd, md = alc_map_prov('defaultcam', 2.0, radius=5.0) dv, _ = map_vertices(md) assert 3 not in {v[10] for v in dv}, 'default camera left INCOMPLETE rays' assert sum_rhs(dv) > 0 # 5) Real small images at the critical velocities: the direction along # the bubble motion is the DARK direction (Pi_x = sign(vs)); the # central vertex must be DARK and some edge ray must escape. The # 16x8 film with a 4-pixel coarse cell places a vertex exactly at the # image center. for vs in (1.0, -1.0, 2.0, -2.0): ra = 0.0 if vs < 0.0 else 180.0 pimg, mimg = alc_map_prov(f'img_{vs!r}', vs, width=16, height=8, cell=4, camera=alc_camera(vs, ra)) verts, _ = map_vertices(mimg) outcomes = {v[10] for v in verts} assert 3 not in outcomes, (vs, 'INCOMPLETE outcome', outcomes) assert 0 in outcomes and 1 in outcomes, (vs, outcomes) assert sum_rhs(verts) > 0, vs central = min(verts, key=lambda v: (v[0] - 8.0) ** 2 + (v[1] - 4.0) ** 2) assert central[10] == 1, \ (vs, 'central vertex is not DARK', central[0], central[1], central[10]) # 6) Extreme tiny-budget quota path: an explicit 4-step, 1-time # allowance from an inside camera must stop as UNRESOLVED, never as # a fabricated escape from a trace that took no steps. extreme = (alc_camera(0.99999999, 0.0) + ['--alcubierre-vs', '0.99999999', '--alcubierre-radius', '1', '--alcubierre-sigma', '1', '--catalog', 'assets/sky_grid_5deg.csv', '--width', '8', '--height', '4', '--fov-deg', '80', '--exposure', '1e-3', '--coarse-cell-pixels', '4', '--refine-max-level', 0, '--psf-relative-tail', '1e-4']) ext_map = tmp / 'alc_extreme.grlens' run(alc, *extreme, '--integrator', 'dp54', '--trace-lookback-time', '1', '--trace-max-steps', '4', '--max-total-steps', '4', '--retry-step-increment', '0', '--max-total-lookback-time', '1', '--retry-lookback-increment', '0', '--allow-incomplete', '--output', tmp / f'alc_extreme.{ext}', '--lens-map-output', ext_map) _, _, ext_prov = map_provenance(ext_map) assert ext_prov['integrator'] == 1 assert abs(ext_prov['max_lookback_time'] - 1.0) < 1e-15, ext_prov assert ext_prov['initial_max_steps'] == 4, ext_prov ext_vertices, _ = map_vertices(ext_map) assert all(v[10] == 2 for v in ext_vertices), \ ('a 1-time/4-step trace fabricated a non-UNRESOLVED outcome', [v[10] for v in ext_vertices]) # 7) Large dark threshold (D=1000) with vs=1: exp(-1000) underflows to # 0 and the separation is exactly 0, so the log fallback saturates # the default allowance to DBL_MAX/4. A 4-step/4-total cap with # retry disabled keeps the trace short while the provenance records # the non-masked saturated default. An explicit --trace-lookback # overrides it without masking the independent step allowance. psat, _ = alc_map_prov('sat1000', 1.0, D=1000.0, extra=('--trace-max-steps', '4', '--max-total-steps', '4', '--retry-step-increment', '0'), camera=alc_camera(1.0, 0.0)) assert math.isclose(psat['max_lookback_time'], sys.float_info.max / 4.0, rel_tol=1e-12), \ psat['max_lookback_time'] assert psat['initial_max_steps'] == 4 psat_ov, _ = alc_map_prov('sat1000_ov', 1.0, D=1000.0, extra=('--trace-lookback-time', '1', '--trace-max-steps', '4', '--max-total-steps', '4', '--retry-step-increment', '0'), camera=alc_camera(1.0, 0.0)) assert psat_ov['max_lookback_time'] == 1.0, psat_ov assert psat_ov['initial_max_steps'] == 4, psat_ov # Explicit time override must not mask the (default) step allowance. pind, _ = alc_map_prov('indep', 1.0, D=8.0, extra=('--trace-lookback-time', '1'), camera=alc_camera(1.0, 0.0)) assert pind['max_lookback_time'] == 1.0, pind assert pind['initial_max_steps'] > 1, pind # 8) RK4 guard: a super-luminal default (vs=2, small estimate) is no # longer rejected; the guard triggers only when the *derived default* # estimate exceeds the cap (D=12, vs=1), and an explicit # --trace-max-steps is a user allowance that bypasses it. run(alc, '--integrator', 'rk4', '--alcubierre-vs', '2', '--alcubierre-radius', '1', '--alcubierre-sigma', '1', '--catalog', 'assets/sky_grid_5deg.csv', '--width', '8', '--height', '4', '--fov-deg', '80', '--exposure', '1e-3', '--coarse-cell-pixels', '4', '--refine-max-level', 0, '--psf-relative-tail', '1e-4', '--allow-incomplete', '--output', tmp / f'alc_rk4_v2.{ext}') rk4_guard = run( alc, '--integrator', 'rk4', '--alcubierre-vs', '1', '--alcubierre-radius', '1', '--alcubierre-sigma', '1', '--dark-threshold', '12', '--catalog', 'assets/sky_grid_5deg.csv', '--width', '8', '--height', '4', '--fov-deg', '80', '--exposure', '1e-3', '--coarse-cell-pixels', '4', '--refine-max-level', 0, '--psf-relative-tail', '1e-4', '--output', tmp / f'alc_rk4_guard.{ext}', ok=False) assert rk4_guard.returncode == 2, rk4_guard.stderr assert 'cap' in rk4_guard.stderr, rk4_guard.stderr run(alc, '--integrator', 'rk4', '--alcubierre-vs', '1', '--alcubierre-radius', '1', '--alcubierre-sigma', '1', '--dark-threshold', '12', '--trace-max-steps', '4', '--catalog', 'assets/sky_grid_5deg.csv', '--width', '8', '--height', '4', '--fov-deg', '80', '--exposure', '1e-3', '--coarse-cell-pixels', '4', '--refine-max-level', 0, '--psf-relative-tail', '1e-4', '--allow-incomplete', '--output', tmp / f'alc_rk4_expl.{ext}') # 9) Impossible parameters stay clearly rejected. for bad in (['--alcubierre-vs', 'nan'], ['--alcubierre-vs', 'inf'], ['--alcubierre-radius', '0'], ['--alcubierre-sigma', '0']): bad_out = tmp / f'alc_bad.{ext}' rejected = run(alc, *bad, '--catalog', 'assets/sky_grid_5deg.csv', '--width', '8', '--height', '4', '--fov-deg', '80', '--exposure', '1e-3', '--coarse-cell-pixels', '4', '--refine-max-level', 0, '--psf-relative-tail', '1e-4', '--output', bad_out, ok=False) assert rejected.returncode != 0, rejected.stderr assert not bad_out.exists() print('alcubierre: budget/provenance, vcut scans, vcut images with ' 'central DARK, default camera, large-D saturation, explicit ' 'overrides and RK4 guard all passed', flush=True)