Replace the position capture cutoff with a camera-relative dark threshold shared by every backend, and carry explicit outcome/reason provenance through the ray, RayPool, adaptive mesh, lens-map and replay paths. - eval/eval_slab return SpacetimePointStatus; remove SPACETIME_RAY_CAPTURED and the Schwarzschild capture radius; decouple observer construction from ray position. - RayEndpoint stores RayOutcome/RayReason plus the last trusted state; budget exhaustion is retryable UNRESOLVED, data/integration failures are INCOMPLETE. - Normal dark terminal is L - L0 >= --dark-threshold (default 8), with L0 taken at the camera event and kept distinct from the worldtube entry energy; photon energy and frequency ratio are never reset. - Implement E/D/U triangle decisions with merged budget retries, persistent probe witnesses promoted in place by vertex identity, conformity settling, and approximate-black boundary provenance with achieved-scale statistics. - Add RayPool continuation state and per-ray step budgets. - Bump lens-map to v2 with explicit end/outcome/reason, approx_black, threshold/retry/geometry provenance and per-frame retry counts; reject v1. - Gate production output on incomplete/error results, overridable with --allow-incomplete. - Update AGENTS.md, the design document and usage docs; add the termination oracle and regression coverage. make -B -j4 BUILD_TYPE=Debug test passes with bit-identical reference HDRs.
100 lines
3.1 KiB
C
100 lines
3.1 KiB
C
#include "spacetime.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
typedef struct {
|
|
double escape_radius;
|
|
} MinkowskiContext;
|
|
|
|
static SpacetimePointStatus minkowski_eval(const SpacetimeSource *source,
|
|
double t, const double x[3],
|
|
MetricData *metric) {
|
|
(void)source;
|
|
(void)t;
|
|
(void)x;
|
|
*metric = (MetricData){
|
|
.alpha = 1.0,
|
|
.gamma = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}};
|
|
return SPACETIME_POINT_OK;
|
|
}
|
|
|
|
static SpacetimeRayStatus minkowski_classify(const SpacetimeSource *source,
|
|
double t, const double x[3]) {
|
|
const MinkowskiContext *context = source->context;
|
|
const double radius_squared = x[0] * x[0] + x[1] * x[1] + x[2] * x[2];
|
|
(void)t;
|
|
return radius_squared >= context->escape_radius * context->escape_radius
|
|
? SPACETIME_RAY_ESCAPED
|
|
: SPACETIME_RAY_ACTIVE;
|
|
}
|
|
|
|
static void minkowski_destroy(SpacetimeSource *source) {
|
|
free(source->context);
|
|
source->context = NULL;
|
|
source->ops = NULL;
|
|
}
|
|
|
|
static size_t minkowski_asymptotic_end_count(const SpacetimeSource *source) {
|
|
(void)source;
|
|
return 1;
|
|
}
|
|
|
|
static int minkowski_asymptotic_end(const SpacetimeSource *source,
|
|
size_t index, SpacetimeAsymptoticEnd *out) {
|
|
(void)source;
|
|
if (index != 0)
|
|
return -1;
|
|
*out = (SpacetimeAsymptoticEnd){
|
|
.end_id = 0,
|
|
.exterior_kind = ASYMPTOTIC_EXTERIOR_MINKOWSKI,
|
|
.mass = 0.0,
|
|
.frame_origin = {0.0, 0.0, 0.0},
|
|
.frame_axes = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}}};
|
|
return 0;
|
|
}
|
|
|
|
static int minkowski_escape_worldtube_sample(
|
|
const SpacetimeSource *source, SpacetimeEndId end_id, double t,
|
|
SpacetimeEscapeWorldtubeSample *out) {
|
|
const MinkowskiContext *context = source->context;
|
|
if (end_id != 0)
|
|
return -1;
|
|
*out = (SpacetimeEscapeWorldtubeSample){.center = {0.0, 0.0, 0.0},
|
|
.velocity = {0.0, 0.0, 0.0},
|
|
.radius = context->escape_radius,
|
|
.radius_rate = 0.0,
|
|
.velocity_constant = 1,
|
|
.valid = 1};
|
|
(void)t;
|
|
return 0;
|
|
}
|
|
|
|
static const SpacetimeOps minkowski_ops = {
|
|
.eval = minkowski_eval,
|
|
.classify = minkowski_classify,
|
|
.asymptotic_end_count = minkowski_asymptotic_end_count,
|
|
.asymptotic_end = minkowski_asymptotic_end,
|
|
.escape_worldtube_sample = minkowski_escape_worldtube_sample,
|
|
.destroy = minkowski_destroy,
|
|
};
|
|
|
|
int spacetime_create_minkowski(SpacetimeSource *source, double escape_radius) {
|
|
if (source == NULL || escape_radius <= 0.0)
|
|
return -1;
|
|
MinkowskiContext *context = malloc(sizeof *context);
|
|
if (context == NULL)
|
|
return -1;
|
|
context->escape_radius = escape_radius;
|
|
source->ops = &minkowski_ops;
|
|
source->context = context;
|
|
if (spacetime_source_finalize(source)) {
|
|
minkowski_destroy(source);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int spacetime_create_default(SpacetimeSource *source) {
|
|
return spacetime_create_minkowski(source, 1024.0);
|
|
}
|