#include "frame.h" #include "lens_map.h" #include "mesh_overlay.h" #include "optics.h" #include #include #include #include #include #include /* Self-contained legacy v2 lens-map fixture writer. The production writer now * emits v3, so this serializes a real little-endian v2 map (v2 provenance, no * per-vertex cost counters) from a live mesh to keep the import path covered by * genuine bytes instead of a hand-maintained golden blob. */ static uint32_t v2_crc32(uint32_t crc, const void *data, size_t size) { const unsigned char *bytes = data; for (size_t i = 0; i < size; ++i) { crc ^= bytes[i]; for (int bit = 0; bit < 8; ++bit) crc = (crc >> 1) ^ (0xedb88320u & (uint32_t)-(int)(crc & 1)); } return crc; } static int v2_fwrite_u32(FILE *f, uint32_t v) { unsigned char b[4] = {(unsigned char)v, (unsigned char)(v >> 8), (unsigned char)(v >> 16), (unsigned char)(v >> 24)}; return fwrite(b, 1, sizeof b, f) == sizeof b ? 0 : -1; } static int v2_fwrite_u64(FILE *f, uint64_t v) { unsigned char b[8]; for (int i = 0; i < 8; ++i) b[i] = (unsigned char)(v >> (8 * i)); return fwrite(b, 1, sizeof b, f) == sizeof b ? 0 : -1; } static int v2_fwrite_double(FILE *f, double v) { uint64_t bits; memcpy(&bits, &v, sizeof bits); return v2_fwrite_u64(f, bits); } static int write_v2_lens_map(const char *path, int width, int height, double fov, const LensMapProvenance *p, const LensMapFrame *frame) { static const unsigned char magic[8] = {'G', 'R', 'L', 'E', 'N', 'S', 1, 0}; FILE *f = fopen(path, "wb"); if (f == NULL) return -1; int failed = fwrite(magic, 1, sizeof magic, f) != sizeof magic || v2_fwrite_u32(f, 2) || v2_fwrite_u32(f, 0x01020304u) || v2_fwrite_u32(f, (uint32_t)width) || v2_fwrite_u32(f, (uint32_t)height) || v2_fwrite_double(f, fov) || v2_fwrite_u64(f, 1) || v2_fwrite_u32(f, p->threshold_kind) || v2_fwrite_u32(f, p->threshold_policy_version) || v2_fwrite_double(f, p->threshold_value) || v2_fwrite_u32(f, p->retry_step_increment) || v2_fwrite_u32(f, p->max_total_steps) || v2_fwrite_u32(f, p->max_level) || v2_fwrite_u32(f, p->integrator) || v2_fwrite_double(f, p->min_edge_pixels) || v2_fwrite_double(f, p->min_area_pixels2) || v2_fwrite_double(f, p->coordinate_time_step) || v2_fwrite_u32(f, p->initial_max_steps); const FrameLensMesh *m = &frame->mesh; failed = failed || v2_fwrite_u64(f, frame->frame_id) || v2_fwrite_double(f, frame->coordinate_time) || v2_fwrite_double(f, frame->proper_time) || v2_fwrite_u64(f, (uint64_t)m->vertex_count) || v2_fwrite_u64(f, (uint64_t)m->triangle_count) || v2_fwrite_u64(f, (uint64_t)m->retry_requests); /* The payload CRC covers vertices+triangles only; the header stays * deliberately independent, exactly as in the production writers. */ uint32_t crc = UINT32_MAX; for (size_t i = 0; i < m->vertex_count; ++i) { const LensVertex *v = &m->vertices[i]; const double vals[9] = {v->image_x, v->image_y, v->camera_direction[0], v->camera_direction[1], v->camera_direction[2], v->n_infinity[0], v->n_infinity[1], v->n_infinity[2], v->log_frequency_ratio}; const uint32_t tail[3] = {(uint32_t)v->end_id, (uint32_t)v->outcome, (uint32_t)v->reason}; unsigned char b[84]; size_t off = 0; for (int k = 0; k < 9; ++k) { uint64_t bits; memcpy(&bits, &vals[k], sizeof bits); for (int q = 0; q < 8; ++q) b[off++] = (unsigned char)(bits >> (8 * q)); } for (int k = 0; k < 3; ++k) { b[off++] = (unsigned char)tail[k]; b[off++] = (unsigned char)(tail[k] >> 8); b[off++] = (unsigned char)(tail[k] >> 16); b[off++] = (unsigned char)(tail[k] >> 24); } if (fwrite(b, 1, sizeof b, f) != sizeof b) failed = 1; crc = v2_crc32(crc, b, sizeof b); } for (size_t i = 0; i < m->triangle_count; ++i) { unsigned char b[32]; size_t off = 0; for (int j = 0; j < 3; ++j) { const uint64_t idx = (uint64_t)m->triangles[i].vertex[j]; for (int q = 0; q < 8; ++q) b[off++] = (unsigned char)(idx >> (8 * q)); } const uint32_t tail[2] = {m->triangles[i].level, (uint32_t)m->triangles[i].approx_black}; for (int k = 0; k < 2; ++k) { b[off++] = (unsigned char)tail[k]; b[off++] = (unsigned char)(tail[k] >> 8); b[off++] = (unsigned char)(tail[k] >> 16); b[off++] = (unsigned char)(tail[k] >> 24); } if (fwrite(b, 1, sizeof b, f) != sizeof b) failed = 1; crc = v2_crc32(crc, b, sizeof b); } if (v2_fwrite_u32(f, crc ^ UINT32_MAX)) failed = 1; if (fclose(f)) failed = 1; return failed ? -1 : 0; } static int mesh_has_hanging_vertex(const FrameLensMesh *mesh) { for (size_t triangle = 0; triangle < mesh->triangle_count; ++triangle) for (size_t side = 0; side < 3; ++side) { const LensVertex *a = &mesh->vertices[mesh->triangles[triangle].vertex[side]]; const LensVertex *b = &mesh->vertices[mesh->triangles[triangle].vertex[(side + 1) % 3]]; const double dx = b->image_x - a->image_x; const double dy = b->image_y - a->image_y; const double length_squared = dx * dx + dy * dy; for (size_t vertex = 0; vertex < mesh->vertex_count; ++vertex) { if (vertex == mesh->triangles[triangle].vertex[side] || vertex == mesh->triangles[triangle].vertex[(side + 1) % 3]) continue; const LensVertex *p = &mesh->vertices[vertex]; const double px = p->image_x - a->image_x; const double py = p->image_y - a->image_y; const double cross = px * dy - py * dx; const double position = (px * dx + py * dy) / length_squared; if (fabs(cross) <= 1e-12 * length_squared && position > 1e-12 && position < 1.0 - 1e-12) return 1; } } return 0; } static int mesh_has_same_winding_shared_edge(const FrameLensMesh *mesh) { for (size_t left_triangle = 0; left_triangle < mesh->triangle_count; ++left_triangle) for (size_t left_side = 0; left_side < 3; ++left_side) { const size_t from = mesh->triangles[left_triangle].vertex[left_side]; const size_t to = mesh->triangles[left_triangle].vertex[(left_side + 1) % 3]; for (size_t right_triangle = left_triangle + 1; right_triangle < mesh->triangle_count; ++right_triangle) for (size_t right_side = 0; right_side < 3; ++right_side) { const size_t other_from = mesh->triangles[right_triangle].vertex[right_side]; const size_t other_to = mesh->triangles[right_triangle].vertex[(right_side + 1) % 3]; if ((from == other_from && to == other_to) || (from == other_to && to == other_from)) { if (from == other_from && to == other_to) return 1; } } } return 0; } static int review_probe_regressions(void) { RefinementConfig c = {.max_level=2, .min_edge_pixels=.5, .min_area_pixels2=.25, .angle_absolute_rad=3.14, .angle_relative=1e6, .retry_step_increment=10, .max_total_steps=100}; RayEndpoint flat = {.outcome=RAY_OUTCOME_ESCAPED, .frequency_ratio=1, .n_infinity={1,0,0}, .end_id=0}; for (int unresolved=0; unresolved<2; ++unresolved) { FrameLensMesh m={0}; if (frame_lens_mesh_build_coarse(&m,100,100,100,30)) return -1; for (size_t i=0;i= 100u || vertices[i].continuation_lookback_limit != 1.0) failed = 1; } const RefinementConfig retry = {.max_level = 0, .retry_step_increment = 0, .max_total_steps = 100, .retry_lookback_increment = 1.0, .max_total_lookback_time = 100.0}; if (!failed && frame_lens_mesh_prepare_generation(&m, &retry) != 3) failed = 1; for (size_t i = 0; i < m.sample_count && !failed; ++i) if (m.samples[i].kind != FRAME_SAMPLE_RETRY || m.samples[i].step_limit != 100u || m.samples[i].lookback_limit != 2.0) failed = 1; free(m.samples); free(m.probe_slots); } /* B. Translated time origins (positive, negative and zero) still detect the * lookback boundary with the integrator's own comparison and retry with a * strictly larger time region while preserving the step grant. */ for (int origin = 0; origin < 3 && !failed; ++origin) { const double t0 = origin == 0 ? 0.0 : origin == 1 ? 1.0e9 : -1.0e9; ObserverState o = observer_fixed_at_origin(); o.coordinate_time = t0; const GeodesicTraceConfig trace = frame_dp_config(0.3); MetricData metric; if (spacetime_eval(&source, t0, o.coordinate_position, &metric)) { failed = 1; break; } GeodesicRayState state; if (geodesic_initialize_past_ray_metric(&metric, &o, (double[]){1, 0, 0}, &state)) { failed = 1; break; } const RayEndpoint endpoint = geodesic_trace_past_from_state(&source, &state, &trace); if (endpoint.outcome != RAY_OUTCOME_UNRESOLVED || endpoint.accepted_step_limit != 100u || endpoint.accepted_steps != 1u) { failed = 1; break; } LensVertex vertices[3]; memset(vertices, 0, sizeof vertices); vertices[1].traced = vertices[2].traced = 1; vertices[1].outcome = vertices[2].outcome = RAY_OUTCOME_ESCAPED; vertices[1].n_infinity[0] = vertices[2].n_infinity[0] = 1.0; vertices[1].end_id = vertices[2].end_id = 0; LensTriangle triangle = {{0, 1, 2}, 0, 0, 0}; FrameLensMesh m = {.vertices = vertices, .vertex_count = 3, .triangles = &triangle, .triangle_count = 1}; const RefinementConfig plain = {.max_level = 0}; if (frame_lens_mesh_prepare_generation(&m, &plain) != 1 || frame_lens_mesh_install_sample(&m, 0, &endpoint) || vertices[0].continuation_limit != 100u || vertices[0].continuation_lookback_limit != 0.3) { free(m.samples); free(m.probe_slots); failed = 1; break; } free(m.samples); m.samples = NULL; m.sample_count = m.sample_capacity = 0; const RefinementConfig retry = {.max_level = 0, .retry_step_increment = 0, .max_total_steps = 100, .retry_lookback_increment = 0.3, .max_total_lookback_time = 10.0}; if (frame_lens_mesh_prepare_generation(&m, &retry) != 1 || m.samples[0].kind != FRAME_SAMPLE_RETRY || m.samples[0].step_limit != 100u || m.samples[0].lookback_limit != 0.6) failed = 1; free(m.samples); free(m.probe_slots); } /* C. A larger quota that does not move the left boundary (increment rounds * away, or a large time origin absorbs it) must not launch a retry. */ { LensVertex vertices[3] = { unresolved_vertex(0.0, -1.0e9, 0.0, 1, 100, 1.0e9), unresolved_vertex(10.0, -1.0e9, 0.0, 1, 100, 1.0e9), unresolved_vertex(0.0, -1.0e9, 0.0, 1, 100, 1.0e9)}; LensTriangle triangle; uuu_fixture(vertices, &triangle); FrameLensMesh m = {.vertices = vertices, .vertex_count = 3, .triangles = &triangle, .triangle_count = 1}; const RefinementConfig rounded = {.max_level = 0, .retry_step_increment = 0, .max_total_steps = 100, .retry_lookback_increment = 1.0e-8, .max_total_lookback_time = 2.0e9}; if (frame_lens_mesh_prepare_generation(&m, &rounded) != 0) failed = 1; FrameBoundaryStats stats; frame_lens_mesh_boundary_stats(&m, &rounded, &stats); if (stats.uuu != 1 || stats.budget_incomplete_triangles == 0) failed = 1; free(m.samples); free(m.probe_slots); } { const double start = 1.0e12; const double quota = 1.0e6; LensVertex vertices[3] = { unresolved_vertex(0.0, start - quota, start, 1, 100, quota), unresolved_vertex(10.0, start - quota, start, 1, 100, quota), unresolved_vertex(0.0, start - quota, start, 1, 100, quota)}; LensTriangle triangle; uuu_fixture(vertices, &triangle); FrameLensMesh m = {.vertices = vertices, .vertex_count = 3, .triangles = &triangle, .triangle_count = 1}; const RefinementConfig absorbed = {.max_level = 0, .retry_step_increment = 0, .max_total_steps = 100, .retry_lookback_increment = 1.0e-6, .max_total_lookback_time = 2.0e6}; if (frame_lens_mesh_prepare_generation(&m, &absorbed) != 0) failed = 1; free(m.samples); free(m.probe_slots); } spacetime_destroy(&source); return failed ? -1 : 0; } int main(void) { if (review_probe_regressions()) { fputs("probe persistence / retry invalidation regression failed\n",stderr); return 1; } if (review_retry_quota_regressions()) { fputs("independent retry quota regression failed\n", stderr); return 1; } if (review_real_grant_and_time_growth()) { fputs("real grant / representable time growth regression failed\n", stderr); return 1; } const int width = 100, height = 100; const double test_exposure = 1e-3; const double psf_relative_tail = 1e-8; const PointSpreadFunction psf = {.fwhm_pixels = 2.7, .moffat_beta = 4.5}; const GeodesicTraceConfig trace = {.coordinate_time_step = 0.25, .max_steps = 100}; const ObserverState observer = observer_fixed_at_origin(); Star star = { .direction = {0.0, 0.0, -1.0}, .temperature_K = 7000.0, .amplitude = 1.0}; StarCatalog catalog = {.stars = &star, .count = 1}; SpacetimeSource spacetime = {0}; FrameLensMesh mesh = {0}; double *hdr = calloc((size_t)width * height * 3, sizeof *hdr); int result = 1; if (blackbody_backend_init(NULL, 0, NAN, NAN, NULL, stderr) || hdr == NULL || spacetime_create_minkowski(&spacetime, 10.0) || frame_lens_mesh_build_coarse(&mesh, width, height, 20, 30.0) || frame_lens_mesh_trace(&mesh, &spacetime, &observer, &trace)) goto done; const size_t images = frame_splat_catalog(&mesh, &catalog, hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL); if (images != 1 || hdr[3 * (50 * width + 50)] <= 0.0) { fputs("flat-space inverse lens-map regression failed\n", stderr); goto done; } /* A finalized mesh can be persisted independently of spacetime and then * drive the exact same catalog inverse-map and PSF pass. */ const char *lens_map_path = "/tmp/opencode/gr_lens_map_test.grlens"; mesh.retry_requests = 2; /* cumulative per-frame retry accounting round-trips */ const LensMapFrame saved_frame = {.frame_id = 7, .coordinate_time = 3.0, .proper_time = 2.0, .mesh = mesh}; LensMap loaded_map = {0}; const LensMapProvenance provenance = {.threshold_kind = THRESHOLD_LOG_ALPHA_P0, .threshold_policy_version = 1, .threshold_value = 8.0, .retry_step_increment = 16, .max_total_steps = 64, .max_level = 2, .integrator = 0, .min_edge_pixels = 0.5, .min_area_pixels2 = 0.25, .coordinate_time_step = 0.1, .initial_max_steps = 4096}; double *roundtrip_hdr = calloc((size_t)width * height * 3, sizeof *roundtrip_hdr); if (roundtrip_hdr == NULL || lens_map_write(lens_map_path, width, height, 30.0, &provenance, &saved_frame, 1) || lens_map_read(lens_map_path, NULL, &loaded_map) || loaded_map.frame_count != 1 || loaded_map.frames[0].frame_id != 7 || loaded_map.width != width || loaded_map.height != height || loaded_map.provenance.threshold_kind != THRESHOLD_LOG_ALPHA_P0 || loaded_map.provenance.threshold_value != 8.0 || loaded_map.provenance.retry_step_increment != 16 || loaded_map.provenance.max_total_steps != 64 || loaded_map.provenance.max_level != 2 || loaded_map.provenance.coordinate_time_step != 0.1 || loaded_map.provenance.initial_max_steps != 4096 || loaded_map.frames[0].mesh.retry_requests != 2 || loaded_map.frames[0].mesh.vertex_count != mesh.vertex_count || frame_splat_catalog(&loaded_map.frames[0].mesh, &catalog, roundtrip_hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL) != images) { fputs("lens-map round-trip regression failed\n", stderr); free(roundtrip_hdr); lens_map_destroy(&loaded_map); unlink(lens_map_path); goto done; } for (int value = 0; value < width * height * 3; ++value) if (hdr[value] != roundtrip_hdr[value]) { fputs("lens-map round-trip HDR regression failed\n", stderr); free(roundtrip_hdr); lens_map_destroy(&loaded_map); unlink(lens_map_path); goto done; } free(roundtrip_hdr); lens_map_destroy(&loaded_map); /* A damaged payload must not be mistaken for a reusable physical map. */ FILE *damaged = fopen(lens_map_path, "r+b"); int damage_failed = damaged == NULL; if (!damage_failed) { if (fseek(damaged, -5L, SEEK_END)) damage_failed = 1; const int original = damage_failed ? EOF : fgetc(damaged); if (damage_failed || fseek(damaged, -5L, SEEK_END) || original == EOF || fputc(original ^ 0xff, damaged) == EOF) damage_failed = 1; } if (damaged != NULL && fclose(damaged)) damage_failed = 1; if (damage_failed || !lens_map_read(lens_map_path, NULL, &loaded_map)) { fputs("lens-map corruption rejection regression failed\n", stderr); lens_map_destroy(&loaded_map); unlink(lens_map_path); goto done; } unlink(lens_map_path); /* A version-1 header must be rejected outright: its captured bit cannot be * upgraded into the new dark/unresolved/error provenance. */ { const char *legacy_path = "/tmp/opencode/gr_lens_map_v1_test.grlens"; FILE *legacy = fopen(legacy_path, "wb"); int legacy_failed = legacy == NULL; if (!legacy_failed) { const unsigned char magic[8] = {'G', 'R', 'L', 'E', 'N', 'S', 1, 0}; const unsigned char header[32] = { 1, 0, 0, 0, /* version 1 */ 4, 3, 2, 1, /* endian 0x01020304 */ 8, 0, 0, 0, 8, 0, 0, 0, /* width, height */ 0, 0, 0, 0, 0, 0, 0, 0, /* fov */ 1, 0, 0, 0, 0, 0, 0, 0 /* frame_count 1 */ }; legacy_failed = fwrite(magic, 1, sizeof magic, legacy) != sizeof magic || fwrite(header, 1, sizeof header, legacy) != sizeof header; } if (legacy != NULL && fclose(legacy)) legacy_failed = 1; if (legacy_failed || !lens_map_read(legacy_path, NULL, &loaded_map)) { fputs("lens-map v1 rejection regression failed\n", stderr); lens_map_destroy(&loaded_map); unlink(legacy_path); goto done; } unlink(legacy_path); } memset(hdr, 0, (size_t)width * height * 3 * sizeof *hdr); PsfSplatStats min_y_stats = {0}; if (frame_splat_catalog(&mesh, &catalog, hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 1e300, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, &min_y_stats, NULL, NULL, NULL) != 1 || min_y_stats.discarded_below_min_y != 1 || hdr[3 * (50 * width + 50)] != 0.0) { fputs("PSF minimum-Y discard regression failed\n", stderr); goto done; } /* Private HDR accumulation must preserve the serial splat result. */ double *serial_hdr = calloc((size_t)width * height * 3, sizeof *serial_hdr); double *parallel_hdr = calloc((size_t)width * height * 3, sizeof *parallel_hdr); if (serial_hdr == NULL || parallel_hdr == NULL) { free(serial_hdr); free(parallel_hdr); goto done; } const int original_threads = omp_get_max_threads(); omp_set_dynamic(0); omp_set_num_threads(1); const size_t serial_images = frame_splat_catalog( &mesh, &catalog, serial_hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL); omp_set_num_threads(4); const size_t parallel_images = frame_splat_catalog( &mesh, &catalog, parallel_hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL); omp_set_num_threads(original_threads); for (int value = 0; value < width * height * 3; ++value) if (fabs(serial_hdr[value] - parallel_hdr[value]) > 1e-12 * fmax(1.0, fabs(serial_hdr[value]))) { fputs("parallel catalog splat regression failed\n", stderr); free(serial_hdr); free(parallel_hdr); goto done; } free(serial_hdr); free(parallel_hdr); if (serial_images != 1 || parallel_images != serial_images) { fputs("parallel catalog image-count regression failed\n", stderr); goto done; } const LinearRgb cool = blackbody_to_linear_rgb(3000.0); const LinearRgb hot = blackbody_to_linear_rgb(10000.0); if (!(cool.r > cool.b && hot.b > hot.r && hot.r + hot.g + hot.b > cool.r + cool.g + cool.b)) { fputs("blackbody spectral-color regression failed\n", stderr); goto done; } /* The Moffat is flux-normalized and retains a measurable, continuous wing * beyond the former Gaussian's 3-sigma raster box. */ memset(hdr, 0, (size_t)width * height * 3 * sizeof *hdr); splat_moffat(hdr, width, height, 50.5, 50.5, (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, psf_relative_tail, 0.0); double moffat_flux = 0.0; for (int pixel = 0; pixel < width * height; ++pixel) moffat_flux += hdr[3 * pixel]; if (fabs(moffat_flux - 1.0) > 0.01 || hdr[3 * (50 * width + 62)] <= 0.0) { fputs("Moffat normalization or wing regression failed\n", stderr); goto done; } /* The cache stores 4-point pixel-area integrals over a 64x64 sub-pixel * lattice. Compare its bilinear interpolation with the independent 8-point * direct reference at phases on both sides of a pixel boundary. */ PsfKernelCache cache = {0}; double *cached_hdr = calloc((size_t)width * height * 3, sizeof *cached_hdr); double *reference_hdr = calloc((size_t)width * height * 3, sizeof *reference_hdr); if (cached_hdr == NULL || reference_hdr == NULL || psf_kernel_cache_init(&cache, &psf, psf_relative_tail)) { free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); fputs("PSF cache construction regression failed\n", stderr); goto done; } PsfKernelCache loose_tail_cache = {0}; if (psf_kernel_cache_init(&loose_tail_cache, &psf, 1e-5) || loose_tail_cache.relative_tail_fraction != 1e-5 || loose_tail_cache.radius_pixels >= cache.radius_pixels) { fputs("PSF relative-tail cache-radius regression failed\n", stderr); psf_kernel_cache_destroy(&loose_tail_cache); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } psf_kernel_cache_destroy(&loose_tail_cache); /* This is the exact eligibility split that a future event sink exposes to * HIP: cache event, CPU direct fallback, or min-Y discard. */ PsfCachedEvent prepared = {0}; if (psf_prepare_cached_event(&prepared, 12.25, 14.75, (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, &cache, 1.0, psf_relative_tail, 0.0) != 0 || prepared.x != 12.25 || prepared.y != 14.75 || !(prepared.support_radius > 0.0) || psf_prepare_cached_event(&prepared, 12.25, 14.75, (LinearRgb){1.0, 1.0, 1.0}, 1000.0, &psf, &cache, 1.0, psf_relative_tail, 0.0) != 1 || psf_prepare_cached_event(&prepared, 12.25, 14.75, (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, &cache, 1.0, psf_relative_tail, 1.0) != 3) { fputs("PSF event eligibility regression failed\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } const double phases[][2] = {{0.01, 0.99}, {0.499, 0.501}, {0.999, 0.001}}; for (size_t phase = 0; phase < sizeof phases / sizeof *phases; ++phase) { memset(cached_hdr, 0, (size_t)width * height * 3 * sizeof *cached_hdr); memset(reference_hdr, 0, (size_t)width * height * 3 * sizeof *reference_hdr); if (splat_moffat_cached(cached_hdr, width, height, 50.0 + phases[phase][0], 50.0 + phases[phase][1], (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, &cache, 1.0, psf_relative_tail, 0.0) != 0) { fputs("ordinary PSF cache unexpectedly fell back\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } splat_moffat_direct(reference_hdr, width, height, 50.0 + phases[phase][0], 50.0 + phases[phase][1], (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, psf_relative_tail, 0.0); double peak = 0.0, max_error = 0.0; for (int value = 0; value < width * height * 3; ++value) { peak = fmax(peak, reference_hdr[value]); max_error = fmax(max_error, fabs(cached_hdr[value] - reference_hdr[value])); } if (peak <= 0.0 || max_error > 4e-5 * peak) { fputs("PSF cache interpolation accuracy regression failed\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } } if (splat_moffat_cached(cached_hdr, width, height, 50.5, 50.5, (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, &cache, 1.0, psf_relative_tail, 1.0) != 3) { fputs("PSF minimum-Y cached discard regression failed\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } /* A bright event must avoid a cached hard cutoff by selecting the direct * reference path when the requested support exceeds the cache. */ if (splat_moffat_cached(cached_hdr, width, height, 50.5, 50.5, (LinearRgb){1.0, 1.0, 1.0}, 1000.0, &psf, &cache, 1.0, psf_relative_tail, 0.0) != 1) { fputs("bright PSF direct-fallback regression failed\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } memset(cached_hdr, 0, (size_t)width * height * 3 * sizeof *cached_hdr); memset(reference_hdr, 0, (size_t)width * height * 3 * sizeof *reference_hdr); if (splat_moffat_cached(cached_hdr, width, height, 50.5, 50.5, (LinearRgb){1.0, 1.0, 1.0}, 1000.0, &psf, &cache, 1000.0, psf_relative_tail, 0.0) != 2) { fputs("bright PSF cached-wing-clipping regression failed\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } splat_moffat_direct(reference_hdr, width, height, 50.5, 50.5, (LinearRgb){1.0, 1.0, 1.0}, 1000.0, &psf, psf_relative_tail, 0.0); const size_t center = 3 * (50 * width + 50); if (cached_hdr[center] <= 0.0 || fabs(cached_hdr[center] - reference_hdr[center]) > 4e-5 * reference_hdr[center]) { fputs("cached-wing clipping changed the bright PSF core\n", stderr); free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); goto done; } free(cached_hdr); free(reference_hdr); psf_kernel_cache_destroy(&cache); /* Fast mode: a nearest deposit must reproduce the current pixel-integrated * Moffat at the snapped supersampled centre, preserve total flux, and honour * the min-Y discard rule; bilinear deposition must preserve the centroid. */ { int fast_ok = 1; const int supersample = 2; FastPsfAccumulator fast = {0}; FastPsfAccumulator bilinear = {0}; FastPsfAccumulator min_y_fast = {0}; FastPsfAccumulator accumulation = {0}; double *fast_hdr = calloc((size_t)width * height * 3, sizeof *fast_hdr); double *direct_hdr = calloc((size_t)width * height * 3, sizeof *direct_hdr); double *background_hdr = calloc((size_t)width * height * 3, sizeof *background_hdr); if (fast_hdr == NULL || direct_hdr == NULL || background_hdr == NULL || fast_psf_accumulator_init(&fast, width, height, supersample, FAST_PSF_DEPOSIT_NEAREST, &psf, psf_relative_tail, 0.0, 1) || fast_psf_accumulator_init(&bilinear, width, height, supersample, FAST_PSF_DEPOSIT_BILINEAR, &psf, psf_relative_tail, 0.0, 1) || fast_psf_accumulator_init(&min_y_fast, width, height, supersample, FAST_PSF_DEPOSIT_NEAREST, &psf, psf_relative_tail, 0.5, 1) || fast_psf_accumulator_init(&accumulation, width, height, supersample, FAST_PSF_DEPOSIT_NEAREST, &psf, psf_relative_tail, 0.0, 1)) { fputs("fast-mode accumulator construction regression failed\n", stderr); fast_ok = 0; goto fast_done; } /* (50.2, 50.2) snaps to supersampled cell 100, centre (100.5, 100.5) in * ss coordinates, i.e. final position (50.25, 50.25). */ if (fast_psf_accumulator_deposit(&fast, 50.2, 50.2, (LinearRgb){1.0, 1.0, 1.0}, 1.0) == 3 || fast_psf_accumulator_resolve(&fast, fast_hdr, 4)) { fputs("fast-mode nearest deposit regression failed\n", stderr); fast_ok = 0; goto fast_done; } splat_moffat_direct(direct_hdr, width, height, 50.25, 50.25, (LinearRgb){1.0, 1.0, 1.0}, 1.0, &psf, psf_relative_tail, 0.0); double peak = 0.0, max_error = 0.0, fast_flux = 0.0, direct_flux = 0.0; for (int value = 0; value < width * height * 3; ++value) { peak = fmax(peak, direct_hdr[value]); max_error = fmax(max_error, fabs(fast_hdr[value] - direct_hdr[value])); fast_flux += fast_hdr[value]; direct_flux += direct_hdr[value]; } if (!(peak > 0.0) || max_error > 1e-4 * peak || fabs(fast_flux - direct_flux) > 1e-4) { fputs("fast-mode nearest semantics regression failed\n", stderr); fast_ok = 0; goto fast_done; } /* Bilinear keeps the exact continuous centroid. */ memset(fast_hdr, 0, (size_t)width * height * 3 * sizeof *fast_hdr); if (fast_psf_accumulator_deposit(&bilinear, 50.37, 50.62, (LinearRgb){1.0, 1.0, 1.0}, 1.0) == 3 || fast_psf_accumulator_resolve(&bilinear, fast_hdr, 4)) { fputs("fast-mode bilinear deposit regression failed\n", stderr); fast_ok = 0; goto fast_done; } double weight_sum = 0.0, cx = 0.0, cy = 0.0; for (int row = 0; row < height; ++row) for (int column = 0; column < width; ++column) { const double weight = fast_hdr[3 * (row * width + column)]; weight_sum += weight; cx += weight * (column + 0.5); cy += weight * (row + 0.5); } if (!(weight_sum > 0.0) || hypot(cx / weight_sum - 50.37, cy / weight_sum - 50.62) > 1e-6) { fputs("fast-mode bilinear centroid regression failed\n", stderr); fast_ok = 0; goto fast_done; } /* The min-Y cutoff discards an event whose peak luminance is below it. */ if (fast_psf_accumulator_deposit(&fast, 10.5, 10.5, (LinearRgb){1.0, 1.0, 1.0}, 1.0) != 0 || fast_psf_accumulator_deposit(&min_y_fast, 10.5, 10.5, (LinearRgb){1.0, 1.0, 1.0}, 1.0) != 3) { fputs("fast-mode min-Y discard regression failed\n", stderr); fast_ok = 0; goto fast_done; } /* End-to-end plumbing through the frame splat path. */ memset(fast_hdr, 0, (size_t)width * height * 3 * sizeof *fast_hdr); PsfSplatStats fast_stats = {0}; const size_t fast_images = frame_splat_catalog( &mesh, &catalog, fast_hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, &fast_stats, NULL, &fast, NULL); if (fast_images != 1 || fast_stats.discarded_below_min_y != 0) { fputs("fast-mode frame splat regression failed\n", stderr); fast_ok = 0; goto fast_done; } /* HDR accumulation semantics: resolve must add onto an existing * background, not overwrite it. A prefilled buffer plus one deposit must * preserve the far-field background exactly and add the PSF core. */ for (int value = 0; value < width * height * 3; ++value) background_hdr[value] = 0.25; if (fast_psf_accumulator_deposit(&accumulation, 10.5, 10.5, (LinearRgb){1.0, 1.0, 1.0}, 1.0) == 3 || fast_psf_accumulator_resolve(&accumulation, background_hdr, 4)) { fputs("fast-mode HDR accumulation regression failed\n", stderr); fast_ok = 0; goto fast_done; } /* (90, 90) is far outside the kernel support of a star at (10.5, 10.5). */ if (background_hdr[3 * (90 * width + 90)] != 0.25) { fputs("fast-mode HDR accumulation lost the background\n", stderr); fast_ok = 0; goto fast_done; } if (!(background_hdr[3 * (10 * width + 10)] > 0.25)) { fputs("fast-mode HDR accumulation did not add the deposit\n", stderr); fast_ok = 0; goto fast_done; } fast_done: free(fast_hdr); free(direct_hdr); free(background_hdr); fast_psf_accumulator_destroy(&fast); fast_psf_accumulator_destroy(&bilinear); fast_psf_accumulator_destroy(&min_y_fast); fast_psf_accumulator_destroy(&accumulation); if (!fast_ok) goto done; } /* Diagnostic overlay draws the finalized mesh as an sRGB8 edge map: the * vertical coarse edge crossing (20, 10) must be painted, while an interior * pixel away from every edge must stay at the background value. */ { MeshOverlayLines overlay_lines = {0}; const MeshOverlaySettings overlay_settings = mesh_overlay_default_settings(); unsigned char *overlay_rgb = calloc((size_t)width * height * 3, 1); const int overlay_ok = overlay_rgb != NULL && mesh_overlay_prepare(&mesh, &overlay_lines) == 0 && overlay_lines.count != 0 && mesh_overlay_draw_rgb8(&overlay_lines, overlay_rgb, width, height, &overlay_settings) == 0 && overlay_rgb[3 * (10 * width + 20)] != 0 && overlay_rgb[3 * (12 * width + 5)] == 0; mesh_overlay_lines_destroy(&overlay_lines); free(overlay_rgb); if (!overlay_ok) { fputs("mesh diagnostic overlay regression failed\n", stderr); goto done; } } /* A fixed absolute edge tolerance used to make tiny source triangles claim * sources far outside their field. */ FrameLensMesh fine_mesh = {0}; Star fine_stars[2] = {{.direction = {0.0, 0.0, -1.0}, .temperature_K = 7000.0, .amplitude = 1.0}, {.direction = {0.01, 0.0, -0.9999499987499375}, .temperature_K = 7000.0, .amplitude = 1.0}}; StarCatalog fine_catalog = {.stars = fine_stars, .count = 2}; memset(hdr, 0, (size_t)width * height * 3 * sizeof *hdr); if (frame_lens_mesh_build_coarse(&fine_mesh, width, height, 1, 0.1) || frame_lens_mesh_trace(&fine_mesh, &spacetime, &observer, &trace) || frame_splat_catalog(&fine_mesh, &fine_catalog, hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL) != 1) { fputs("fine source-triangle containment regression failed\n", stderr); frame_lens_mesh_destroy(&fine_mesh); goto done; } frame_lens_mesh_destroy(&fine_mesh); /* Schwarzschild level-4/J=0.2 ring triangle: the old edge tolerance accepts * (1,0,0) although it is outside, producing unsigned weights summing to * 1.09608. Keep a genuine interior source after it to check that rejecting * one source does not discard subsequent stars. Exercise both parities. */ const double thin_directions[3][3] = { {0.99999998891116071, 0.00013431364716360775, 6.4323579270168807e-05}, {0.99999997228355786, -0.00021216644782556991, -0.00010206998544149922}, {0.9999927016945267, -0.0034455730513416835, -0.001650631403158936}}; LensVertex thin_vertices[3] = { {.image_x = 40, .image_y = 40, .outcome = RAY_OUTCOME_ESCAPED}, {.image_x = 48, .image_y = 40, .outcome = RAY_OUTCOME_ESCAPED}, {.image_x = 40, .image_y = 48, .outcome = RAY_OUTCOME_ESCAPED}}; LensTriangle thin_triangle = {.vertex = {0, 1, 2}}; FrameLensMesh thin_mesh = {.vertices = thin_vertices, .vertex_count = 3, .triangles = &thin_triangle, .triangle_count = 1}; Star thin_stars[2] = { {.direction = {1, 0, 0}, .temperature_K = 7000, .amplitude = 1}, {.temperature_K = 7000, .amplitude = 1}}; for (int i = 0; i < 3; ++i) { memcpy(thin_vertices[i].n_infinity, thin_directions[i], sizeof thin_directions[i]); memcpy(thin_vertices[i].camera_direction, thin_directions[i], sizeof thin_directions[i]); for (int axis = 0; axis < 3; ++axis) thin_stars[1].direction[axis] += thin_directions[i][axis]; } const double thin_norm = hypot(hypot(thin_stars[1].direction[0], thin_stars[1].direction[1]), thin_stars[1].direction[2]); for (int axis = 0; axis < 3; ++axis) thin_stars[1].direction[axis] /= thin_norm; StarCatalog thin_catalog = {.stars = thin_stars, .count = 2}; for (int parity = 0; parity < 2; ++parity) { thin_triangle.vertex[1] = parity ? 2 : 1; thin_triangle.vertex[2] = parity ? 1 : 2; memset(hdr, 0, (size_t)width * height * 3 * sizeof *hdr); if (frame_splat_catalog(&thin_mesh, &thin_catalog, hdr, width, height, test_exposure, &psf, NULL, 1.0, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL) != 1 || hdr[3 * (43 * width + 43)] <= 0.0) { fputs("thin source-triangle inverse-map regression failed\n", stderr); goto done; } } /* Refinement probes are temporary until their generation is complete. A * shared diagonal probe must produce one stable midpoint and conforming * children only after its endpoint has been installed. */ FrameLensMesh adaptive_mesh = {0}; RefinementConfig refine = {.max_level = 1, .angle_absolute_rad = 1e-4, .angle_relative = 1e-4, .jacobian_minimum = 1e-3, .min_edge_pixels = 1.0, .min_area_pixels2 = 1.0}; if (frame_lens_mesh_build_coarse(&adaptive_mesh, width, height, 100, 30.0)) goto done; for (size_t i = 0; i < adaptive_mesh.vertex_count; ++i) { adaptive_mesh.vertices[i].traced = 1; adaptive_mesh.vertices[i].outcome = RAY_OUTCOME_ESCAPED; adaptive_mesh.vertices[i].n_infinity[0] = 1.0; } if (frame_lens_mesh_prepare_generation(&adaptive_mesh, &refine) != 1) { fputs("adaptive shared-edge probe setup regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } const RayEndpoint bent_probe = {.n_infinity = {0.0, 1.0, 0.0}, .frequency_ratio = 1.0, .outcome = RAY_OUTCOME_ESCAPED}; if (frame_lens_mesh_install_sample(&adaptive_mesh, 0, &bent_probe) || frame_lens_mesh_finish_generation(&adaptive_mesh, &refine) != 1 || adaptive_mesh.vertex_count != 5 || adaptive_mesh.triangle_count != 4) { fputs("adaptive shared-edge split regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } frame_lens_mesh_destroy(&adaptive_mesh); /* A capture/escape discontinuity is a shadow boundary, not a smooth map * error: request all three midpoint rays and red-refine in one generation. */ if (frame_lens_mesh_build_coarse(&adaptive_mesh, width, height, 100, 30.0)) goto done; adaptive_mesh.triangle_count = 1; for (size_t i = 0; i < adaptive_mesh.vertex_count; ++i) { adaptive_mesh.vertices[i].traced = 1; adaptive_mesh.vertices[i].outcome = RAY_OUTCOME_ESCAPED; adaptive_mesh.vertices[i].n_infinity[0] = 1.0; } adaptive_mesh.vertices[0].outcome = RAY_OUTCOME_DARK; refine.max_level = 1; refine.angle_absolute_rad = 3.14159265358979323846; refine.angle_relative = 1e6; refine.jacobian_minimum = 1e-12; if (frame_lens_mesh_prepare_generation(&adaptive_mesh, &refine) != 3) { fputs("shadow-boundary red-probe setup regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } for (size_t i = 0; i < adaptive_mesh.sample_count; ++i) if (frame_lens_mesh_install_sample(&adaptive_mesh, i, &bent_probe)) { fputs("shadow-boundary red-probe installation regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } if (frame_lens_mesh_finish_generation(&adaptive_mesh, &refine) != 3 || adaptive_mesh.vertex_count != 7 || adaptive_mesh.triangle_count != 4) { fputs("shadow-boundary red-refinement regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } frame_lens_mesh_destroy(&adaptive_mesh); /* Two shadow leaves can force two edges of an escaped neighbour. That * neighbour must use a local three-child blue split, not create a third * requested edge that spreads red refinement farther outward. */ if (frame_lens_mesh_build_coarse(&adaptive_mesh, 200, 100, 100, 30.0)) goto done; adaptive_mesh.triangle_count = 3; for (size_t i = 0; i < adaptive_mesh.vertex_count; ++i) { adaptive_mesh.vertices[i].traced = 1; adaptive_mesh.vertices[i].outcome = RAY_OUTCOME_ESCAPED; adaptive_mesh.vertices[i].n_infinity[0] = 1.0; } adaptive_mesh.vertices[3].outcome = RAY_OUTCOME_DARK; adaptive_mesh.vertices[5].outcome = RAY_OUTCOME_DARK; if (frame_lens_mesh_prepare_generation(&adaptive_mesh, &refine) != 6) { fputs("shadow-boundary blue-neighbour probe setup regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } for (size_t i = 0; i < adaptive_mesh.sample_count; ++i) if (frame_lens_mesh_install_sample(&adaptive_mesh, i, &bent_probe)) { fputs("shadow-boundary blue-neighbour probe installation regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } if (frame_lens_mesh_finish_generation(&adaptive_mesh, &refine) != 6 || adaptive_mesh.vertex_count != 12 || adaptive_mesh.triangle_count != 11 || mesh_has_hanging_vertex(&adaptive_mesh) || mesh_has_same_winding_shared_edge(&adaptive_mesh)) { fputs("shadow-boundary blue-neighbour refinement regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } frame_lens_mesh_destroy(&adaptive_mesh); const RayEndpoint flat_probe = {.n_infinity = {1.0, 0.0, 0.0}, .frequency_ratio = 1.0, .outcome = RAY_OUTCOME_ESCAPED}; /* Opposite nonzero discrete-Jacobian signs on the two sides of the shared * diagonal require a sufficiently small magnitude before requesting it. */ refine.jacobian_minimum = 10.0; refine.angle_absolute_rad = 3.14159265358979323846; refine.angle_relative = 1e6; if (frame_lens_mesh_build_coarse(&adaptive_mesh, width, height, 100, 30.0)) goto done; const double source_directions[4][3] = { {1.0, 0.0, 0.0}, {sqrt(0.99), 0.0, 0.1}, {sqrt(0.99), 0.0, 0.1}, {sqrt(0.98), 0.1, 0.1}}; for (size_t i = 0; i < adaptive_mesh.vertex_count; ++i) { adaptive_mesh.vertices[i].traced = 1; adaptive_mesh.vertices[i].outcome = RAY_OUTCOME_ESCAPED; memcpy(adaptive_mesh.vertices[i].n_infinity, source_directions[i], sizeof source_directions[i]); } if (frame_lens_mesh_prepare_generation(&adaptive_mesh, &refine) != 1 || frame_lens_mesh_install_sample(&adaptive_mesh, 0, &flat_probe) || frame_lens_mesh_finish_generation(&adaptive_mesh, &refine) != 1 || adaptive_mesh.vertex_count != 5 || adaptive_mesh.triangle_count != 4) { fputs("adaptive fold-parity split regression failed\n", stderr); frame_lens_mesh_destroy(&adaptive_mesh); goto done; } frame_lens_mesh_destroy(&adaptive_mesh); /* E/D/U accounting. A UUU triangle must request one merged retry per * unresolved vertex with the next budget increment, and must not be * blackened. */ { LensVertex uuu_vertices[3] = { {.image_x = 0, .image_y = 0, .outcome = RAY_OUTCOME_UNRESOLVED, .traced = 1, .continuation_t = -1.0, .continuation_steps = 5, .continuation_limit = 5}, {.image_x = 10, .image_y = 0, .outcome = RAY_OUTCOME_UNRESOLVED, .traced = 1, .continuation_t = -1.0, .continuation_steps = 5, .continuation_limit = 5}, {.image_x = 0, .image_y = 10, .outcome = RAY_OUTCOME_UNRESOLVED, .traced = 1, .continuation_t = -1.0, .continuation_steps = 5, .continuation_limit = 5}}; for (int i = 0; i < 3; ++i) uuu_vertices[i].camera_direction[0] = 1.0; LensTriangle uuu_triangle = {{0, 1, 2}, 0, 0, 0}; FrameLensMesh uuu_mesh = {.vertices = uuu_vertices, .vertex_count = 3, .triangles = &uuu_triangle, .triangle_count = 1}; RefinementConfig uuu_config = {.max_level = 1, .angle_absolute_rad = 1.0, .angle_relative = 1.0, .jacobian_minimum = 1e-3, .min_edge_pixels = 1.0, .min_area_pixels2 = 1.0, .retry_step_increment = 10, .max_total_steps = 25}; if (frame_lens_mesh_prepare_generation(&uuu_mesh, &uuu_config) != 3) { fputs("UUU forced-retry regression failed\n", stderr); free(uuu_mesh.samples); free(uuu_mesh.probe_slots); goto done; } for (size_t i = 0; i < uuu_mesh.sample_count; ++i) { if (uuu_mesh.samples[i].kind != FRAME_SAMPLE_RETRY || uuu_mesh.samples[i].step_limit != 15) { fputs("UUU retry shape regression failed\n", stderr); free(uuu_mesh.samples); free(uuu_mesh.probe_slots); goto done; } } free(uuu_mesh.samples); free(uuu_mesh.probe_slots); } /* UUD/UDD is red-refined while the geometry can still support children. * At the geometric stop scale it becomes an approximate-black boundary * triangle while its shared U vertex keeps its unresolved outcome. */ { LensVertex ud_vertices[3] = { {.image_x = 0, .image_y = 0, .outcome = RAY_OUTCOME_UNRESOLVED, .traced = 1, .continuation_limit = 5}, {.image_x = 10, .image_y = 0, .outcome = RAY_OUTCOME_UNRESOLVED, .traced = 1, .continuation_limit = 5}, {.image_x = 0, .image_y = 10, .outcome = RAY_OUTCOME_DARK, .traced = 1}}; for (int i = 0; i < 3; ++i) ud_vertices[i].camera_direction[0] = 1.0; LensTriangle ud_triangle = {{0, 1, 2}, 0, 0, 0}; FrameLensMesh ud_mesh = {.vertices = ud_vertices, .vertex_count = 3, .triangles = &ud_triangle, .triangle_count = 1}; RefinementConfig red_config = {.max_level = 1, .angle_absolute_rad = 1.0, .angle_relative = 1.0, .jacobian_minimum = 1e-3, .min_edge_pixels = 0.5, .min_area_pixels2 = 0.5, .retry_step_increment = 10, .max_total_steps = 25}; if (frame_lens_mesh_prepare_generation(&ud_mesh, &red_config) != 3) { fputs("UUD red-refinement probe regression failed\n", stderr); free(ud_mesh.probe_slots); goto done; } for (size_t i = 0; i < ud_mesh.sample_count; ++i) if (ud_mesh.samples[i].kind != FRAME_SAMPLE_PROBE) { fputs("UUD red-refinement sample-kind regression failed\n", stderr); free(ud_mesh.probe_slots); goto done; } free(ud_mesh.samples); free(ud_mesh.probe_slots); ud_mesh.samples = NULL; ud_mesh.sample_count = ud_mesh.sample_capacity = 0; ud_mesh.probe_slots = NULL; ud_mesh.probe_slot_capacity = 0; RefinementConfig stop_config = red_config; stop_config.min_edge_pixels = 1e6; stop_config.min_area_pixels2 = 1e6; if (frame_lens_mesh_prepare_generation(&ud_mesh, &stop_config) != 0) { fputs("UUD stop-scale retry regression failed\n", stderr); free(ud_mesh.probe_slots); goto done; } FrameBoundaryStats ud_stats; frame_lens_mesh_boundary_stats(&ud_mesh, &stop_config, &ud_stats); if (ud_stats.uud_udd != 1 || ud_stats.approx_black_triangles != 1 || ud_stats.approx_black_area_pixels2 <= 0.0 || ud_stats.escaped_only != 0 || !ud_triangle.approx_black || ud_vertices[0].outcome != RAY_OUTCOME_UNRESOLVED) { fputs("UUD approximate-black regression failed\n", stderr); free(ud_mesh.probe_slots); goto done; } stop_config = red_config; stop_config.max_level = 0; frame_lens_mesh_boundary_stats(&ud_mesh, &stop_config, &ud_stats); if (ud_stats.approx_black_triangles != 1 || ud_stats.approx_black_level_stops != 1 || ud_stats.approx_black_max_edge_pixels < 10 || ud_stats.approx_black_area_pixels2 != 50) { fputs("max-level approximate-black provenance regression failed\n",stderr); goto done; } free(ud_mesh.probe_slots); } /* v3 DP54 round-trip: every adaptive/quota field and the per-vertex cost * counters must survive the wire exactly. */ { const char *dp_path = "/tmp/opencode/gr_lens_map_v3_dp_test.grlens"; LensVertex dv[3]; for (int i = 0; i < 3; ++i) dv[i] = (LensVertex){.image_x = (double)i, .image_y = 2.0, .camera_direction = {0.0, 0.0, -1.0}, .outcome = RAY_OUTCOME_DARK, .reason = RAY_REASON_REDSHIFT_LIMIT, .end_id = SPACETIME_END_NONE, .traced = 1}; /* An appended detail reason with its coherent outcome must survive the * frozen v3 schema exactly. */ dv[2].outcome = RAY_OUTCOME_INCOMPLETE; dv[2].reason = RAY_REASON_REJECTION_LIMIT; dv[0].trace_accepted_steps = 11; dv[0].trace_rejected_steps = 2; dv[0].trace_rhs_evaluations = 79; dv[1].trace_accepted_steps = 5; LensTriangle dt = {{0, 1, 2}, 1, 1, 0}; FrameLensMesh dm = {.vertices = dv, .triangles = &dt, .vertex_count = 3, .vertex_capacity = 3, .triangle_count = 1, .triangle_capacity = 1}; LensMapFrame df = {.frame_id = 3, .coordinate_time = 1.5, .proper_time = 1.25, .mesh = dm}; const LensMapProvenance dp = {.threshold_kind = THRESHOLD_LOG_ENERGY_GROWTH, .threshold_policy_version = 3, .threshold_value = 8.0, .retry_step_increment = 64, .max_total_steps = 256, .max_level = 2, .integrator = (uint32_t)GEODESIC_STEPPER_DP54, .min_edge_pixels = 0.5, .min_area_pixels2 = 0.25, .coordinate_time_step = 0.1, .initial_max_steps = 1024, .atol_x = 1e-9, .atol_Pi = 1e-9, .atol_L = 1e-9, .rtol = 1e-9, .min_step = 1e-12, .max_step = 2.0, .max_lookback_time = 102.4, .retry_lookback_increment = 102.4, .max_total_lookback_time = 409.6, .max_consecutive_rejections = 32}; LensMap dloaded = {0}; if (lens_map_write(dp_path, 4, 3, 30.0, &dp, &df, 1) || lens_map_read(dp_path, NULL, &dloaded)) { fputs("lens-map v3 DP54 round-trip regression failed\n", stderr); lens_map_destroy(&dloaded); unlink(dp_path); goto done; } const LensMapProvenance *lp = &dloaded.provenance; if (dloaded.file_version != 3 || lp->integrator != (uint32_t)GEODESIC_STEPPER_DP54 || lp->atol_x != 1e-9 || lp->atol_Pi != 1e-9 || lp->atol_L != 1e-9 || lp->rtol != 1e-9 || lp->min_step != 1e-12 || lp->max_step != 2.0 || lp->max_lookback_time != 102.4 || lp->retry_lookback_increment != 102.4 || lp->max_total_lookback_time != 409.6 || lp->max_consecutive_rejections != 32 || lp->retry_step_increment != 64 || lp->max_total_steps != 256 || lp->coordinate_time_step != 0.1 || lp->initial_max_steps != 1024 || dloaded.frames[0].mesh.vertices[0].trace_accepted_steps != 11 || dloaded.frames[0].mesh.vertices[0].trace_rejected_steps != 2 || dloaded.frames[0].mesh.vertices[0].trace_rhs_evaluations != 79 || dloaded.frames[0].mesh.vertices[1].trace_accepted_steps != 5 || dloaded.frames[0].mesh.vertices[2].outcome != RAY_OUTCOME_INCOMPLETE || dloaded.frames[0].mesh.vertices[2].reason != RAY_REASON_REJECTION_LIMIT || dloaded.frames[0].mesh.triangles[0].level != 1) { fputs("lens-map v3 DP54 field round-trip regression failed\n", stderr); lens_map_destroy(&dloaded); unlink(dp_path); goto done; } lens_map_destroy(&dloaded); /* Truncate within the first v3 vertex, including each terminal field. * Failed reads must reject the map and release its partially read mesh. */ { unsigned char prefix[316]; FILE *fixture = fopen(dp_path, "rb"); int fixture_failed = fixture == NULL || fread(prefix, 1, sizeof prefix, fixture) != sizeof prefix; if (fixture != NULL && fclose(fixture)) fixture_failed = 1; if (fixture_failed) { fputs("lens-map truncation fixture read failed\n", stderr); unlink(dp_path); goto done; } const size_t cuts[] = {232, 303, 304, 307, 308, 311, 312, 315}; for (size_t c = 0; c < sizeof cuts / sizeof cuts[0]; ++c) { FILE *short_file = fopen(dp_path, "wb"); int short_failed = short_file == NULL || fwrite(prefix, 1, cuts[c], short_file) != cuts[c]; if (short_file != NULL && fclose(short_file)) short_failed = 1; if (short_failed || !lens_map_read(dp_path, NULL, &dloaded) || dloaded.frames != NULL || dloaded.frame_count != 0) { fputs("lens-map truncated vertex rejection regression failed\n", stderr); lens_map_destroy(&dloaded); unlink(dp_path); goto done; } } } /* Unknown wire code and non-finite/out-of-bounds DP fields must be rejected * by the shared schema validator, not accepted as a usable map. */ { /* offset, is_double, double_value, u32_value */ const struct { long offset; int is_double; double dvalue; uint32_t uvalue; } corruptions[4] = {{68, 0, 0.0, 7u}, /* unknown integrator code */ {100, 1, NAN, 0u}, /* atol_x = NaN */ {108, 1, -1.0, 0u}, /* atol_Pi below zero */ {156, 1, -1.0, 0u}}; /* max_lookback below zero */ for (size_t c = 0; c < 4; ++c) { if (lens_map_write(dp_path, 4, 3, 30.0, &dp, &df, 1)) { fputs("lens-map v3 corruption fixture write failed\n", stderr); unlink(dp_path); goto done; } FILE *bad = fopen(dp_path, "r+b"); int bad_failed = bad == NULL || fseek(bad, corruptions[c].offset, SEEK_SET); if (!bad_failed) { if (corruptions[c].is_double) bad_failed = fwrite(&corruptions[c].dvalue, sizeof(double), 1, bad) != 1; else bad_failed = fwrite(&corruptions[c].uvalue, sizeof(uint32_t), 1, bad) != 1; } if (bad != NULL && fclose(bad)) bad_failed = 1; if (bad_failed || !lens_map_read(dp_path, NULL, &dloaded)) { fputs("lens-map v3 invalid DP54 field rejection regression failed\n", stderr); lens_map_destroy(&dloaded); unlink(dp_path); goto done; } lens_map_destroy(&dloaded); } } /* RAY_REASON_COUNT is a sentinel, never a valid wire reason: a map that * stores it (or anything above it) must be rejected rather than * reinterpreted. Vertex 0's reason field starts at byte 304 in this v3 * layout (176 provenance + 48 frame header + 80 vertex prefix). */ { if (lens_map_write(dp_path, 4, 3, 30.0, &dp, &df, 1)) { fputs("lens-map sentinel-reason fixture write failed\n", stderr); unlink(dp_path); goto done; } const uint32_t sentinel = (uint32_t)RAY_REASON_COUNT; FILE *bad = fopen(dp_path, "r+b"); int bad_failed = bad == NULL || fseek(bad, 304, SEEK_SET) || fwrite(&sentinel, sizeof sentinel, 1, bad) != 1; if (bad != NULL && fclose(bad)) bad_failed = 1; if (bad_failed || !lens_map_read(dp_path, NULL, &dloaded) || dloaded.frames != NULL || dloaded.frame_count != 0) { fputs("lens-map sentinel reason rejection regression failed\n", stderr); lens_map_destroy(&dloaded); unlink(dp_path); goto done; } lens_map_destroy(&dloaded); } /* The in-memory writer must also reject the sentinel; the wire test above * cannot isolate reason validation from the frame CRC. */ { const RayReason saved_reason = dv[2].reason; dv[2].reason = (RayReason)RAY_REASON_COUNT; const int rejected = lens_map_write(dp_path, 4, 3, 30.0, &dp, &df, 1) != 0; dv[2].reason = saved_reason; if (!rejected) { fputs("lens-map in-memory sentinel reason write regression failed\n", stderr); unlink(dp_path); goto done; } } unlink(dp_path); } /* Legacy v2 import: a real v2 map (no adaptive fields, no cost counters) * must load as RK4 with an explicit zero adaptive policy and render * identically to the live mesh. */ { const char *v2_path = "/tmp/opencode/gr_lens_map_v2_legacy_test.grlens"; const LensMapProvenance v2p = {.threshold_kind = THRESHOLD_LOG_ALPHA_P0, .threshold_policy_version = 1, .threshold_value = 8.0, .retry_step_increment = 16, .max_total_steps = 64, .max_level = 2, .integrator = (uint32_t)GEODESIC_STEPPER_RK4, .min_edge_pixels = 0.5, .min_area_pixels2 = 0.25, .coordinate_time_step = 0.1, .initial_max_steps = 4096}; const LensMapFrame v2f = {.frame_id = 7, .coordinate_time = 3.0, .proper_time = 2.0, .mesh = mesh}; LensMap v2loaded = {0}; double *v2_hdr = calloc((size_t)width * height * 3, sizeof *v2_hdr); double *live_hdr = calloc((size_t)width * height * 3, sizeof *live_hdr); if (v2_hdr == NULL || live_hdr == NULL || write_v2_lens_map(v2_path, width, height, 30.0, &v2p, &v2f) || lens_map_read(v2_path, NULL, &v2loaded) || v2loaded.file_version != 2 || v2loaded.provenance.integrator != (uint32_t)GEODESIC_STEPPER_RK4 || v2loaded.provenance.atol_x != 0.0 || v2loaded.provenance.max_lookback_time != 0.0 || v2loaded.provenance.max_total_lookback_time != 0.0 || v2loaded.provenance.max_consecutive_rejections != 0 || v2loaded.frames[0].mesh.vertices[0].trace_accepted_steps != 0 || v2loaded.frames[0].mesh.vertices[0].trace_rhs_evaluations != 0) { fputs("lens-map v2 legacy import regression failed\n", stderr); free(v2_hdr); free(live_hdr); lens_map_destroy(&v2loaded); unlink(v2_path); goto done; } const size_t live_images = frame_splat_catalog( &mesh, &catalog, live_hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL); const size_t v2_images = frame_splat_catalog( &v2loaded.frames[0].mesh, &catalog, v2_hdr, width, height, test_exposure, &psf, NULL, INFINITY, 1.0, psf_relative_tail, 0.0, 0, 1, FRAME_CATALOG_PREFETCH_FRAME, NULL, NULL, NULL, NULL, NULL); int render_equal = live_images == v2_images && live_images == images; for (int k = 0; render_equal && k < width * height * 3; ++k) if (live_hdr[k] != v2_hdr[k]) render_equal = 0; free(v2_hdr); free(live_hdr); lens_map_destroy(&v2loaded); unlink(v2_path); if (!render_equal) { fputs("lens-map v2 legacy render mismatch regression failed\n", stderr); goto done; } } result = 0; done: frame_lens_mesh_destroy(&mesh); spacetime_destroy(&spacetime); blackbody_backend_destroy(); free(hdr); return result; }